Restore native inference, card-bound readings and paged dialogue. Provide manual, checksum-verified model setup instead of Git LFS so source checkouts work without uploading multi-gigabyte weights. The game stays offline; complete release archives still bundle the model.
52 lines
2.5 KiB
Python
52 lines
2.5 KiB
Python
"""Create a self-contained ZIP64 release, including the offline model."""
|
|
from pathlib import Path
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import zipfile
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
def sha(path):
|
|
with path.open('rb') as source:
|
|
return hashlib.file_digest(source, 'sha256').hexdigest()
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--check-only', action='store_true')
|
|
args = parser.parse_args()
|
|
manifest = json.loads((ROOT / 'ai/model.json').read_text('utf8'))
|
|
model = ROOT / 'ai' / manifest['file']
|
|
assert model.stat().st_size == manifest['bytes']
|
|
assert sha(model) == manifest['sha256']
|
|
game = ROOT / 'bin/poker.exe'
|
|
assert b'ai\\fortune-engine.exe' in game.read_bytes(), 'game must include the native AI integration'
|
|
assert sha(game) == sha(ROOT / 'poker.exe') == sha(ROOT / 'build/graphics/poker.exe')
|
|
assert sha(game).upper() in (ROOT / 'build/AssemblerCasinoLauncher.cs').read_text('utf8')
|
|
files = [(ROOT / 'dist/Assembler Casino.exe', 'Assembler Casino.exe'),
|
|
(game, 'bin/poker.exe')]
|
|
files += [(p, p.relative_to(ROOT).as_posix()) for p in sorted((ROOT / 'assets').rglob('*')) if p.is_file()]
|
|
files += [(p, p.relative_to(ROOT).as_posix()) for p in sorted((ROOT / 'ai').rglob('*'))
|
|
if p.is_file() and p.suffix != '.part' and not p.name.endswith('.download.lock')]
|
|
assert (ROOT / 'ai/fortune-engine.exe', 'ai/fortune-engine.exe') in files
|
|
assert (ROOT / 'ai/licenses/Qwen.txt', 'ai/licenses/Qwen.txt') in files
|
|
assert (ROOT / 'ai/licenses/llama.cpp.txt', 'ai/licenses/llama.cpp.txt') in files
|
|
if args.check_only:
|
|
print(f'PASS: complete offline bundle, pinned model hash, matching game and launcher; {len(files)} files')
|
|
return
|
|
output = ROOT / 'dist/Assembler Casino Offline.zip'
|
|
with zipfile.ZipFile(output, 'w', compression=zipfile.ZIP_DEFLATED, compresslevel=1, allowZip64=True) as archive:
|
|
for path, name in files:
|
|
archive.write(path, name, compress_type=zipfile.ZIP_STORED if path == model else zipfile.ZIP_DEFLATED)
|
|
with zipfile.ZipFile(output) as archive:
|
|
entry = archive.getinfo('ai/' + manifest['file'])
|
|
assert entry.file_size == manifest['bytes']
|
|
assert len(archive.infolist()) == len(files)
|
|
assert archive.testzip() is None, 'release archive failed its CRC check'
|
|
print(f'Created self-contained ZIP64 bundle: {output} ({output.stat().st_size / 1e9:.2f} GB)')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|