diff --git a/Makefile b/Makefile index 10cd2eb..b74fcb3 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,7 @@ $(TWEAK_NAME)_FILES += vendor/KIOU-Hook/KIOUHook.m $(TWEAK_NAME)_FILES += vendor/KIOU-Hook/Account/Persistence.m $(TWEAK_NAME)_FILES += vendor/KIOU-Hook/Hook/AccountObserve.m $(TWEAK_NAME)_FILES += vendor/KIOU-Hook/Hook/GrpcLogging.m +$(TWEAK_NAME)_FILES += vendor/KIOU-Hook/Hook/AfkSuppress.m BUILD_COMMIT ?= $(shell git rev-parse --short=7 HEAD 2>/dev/null || echo unknown) diff --git a/Sources/KiouForge/Internal.h b/Sources/KiouForge/Internal.h index 7b4a673..793c2d0 100644 --- a/Sources/KiouForge/Internal.h +++ b/Sources/KiouForge/Internal.h @@ -164,6 +164,19 @@ static const uintptr_t kKiouMatchModeAdapterOffsets[KIOU_MMODE_COUNT] = { [KIOU_MMODE_RECORD_REPLAY] = 0x18, }; +// IMatchMode self -> _stateStore field offsets. All five IMatchMode +// implementations carry a GameStateStore reference sitting one pointer +// slot before _gameAdapter — reading it lets the kif writer pull +// player names via the same ReactiveProperty path online +// matches use. +static const uintptr_t kKiouMatchModeStateStoreOffsets[KIOU_MMODE_COUNT] = { + [KIOU_MMODE_AI_MATCH] = 0x40, + [KIOU_MMODE_CPU_STREAM] = 0x48, + [KIOU_MMODE_LOCAL_PVP] = 0x10, + [KIOU_MMODE_ONLINE_PVP] = 0x28, + [KIOU_MMODE_RECORD_REPLAY] = 0x10, +}; + static const char *const kKiouMatchModeTags[KIOU_MMODE_COUNT] = { [KIOU_MMODE_AI_MATCH] = "AIMatchMode", [KIOU_MMODE_CPU_STREAM] = "CPUStreamMode", diff --git a/Sources/KiouForge/Kif/Helpers.m b/Sources/KiouForge/Kif/Helpers.m index e575473..af7f607 100644 --- a/Sources/KiouForge/Kif/Helpers.m +++ b/Sources/KiouForge/Kif/Helpers.m @@ -74,11 +74,15 @@ // --------------------------------------------------------------------------- // RVAs (KIOU 1.0.1 build 11). Same source of truth as KiouUsiProxy. // --------------------------------------------------------------------------- -#define RVA_GAMECTRL_GET_USI_TEXT 0x5D44074 // string GameController.GetUSIText(this) -#define RVA_POSITION_TO_SFEN 0x5D44374 // string Position.ToSFEN(this) -#define RVA_USIPARSER_PARSE_USI 0x5D572B4 // static RecordManager USIParser.ParseUSI(string) -#define RVA_KIFWRITEOPTIONS_CTOR 0x5D53960 // void KIFWriteOptions..ctor(this) -#define RVA_KIFWRITER_WRITE 0x5D53968 // static string KIFWriter.Write(RecordManager, KIFWriteOptions) +// RVAs pinned to KIOU 1.0.2 (dump.cs verified 2026-07-02). The previous +// values were 1.0.1 leftovers pointing at unrelated methods — calling +// through them at match-end crashed with a SIGSEGV inside GetUSIText +// (LDR from a bogus X10 loaded from *(gameCtrl+0xB0)). +#define RVA_GAMECTRL_GET_USI_TEXT 0x5D49970 // string GameController.GetUSIText(this) +#define RVA_POSITION_TO_SFEN 0x5D49C70 // string Position.ToSFEN(this) +#define RVA_USIPARSER_PARSE_USI 0x5D5CBB0 // static RecordManager USIParser.ParseUSI(string) +#define RVA_KIFWRITEOPTIONS_CTOR 0x5D5925C // void KIFWriteOptions..ctor(this) +#define RVA_KIFWRITER_WRITE 0x5D59264 // static string KIFWriter.Write(RecordManager, KIFWriteOptions) // KIFWriteOptions instance size needed for the raw-buffer trick. See the // KIFOPTS_OFF_* constants in Internal.h for the field map. Last field diff --git a/Sources/KiouForge/Kif/Writer.m b/Sources/KiouForge/Kif/Writer.m index 69615d1..20e7b4e 100644 --- a/Sources/KiouForge/Kif/Writer.m +++ b/Sources/KiouForge/Kif/Writer.m @@ -146,13 +146,18 @@ KIOUUniTaskRet KIOUKifuObserveMatchEnd(void *self, void *ct, return zero; } - // MatchConfig / GameStateStore only available on OnlinePvPMode's `self`; - // other modes' KIF gets blank player names (acceptable for offline play). + // All five IMatchMode implementations carry a GameStateStore that + // KIOUKifDescribeOpponents / KIOUKifFillWriteOptions can read player + // names from via ReactiveProperty. Only OnlinePvPMode + // additionally exposes a MatchConfig — the other modes seed the + // PlayerInfo directly into stateStore at match start. void *matchConfig = NULL; void *stateStore = NULL; + if (mode_index < KIOU_MMODE_COUNT && ptrLooksValid(self)) { + stateStore = readPtr(self, kKiouMatchModeStateStoreOffsets[mode_index]); + } if (mode_index == KIOU_MMODE_ONLINE_PVP && ptrLooksValid(self)) { matchConfig = readPtr(self, ONLINEPVPMODE_OFF_MATCHCONFIG); - stateStore = readPtr(self, ONLINEPVPMODE_OFF_STATE_STORE); } IPALog([NSString stringWithFormat: diff --git a/Sources/KiouForge/Tweak.m b/Sources/KiouForge/Tweak.m index 94df713..e2a8f90 100644 --- a/Sources/KiouForge/Tweak.m +++ b/Sources/KiouForge/Tweak.m @@ -55,6 +55,7 @@ static void installUnityHooks(uintptr_t unityBase, const char *unityName) { KIOUInstallKifuObserveHook(unityBase); KIOUInstallAccountObserveHook(unityBase); KIOUInstallGrpcLoggingHook(unityBase); + KIOUInstallAfkSuppressHook(unityBase); g_unityHooked = YES; IPALog(@"=== KiouForge: all hooks installed ==="); diff --git a/vendor/KIOU-Hook b/vendor/KIOU-Hook index 3079c5e..be4cc6a 160000 --- a/vendor/KIOU-Hook +++ b/vendor/KIOU-Hook @@ -1 +1 @@ -Subproject commit 3079c5e5b96867cb81d54b4e92c11cd0ab31673d +Subproject commit be4cc6ae2a250687bf14d5622181d6cebc6a90a0