Repro
tmp=$(mktemp -d /tmp/goboscript-asset-ext-collision-XXXXXX)
printf 'costumes "same.png" as "png", "same.jpg" as "jpg";\n\n' > "$tmp/stage.gs"
printf '\x89PNG\r\n\x1a\n' > "$tmp/same.png"
cp "$tmp/same.png" "$tmp/same.jpg"
cargo run --quiet -- build "$tmp"
python3 - <<'PY' "$tmp/$(basename "$tmp").sb3"
import json, sys, zipfile
with zipfile.ZipFile(sys.argv[1]) as z:
names=sorted(z.namelist())
p=json.loads(z.read('project.json'))
print('zip', names)
print('md5exts', [c['md5ext'] for c in p['targets'][0]['costumes']])
print('missing', [c['md5ext'] for c in p['targets'][0]['costumes'] if c['md5ext'] not in names])
PY
Observed:
zip ['e9dd2797018cad79186e03e8c5aec8dc.jpg', 'project.json']
md5exts ['e9dd2797018cad79186e03e8c5aec8dc.png', 'e9dd2797018cad79186e03e8c5aec8dc.jpg']
missing ['e9dd2797018cad79186e03e8c5aec8dc.png']
The build succeeds, but project.json references hash.png and the zip only contains hash.jpg.
AssetObjectStore::assets() de-duplicates by hash only, while Scratch asset filenames are hash.extension. Same content with different allowed extensions needs both files, or all references must use the one emitted md5ext.
Expected
Every md5ext referenced by project.json should exist in the .sb3 archive after a successful build.
Repro
Observed:
The build succeeds, but
project.jsonreferenceshash.pngand the zip only containshash.jpg.AssetObjectStore::assets()de-duplicates by hash only, while Scratch asset filenames arehash.extension. Same content with different allowed extensions needs both files, or all references must use the one emittedmd5ext.Expected
Every
md5extreferenced byproject.jsonshould exist in the.sb3archive after a successful build.