Skip to content

Conversation

@KunalGehlot
Copy link

Summary

Updates the Modding API to work with Hollow Knight build 1.5.12459 (released Feb 5, 2026), which upgraded the game engine to Unity 6 (6000.0.61f1) and made significant changes to controller input, localization, and scene management.

This PR builds on the work started in #164 by @SFGrenade, extending it to the latest public release (12459 vs 12331) and fixing additional issues discovered during testing.

Closes #169.

Changes

Build System (Assembly-CSharp.csproj)

  • FrameworkPathOverride for Unity 6: Use FrameworkPathOverride pointing to Vanilla/ to resolve all assemblies, replacing individual HintPath references. Unity 6 ships additional TeamCherry.* and System.* assemblies that need to be referenced.
  • System.Memory NuGet package: Required because Unity 6 uses ReadOnlySpan<byte> in Texture2D.LoadImage.
  • Removed Newtonsoft.Json dependency: Now shipped with the game binaries.
  • Removed mscorlib override: No longer needed with Unity 6 runtime.

Localization System Rewrite

  • Deleted Patches/Language.cs: The Language class moved from the global namespace to TeamCherry.Localization in HK 1.5, breaking the old MonoMod patch target.
  • Added Language/Language.cs: A backwards-compatible shim that delegates to TeamCherry.Localization.Language via reflection, using MonoModLinkFrom to redirect existing mod references. Mods using Language.Language.Get() continue working without recompilation.

Mod Loading Bootstrap (StartManager.cs)

  • Moved mod init from OnScreenDebugInfo to StartManager: The OnScreenDebugInfo component was removed in HK 1.5.
  • Rewrote Start() to match HK 1.5 startup: Language verification, PlayerPrefs loading, scene load state management.
  • Deferred Menu_Title loading: When mod preloading is active, waits for mods to finish before transitioning to Menu_Title.

HeroController Patches

  • rb2d.velocityrb2d.linearVelocity (Unity 6 API change)
  • wallSlideVibrationPlayer.Stop()vibrationCtrl.StopWallSlide() (HK 1.5 replaced individual vibration players with HeroVibrationController)
  • Attack(): Added grubberfly beam support for wall slashes; == maxHealth>= maxHealth for beam activation
  • SoulGain(): String literals → nameof() for PlayerData fields
  • LookForQueueInput(): Removed duplicate CanDash() call
  • TakeDamage(): Renamed flagcarefreeShouldStopDamage, string literals → nameof(), added explicit return statements after death/hazard coroutine starts (matching upstream flow)
  • OrigDashVector(): Simplified ternary for readability

InputHandler.OnGUI

  • Replaced direct Cursor.visible/Cursor.lockState manipulation with calls to the game's SetCursorVisible() method, preserving the OnCursorVisibilityChange event and proper cursor lock management through SetCursorEnabled(). This fixes controller detection and connection mode switching.

GameManager Patches

  • Import TeamCherry.SharedUtils.Encryption (moved namespace)
  • Rewrote PauseToggleDynamicMenu for HK 1.5 pause flow (SetPausedState calls, reordered input prevention)
  • SceneManager.UnloadSceneAsyncSceneManager.UnloadScene

SceneManager Patches

  • Replaced DrawBlackBorders() full replacement with OnCameraAspectChanged() hook (HK 1.5 refactored border drawing into the camera aspect handler with persistent transforms)
  • ModHooks.OnDrawBlackBorders hook preserved by collecting border transforms after orig_OnCameraAspectChanged runs

Other Patches

  • MenuSetting.cs: Added new HK 1.5 settings enum values (SwitchFrameCap, Dithering, Noise, ControllerRumble, HudVisibility, CameraShake, NativeInput, XInput, MFi)
  • MenuButtonList.cs: Null-conditional on menuButtonLists to prevent NullReferenceException during early UIManager initialization
  • UIManager.cs: Added ADVANCED_GAMEPAD_MENU and ADVANCED_VIDEO_MENU to MainMenuState enum
  • TakeDamage.cs: Fixed Multiplier ternary operand order
  • PlayMakerUnity2DProxy.cs: Added explicit this. qualifier
  • ModHooks.cs: Added bounds checking on version string split for version formats with fewer than 4 segments

Test Plan

Tested on macOS (Apple M2 Pro) with Unity 6000.0.61f1:

  • dotnet build succeeds with 0 errors
  • Full pipeline runs: PrePatcher (2239 get/set calls) → MonoMod → HookGen
  • Game launches and reaches title screen
  • Mod menu appears in Options, lists installed mods
  • Mod toggling (enable/disable) works
  • CompassAlwaysOn loads and functions (compass visible without charm)
  • GatheringSwarmAlwaysOn loads and functions (auto geo collection)
  • Controller support: USB and Bluetooth connection modes
  • Controller vibration works
  • Scene transitions work (entering/exiting areas)
  • Pause menu and all settings submenus functional
  • No errors in Player.log or ModLog.txt

Hollow Knight received a major update on Feb 5, 2026 (build 12459) which
upgraded the engine to Unity 6 (6000.0.61f1) and introduced significant
changes to controller input handling, localization, and scene management.
This commit updates the Modding API to compile against and work correctly
with the new game binaries.

Build system changes (Assembly-CSharp.csproj):
- Use FrameworkPathOverride to resolve assemblies from Vanilla/ directory
  instead of individual HintPath references (required for Unity 6 which
  ships additional TeamCherry.* and System.* assemblies)
- Add System.Memory NuGet package (Unity 6 uses ReadOnlySpan<byte> in
  Texture2D.LoadImage)
- Remove Newtonsoft.Json from dependencies (now shipped with the game)
- Remove mscorlib override (no longer needed with Unity 6 runtime)

Localization system rewrite:
- Delete Patches/Language.cs: The Language class moved from the global
  namespace to TeamCherry.Localization in HK 1.5. The old MonoMod patch
  targeting "global::Language.Language" no longer resolves.
- Add Language/Language.cs: A backwards-compatible shim in the
  Language.Language namespace that delegates to TeamCherry.Localization
  via reflection, with MonoModLinkFrom to redirect existing mod references.
  This allows mods using Language.Language.Get() to continue working without
  recompilation.
- Update ModHooks.cs LanguageGet to call Language.Language.GetInternal
  instead of the removed Patches.Language.GetInternal.

Mod loading initialization (StartManager.cs):
- Move mod loading bootstrap from OnScreenDebugInfo.Awake to
  StartManager.Awake. The OnScreenDebugInfo component was removed in
  HK 1.5, so it can no longer serve as the mod loading entry point.
- Delete Patches/OnScreenDebugInfo.cs (component no longer exists in game).
- Rewrite StartManager.Start to match the new HK 1.5 startup sequence:
  language verification, PlayerPrefs loading, and scene load state
  management.
- Add deferred Menu_Title scene loading: when mod preloading is active,
  wait for mods to finish loading before transitioning to Menu_Title
  instead of using the allowSceneActivation pattern.

HeroController patches updated for HK 1.5 game logic:
- rb2d.velocity → rb2d.linearVelocity (Unity 6 Rigidbody2D API change)
- wallSlideVibrationPlayer.Stop() → vibrationCtrl.StopWallSlide()
  (HK 1.5 replaced individual vibration players with HeroVibrationController)
- Attack(): Add grubberfly beam (charm_35) support for wall slashes,
  change health check from == to >= for grubberfly beam activation on
  normal/up/down attacks (matches upstream game logic)
- SoulGain(): String literals to nameof() for PlayerData fields
- LookForQueueInput(): Remove duplicate CanDash() call
- TakeDamage(): Rename flag → carefreeShouldStopDamage for clarity,
  string literals to nameof(), add explicit returns after death/hazard
  coroutine starts to match upstream flow control, fix ternary null check
  on damage angle
- OrigDashVector(): Simplify ternary for bump velocity readability

InputHandler.OnGUI rewrite:
- Replace direct Cursor.visible/Cursor.lockState manipulation with calls
  to the game's SetCursorVisible() method. This preserves the
  OnCursorVisibilityChange event and proper cursor lock management through
  SetCursorEnabled(), fixing controller detection and connection mode
  switching that was broken by the old approach.

GameManager patches:
- Import TeamCherry.SharedUtils.Encryption (class moved in HK 1.5)
- Add SetPausedState() MonoModIgnore declaration
- Rewrite PauseToggleDynamicMenu to match HK 1.5 pause/unpause flow
  (SetPausedState calls, reordered input prevention, reduced wait times)
- SceneManager.UnloadSceneAsync → SceneManager.UnloadScene (API change)

SceneManager patches:
- Replace DrawBlackBorders() full replacement with OnCameraAspectChanged()
  hook. HK 1.5 refactored border drawing into the camera aspect change
  handler with persistent border transforms (borderLeft/Right/Up/Down)
  instead of instantiating new GameObjects each time.
- The ModHooks.OnDrawBlackBorders hook is preserved by collecting the
  border transforms after orig_OnCameraAspectChanged runs.

Other patch updates:
- MenuSetting.cs: Add new HK 1.5 settings enum values (SwitchFrameCap,
  Dithering, Noise, ControllerRumble, HudVisibility, CameraShake,
  NativeInput, XInput, MFi)
- MenuButtonList.cs: Null-conditional on menuButtonLists to prevent
  NullReferenceException during early UIManager initialization
- UIManager.cs: Add ADVANCED_GAMEPAD_MENU and ADVANCED_VIDEO_MENU to
  MainMenuState enum
- TakeDamage.cs: Fix Multiplier ternary to match HK 1.5 operand order
- PlayMakerUnity2DProxy.cs: Add explicit this. qualifier
- ModHooks.cs: Add bounds checking on version string split to handle
  version formats with fewer than 4 segments

Version: hollowknight.version updated to 1.5.12459

Tested on macOS (Apple M2 Pro) with Unity 6000.0.61f1:
- Game launches and reaches title screen
- Mod menu appears in Options with working mod list
- CompassAlwaysOn and GatheringSwarmAlwaysOn load and function correctly
- Controller support works (USB/Bluetooth, vibration, mode switching)
- Scene transitions, pause menu, and settings menus all functional
- No errors in Player.log or ModLog.txt

Builds on work started in PR hk-modding#164 by SFGrenade.
Closes hk-modding#169.
@KunalGehlot KunalGehlot reopened this Feb 11, 2026
@KunalGehlot
Copy link
Author

Feel free to ping me at @zackcodesai on discord server.

@SFGrenade
Copy link
Member

practically the same as #164

@SFGrenade SFGrenade closed this Feb 11, 2026
@KunalGehlot
Copy link
Author

I would call that an overstatement, but you're the maintainer...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API can't work in the last update of the game

2 participants