Native iPhone port of Factorio 2.0.77
Run the original macOS ARM64 game code on iOS: - tools/retarget.py: header-only Mach-O retargeting to an iOS dylib - platform/native: UIKit host and macOS API shims (AppKit for SDL's Cocoa backend, CoreGraphics displays, CoreAudio device, Metal device properties, Wuffs PNG decoding, Steam and peripheral stubs) - touch, overlay, iOS keyboard and hardware keyboard input - tools/build_native.py: build, sign, install, data copy, launch - docs: build guide, controls, architecture Also includes the earlier static-translation research (ARM64 -> WASM -> native) under docs/research, runtime/, tests/ and tools/. No game files are included; the build reads them from a local install.
This commit is contained in:
commit
51d085e865
89 files changed
+7999
No files matched your search
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Statically compile the original MapVersion constructor and its declared I/O adapter."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import struct
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from a64_lift import Compiler
|
||||
from lift_rng import arm64_image, file_range
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
ADDRESS, SIZE = 0x10150BF28, 192
|
||||
EXPECTED = 'b9254262cde89c9e79a9fdf6d700860ff9fd623d53c576efaf431600096c8a9b'
|
||||
READ = 0x10035E264
|
||||
|
||||
|
||||
def run(*args):
|
||||
print('+', ' '.join(map(str, args)), flush=True)
|
||||
subprocess.run(list(map(str, args)), cwd=ROOT, check=True)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('binary', type=Path)
|
||||
args = parser.parse_args()
|
||||
image, slice_offset = arm64_image(args.binary.read_bytes())
|
||||
offset = file_range(image, ADDRESS, SIZE)
|
||||
body = image[offset:offset + SIZE]
|
||||
if hashlib.sha256(body).hexdigest() != EXPECTED:
|
||||
raise ValueError('Unrecognized MapVersion constructor bytes')
|
||||
compiler = Compiler({READ: 'read_or_throw'})
|
||||
wat = compiler.compile(body, ADDRESS)
|
||||
out = ROOT / 'build/version'
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
(out / 'factorio_version.wat').write_text(wat)
|
||||
manifest = {'symbol': 'MapVersion::MapVersion(Deserialiser&)', 'address': hex(ADDRESS),
|
||||
'source_file_offset': slice_offset + offset, 'bytes': SIZE, 'sha256': EXPECTED,
|
||||
'instructions': compiler.instructions, 'host_calls': compiler.calls,
|
||||
'scope': 'automatic straight-line integer lift; host read errors return status rather than C++ exceptions'}
|
||||
(out / 'manifest.json').write_text(json.dumps(manifest, indent=2) + '\n')
|
||||
assembly = ['.text', '.p2align 2', '.globl _factorio_version_original', '_factorio_version_original:']
|
||||
for (word,) in struct.iter_unpack('<I', body):
|
||||
assembly.append(' bl _native_version_read' if word & 0xfc000000 == 0x94000000 else f' .long 0x{word:08x}')
|
||||
(out / 'oracle.S').write_text('\n'.join(assembly) + '\n')
|
||||
run(ROOT / 'build/wabt/wat2wasm', out / 'factorio_version.wat', '-o', out / 'factorio_version.wasm')
|
||||
run(ROOT / 'build/wabt/wasm2c', out / 'factorio_version.wasm', '-o', out / 'factorio_version.c', '--module-name=factorio_version')
|
||||
includes = ['-I' + str(out), '-I' + str(ROOT / 'runtime'), '-I' + str(ROOT / 'third_party/wabt/wasm2c')]
|
||||
flags = ['-O2', '-DWASM_RT_USE_MMAP=0', '-DWASM_RT_MEMCHECK_BOUNDS_CHECK=1']
|
||||
sources = [out / 'factorio_version.c', ROOT / 'runtime/version_bridge.c', ROOT / 'runtime/save_header.c']
|
||||
runtime = [ROOT / 'third_party/wabt/wasm2c' / x for x in ['wasm-rt-impl.c', 'wasm-rt-mem-impl.c']]
|
||||
run('xcrun', 'clang', *flags, *includes, *sources, *runtime, out / 'oracle.S',
|
||||
ROOT / 'tests/version_equivalence.c', '-lz', '-o', out / 'verify_version')
|
||||
run(out / 'verify_version')
|
||||
run('xcrun', 'clang', *flags, *includes, *sources, *runtime, ROOT / 'tests/save_probe.c',
|
||||
'-lz', '-o', out / 'save_probe')
|
||||
sdk = subprocess.check_output(['xcrun', '--sdk', 'iphoneos', '--show-sdk-path'], text=True).strip()
|
||||
objects = []
|
||||
for source in sources:
|
||||
obj = out / (source.stem + '.ios.o')
|
||||
run('xcrun', '--sdk', 'iphoneos', 'clang', '-target', 'arm64-apple-ios15.0', '-isysroot', sdk,
|
||||
*flags, *includes, '-c', source, '-o', obj)
|
||||
objects.append(obj)
|
||||
run('xcrun', 'libtool', '-static', '-o', out / 'libfactorio_version_ios.a', *objects)
|
||||
(out / 'verification.json').write_text(json.dumps({'status': 'pass', 'native_comparisons': 20000,
|
||||
'instruction_count': len(compiler.instructions), 'host_calls': len(compiler.calls),
|
||||
'scope': 'MapVersion constructor success path; stream errors use a host status adapter',
|
||||
'whole_map_loading': False}, indent=2) + '\n')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in new issue
Block a user