If you have not purchased the game yet, please visit Steam and experience this unique and truly wonderful game! You can also visit its official website.
English | 简体中文
This repository documents a private technical study that reconstructed a maintainable Unity project from a legally owned Steam macOS copy of A Short Hike, restored its desktop baseline, and adapted it for a personal iPhone. Device validation was completed on 18 July 2026. The final local Unity-generated Xcode export is:
build/ios-xcode-20260718-114718
It contains the final Release project used for signing, installation, startup-logo correction, and device validation, and is intentionally ignored by Git.
| Item | Value |
|---|---|
| Game version used for research | 1.10.2, legally owned Steam macOS copy |
| Original Unity version | 2021.3.27f1 (ca3ffb99bcc6) |
| Reconstruction Unity version | 2021.3.27f1 |
| Original scripting backend | Mono |
| iOS scripting backend | IL2CPP |
| iOS architecture | ARM64 |
| Graphics | Built-in Render Pipeline, Metal on iOS |
| Orientation | Landscape left/right |
| Managed stripping | Low, with targeted preservation |
| Example bundle ID | com.example.AShortHikeResearch |
| Final Xcode configuration | Release, automatic personal-team signing |
| Target device used for validation | iPhone 16 Pro |
This is a research record, not a source release or distributable iOS port. You must own the game and obtain every input from your own installation. Game binaries, decompiled source, Unity assets/projects, localization files, saves, Xcode exports, and built applications are excluded by a default-deny .gitignore; a fresh clone is intentionally not buildable on its own. Only documentation, generic automation, audit helpers, and the user-supplied README image are eligible for tracking. Do not bypass these rules with git add -f. All game and third-party rights remain with their respective owners.
The first phase was strictly read-only. The Steam app was inspected in place and no file under it was modified.
Confirmed facts included:
- Unity 2021.3.27f1 and player version 1.10.2;
- a native Universal macOS player containing both
x86_64andarm64slices; - Mono, not IL2CPP, proven by
MonoBleedingEdge, the native Mono runtime and readable managed assemblies; - 121 managed DLLs, with
Assembly-CSharp.dllholding 984 type definitions and 5,932 method definitions; - six serialized levels corresponding to Logo, Title, Game, Credits, Test and Island scenes;
- two macOS-only native plugins: Steam API and InControl Native;
- 37 macOS Addressables AssetBundles in StreamingAssets;
- Built-in Render Pipeline evidence, legacy Image Effects, Terrain rendering, and at least 32 named custom shaders;
- a legacy
BinaryFormattersave graph tied to full type names and private serialized field names.
A file list and SHA-256 manifest were generated locally to make every subsequent copy auditable. Those manifests remain private because they describe the copyrighted installation.
To reproduce the staged workflow with a coding agent, begin with the English project prompt.
The host was checked before any extraction. The final workflow used:
- Unity Hub and Unity 2021.3.27f1;
- Unity iOS Build Support and its bundled IL2CPP toolchain;
- Xcode and the iPhoneOS SDK;
- a stable .NET SDK and
ilspycmd; - AssetRipper 1.3.14 Free for macOS arm64;
- Python 3 for independent asset, material, texture and report audits;
- standard macOS tools such as
file,lipo,otool,codesign,plutil,shasum,xcrun, andxcodebuild.
Large software was never silently installed. Analysis-tool installation was separated from AssetRipper selection, and potentially destructive scripts defaulted to dry-run or required explicit confirmation.
The entire managed directory was copied twice:
- an immutable
managed-originalcopy for hash verification; - a
managed-workingcopy for analysis tools.
The copies were checked against the original manifest before use. Assembly-CSharp.dll was decompiled with ILSpy project mode without renaming namespaces, types, nested types, fields, methods, or serialization identities.
Results:
- ILSpy completed with exit code 0;
- no method failed to decompile;
- no obvious obfuscation was detected;
- async state machines, iterators and compiler-generated closure types remained inspectable;
- four existing
NotImplementedExceptionbodies were identified as original assembly behavior rather than decompiler failures; - platform APIs, reflection, P/Invoke, Steam, Sony, input, save and Addressables use were indexed separately.
The decompiled output is not equivalent to the original authoring source: comments, formatting, local names, conditional-compilation history, some high-level syntax choices and original project structure cannot be recovered from a player assembly.
The save format was treated as a compatibility contract rather than rewritten.
The recovered game stores GameSaveNew*.mountain under Application.persistentDataPath using BinaryFormatter. The object graph depends on:
- exact assembly-qualified type identities;
- exact serialized field names, including private fields;
- a custom
SerializationBinder; Vector3andQuaternionserialization surrogates;- backup rotation using a sibling
_backupfile; - version/default-value behavior inside the reconstructed data graph.
Therefore the port preserved type names, namespaces, field names, inheritance and object layout. Renaming for style or replacing the format during reconstruction would have broken compatibility. IL2CPP/linker preservation was added only where evidence required it, and read/write/backup/position restoration was later tested on desktop and on the iPhone.
AssetRipper was selected deliberately instead of downloading an arbitrary latest build. Version 1.3.14 Free for macOS arm64 was chosen from the official release after checking Unity 2021.3 support, project export, MonoBehaviour metadata handling, local execution and licensing.
The tool read the private Data directory, including global managers, six level files, shared assets, resources, StreamingAssets and the 37 Addressables bundles. The observed export completed 2,063/2,063 items with no logged error or warning category.
Quantitative highlights:
- all six scenes exported as readable Unity YAML;
- 3,376 script references were resolvable inside the export snapshot;
- explicit Missing Script count was zero;
- 73 Shader assets were exported;
- 346 compact Addressables runtime entries and all 37 bundles were readable.
Important limitations were recorded rather than hidden:
- the original source
.metafiles were not present, so source-project GUID equality cannot be proven; - original Prefab authoring boundaries may be flattened or reconstructed heuristically;
- all 73 exported Shader files were AssetRipper dummy representations, not original ShaderLab/HLSL;
- runtime catalogs and dependencies were recoverable, but original Addressables groups, schemas, labels, profiles and authoring settings were not.
The AssetRipper export remained immutable. A separate copy became the reconstruction input.
A new project was created under unity-project/AShortHike and pinned to Unity 2021.3.27f1. The objective was desktop correctness before any iOS change.
The work included:
- importing the isolated AssetRipper snapshot;
- integrating the ILSpy project while preserving Unity serialization identities;
- rebuilding assembly/package boundaries;
- adding compatible official Unity packages such as Input System, Cinemachine, 2D Pixel Perfect, TextMeshPro and Addressables where required;
- preserving or explicitly rebinding script GUID/fileID relationships;
- excluding Editor-only and console-only assemblies from normal runtime builds;
- reconstructing a minimal equivalent local runtime-loading layout where original Addressables authoring data no longer existed;
- repairing exported audio headers and local runtime asset paths without altering the source snapshot.
Every compile-error class was handled separately. Game types and serialized fields were not bulk-deleted or renamed merely to obtain a green compiler.
The reconstructed project first reached a macOS Mono baseline:
- TitleScene and main menu;
- new game and GameScene;
- movement, jumping, gliding and climbing;
- dialogue and scene loading;
- pause, Save and Quit, automatic backup and Continue;
- exact position restoration;
- audio and physical DualSense input;
- safe behavior when Steam was unavailable.
Visual recovery became the largest manual task because exported shaders were placeholders. Fixes were made one attributable shader/material path at a time, with before/after evidence and rollback backups. The work restored or reconstructed the semantics of:
- the legacy
Hidden/EdgeDetectmulti-pass image effect; - title TextMeshPro font assets, atlases and material bindings;
- color correction and screen gradients;
- terrain axis/triplanar and baked terrain attribution;
- water, buoy, clouds, trees, billboards, wire, stencil, fades, aura and transparency paths;
- projector shadows, world-detail shaders and vertex-color materials;
- texture/material bindings that AssetRipper had assigned incorrectly;
- startup/title composition and pause-menu background behavior.
Broad workarounds such as disabling all post-processing or replacing every material with Standard Shader were intentionally rejected. The final six-scene audit reported zero Missing Scripts, and the previously observed tree soft-occlusion and convex-hull Editor warnings were addressed without changing gameplay.
| Check | Result |
|---|---|
| Scene coverage | 6 scenes and 7,096 scene objects |
| Prefab coverage | 87 Prefabs and 296 Prefab objects |
| Camera captures | 29/29 succeeded across 16 cameras |
| Serialized integrity | 0 Missing Scripts, missing references, null material slots, or unsupported production Shaders |
| Resource parity | 390/390 Materials, 232/232 animations, and 6/6 fonts matched the recovery baseline |
Two subtle AssetRipper artifacts were isolated rather than suppressed. The tree warning came from missing Unity billboard dependency declarations; the repair retained the recovered Shader GUIDs and pass layout. The convex-hull warning came from stale m_MeshUsageFlags: 8 metadata on an exported Mesh; clearing that invalid role and assigning a measured dedicated collider removed the warning. After both repairs, all 29 visual captures remained byte-identical to the pre-fix baseline.
Desktop-specific behavior was centralized behind small services instead of spreading platform directives across gameplay code:
IPlatformServices;IAchievementService;ICloudSaveService;IInputBackend;IPlatformUserService.
The resulting backends were:
- Steam services for macOS Editor/Standalone;
- iOS services using local/null platform features for this research build;
- a safe null backend for unsupported environments.
Steam initialization, Overlay, achievements, cloud and native input remain excluded on iOS. Sony NP and PS4 save assemblies are excluded from Editor and iOS. The macOS Steam and InControl native bundles never enter the iOS build. Game Center and iCloud were deliberately not claimed as implemented.
The original InControl semantics were preserved while adding a managed Unity Input System bridge suitable for iOS controllers.
The input pass covered:
- Xbox, PlayStation and MFi-style controller mappings;
- attach, detach and reconnect;
- original movement/action/menu semantics;
- an inset safe-area-aware left virtual stick;
- a diamond ABXY layout;
- controlled opacity for stick, background and action buttons;
- an invisible right-half drag area for camera look, excluding action buttons;
- multi-touch ownership and lifecycle cleanup;
- automatic hiding of virtual controls while a physical controller is connected and restoration after disconnect.
A DualSense was later identified on the physical iPhone as a PlayStation 5 controller. Controller-hidden touch UI, reconnect behavior and the managed input path were validated on device.
Only after the desktop baseline was stable was the active target changed to iOS.
The final engineering choices included:
- IL2CPP and ARM64;
- Metal and landscape orientation;
- Managed Stripping Level Low rather than disabling stripping globally;
- targeted
link.xml/preservation for reflection and serialization paths; - no dynamic assembly generation or unsupported native plugin linkage;
- platform guards for Steam, Sony and macOS APIs;
- Resources-based runtime fallbacks for content that existed only in macOS Addressables bundles;
- retention of the original save object graph and backup behavior.
Simplified Chinese was imported locally from the owner's installation and remained private. The port built local Chinese and Japanese font/TMP fallbacks for IL2CPP so glyphs were not stripped or missing on device. The menu language label was intentionally shown as lowercase chinese, while the internal compatibility key remained Chinese.
Unity exported an Xcode project with:
- an owner-supplied bundle identifier such as
com.example.AShortHikeResearch; - ARM64, IL2CPP and Metal;
- landscape left/right;
- automatic signing using the owner's Apple developer account;
- the legally owned app icon converted locally from the Steam app's
PlayerIcon.icnsinto the complete iOS AppIcon set; - high-refresh support through
CADisableMinimumFrameDurationOnPhone; - no Steam/Sony/macOS native libraries.
Early builds used Development Build and debugging to collect IL2CPP, linker, launch, shader and lifecycle evidence. The final exporter disabled Development Build and script debugging, and the Xcode configuration was changed to Release. The final runtime console identified itself as Unity 2021.3.27f1, Build type Release, Scripting Backend IL2CPP.
The first physical-device blocker was a black screen caused by the generated iOS application/window-scene lifecycle on the target OS. A minimal scene-delegate bridge restored Unity foreground activation and rendering. Subsequent device work verified the user-visible result and collected targeted logs.
Final device behavior included:
- startup, restored colored logo sequence, title and main menu;
- Chinese and Japanese glyph rendering;
- new game, touch controls and camera look;
- physical controller attach/detach with touch UI visibility switching;
- save, backup, Continue and exact-position restoration;
- foreground/background transitions and background autosave;
- full-width world rendering while keeping important UI/dialogue content inside safe bounds;
- full-width pause/telescope backgrounds rather than a hard internal 16:9 rectangle;
- 30/60/120 FPS choices, with the old
unlimitedvalue mapped to 120 FPS on mobile; - a performance governor that caps non-gameplay/paused scenes at 60 FPS, background work at 15 FPS, and lowers the cap for Low Power Mode or elevated thermal state;
- no Development Build watermark in the final Release player;
- a mobile-only analytic circular shader for the startup landscape logo, eliminating an iOS Metal stencil-edge artifact.
The world is allowed to extend under the notch/home-indicator regions; interactive UI and dialogue retain the authored safe content area. Continuous 120 FPS is intentionally conditional: thermal and power safeguards can lower it.
The following is a workflow outline, not a one-command game downloader or builder. It assumes a legally owned Steam installation already exists on the same Mac.
- macOS on Apple silicon.
- Unity Hub with Unity 2021.3.27f1.
- Unity 2021.3.27f1 iOS Build Support.
- Xcode, Command Line Tools and a personal Apple developer account.
- .NET SDK and
ilspycmd. - Python 3.
- AssetRipper 1.3.14 Free for macOS arm64, downloaded separately from its official release.
- Sufficient private disk space. This research workspace grew beyond 50 GB when builds, backups and logs were retained.
Suggested local variables:
export GAME_APP="$HOME/Library/Application Support/Steam/steamapps/common/A Short Hike/AShortHike.app"
export WORKSPACE="$HOME/Developer/AShortHike-iOS-Port"Review every script before running it. Prefer dry-run modes first.
# Read-only audit and environment inventory
./scripts/audit-game.sh "$GAME_APP" "$WORKSPACE"
./scripts/check-environment.sh "$WORKSPACE"
./scripts/check-unity-version.sh "$GAME_APP"
# Review first; execute only after paths and tool source are accepted
./scripts/install-analysis-tools.sh
./scripts/copy-managed.sh
./scripts/copy-managed.sh --execute
./scripts/decompile-assemblies.sh
./scripts/decompile-assemblies.sh --execute
# Asset extraction is private and writes to a fresh timestamped directory
./scripts/extract-assets.sh --dry-run
./scripts/extract-assets.sh --executeSome later scripts have project-specific timestamps or absolute workspace guards. They are preserved as an audit trail, not advertised as universal installers. Update those constants only after reviewing their safety checks. Never point output into the Steam app.
After private extraction:
- audit the AssetRipper snapshot;
- create a separate Unity reconstruction copy;
- import and compile in Unity 2021.3.27f1;
- resolve packages, script bindings and Addressables runtime paths;
- validate all six scenes and desktop Mono behavior;
- restore visual semantics one shader/material at a time;
- add platform isolation and touch/controller adaptations;
- switch to iOS/IL2CPP only after desktop acceptance;
- export Xcode, build Release, sign locally and validate on a personally owned device.
The project followed these rules throughout:
- never modify the original Steam directory;
- retain immutable input copies and SHA-256 manifests locally;
- stop on failure and preserve stdout, stderr and exit codes;
- use timestamped output directories instead of silently overwriting work;
- create backups or reversible patches before material changes;
- distinguish static evidence, Editor behavior, desktop builds, iOS compilation and physical-device results;
- never report an unobserved result as successful;
- keep exploratory failures in local logs instead of deleting them;
- perform desktop validation before platform adaptation;
- preserve serialization identity and gameplay code unless a verified reconstruction error requires a minimal fix.
- This repository cannot produce the game without private, copyrighted inputs.
- The result is a reconstruction, not the original Unity authoring project. Original comments, source layout, Prefab boundaries, Addressables authoring settings and source GUID history cannot be guaranteed.
- Some shaders were semantically reconstructed from serialized properties, materials, compiled metadata, upstream legacy implementations and visual comparison; they are not claimed to be the original source text.
- The iOS build intentionally omits Steam, Steam Cloud, Steam achievements, Steam Input, Sony NP and PS4 save support.
- Game Center and iCloud are not implemented; local/null platform services are used.
- The existing legacy save format remains fragile because it is tied to .NET type and field identities, although the tested port preserved and validated it.
- The Unity splash screen may remain where the installed Unity license does not permit its removal.
- 120 FPS depends on device refresh rate, scene load, temperature and power state; the governor may reduce the target.
- This was validated for personal research, not App Store submission, redistribution, long-term support or every iPhone/iOS combination.
Before every commit, verify that only the documentation and allow-listed automation are visible:
git status --short
git ls-files
git check-ignore -v \
unity-project/AShortHike/Assets \
decompiled/Assembly-CSharp \
extracted \
build/ios-xcode-20260718-114718 \
reports/evidenceExpected: all private/game-derived paths are ignored. If such a path was ever staged accidentally, do not commit it. Remove it from the index while keeping the local file, then review the complete index again:
git rm -r --cached -- path/to/private-content
git status --short
git diff --cached --statDo not use Git LFS as a workaround: ignored copyrighted files must remain local and untracked.
This research used the legally obtained game build together with:
Their names identify tools used in the workflow; they do not imply endorsement of this project.
