Files
nxnative-easy/dm/host/dm_unit.h
T
seedds d1b17080ed smbw-mobile: Mac host boots Mario Wonder v0 into its frame loop
Generic host, gfx and tools taken from d2r-mobile (MIT), with the D2R
gameplay, diagnostics and Blizzard/Granny/movie layers removed.

- hle_hid.c: generic standard-controller layer (all Npad styles)
- hle_sdk16.c: newer-SDK oe/time/pl/vsync/diag hooks
- hle_offline.c: offline stubs for prepo/ldn/socket/ssl/nifm/nsd/friends/ngc/err
- hle_fs.c, hle_account.c: SDK 16 overloads
- loader.c: unreferenced forced hooks only logged (DM_FORCE_STRICT=1 aborts)
- NVN: API 55.15, 13 newer names, ~45 state-only functions, tex_t packed
  to 0x80 (Mario allocates NVNtexture as 0x80; 0x88 corrupted the heap)

Frontier: null read at main+0x64763c inside the frame loop.
2026-10-12 22:04:20 +08:00

45 lines
4.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 单位 → 所在关卡(宿主直接读游戏内存,服务端单位与客户端单位同一套偏移):
// 单位 +0x38 路径 → 路径 +0x20 房间(物件 / 物品类单位的「路径」是另一种结构,房间在 +0)→ 房间 +0x18 → +0x90 关卡 → 关卡 +0x1f8 关卡号。
// 每一步都可能是空的,必须逐步判空:换幕的读取画面期间客户端玩家有路径、没有房间。
// 原先各处一口气连读四层 rd(rd(rd(rd(u + 0x38) + 0x20) + 0x18) + 0x90),rd 只挡地址 0,房间为空时去读地址 0x18 →
// 真机 / Mac 都是 sig=11 addr=0x18(秘境里死在别的幕的图里点「继续」、换幕读取那几帧)。单测 tests/t_unit_level.c。
// Unit → the level it is in (the host reads game memory directly; server units and client units share the same offsets):
// unit +0x38 path → path +0x20 room (for object / item class units the "path" is a different struct, with the room at +0) → room +0x18 → +0x90 level → level +0x1f8 level id.
// Every step can be NULL and must be null-checked one by one: during the act-change loading screen the client player has a path but no room.
// Previously various places read four levels in one go, rd(rd(rd(rd(u + 0x38) + 0x20) + 0x18) + 0x90); rd only guards address 0, so with a NULL room it went on to read address 0x18 →
// sig=11 addr=0x18 on both real device and Mac (in a rift, tapping 「继续」(Continue) after dying in another act's map, during those few act-change loading frames). Unit test tests/t_unit_level.c.
#ifndef DM_UNIT_H
#define DM_UNIT_H
#include <stdint.h>
static inline uint64_t dm_unit_rd64(uint64_t a) { return a ? *(volatile uint64_t *)(uintptr_t)a : 0; }
// 关卡结构指针;任何一步为空返回 0
// Level struct pointer; returns 0 if any step is NULL
static inline uint64_t dm_unit_level_ptr(uint64_t u) {
uint64_t path = u ? dm_unit_rd64(u + 0x38) : 0, room = path ? dm_unit_rd64(path + 0x20) : 0, ex = room ? dm_unit_rd64(room + 0x18) : 0;
return ex ? dm_unit_rd64(ex + 0x90) : 0;
}
// 关卡号;读不到(单位 / 路径 / 房间任何一步为空)返回 0 = 未知关卡
// Level id; returns 0 = unknown level when it cannot be read (unit / path / room NULL at any step)
static inline int dm_unit_level(uint64_t u) { uint64_t lv = dm_unit_level_ptr(u); return lv ? *(volatile int32_t *)(uintptr_t)(lv + 0x1f8) : 0; }
// 关卡的房间链头(关卡 +0x10,下一间 = 房间 +0x48);关卡指针为空返回 0——拿 dm_unit_level_ptr 的结果往下遍历房间一律走这里,
// 不让「读不到关卡」变成去读地址 0x10
// Head of a level's room chain (level +0x10, next room = room +0x48); returns 0 when the level pointer is NULL - anything that walks rooms from the result of dm_unit_level_ptr must go through here,
// so that "level could not be read" never turns into reading address 0x10
static inline uint64_t dm_level_rooms(uint64_t lv) { return lv ? dm_unit_rd64(lv + 0x10) : 0; }
// 定点传送:把单位放到 (目标房间, x, y) 旁的空位并给客户端发重定位 = 原版 main+0x7cc530(游戏, 单位, 目标房间, x, y, 0, 0)。
// 目标房间必须给:原版按关卡号换关 0x634000 自己就是「0x5596c0 取落点与房间 → 0x7cc530(…, 房间, x, y, 0, 0)」(0x634168–0x634188)。
// 传 0 时只有目标就在单位所在房间附近才成,目标在另一片房间就返回失败(秘境打完回城后点「继续」落在那张图的小站上)。
// 房间为 0(目标那间没载入 / 不在这张图里)直接返回 0,不去碰运气
// Fixed-point teleport: put the unit in a free spot next to (target room, x, y) and send the client a relocation = the original main+0x7cc530(game,
// unit, target room, x, y, 0, 0).
// The target room must be given: the original change-level-by-number 0x634000 is itself "0x5596c0 gets the landing point and room → 0x7cc530(..., room,
// x, y, 0, 0)" (0x634168–0x634188).
// Passing 0 only works when the target is near the unit's current room; a target in another cluster of rooms returns failure (after finishing a Rift and
// returning to town, tapping "Continue" landed on that map's waypoint).
// A room of 0 (the target room is not loaded / not in this map) returns 0 directly without taking chances
static inline int dm_teleport(const uint8_t *main_base, uint64_t G, uint64_t unit, uint64_t room, int x, int y) {
if (!main_base || !G || !unit || !room) return 0;
return ((int (*)(uint64_t, uint64_t, uint64_t, int, int, int, int))(uintptr_t)(main_base + 0x7cc530))(G, unit, room, x, y, 0, 0);
}
#endif