Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions KIOUHook.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,17 @@ uintptr_t KIOUHookSiteAddr(const char *hook_name, uintptr_t unityBase);
void KIOUInstallAccountObserveHook(uintptr_t unityBase);
void KIOUInstallGrpcLoggingHook(uintptr_t unityBase);

// Publish a hook body that unconditionally returns false for
// GameOrchestrator.IsAfkEnabled. This is the "AFK is always off"
// convenience installer for consumers that want the historic
// inline-patch behaviour without wiring the KIOUEditor feature-flag
// surface. Cave slot is populated after this call, so any consumer
// building against a recipe that carries the AFK site as
// CAVE_ENTRY (v1_0_1 and later v1_0_2) can call this once at
// startup and be done. See Hook/AfkDisable.m for the
// feature-flag-gated variant (KIOUEditorInstallAfkDisableHook).
void KIOUAfkDisableAlwaysFalseInstall(uintptr_t unityBase);

// Drive BackToTitleSequence.RunAsync — called by consumer settings UIs after
// the user confirms an account switch so KIOU re-runs AccountExists → Login
// with the pending_device_id substitution in effect (no app relaunch needed).
Expand Down
23 changes: 23 additions & 0 deletions KIOUHook.m
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,26 @@ uintptr_t KIOUHookSiteAddr(const char *name, uintptr_t unityBase) {
return orig;
#endif
}

// ---------------------------------------------------------------------------
// KIOUAfkDisableAlwaysFalseInstall — publishes an unconditional
// GameOrchestrator.IsAfkEnabled -> false stub into the AFK cave slot.
//
// This is the drop-in replacement for the retired
// (AFK_SITE / AFK_ORIG_8) inline patch on 1.0.2: consumers that want
// the historic "AFK is always off" behaviour without any feature-flag
// wiring call this once from their Tweak.m and are done. The
// KIOUEditor feature-flag-gated variant
// (KIOUEditorInstallAfkDisableHook in Hook/AfkDisable.m) is a separate
// module that swaps in on top of this.
// ---------------------------------------------------------------------------

static bool kiou_afk_always_false(void *self) {
(void)self;
return false;
}

void KIOUAfkDisableAlwaysFalseInstall(uintptr_t unityBase) {
KIOUHookInstall(KIOU_HOOK_NAME_GAME_ORCHESTRATOR_IS_AFK,
(void *)kiou_afk_always_false, unityBase);
}
34 changes: 31 additions & 3 deletions recipes/v1_0_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@
ENTRY_SLOT_BASE_RVA = 0x091E91B8
ZERO_REGION_END_RVA = 0x091F5978

# GameOrchestrator.IsAfkEnabled — inline-patched to return false.
AFK_SITE = 0x594A034
AFK_ORIG_8 = "f44fbea9fd7b01a9"
# GameOrchestrator.IsAfkEnabled is now handled via CAVE_ENTRY (see SITES
# below). The inline patch is retired so both 1.0.1 and 1.0.2 route AFK
# through the same hook-body path. Consumers that want the historic
# "always disabled" behaviour without wiring KIOUEditorFeatureEnabled
# can call KIOUAfkDisableAlwaysFalseInstall(unityBase) — see KIOUHook.h.
AFK_SITE = None
AFK_ORIG_8 = ""

# fmt: off
SITES = [
Expand Down Expand Up @@ -50,5 +54,29 @@
# HttpMessageInvoker.SendAsync / Yaha borrow path that crashes when
# the request or HttpHeaders internal dictionary is touched.
(0x5BD9EE8, "f657bda9", "KIOU_HOOK_ID_HEADER_PROVIDER_SET_OR_UPDATE_HEADER", CAVE_ENTRY, "Project.Network.HeaderProvider.SetOrUpdateHeader"),

# --- KiouEditor entry caves (CAVE_ENTRY, 1.0.2 port of the 1.0.1 sites) ---
# RVAs verified against assets/1.0.2/dump.cs on 2026-07-01. Prologues
# captured from assets/1.0.2/Kiou-1.0.2.ipa UnityFramework. None are
# PC-relative; each first-4-bytes can be relocated verbatim into the
# cave tail.
(0x5C3C29C, "fc6fbaa9", "KIOU_HOOK_ID_SYNC_ITEM_LIST_MERGE", CAVE_ENTRY, "SyncItemListReply.InternalMergeFrom"),
(0x5C458C4, "fa67bba9", "KIOU_HOOK_ID_COLLECTION_PRESET_MERGE", CAVE_ENTRY, "UpdateCollectionPresetReply.InternalMergeFrom"),
(0x5CACEF8, "ffc302d1", "KIOU_HOOK_ID_SELECT_CHAR_ASYNC", CAVE_ENTRY, "SelectCharacterAsync"),
(0x5C2C034, "fc6fbaa9", "KIOU_HOOK_ID_SELECT_CHAR_REPLY_MERGE", CAVE_ENTRY, "SelectCharacterReply.InternalMergeFrom"),
(0x5B51C3C, "fc6fbaa9", "KIOU_HOOK_ID_MATCHING_PLAYER_MERGE", CAVE_ENTRY, "ShogiMatchingPlayerStatus.InternalMergeFrom"),
(0x5C06590, "fc6fbaa9", "KIOU_HOOK_ID_HISTORY_DETAIL_MERGE", CAVE_ENTRY, "GetShogiHistoryDetailListReply.InternalMergeFrom"),
(0x5C05FF0, "00804039", "KIOU_HOOK_ID_HISTORY_GET_PREMIUM", CAVE_ENTRY, "GetShogiHistoryDetailListReply.get_IsPremiumUser"),
(0x585E000, "00004139", "KIOU_HOOK_ID_KIFU_DETAIL_IS_PREMIUM", CAVE_ENTRY, "KifuDetailModel.IsPremiumUser"),
(0x582E614, "e80300aa", "KIOU_HOOK_ID_VOICE_PLAYER_SATISFIES", CAVE_ENTRY, "CharacterVoicePlayer.SatisfiesRule"),
(0x584DB64, "00704039", "KIOU_HOOK_ID_VOICE_CELL_GET_IS_LOCKED", CAVE_ENTRY, "CharacterVoiceScrollerCellModel.get_IsLocked"),
(0x597E608, "f85fbca9", "KIOU_HOOK_ID_BSE_CTOR", CAVE_ENTRY, "BeginnerSupportEvaluator.ctor"),
(0x5980890, "f657bda9", "KIOU_HOOK_ID_BSE_ENSURE_INITIALIZED", CAVE_ENTRY, "BeginnerSupportEvaluator.EnsureInitializedLocked"),
(0x5942AA0, "00404039", "KIOU_HOOK_ID_RBSUPPORT_GET_ENABLED", CAVE_ENTRY, "ResolvedBeginnerSupport.get_Enabled"),
(0x5942AC0, "002040b9", "KIOU_HOOK_ID_RBSUPPORT_GET_DEPTH", CAVE_ENTRY, "ResolvedBeginnerSupport.get_Depth"),
(0x5AA4054, "fc6fbaa9", "KIOU_HOOK_ID_HOME_UTILITY_PRESENTER_CTOR", CAVE_ENTRY, "HomeUtilityPresenter.ctor"),
(0x5DD7F54, "f44fbea9", "KIOU_HOOK_ID_UIBUTTONBASE_ONPOINTERCLICK", CAVE_ENTRY, "UIButtonBase.OnPointerClick"),
(0x5DD2874, "ff0303d1", "KIOU_HOOK_ID_TITLE_SCENE_MOVENEXT", CAVE_ENTRY, "TitleScene+<OnActivateAsync>d__10.MoveNext"),
(0x594A034, "f44fbea9", "KIOU_HOOK_ID_GAME_ORCHESTRATOR_IS_AFK", CAVE_ENTRY, "GameOrchestrator.IsAfkEnabled"),
]
# fmt: on
Empty file removed tools/__init__.py
Empty file.
Loading