| … | … | @@ -313,12 +313,25 @@ static func _canon(v: Variant) -> Variant: |
| 313 | 313 | return v |
| 314 | 314 | |
| 315 | 315 | |
| 316 | | ## The blob's name: SHA-256, hex. |
| 316 | ## The blob's name = the CONTENT OVERLAY's hash of its bytes (hyper-overlay v2's streaming |
| 317 | ## chunk-tree hash, cdc::StreamingHasher — NOT a plain SHA-256): a placement names its blob |
| 318 | ## by this, and a peer fetches it with ContentOverlay.request(hash), so it must be the |
| 319 | ## overlay's own name. The overlay hashes files, so the bytes go through a scratch file. |
| 320 | ## "" when the overlay is not loaded: no name rather than one nobody can fetch. |
| 317 | 321 | static func hash_of(bytes: PackedByteArray) -> String: |
| 318 | | var h := HashingContext.new() |
| 319 | | h.start(HashingContext.HASH_SHA256) |
| 320 | | h.update(bytes) |
| 321 | | return h.finish().hex_encode() |
| 322 | var co: Node = (Engine.get_main_loop() as SceneTree).root.get_node_or_null("ContentOverlay") |
| 323 | if co == null: |
| 324 | return "" |
| 325 | var tmp := "user://content/.asset_hash.tmp" |
| 326 | DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path("user://content")) |
| 327 | var f := FileAccess.open(tmp, FileAccess.WRITE) |
| 328 | if f == null: |
| 329 | return "" |
| 330 | f.store_buffer(bytes) |
| 331 | f.close() |
| 332 | var h := String(co.content_hash_of_file(tmp)) |
| 333 | DirAccess.remove_absolute(ProjectSettings.globalize_path(tmp)) |
| 334 | return h |
| 322 | 335 | |
| 323 | 336 | |
| 324 | 337 | ## Read a blob — FROM ANOTHER PEER, so nothing is trusted: no Objects (bytes_to_var's |