@@ -90,10 +90,10 @@ Sign and install the IPA with your own tool (AltStore, Sideloadly, LiveContainer
- **Controls:** a translucent touch gamepad over the picture:
- ZL above L in the top-left corner, ZR above R in the top-right;
-− and + side by side at the top centre;
-− and + at the top centre, with the layout button (**2D** / **3D**) between them;
- the left stick in the bottom-left corner, and A/B/X/Y (Nintendo positions) in the bottom-right, the same size and mirrored.
There is no on-screen D-pad or right stick. A connected physical controller hides the touch gamepad and keeps every button, mapped by position.
The**3D** layout adds a D-pad inward of the left stick, a right stick inward of A/B/X/Y, and L3 / R3 next to ZL / ZR. Tap the layout button to switch; the app remembers your choice. 3D World + Bowser's Fury and Breath of the Wild start in 3D, the other games in 2D (`pad_layout` in the game profile). A connected physical controller hides the touch gamepad and keeps every button, mapped by position.
- **Saves and logs** live in the app's Documents, visible in the Files app: `save/`, `log.txt` (the previous run in `log.prev.txt`) and `pso_user.tsv`. When reporting a problem, send `log.txt`.
- **Reinstalling:** sideloading tools may give a reinstalled app a new data folder; LiveContainer did, under its `Data/Application/<UUID>/Documents`. To keep your saves and prewarm list, copy them from the old folder while the app is closed.
- **Switches without rebuilding:** environment switches can go in `Documents/env.txt` (one `KEY=VALUE` per line). Game files are also accepted at `Documents/romfs`.
# 虚拟手柄首次用 3D 布局(十字键、右摇杆、L3 / R3):右摇杆转视角 | the virtual gamepad starts in the 3D layout (D-pad, right stick, L3 / R3): the right stick turns the camera
pad_layout full
# ---- 版本 | Versions ----
# 只解了合并 1.2.2 的那份;基础版单独的构建号用到时再补 | only the merged 1.2.2 copy is extracted; the base game's own build IDs are added when needed
1
# 超级马力欧 3D 世界 + 狂怒世界(Switch,基础版 v0 + 更新 1.2.2 = v262144)的游戏档案。移植中:Mac 上 3D 世界进到 1-1,狂怒世界进到开放世界
16
app_category
17
# ---- 版本 | Versions ----# 虚拟手柄首次用 3D 布局(十字键、右摇杆、L3 / R3):右摇杆转视角 | the virtual gamepad starts in the 3D layout (D-pad, right stick, L3 / R3): the right stick turns the camera
18
# 只解了合并 1.2.2 的那份;基础版单独的构建号用到时再补 | only the merged 1.2.2 copy is extracted; the base game's own build IDs are added when neededpad_layout
19
# ---- 版本 | Versions ----
20
# 只解了合并 1.2.2 的那份;基础版单独的构建号用到时再补 | only the merged 1.2.2 copy is extracted; the base game's own build IDs are added when needed
# ---- 版本 | Versions ----# 虚拟手柄首次用 3D 布局(十字键、右摇杆、L3 / R3):右摇杆转视角 | the virtual gamepad starts in the 3D layout (D-pad, right stick, L3 / R3): the right stick turns the camera
18
# 只解了合并 1.9.0 的那份;基础版单独的构建号用到时再补 | only the merged 1.9.0 copy is extracted; the base game's own build IDs are added when neededpad_layout
19
# ---- 版本 | Versions ----
20
# 只解了合并 1.9.0 的那份;基础版单独的构建号用到时再补 | only the merged 1.9.0 copy is extracted; the base game's own build IDs are added when needed
@@ -40,6 +40,7 @@ None of them has a default game: without one they stop and list the profiles. To
| `core_preempt` | `on` / `off` (the default): approximate Horizon's per-core preemption. When an SVC wakes a higher-priority thread pinned to the caller's core, the caller waits (at most 5 ms) until such threads block again (`hle_thread.c`). Metroid Dread's movie player relies on it; Mario's loading gets slower with it (first frame 0.6 → 2.9 s), so it is off unless a game needs it. `DM_PREEMPT=0` / `1` overrides |
| `shared_font` | What the shared-font address points at: `bfttf` (the default) = the 8-byte BFTTF header (with the "already decoded" marker) followed by the TTF, which Mario passes to `ScalableFontEngineHelper::Decode`; `ttf` = the TTF itself, which Super Mario 3D World + Bowser's Fury (SDK 10) hands straight to `ScalableFontEngine::LoadFont` (with the header the engine fails with error 403 and the game crashes looking up a glyph) |
| `device_api` | NVN API version `major.minor` that `nvnDeviceGetInteger` reports (default `55.15`, what Mario requires). Games check it and skip creating their device on a mismatch: Super Mario 3D World + Bowser's Fury (SDK 10) requires major 53 and minor ≥ 313. `DM_NVN_API` overrides. Not part of the shader chain version (only `nvn_*` / `shader_*` keys are) |
| `pad_layout` | The iPhone virtual gamepad's layout on first launch: `simple` (the default) = 2D (left stick, A/B/X/Y, shoulders, − / +), `full` = 3D (adds a D-pad, a right stick and L3 / R3). The layout button at the top centre switches between them in game and the app remembers the player's choice (`DmGamepad.m`) |
| `nvn_tex_base`, `nvn_tex_slots`, `nvn_samp_base`, `nvn_img_base`, `nvn_img_slots`, `nvn_ssbo_bases` | NVN driver constant segments, measured over all shaders |
| `shader_groups`, `shader_note` | `shader_split.py` source groups and the map header note (Engage: `engine` for `data.unity3d` and `Resources/`, `assets` for the Addressables bundles) |
| `shader_main_glslc` | `on` / `off` (the default): `shader_split.py` also reads GLSLC compiler outputs (magic `0x19866891`) in `main`. 13 Sentinels keeps all its shaders there; Engage's `main` has 11 that it does not use, so the key stays off for other games |
ifcpnotin('on','off'):sys.exit(f'{g.id}: core_preempt 只能是 on / off | core_preempt must be on or off: {cp}')
sf=g.get('shared_font','bfttf')# 共享字体地址处放什么(hle_sdk16.c):bfttf = 8 字节头 + TTF,ttf = 只有 TTF | what the shared-font address points at (hle_sdk16.c): bfttf = 8-byte header + TTF, ttf = the TTF alone
ifsfnotin('bfttf','ttf'):sys.exit(f'{g.id}: shared_font 只能是 bfttf / ttf | shared_font must be bfttf or ttf: {sf}')
pl=g.get('pad_layout','simple')# 虚拟手柄首次的布局(DmGamepad.m,之后按玩家在游戏里切的记):simple = 2D,full = 3D(十字键、右摇杆、L3 / R3) | the virtual gamepad's first layout (DmGamepad.m; afterwards whatever the player switched to in game is kept): simple = 2D, full = 3D (D-pad, right stick, L3 / R3)
ifplnotin('simple','full'):sys.exit(f'{g.id}: pad_layout 只能是 simple / full | pad_layout must be simple or full: {pl}')
api=g.get('device_api','55.15')# nvnDeviceGetInteger 报的 NVN API 主.次版本(hle_nvn.c) | the NVN API major.minor version nvnDeviceGetInteger reports (hle_nvn.c)
ifnotre.fullmatch(r'\d+\.\d+',api):sys.exit(f'{g.id}: device_api 要写成 主.次 | device_api must be major.minor: {api}')
L=[f'// 由 dm/games/game.py 从 dm/games/{g.id}/game.tsv 生成,勿手改 | Generated by dm/games/game.py from dm/games/{g.id}/game.tsv; do not edit',
// Virtual gamepad (Nintendo button positions) + physical controllers (GameController). Both are merged and handed to the host through dm_input_set (hle_hid.c, bit layout in dm_input.h).
// Top corners: ZL above L (one column), ZR above R likewise, teardrops with the tip toward the screen corner; top edge, centred: − and + side by side;
// bottom-left corner: the left stick (fixed ring, tilt measured from the ring centre, small dead zone); bottom-right corner: the A (right) B (bottom) X (top) Y (left) diamond, sliding a finger between keys switches keys.
// The virtual gamepad has no D-pad and no right stick, so each bottom corner holds a single control and it sits close in (reaching halfway into the side safe-area inset). Everything hugs the edges and corners to leave the picture room;
// controls sit overthe picture, one CAShapeLayer each: a press only swaps the fill, the stick only moves its knob, nothing redraws the whole screen.
// The virtual gamepad hides while a physical controller is connected and comes back when it is removed. Physical controllers keep every button (D-pad and right stick included) and map by position: bottom = B, right = A, left = Y, top = X (same positions as on a Switch controller).
// Two layouts; one tap on the layout button at the top centre (labelled with the current layout, "2D" / "3D") switches them, and the choice is kept in NSUserDefaults (each game is its own app, so per game); the first launch uses the game profile's pad_layout (DM_GAME_PAD_FULL).
// 2D (simple): top corners ZL above L (one column), ZR above R likewise, teardrops with the tip toward the screen corner; − and + side by side at the top centre; the left stick in the bottom-left corner (fixed ring, tilt measured from the ring centre, small dead zone);
// the A (right) B (bottom) X (top) Y (left) diamond in the bottom-right corner, sliding a finger between keys switches keys. Each bottom corner holds a single control, so it sits close in (reaching halfway into the side safe-area inset).
// 3D (full, Pro Controller style): everything in 2D (left stick and diamond keep their place and size), plus a D-pad (inward of and below the left stick, 8-way), a right stick (inward of and below the diamond, a smaller ring)
// and L3 / R3 (small round keys in the top row, inward of ZL / ZR). Breath of the Wild crouches with L3 and uses the scope with R3; 3D World and Breath of the Wild turn the camera with the right stick.
// Touch-down ownership: locked keys first (shoulders, − / +, the layout button, L3 / R3), then whichever of the diamond, the D-pad and the two sticks has the smallest distance / grab radius (the left stick's grab circle borders the D-pad).
// Everything hugs the edges and corners to leave the picture room; controls sit over the picture, one CAShapeLayer each: a press only swaps the fill, a stick only moves its knob, nothing redraws the whole screen.
// The virtual gamepad (layout button included) hides while a physical controller is connected and comes back when it is removed. Physical controllers keep every button (D-pad and right stick included) and map by position: bottom = B, right = A, left = Y, top = X (same positions as on a Switch controller).
K_CORNER_IN=0.5,// 下角控件伸进侧边安全区的比例(横屏时那里只有屏幕圆角,灵动岛在边的正中) | how far the bottom-corner controls reach into the side safe-area inset (in landscape there is only the rounded screen corner there; the Dynamic Island is mid-edge)
K_FACE_X=81,K_PAD_Y=82,// 菱形中心离外侧;菱形、摇杆中心离底(B 键下沿离底约 5) | diamond centre from the outer edge; diamond and stick centre from the bottom (B's lower edge about 5 above it)
K_FACE_GAP=50,K_FACE_R=27,// 菱形:键离中心、键半径 | diamond: key distance from the centre, key radius
K_PILL_DX=40,K_PILL_Y=22,K_PILL_W=50,K_PILL_H=28,// − / +:中心离屏幕中线、离顶,宽高 | − / +: centre from the screen's midline and from the top, size
K_PILL_DX=52,K_PILL_Y=22,K_PILL_W=50,K_PILL_H=28,// − / +:中心离屏幕中线(中间让给布局键)、离顶,宽高 | − / +: centre from the screen's midline (the middle goes to the layout button) and from the top, size
K_SWAP_R=15,// 布局键:顶边正中,与 − / + 同高 | layout button: top centre, level with − / +
K_STICK_X=81,K_STICK_R=77,K_KNOB_R=30,// 左摇杆:与菱形左右对称,环和整个菱形一样大(键距 + 键半径),手柄头比菱形的键略大 | left stick: mirrors the diamond, the ring as large as the whole diamond (key distance + key radius), the knob a little larger than a diamond key
K_STICK_GRAB=1.4,// 按下点离环心多近算抓住摇杆(环半径的倍数;左下角没有别的控件和它抢) | how near the ring centre a touch-down grabs the stick (times the ring radius; nothing else in the bottom-left corner competes)
K_FULL=0.8,// 推到环半径的这么多就算推满(约 62,原先小环是 50;手柄头仍能走到环边) | full tilt at this fraction of the ring radius (about 62; the former small ring had 50; the knob still travels to the ring edge)
K_DEAD=0.1;// 摇杆死区(环半径的倍数) | stick dead zone (times the ring radius)
K_STICK_GRAB=1.4,// 按下点离环心多近算抓住摇杆(环半径的倍数) | how near the ring centre a touch-down grabs a stick (times the ring radius)
K_FULL=0.8,// 推到环半径的这么多就算推满(手柄头仍能走到环边) | full tilt at this fraction of the ring radius (the knob still travels to the ring edge)
K_DEAD=0.1,// 摇杆死区(环半径的倍数) | stick dead zone (times the ring radius)
// 3D 布局另有的控件 | controls only the 3D layout has
K_LOW_X=231,K_LOW_Y=64,// 十字键 / 右摇杆中心离外侧、离底(在左摇杆 / 菱形内侧偏下,同 Pro 手柄) | D-pad / right stick centre from the outer edge and the bottom (inward of and below the left stick / the diamond, as on a Pro Controller)
K_DPAD_R=48,K_ARM_W=17,K_ARM_IN=11,// 十字键:箭头外沿离中心、半宽、尖离中心 | D-pad: arm outer edge from the centre, half-width, tip from the centre
K_DPAD_GRAB=1.3,// 十字键抓取半径(外沿的倍数) | D-pad grab radius (times the outer edge)
K_RSTICK_R=60,K_RKNOB_R=24,// 右摇杆:环、手柄头半径 | right stick: ring and knob radius
K_CLICK_X=102,K_CLICK_R=17;// L3 / R3:中心离外侧(与 ZL / ZR 同高),半径 | L3 / R3: centre from the outer edge (level with ZL / ZR), radius
staticconstintk_btns[]={B_ZL,B_L,B_ZR,B_R,B_MINUS,B_PLUS,B_LS,B_RS};// 按下时锁定的键(L3 / R3 只在 3D 布局) | keys locked at touch-down (L3 / R3 only in the 3D layout)
NSMapTable<UITouch*,NSNumber*>*_owner;// 触点 → 控件(C_BTN 时附带键号,<< 8) | touch → control (with the key for C_BTN, << 8)
UITouch*_stick;CGPoint_stickNow;// 握着左摇杆的触点、它现在的位置 | the touch holding the left stick and where it is now
uint64_t_faceBits,_btnBits;
NSMapTable<UITouch*,NSNumber*>*_owner;// 触点 → 控件(C_BTN 附带键号、C_STICK 附带摇杆号,<< 8) | touch → control (with the key for C_BTN or the stick for C_STICK, << 8)
UITouch*_stick[2];CGPoint_stickNow[2];// 握着摇杆的触点、它现在的位置(0 左 1 右) | the touch holding each stick and where it is now (0 left, 1 right)
uint64_t_faceBits,_dpadBits,_btnBits;
NSMapTable<UITouch*,NSNumber*>*_faceOf;// 每个落在菱形区的触点各自按着哪些键 | which keys each touch on the diamond currently holds
CAShapeLayer*_key[B_N];CATextLayer*_label[B_N];// 每个键一层(摇杆按下、十字键只有实体手柄有,位空着) | one layer per key (stick clicks and the D-pad exist only on physical controllers; those stay empty)
CAShapeLayer*_ring,*_knob;
BOOL_stickShown;// 上次刷新时摇杆按着 | the stick was held at the last refresh
CAShapeLayer*_key[B_N];CATextLayer*_label[B_N];// 每个键一层 | one layer per key
CGFloatm=fmin((d-dz)/(R*K_FULL-dz),1)/d;// 死区外从 0 起算,到推满处为满 | outside the dead zone: 0 rising to full at the full-tilt radius
ax=(int32_t)lrint(o.x*m*32767);ay=(int32_t)lrint(-o.y*m*32767);// 宿主:上为正;四舍五入,推满正好是 32767 | host: up is positive; rounded so full tilt is exactly 32767
ax[i*2]=(int32_t)lrint(o.x*m*32767);ax[i*2+1]=(int32_t)lrint(-o.y*m*32767);// 宿主:上为正;四舍五入,推满正好是 32767 | host: up is positive; rounded so full tilt is exactly 32767
if(ended&&([_ownerobjectForKey:t].unsignedLongLongValue&0xff)==C_SWAP&&[selfinSwap:[tlocationInView:self]])swap=YES;// 布局键:在键上松手才算 | layout button: counts only when released on the button
staticCGPathRefarmPath(CGPointc,CGFloatR,CGFloatw,CGFloatin,CGFloatangle,CGFloatround){// 十字键一臂:朝上的五边形(尖朝中心)绕中心转 angle | one D-pad arm: an upward pentagon (tip toward the centre) rotated by angle around the centre
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.