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:
SashaGoncharov19 committed 2026-10-23 15:27:58 +04:00
commit 51d085e865
89 files changed
+7999

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
#include "map_header_bridge.h"
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
typedef struct {
const uint8_t *bytes;
size_t length, cursor;
uint64_t version[2];
unsigned reads;
size_t sizes[3];
} NativeReader;
_Static_assert(offsetof(NativeReader, version) == 24, "MapDeserialiser version offset");
extern void *factorio_map_header_original(void *, NativeReader *);
void native_map_header_read(NativeReader *reader, void *out, size_t length) {
assert(reader->reads < 3 && (length == 4 || length == 8));
assert(reader->cursor + length <= reader->length);
memcpy(out, reader->bytes + reader->cursor, length);
reader->cursor += length;
reader->sizes[reader->reads++] = length;
}
static uint64_t random_value(uint64_t *state) {
*state ^= *state << 13; *state ^= *state >> 7; *state ^= *state << 17; return *state;
}
int main(void) {
uint64_t seed = 0x123456789abcdef;
const uint64_t cutoff = UINT64_C(0x1000200000175);
for (unsigned test = 0; test < 20000; ++test) {
uint64_t packed = test < 4 ? cutoff + test - 1 : random_value(&seed);
if (test % 4 == 0) packed &= UINT64_C(0xffffffffffff);
uint64_t payload[3] = {random_value(&seed), random_value(&seed), random_value(&seed)};
if (test < 8) memset(payload, test & 1 ? 0xff : 0, sizeof(payload));
uint64_t original_payload[3]; memcpy(original_payload, payload, sizeof(payload));
uint8_t flag = (uint8_t)test;
NativeReader reader = {.bytes=(const uint8_t *)payload, .length=sizeof(payload), .version={packed,flag}};
uint8_t native[48]; memset(native, 0xa5, sizeof(native));
assert(factorio_map_header_original(native, &reader) == native);
assert(reader.reads == 3);
size_t field_size = packed > cutoff ? 8 : 4;
assert(reader.cursor == 3 * field_size);
for (unsigned i=0;i<3;++i) assert(reader.sizes[i] == field_size);
for (unsigned i=40;i<48;++i) assert(native[i] == 0xa5);
FactorioMapVersion version = {.major=packed>>48, .minor=packed>>32,
.patch=packed>>16, .build=packed, .flag=flag};
struct { uint64_t before; FactorioMapHeader header; uint64_t after; } output;
memset(&output, 0xa5, sizeof(output));
assert(factorio_map_header_parse((const uint8_t *)payload,sizeof(payload),version,&output.header)==0);
assert(output.before == UINT64_C(0xa5a5a5a5a5a5a5a5) && output.after == output.before);
assert(memcmp(output.header.tick_fields,native+16,24)==0);
assert(output.header.version.major==version.major && output.header.version.flag==flag);
assert(memcmp(payload,original_payload,sizeof(payload))==0);
if (test < 8) for (size_t length=0;length<3*field_size;++length) {
FactorioMapHeader before; memset(&before,0xa5,sizeof(before));
FactorioMapHeader result = before;
assert(factorio_map_header_parse((const uint8_t *)payload,length,version,&result)==1);
assert(memcmp(&before,&result,sizeof(result))==0);
}
}
puts("PASS: 20000 original ARM64 MapHeader comparisons, version branches, legacy sentinels, guards and short-stream failures");
return 0;
}