Dusklight Documentation

repository·main·Indexed 26 days ago

https://github.com/twilitrealm/dusklight

Dusklight is a reverse-engineered reimplementation of Twilight Princess, providing an accurate recreation of the original game with enhancements and customization. This documentation covers installation and build processes for Windows, macOS, Linux, Android, and iOS, as well as developer guidelines for public game helpers, code conventions for decompiled code, and memory allocation using JKR macros.

Tokens
11.5K
Snippets
32
Records
56
Agent score
86%

What's inside Dusklight

  1. Understand the purpose of Public game helpers

    main

    The headers in include/helpers/ provide port-specific types and utilities designed for use by ordinary game headers. These helpers are intended to be consumed by mods that use the game feature.

    Key Constraints for Developers:

    • ABI Stability: These helpers must remain ABI stable within GameService major versions because they are exposed to external mods.
    • Dependency Restriction: Public interfaces for these helpers must not depend on internal src/dusk/ declarations.
    • Mod API Distinction: If you are developing an API specifically for mod use, do not place it in this directory. Instead, use mod services, which are individually versioned, support backwards compatibility, and manage per-mod runtime state.
  2. Import a service from another mod

    main

    Use the IMPORT_SERVICE macro to declare a required dependency on a service. If the dependency is not strictly required, use IMPORT_OPTIONAL_SERVICE.

    Key Behaviors:

    • Dependency Order: The loader ensures that all imported services (required or optional) have finished their mod_initialize before your mod's mod_initialize runs.
    • Failure Handling: If a required provider fails to load, your mod will also be disabled. If an optional provider fails, the import resolves to NULL.
    • Cycles: Required imports that form a cycle will cause all mods in that cycle to fail. Optional imports can be used to break cycles.
    • Dynamic Access: You can use svc_host->get_service(...) to fetch services at runtime. This is an "escape hatch" for intentionally cyclic designs, but it provides no initialization-order guarantees.
  3. Handle Mod Runtime Lifecycle

    main

    Mods can be enabled, disabled, or reloaded at runtime. Your code must handle these transitions:

    • Disable: The engine calls mod_shutdown. You must remove your hooks, services, overlays, and texture replacements, and release any resources (threads, files, etc.) that the loader does not manage.
    • Enable/Reload: The engine loads a fresh copy of your library and runs mod_initialize.
    • Reload: Specifically re-reads the .dusk archive from disk, allowing for rapid iteration of code and assets.

    Caution: Avoid hooking functions that stay on the stack for the entire session (like the main loop), as these cannot be safely unloaded during a lifecycle change.

  4. Use Asset Overlays and Texture Replacements

    main

    You can override game assets using two methods within a .dusk archive:

    1. Asset Overlays: Place files under an overlay/ directory. These files override game files at the corresponding path (similar to replacing files in an ISO).
    2. Texture Replacements: Place files under a textures/ directory. These use Dolphin-style naming and are matched by texture hash (e.g., tex1_{w}x{h}_{texhash}[_{tluthash}]_{fmt}.dds|.png).

    Precedence Rules:

    • Runtime registrations override static textures/ or overlay/ files.
    • Later-loaded mods override earlier-loaded mods.
    • All mod-provided texture replacements override the user's general texture_replacements/ directory.
  5. Handle errors in lifecycle functions

    main

    Service calls return ModResult (e.g., MOD_OK, MOD_UNAVAILABLE). For lifecycle functions like mod_initialize, you can provide a ModError* to report detailed failures. Use mods::set_error to populate the error message and code. If an error is returned, the loader will disable the mod and display the message to the user.

    MOD_EXPORT ModResult mod_initialize(ModError* error) {
        if (!load_my_data()) {
            return mods::set_error(error, MOD_ERROR, "failed to load data");
        }
        return MOD_OK;
    }
  6. Hook game functions using `mods/hook.hpp`

    main

    Dusklight allows mods to hook game functions, including file-local statics, private, and virtual functions. To use typed helpers, include mods/hook.hpp and mods/svc/hook.h, and import the HookService.

    Every hook target must be declared at namespace scope using either DEFINE_HOOK (for functions you can name in C++) or DEFINE_HOOK_SYMBOL (for symbol names).

    Note: Hooking requires the mod to be declared with add_mod(... FEATURES game) in its configuration.

    #include "mods/hook.hpp"
    #include "mods/svc/hook.h"
    
    IMPORT_SERVICE(HookService, svc_hook);
    
    DEFINE_HOOK(&daAlink_c::posMove, LinkPosMove);
    DEFINE_HOOK(&daAlink_c::execute, LinkExecute);
  7. Install Dusklight on iPhone using iloader

    main

    Follow these steps to sideload the Dusklight IPA onto your iOS device:

    1. Sign into your Apple ID in iloader. This is required for registering app IDs and is sent securely to Apple.
    2. Connect your iOS device via USB. If it is not detected, click Refresh in iloader.
    3. Keep settings unchanged: Ensure the Anisette server remains set to Sidestore (.io).
    4. Import the IPA: Click Import IPA and select your Dusklight-v.X.X.X-ios-arm64.ipa file to begin the installation.

    Note: You may be prompted to trust your device during this process.

  8. Install dependencies for building Dusklight on Windows

    main

    To build Dusklight on Windows, ensure you have the following installed:

    1. CMake 3.25+: Install via CMake Tools in Visual Studio.
    2. Python 3: Install from the Microsoft Store and verify it is in your %PATH% by running python in cmd.

    Recommended IDE Setup: Use Visual Studio 2026 Community with the C++ Development workload. Ensure these packages are included:

    • Windows 11 SDK
    • CMake Tools
    • C++ Clang Compiler
    • C++ Clang-cl
  9. Indicate Dusk-specific modifications in decompiled code

    main

    When modifying original game code (decompilation) for Dusk-specific purposes, you must clearly delineate the changes to distinguish them from the original codebase.

    • Use #if TARGET_PC to wrap Dusk-specific logic while keeping the original code intact.
    • Use #if AVOID_UB when implementing fixes for Undefined Behavior in the original codebase.