Merge branch 'main' into hold-to-mash

This commit is contained in:
baxlek
2026-09-18 13:40:41 -05:00
committed by GitHub
1101 changed files with 36995 additions and 12083 deletions
+2
View File
@@ -187,6 +187,8 @@ jobs:
- name: Setup Android SDK
uses: android-actions/setup-android@v4
with:
packages: platform-tools
- name: Install Android SDK packages
run: sdkmanager "platforms;android-36" "build-tools;36.1.0" "ndk;${ANDROID_NDK_VERSION}"
+3
View File
@@ -7,3 +7,6 @@
[submodule "mods/randomizer"]
path = mods/randomizer
url = https://github.com/TwilitRealm/dusklight-randomizer.git
[submodule "mods/cosmetics"]
path = mods/cosmetics
url = https://github.com/TwilitRealm/dusklight-cosmetics
+49 -78
View File
@@ -72,6 +72,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux)
endif ()
set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE)
set(AURORA_ENABLE_CARD ON CACHE BOOL "Enable CARD API support" FORCE)
set(AURORA_ENABLE_THP ON CACHE BOOL "Enable THP decoder" FORCE)
set(AURORA_ENABLE_RMLUI ON CACHE BOOL "Enable RmlUi UI support" FORCE)
add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
target_compile_definitions(aurora_mtx PRIVATE MTX_USE_PS=1)
@@ -88,10 +89,11 @@ endif ()
option(DUSK_BUILD_WARNINGS "Enable compiler warnings (off by default)")
option(DUSK_SELECTED_OPT "If on, selected parts of the project will be compiled with optimizations on Debug, intending to make the game run at 30 FPS. Note for MSVC: you will need to remove '/RTC1' from your debug flags in CMake.")
option(DUSK_MOVIE_SUPPORT "If on, compile against libjpeg-turbo to enable THP file decoding" ON)
option(DUSK_PACKAGE_INSTALL "Install Dusklight with a Linux-native file structure" OFF)
option(DUSK_GFX_DEBUG_GROUPS "Report debug groups to the native graphics API" ${DUSK_GFX_DEBUG_GROUPS_DEFAULT})
option(DUSK_ENABLE_CODE_MODS "Enable code mods" ON)
option(DUSK_ENABLE_OPUS "Enable loading Opus audio files for mods" OFF)
set(DUSK_HAS_FUNCHOOK OFF)
if (DUSK_ENABLE_CODE_MODS AND (NOT APPLE OR CMAKE_SYSTEM_NAME STREQUAL "Darwin"))
@@ -133,69 +135,6 @@ if (MSVC)
endif ()
endif ()
if (DUSK_MOVIE_SUPPORT)
find_package(libjpeg-turbo 3.0 CONFIG QUIET)
if (libjpeg-turbo_FOUND)
message(STATUS "dusklight: Using system libjpeg-turbo")
else ()
message(STATUS "dusklight: Fetching libjpeg-turbo")
include(ExternalProject)
set(_jpeg_install_dir ${CMAKE_BINARY_DIR}/libjpeg-turbo-install)
if (WIN32)
set(_jpeg_lib ${_jpeg_install_dir}/lib/turbojpeg-static.lib)
else ()
set(_jpeg_lib ${_jpeg_install_dir}/lib/libturbojpeg.a)
endif ()
set(_jpeg_cmake_args
-DCMAKE_INSTALL_PREFIX=${_jpeg_install_dir}
-DCMAKE_PROJECT_INCLUDE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/WindowsTargetProcessor.cmake
-DENABLE_SHARED=OFF
-DWITH_TURBOJPEG=ON
-DWITH_JAVA=OFF
-DCMAKE_INSTALL_LIBDIR=lib
)
if (CMAKE_TOOLCHAIN_FILE)
get_filename_component(_jpeg_toolchain_file "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE BASE_DIR "${CMAKE_SOURCE_DIR}")
list(APPEND _jpeg_cmake_args -DCMAKE_TOOLCHAIN_FILE=${_jpeg_toolchain_file})
endif ()
set(_jpeg_passthrough_vars
ANDROID_ABI
ANDROID_PLATFORM
CMAKE_BUILD_TYPE
CMAKE_C_COMPILER
CMAKE_C_COMPILER_LAUNCHER
CMAKE_MAKE_PROGRAM
CMAKE_MSVC_RUNTIME_LIBRARY
CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
CMAKE_OSX_ARCHITECTURES
CMAKE_OSX_DEPLOYMENT_TARGET
CMAKE_OSX_SYSROOT
DEPLOYMENT_TARGET
ENABLE_ARC
ENABLE_BITCODE
PLATFORM
)
foreach(_var IN LISTS _jpeg_passthrough_vars)
if (DEFINED ${_var})
list(APPEND _jpeg_cmake_args -D${_var}=${${_var}})
endif ()
endforeach ()
ExternalProject_Add(libjpeg-turbo-ext
URL https://github.com/libjpeg-turbo/libjpeg-turbo/archive/refs/tags/3.1.0.tar.gz
URL_HASH SHA256=35fec2e1ddfb05ecf6d93e50bc57c1e54bc81c16d611ddf6eff73fff266d8285
CMAKE_ARGS ${_jpeg_cmake_args}
BUILD_BYPRODUCTS ${_jpeg_lib}
)
file(MAKE_DIRECTORY ${_jpeg_install_dir}/include)
add_library(libjpeg-turbo::turbojpeg-static STATIC IMPORTED GLOBAL)
set_target_properties(libjpeg-turbo::turbojpeg-static PROPERTIES
IMPORTED_LOCATION ${_jpeg_lib}
INTERFACE_INCLUDE_DIRECTORIES ${_jpeg_install_dir}/include
)
add_dependencies(libjpeg-turbo::turbojpeg-static libjpeg-turbo-ext)
endif ()
endif ()
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
# -Wno-multichar: Multi-character constants ('ABCD') are implementation-defined but all compilers
# (CW, GCC, Clang, MSVC) encode them identically in big-endian order.
@@ -243,8 +182,34 @@ FetchContent_Declare(miniz
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
message(STATUS "dusklight: Fetching PicoSHA2")
FetchContent_Declare(picosha2
URL https://github.com/okdshin/PicoSHA2/archive/refs/tags/v1.0.1.tar.gz
URL_HASH SHA256=9983136544234e573fe07cc1a22fdf978ad7979043e7be2e9082f6d4991ff8a8
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
set(_fetch_content_deps miniz picosha2)
if (DUSK_ENABLE_OPUS)
message(STATUS "dusklight: Fetching opusfile")
# Opusfile options
SET(OP_DISABLE_HTTP ON CACHE BOOL "" FORCE)
SET(OP_DISABLE_DOCS ON CACHE BOOL "" FORCE)
SET(OP_DISABLE_EXAMPLES ON CACHE BOOL "" FORCE)
message(STATUS "dusklight: Fetching opusfile")
FetchContent_Declare(
opusfile
GIT_REPOSITORY https://github.com/xiph/opusfile.git
GIT_TAG 6dfd29e7adb87f2e193575fc3fa88cbf1a0b27df
)
list(APPEND _fetch_content_deps opusfile)
endif ()
set(_fetch_content_deps miniz)
if (DUSK_HAS_FUNCHOOK)
message(STATUS "dusklight: Fetching funchook")
# cmake/PatchFunchook.cmake patches funchook's cmake/capstone.cmake.in to inject a
@@ -279,6 +244,14 @@ if (DUSK_HAS_FUNCHOOK)
endif ()
FetchContent_MakeAvailable(${_fetch_content_deps})
if (DUSK_HAS_FUNCHOOK AND APPLE)
target_sources(funchook-static PRIVATE src/dusk/mods/loader/code_patch_macos.cpp)
target_include_directories(funchook-static PRIVATE src/dusk/mods/loader)
set_source_files_properties(src/dusk/mods/loader/code_patch_macos.cpp
TARGET_DIRECTORY funchook-static PROPERTIES
COMPILE_OPTIONS "-O2;-fno-sanitize=all;-fno-stack-protector")
endif ()
# Use signed char on ARM to match the original game (and x86)
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" _arch)
if(_arch MATCHES "^(arm|aarch64)" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
@@ -303,26 +276,21 @@ include(cmake/GameABIConfig.cmake)
find_package(Threads REQUIRED)
set(GAME_COMPILE_DEFS DUSK_BUILDING_GAME=1)
set(GAME_LIBS aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd
aurora::card borealis::cli borealis::crash borealis::data borealis::disc borealis::discord borealis::file_select borealis::io borealis::log borealis::presentation borealis::sentry borealis::update freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json TracyClient fmt::fmt
Threads::Threads zstd::libzstd dusklight_game_headers)
set(GAME_LIBS aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd aurora::thp
aurora::card borealis::http borealis::cli borealis::crash borealis::data borealis::disc borealis::discord borealis::file_select borealis::io borealis::log borealis::net borealis::presentation borealis::sentry borealis::update borealis::ws freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json TracyClient fmt::fmt
Threads::Threads zstd::libzstd dusklight_game_headers picosha2 PNG::PNG)
if (DUSK_HAS_FUNCHOOK)
list(APPEND GAME_LIBS funchook-static)
endif ()
if (DUSK_ENABLE_OPUS)
list(APPEND GAME_LIBS OpusFile::opusfile)
list(APPEND GAME_COMPILE_DEFS DUSK_OPUS=1)
endif ()
if (WIN32)
list(APPEND GAME_LIBS Ws2_32)
endif ()
if (DUSK_MOVIE_SUPPORT)
if (TARGET libjpeg-turbo::turbojpeg-static)
list(APPEND GAME_LIBS libjpeg-turbo::turbojpeg-static)
else ()
list(APPEND GAME_LIBS libjpeg-turbo::turbojpeg)
endif ()
list(APPEND GAME_COMPILE_DEFS MOVIE_SUPPORT=1)
endif ()
if (DUSK_ENABLE_CODE_MODS)
list(APPEND GAME_COMPILE_DEFS DUSK_CODE_MODS=1)
endif ()
@@ -565,13 +533,16 @@ include(cmake/ModSDK.cmake)
if (DUSK_ENABLE_CODE_MODS AND CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
add_custom_target(dusklight_mods) # Aggregate target for all in-tree mods
add_subdirectory(mods/luau_runtime)
add_subdirectory(mods/template_mod)
add_subdirectory(mods/ao_mod)
add_subdirectory(mods/shadow_mod)
add_subdirectory(mods/window_demo)
add_subdirectory(mods/flow_demo)
add_subdirectory(mods/basic_cosmetics_mod)
add_subdirectory(mods/custom_actor_demo)
add_subdirectory(mods/cosmetics)
add_subdirectory(mods/randomizer)
add_subdirectory(mods/audio_mod)
endif ()
if (APPLE)
+3
View File
@@ -14,6 +14,9 @@ Dusklight is a reverse-engineered reimplementation of Twilight Princess.
It aims to be as accurate as possible to the original while also providing new options, enhancements, and tools to customize your experience.
> [!IMPORTANT]
> Dusklight's official website is https://twilitrealm.dev/, any other website is not affiliated and may be promoting AI-generated misinformation.
# Setup
> [!IMPORTANT]
-2
View File
@@ -296,8 +296,6 @@ function(add_mod target_name)
endif ()
target_link_libraries(${target_name} PRIVATE "${_game_lib}")
endif ()
set_target_properties(${target_name} PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
target_compile_definitions(${target_name} PRIVATE _ITERATOR_DEBUG_LEVEL=0)
endif ()
endif ()
if (ARG_RUNTIME_LIBRARIES AND NOT _has_lib)
+49 -53
View File
@@ -2,59 +2,55 @@ file(READ "${SOURCE_DIR}/cmake/capstone.cmake.in" _content)
# Insert PATCH_COMMAND before CONFIGURE_COMMAND in the ExternalProject_Add.
# Bracket args prevent cmake from substituting ${...} while writing this file.
string(REPLACE
" CONFIGURE_COMMAND \"\""
[=[ PATCH_COMMAND "${CMAKE_COMMAND}" -DDIR=${CMAKE_CURRENT_BINARY_DIR}/capstone-src -P "${CAPSTONE_FIX_SCRIPT}"
if (NOT _content MATCHES "CAPSTONE_FIX_SCRIPT")
string(REPLACE
" CONFIGURE_COMMAND \"\""
[=[ PATCH_COMMAND "${CMAKE_COMMAND}" -DDIR=${CMAKE_CURRENT_BINARY_DIR}/capstone-src -P "${CAPSTONE_FIX_SCRIPT}"
CONFIGURE_COMMAND ""]=]
_content "${_content}")
file(WRITE "${SOURCE_DIR}/cmake/capstone.cmake.in" "${_content}")
file(READ "${SOURCE_DIR}/src/funchook_unix.c" _unix_content)
# macOS rejects the POSIX mprotect RWX/RW transition for executable image pages on arm64.
# Use Mach VM_PROT_COPY for the short patch window, then restore RX permissions.
if (NOT _unix_content MATCHES "VM_PROT_READ \\| VM_PROT_WRITE \\| VM_PROT_COPY")
string(REPLACE
[=[ rv = mprotect(mstate->addr, mstate->size, prot);]=]
[=[#ifdef __APPLE__
kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)mstate->addr,
(vm_size_t)mstate->size, FALSE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY);
if (kr == KERN_SUCCESS) {
funchook_log(funchook, " unprotect memory %p (size=%"PRIuPTR", prot=read,write,copy) <- %p (size=%"PRIuPTR")\n",
mstate->addr, mstate->size, start, len);
return 0;
}
funchook_set_error_message(funchook, "Failed to unprotect memory %p (size=%"PRIuPTR", prot=read,write,copy) <- %p (size=%"PRIuPTR", error=%s)",
mstate->addr, mstate->size, start, len,
mach_error_string(kr));
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
#endif
rv = mprotect(mstate->addr, mstate->size, prot);]=]
_unix_content "${_unix_content}")
string(REPLACE
[=[ char errbuf[128];
int rv = mprotect(mstate->addr, mstate->size, PROT_READ | PROT_EXEC);]=]
[=[ char errbuf[128];
#ifdef __APPLE__
kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)mstate->addr,
(vm_size_t)mstate->size, FALSE,
VM_PROT_READ | VM_PROT_EXECUTE);
if (kr == KERN_SUCCESS) {
funchook_log(funchook, " protect memory %p (size=%"PRIuPTR", prot=read,exec)\n",
mstate->addr, mstate->size);
return 0;
}
funchook_set_error_message(funchook, "Failed to protect memory %p (size=%"PRIuPTR", prot=read,exec, error=%s)",
mstate->addr, mstate->size,
mach_error_string(kr));
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
#endif
int rv = mprotect(mstate->addr, mstate->size, PROT_READ | PROT_EXEC);]=]
_unix_content "${_unix_content}")
_content "${_content}")
file(WRITE "${SOURCE_DIR}/cmake/capstone.cmake.in" "${_content}")
endif ()
file(WRITE "${SOURCE_DIR}/src/funchook_unix.c" "${_unix_content}")
file(READ "${SOURCE_DIR}/src/funchook.c" _content)
if (NOT _content MATCHES "commit_code_patch")
string(REPLACE "#include \"funchook_internal.h\""
"#include \"funchook_internal.h\"\n#ifdef __APPLE__\n#include \"code_patch_macos.hpp\"\n#endif"
_content "${_content}")
foreach(_operation install uninstall)
if (_operation STREQUAL "install")
set(_expected old_code)
set(_replacement new_code)
else ()
set(_expected new_code)
set(_replacement old_code)
endif ()
set(_original " mem_state_t mstate;
int rv = funchook_unprotect_begin(funchook, &mstate, entry->target_func, JUMP32_BYTE_SIZE);
if (rv != 0) {
return rv;
}
memcpy(entry->target_func, entry->${_replacement}, JUMP32_BYTE_SIZE);
rv = funchook_unprotect_end(funchook, &mstate);
if (rv != 0) {
return rv;
}
flush_instruction_cache(entry->target_func, JUMP32_BYTE_SIZE);")
string(FIND "${_content}" "${_original}" _position)
if (_position EQUAL -1)
message(FATAL_ERROR "Funchook ${_operation} patch site changed")
endif ()
string(REPLACE "${_original}" "#ifdef __APPLE__
int rv = commit_code_patch(entry->target_func, entry->${_expected},
entry->${_replacement}, JUMP32_BYTE_SIZE);
if (rv != 0) {
funchook_set_error_message(funchook, \"Code patch commit failed (Mach error %d)\", rv);
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
}
#else
${_original}
#endif" _content "${_content}")
endforeach ()
file(WRITE "${SOURCE_DIR}/src/funchook.c" "${_content}")
endif ()
+11 -9
View File
@@ -2,7 +2,7 @@ include_guard(GLOBAL)
get_filename_component(_SYMBOL_MANIFEST_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
set(_SYMGEN_VERSION "1.3.4")
set(_SYMGEN_VERSION "1.3.6")
set(_SYMGEN_RELEASE_BASE_URL "https://github.com/encounter/symgen/releases/download/v${_SYMGEN_VERSION}")
set(SYMGEN_PATH "" CACHE FILEPATH "Path to a symgen executable; empty downloads the pinned release")
mark_as_advanced(SYMGEN_PATH)
@@ -15,32 +15,32 @@ function(symgen_host_asset out_name out_hash)
if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
if (_host_processor MATCHES "^(arm64|aarch64)$")
set(_asset "symgen-macos-arm64")
set(_asset_hash "SHA256=983ef6278d30bee38f240f451ca736fd294da0e5705ee15029accac5c7a33829")
set(_asset_hash "SHA256=6b836f4fd7e57fc198ca6bfb3e0161504c98f2be2622819849bfc3f265edf4af")
elseif (_host_processor MATCHES "^(x86_64|amd64)$")
set(_asset "symgen-macos-x86_64")
set(_asset_hash "SHA256=b6ab1720a4f04fadcf291f42d133e2ee68ef2e9a75d143e51584929e808af8a2")
set(_asset_hash "SHA256=93218f786d34d3ec58f96624e0494ff605e6102cdb31cd7c9922364cfc7885a5")
endif ()
elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
if (_host_processor MATCHES "^(aarch64|arm64)$")
set(_asset "symgen-linux-aarch64")
set(_asset_hash "SHA256=ba84486ff1ceb753973e6213c9bc5f195b5ff6f220f5d3322fd861966cdc791c")
set(_asset_hash "SHA256=7891446505c4dd428f4b84c7ceed1441719d910b3d5a47d3540aa890538449ae")
elseif (_host_processor MATCHES "^(x86_64|amd64)$")
set(_asset "symgen-linux-x86_64")
set(_asset_hash "SHA256=8b81a00a2ef8f5dd4b59adba1badfaca57e472bf272516bc12c4625cefb37718")
set(_asset_hash "SHA256=236bc5cd4bda03a8dd53a4531efff1fec3bcd19b09890893b9b6f8f5ae77f041")
elseif (_host_processor MATCHES "^(i[3-6]86|x86)$")
set(_asset "symgen-linux-i686")
set(_asset_hash "SHA256=01aa85d84148a6806fdf69839dea7e962e6ac46956aed63b9ecb7d596f179f93")
set(_asset_hash "SHA256=e3b4e8e978d630f07ed6aa58d387145356026116b2e8fa99801902dfac73b2ea")
endif ()
elseif (CMAKE_HOST_WIN32)
if (_host_processor MATCHES "^(arm64|aarch64)$")
set(_asset "symgen-windows-arm64.exe")
set(_asset_hash "SHA256=e116099f859177d7e29fc3444d67083596330e5c4fb3a0461b21402c89249d96")
set(_asset_hash "SHA256=36e2c68bb4f9e3abea728c4cd7ddc01ff1f462be7156af18baa20621b7d39df8")
elseif (_host_processor MATCHES "^(x86_64|amd64)$")
set(_asset "symgen-windows-x86_64.exe")
set(_asset_hash "SHA256=57ef1c2f563e33fa4915c40194c4ced540f985c48d9cf081047c6bbcb585fa37")
set(_asset_hash "SHA256=171995a33bfd5a5271b5bb78d3f2c1d4aec58721bf3a894aaad5607ff648e2a4")
elseif (_host_processor MATCHES "^(i[3-6]86|x86)$")
set(_asset "symgen-windows-x86.exe")
set(_asset_hash "SHA256=cc0ba337c798d3f63d8acbb2d16d531d0c2da878fbdd2b6307702334ec880528")
set(_asset_hash "SHA256=9ed095a01e05eb05e91472bfa7b95b84dfeaeead0941a80708196199c95188db")
endif ()
endif ()
@@ -116,6 +116,7 @@ function(setup_symbol_manifest target)
return()
endif ()
add_dependencies(${target} symgen)
set_property(TARGET ${target} APPEND PROPERTY LINK_DEPENDS "${SYMGEN_EXE}")
# Reserve an ELF program-header entry when the linker supports it (mold).
# symgen can replace the PT_NULL entry without relocating the table, keeping later post-link tools safe.
@@ -148,6 +149,7 @@ function(setup_symbol_manifest target)
# signature.
add_custom_command(TARGET ${target} POST_BUILD
COMMAND "${SYMGEN_EXE}" manifest ${_input} --embed "$<TARGET_FILE:${target}>"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Embedding symbol manifest"
VERBATIM)
endfunction()
+58
View File
@@ -0,0 +1,58 @@
flowchart TD
Start[Start Sound Effect]
subgraph BST
params[Look up sound parameters]
end
Start-->|Sound ID|BST
subgraph BSC
bms_start[Look up BMS start]
end
Start-->|Sound ID|BSC
BSC-->|BMS data| bms[BMS interpreter]
subgraph IBNK
bnk[Look up instrument parameters]
end
bms-->|Plays notes| IBNK
subgraph WSYS
wsys[Look up wave sample]
end
IBNK-->|Wave ID|WSYS
flowchart TD
Start[Start Sound Effect]
subgraph BST
params[Look up sound parameters]
end
Start-->|Sound ID|BST
BST-->|File path| ast[Stream /AudioRes/Stream/xxx.ast from disc]
flowchart TD
Start[Start Sound Effect]
subgraph BST
params[Look up sound parameters]
end
Start-->|Sound ID|BST
BST-->|Resource ID| arc[Z2SoundSeqs.arc]
arc-->|BMS file| bms[BMS interpreter]
subgraph IBNK
bnk[Look up instrument parameters]
end
bms-->|Plays notes| IBNK
subgraph WSYS
wsys[Look up wave sample]
end
IBNK-->|Wave ID|WSYS
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

+26
View File
@@ -0,0 +1,26 @@
#pragma endian big
#include "std/sys.pat"
#include "type/magic.pat"
#include "std/array.pat"
/**
* Wrapper for a file-global pointer that allows it to be stored in an array.
*/
struct Offset<T> {
T* offset : u32 [[inline]];
};
struct JAUSeqCollectionTable {
u32 mEntryCount;
u32 mBmsOffset[mEntryCount];
};
struct JAUSeqCollectionData {
type::Magic<"SC"> mMagic;
u16 mNumSoundCategories;
u32 mSectionSize;
Offset<JAUSeqCollectionTable> mTableOffsets[mNumSoundCategories];
};
JAUSeqCollectionData data @ 0x0;
+71
View File
@@ -0,0 +1,71 @@
#pragma endian big
#include "std/sys.pat"
#include "type/magic.pat"
#include "std/array.pat"
/**
* Wrapper for a file-global pointer that allows it to be stored in an array.
*/
struct Offset<T> {
T* offset : u32 [[inline]];
};
struct ItemSoundEffect {
u8 mPriority;
u8 mVolume;
padding[2];
u32 mSwBit;
float mPitch;
};
struct ItemSequence {
u8 mPriority;
u8 mVolume;
u16 mResourceId;
};
struct ItemStream {
u8 mPriority;
u8 mVolume;
u16 mStreamPanParameters;
char* mStreamFilePath[] : u32;
};
struct SoundTableGroupEntry {
u8 mTypeId;
if (mTypeId == 0x51) {
ItemSoundEffect* mOffset : u24 [[inline]];
} else if (mTypeId == 0x60) {
ItemSequence* mOffset : u24 [[inline]];
} else if (mTypeId == 0x70 || mTypeId == 0x71) {
ItemStream* mOffset : u24 [[inline]];
} else {
u24 mOffset;
}
};
struct TGroup {
u32 mNumItems;
padding[4];
SoundTableGroupEntry mEntries[mNumItems];
};
struct TSection {
u32 mNumGroups;
Offset<TGroup> mGroupOffsets[mNumGroups];
};
struct Root {
u32 mSectionNumber;
Offset<TSection> mSectionOffsets[mSectionNumber];
};
struct THeader {
type::Magic<"BST "> mMagic;
padding[8];
Root* mRoot : u32;
};
THeader header @ 0x0;
+228
View File
@@ -0,0 +1,228 @@
#pragma endian big
#include "std/sys.pat"
#include "type/magic.pat"
#include "std/array.pat"
/*
WSYS file
The WSYS file contains roughly two sections: WBCT and WINF.
WBCT contains the mapping of Wave ID -> wave archives.
WINF are the wave archives themselves and their metadata.
*/
/**
* Wrapper for a file-global pointer that allows it to be stored in an array.
*/
struct Offset<T> {
T* offset : u32 [[inline]];
};
/**
* Format that audio data is in..
*/
enum WaveFormat : u8 {
/**
* 16-samples-per-9-bytes custom Nintendo ADPCM.
*/
ADPCM4 = 0,
/**
* 16-samples-per-5-bytes custom Nintendo ADPCM.
*/
ADPCM2 = 1,
/**
* 8-bit-per-sample PCM.
*/
PCM8 = 2,
/**
* 16-bit-per-sample PCM.
*/
PCM16 = 3,
};
/**
* Defines playback info for a single audio "wave".
* This data is stored per archive, making it duplicated (except for mAWOffsetStart)
*/
struct TWave {
padding[1]; // unknown
WaveFormat mWaveFormat;
/**
* Key (as in like, the musical term) this sample is in.
*/
u8 mBaseKey;
padding[1];
/**
* Sample rate of the audio in Hz.
*/
float mSampleRate;
/**
* Position where the sample data starts.
* This is in the .aw file for the archive containing this TWave.
*/
u32 mAWOffsetStart;
/**
* Byte length of the sample data.
*/
u32 mAWLength;
/**
* Indicates whether the sample should loop or not. All bits appear set if so.
*/
u32 mLoopFlags;
/**
* Audio sample at which the loop starts.
*/
u32 mLoopStartSample;
/**
* Audio sample at which the loop ends (and goes back to mLoopStartSample).
*/
u32 mLoopEndSample;
/**
* Total sample count in this wave.
*/
u32 mSampleCount;
/**
* Last sample for continuing ADPCM decode after loop.
*/
s16 mpLast;
/**
* Penult sample for continuing ADPCM decode after loop.
*/
s16 mpPenult;
};
/**
* A single wave archive on disk.
* These are paired 1:1 with TCtrlScene objects.
*/
struct TWaveArchive {
/**
* Filename of the raw sample data on disc. Relative to /Audiores/Waves/
*/
char mFileName[0x70];
/**
* Amount of waves in this archive.
* Matches the count in the paired TCtrl object.
*/
u32 mWaveCount;
/**
* Offsets to the wave metadata (not sample data) in the WSYS.
* These are paired 1:1 to the TCtrlWaves, and the TCtrlWave contains the actual
* "Wave ID" used by the game for lookups.
*/
Offset<TWave> waveOffsets[mWaveCount];
};
/**
* Header containing data for wave archives and their metadata.
*/
struct TWaveArchiveBank {
type::Magic<"WINF"> mMagic;
/**
* Amount of archives in this wave bank.
* Matches the value in TCtrlGroup.
*/
u32 mArchiveCounts;
Offset<TWaveArchive> mArchiveOffsets[mArchiveCounts];
};
/**
* Definition for a single wave in a control group.
*/
struct TCtrlWave {
/**
* Group ID matches the index of the control group this item is referenced by.
*/
u16 mGroupId;
/**
* Wave ID used by the game to look this wave up.
*/
u16 mWaveId;
};
/**
* Contains the actual data for a TCtrlScene.
* Why is this separate? Who knows.
*/
struct TCtrl {
// Other versions of this struct with different magic (C-EX and C-ST) also exist in the file.
// They aren't pointed to so we don't need to worry about them.
type::Magic<"C-DF"> mMagic;
/**
* Amount of waves in this group.
* Matches the value in TWaveArchive.
*/
u32 waveCount;
Offset<TCtrlWave> mWaveOffsets[waveCount];
};
/**
* A single scene or "group" of waves that are loaded at once.
*/
struct TCtrlScene {
type::Magic<"SCNE"> mMagic;
padding[8]; // unknown
TCtrl* mCtrlOffset : u32 [[inline]];
};
/**
* Contains the "control" section of the WSYS.
*/
struct TCtrlGroup {
type::Magic<"WBCT"> mMagic;
padding[4]; // unknown
u32 mGroupCount;
Offset<TCtrlScene> mCtrlSceneOffsets[mGroupCount];
};
struct THeader {
type::Magic<"WSYS"> mMagic;
/**
* Size of WSYS in bytes.
*/
u32 mSize;
/**
* ID of wave bank.
* This matches the value passed to the BAA load command.
* The game originally does not use this value itself, but Dusklight does rely on it.
*/
u32 mId;
/**
* Total amount of waves in this wave bank.
* (not groups! Waves!)
*/
u32 mWaveTableSize;
TWaveArchiveBank* archiveBankOffset : u32;
TCtrlGroup* ctrlGroupOffset : u32;
};
THeader header @ 0x0;
std::assert(
header.archiveBankOffset.mArchiveCounts == header.ctrlGroupOffset.mGroupCount,
"Control group and archive count does not match!");
+241
View File
@@ -0,0 +1,241 @@
# JAudio
**JAudio** is the name for the audio engine used by Twilight Princess (along with many other Nintendo games from the era). TP uses exclusively JAudio v2, while other games use v1 or a mix of v1 and v2 infrastructure. This document will primarily focus on TP's use case, but best efforts will be made to document where behavior is TP-specific.
## Common concepts
Audio is almost exclusively
### `JAISoundID`
A "sound", be that a _sound effect_ or music, is referenced in-code through the `JAISoundID` type. This is a `u32` that the game uses to look up the relevant sound. The actual value is bitpacked (BE) from the following fields:
| Type | Field | Description |
|-------|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `u8` | Section ID | Section of the Sound Table this sound effect is located in. 0 for sound effects, 1 for sequenced music, 2 for streamed music.[^sectionids] |
| `u8` | Group ID | ID of group further used to organize inside the Sound Table's Section. Sound effects are grouped into things like "SYSTEM" and "ENEMY", other sections leave this at 0. |
| `u16` | "Wave ID" | Index inside the group to look up the sound at.<br/>**Note** that the term "wave" in code is extremely confusing[^waveterm]; it does **not** refer to audio samples ("waves") in the wave banks directly. |
[^sectionids]: JAudio itself can seemingly work outside this convention, however it is enforced by some TP-specific game code.
[^waveterm]: Possibly vestigial from JAudio v1, where I believe there were less layers of indirection.
## Disc files
All audio data is stored in `/Audiores` on the disc. Files are as follows:
### `/Audiores/Seqs/Z2SoundSeqs.arc`
Contains the BMS instructions for all BMS-based music. Not all data is kept in memory at once.
### `/Audiores/Stream/*.ast`
Contains individual streamed music. Each file is a separate music track. See [this page](https://www.lumasworkshop.com/wiki/AST_(File_Format)) for file format description.
### `/Audiores/Waves/*.aw`
Contains audio sample data for sequenced music and sound effects. These files are pure meat, no bone: they are loaded directly into ARAM and all metadata is stored in the BAA WSYS sections.
Each file contains audio samples for one "scene", with factors like the current level determining what "scenes" are made resident in memory. There is tons of duplicate data between scenes, presumably to increase simplicity and loading performance.
### `/Audiores/Z2Sound.baa`
Contains all remaining metadata for the audio system. This is effectively a container for a bunch of different sub-sections. The file starts with a bunch of "commands" that indicate where other data in the file is. Each command has a 4-character identifier and depending on the command will be followed by some extra arguments before the next command.
The commands used by TP's BAA file are as follows (note that the decompiled code has support for more load commands, which are unused):
| Command/Argument | Value | Description |
|------------------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------|
| Command | `AA_<` | Start of BAA commands. Must be at the start of the file and only appear once. |
| Command | `>_AA` | End of BAA commands. |
| Command | `ws `[^spaces] | Wave bank/WSYS data. Defines where audio samples are located on disc. |
| Argument | u32 | Wave bank ID, max 255. In TP, 0 is sound effects, 1 is music samples. |
| Argument | u32 | File offset for start of `WSYS` data |
| Argument | u32 | Bit field selecting which groups (= `.aw` files) to load immediately. TP leaves this at zero.[^32ws] |
| Command | `bnk `[^spaces] | Instrument bank/IBNK |
| Argument | u32 | Target wave bank ID |
| Argument | u32 | File offset for start of `IBNK` data |
| Command | `bsc `[^spaces] | Sound effect sequence collection. |
| Argument | u32 | File offset for start of `SC` data. |
| Argument | u32 | File offset for end of `SC` data. |
| Command | `bst `[^spaces] | Sound table. Defines parameters for music and sound effects. |
| Argument | u32 | File offset for start of `BST `[^spaces] data. |
| Argument | u32 | File offset for end of `BST `[^spaces] data. |
| Command | `bstn` | Sound name table. Defines names of all music and sound effects. Present on disc, but loading is disabled on release versions of the game. |
| Argument | u32 | File offset for start of `BSTN` data. |
| Argument | u32 | File offset for end of `BSTN` data. |
| Command | `bfca` | Unknown, something related to initialization of DSP FX data. |
| Argument | u32 | File offset for start of `RARC` data. |
[^spaces]: Padded with spaces.
[^32ws]: Both of TP's wave banks have far more than 32 groups, and seemingly this mechanism would not be able to deal with that.
Following is data descriptions for the remaining data in the `.BAA`, as pointed to by the above commands.
### `WSYS` / Wave banks
`WSYS` / Wave bank data defines where a set of audio samples can be found on disc. Each wave bank is made of multiple "groups", where each group corresponds to one `.aw` file on disc. Each group has a set of "wave IDs" it contains, along with the metadata (e.g. sample rate) and data offset in the `.aw` file.
Multiple groups can contain the same wave ID, thus meaning the raw audio samples can be duplicated on disk.
*Relevant classes: `JASWSParser`, `JASBasicWaveBank`, `JASSimpleWaveBank`.* For the actual binary layout of this data, check [the ImHex pattern](imhex/jaudio/wsys.hexpat)
### `BST ` / Sound Table
The `BST` / Sound table defines various parameters for music and sound effect playback.
The layout is pretty simple: it's hierarchical with sections (sound effects, music sequences, streamed music)[^sectionids],
which have groups (only sound effects use this) and each group just has a flat list of items.
These indices match directly to the fields of the `JAISoundID`.
*Relevant classes: `JAUSoundTable`.* For the actual binary layout of this data, check [the ImHex pattern](imhex/jaudio/bst.hexpat)
Each item has a Type ID and a set of data. Types used by TP are as follows:
#### `0x51` / sound effect
Defines that this is a sound effect. The actual BMS code to execute (and unlike the other types, including its location) is looked up in the BSC.
Layout:
```
u8 mPriority; // Priority relative to other sound effects.
u8 mVolume; // Converted to float: mVolume * (1.0/127.0)
padding[2];
u32 mSwBit; // See below.
float mPitch; // Pitch multiplier
```
```cpp
// Values for mSwBit on sound effect items. (taken from JAUSoundTable.h)
/**
* Sound is always calculated as max priority (0).
*/
#define SOUND_SW_ALWAYS_MAX_PRIORITY 0x0000'0001
/**
* Don't calculate volume by distance.
*/
#define SOUND_SW_IGNORE_DISTANCE_VOL 0x0000'0002
/**
* Don't calculate FX mix (reverb) by distance.
*/
#define SOUND_SW_IGNORE_FX_MIX 0x0000'0004
/**
* Mute all BGM sequences while this sound is playing.
*/
#define SOUND_SW_MUTE_BGM 0x0000'0008
/**
* Offset to shift to access @see SOUND_SW_RANDOM_PITCH_MASK
*/
#define SOUND_SW_RANDOM_PITCH_OFFSET 4
/**
* 4-bit value (0-15) to control the power of pitch randomization on sound playback.
* Code acts different for values above 8, not sure what the exact implication is.
*/
#define SOUND_SW_RANDOM_PITCH_MASK 0x0000'00F0
/**
* Offset to shift to access @see SOUND_SW_DOPPLER_POWER_MASK
*/
#define SOUND_SW_DOPPLER_POWER_OFFSET 8
/**
* 4-bit value (0-15) to scale the power of the Doppler effect for this sound.
*/
#define SOUND_SW_DOPPLER_POWER_MASK 0x0000'0F00
/**
* Don't calculate panning (left/right) values for this sound.
*/
#define SOUND_SW_IGNORE_PAN 0x0000'1000
/**
* Don't calculate Dolby (behind/front) values for this sound.
*/
#define SOUND_SW_IGNORE_DOLBY 0x0000'2000
/**
* Unsure. Relates to Z2 pooling of sound handles.
*/
#define SOUND_SW_POOL_FLAG_1 0x0000'4000
/**
* Unsure. Relates to Z2 pooling of sound handles.
*/
#define SOUND_SW_POOL_FLAG_2 0x0000'8000
/**
* 3-bit mask used to select a volume distance/falloff class for this sound.
*/
#define SOUND_SW_VOL_DIST_BIT_MASK 0x0007'0000
#define SOUND_SW_VOL_DIST_BIT_OFFSET 16
/**
* Limit minimum volume of this sound (after distance falloff) to 0.2.
*/
#define SOUND_SW_CLAMP_MIN_VOLUME 0x0008'0000
/**
* 3-bit mask used to select a *different* volume distance/falloff class for this sound.
* @see SOUND_SW_VOL_DIST_BIT_MASK must be zero for this to work.
*/
#define SOUND_SW_VOL_DIST_BIT_2_MASK 0x0070'0000
#define SOUND_SW_VOL_DIST_BIT_2_OFFSET 20
/**
* Mark sound as "far away" or "culled" when at max distance (selected by distance class).
* This affects a bunch of stuff like culling, automatic stopping, priorities, etc.
*/
#define SOUND_SW_CULL_AT_MAX_DISTANCE 0x0080'0000
/**
* Not sure what this does.
* Something causing volume/pan/dolby adjustment in Z2Audible::setOuterParams?
*/
#define SOUND_SW_VOL_SOMETHING_MASK 0x0F00'0000
/**
* Offset to shift to access @see SOUND_SW_RANDOM_VOLUME_MASK
*/
#define SOUND_SW_RANDOM_VOLUME_OFFSET 28
/**
* 4-bit value (0-15) to control the power of volume randomization on sound playback.
*/
#define SOUND_SW_RANDOM_VOLUME_MASK 0xF000'0000
```
#### `0x60` / music sequence
Defines background music that plays through the BMS system.
```
u8 mPriority;
u8 mVolume; // Converted to float: mVolume * (1.0/127.0)
u16 mResourceId; // ID to look up in Z2SoundSeqs.arc
```
#### `0x70` / `0x71` / music sequence
Defines a streamed music track. Difference between `0x70` and `0x71` seems to only be that `0x71` stops automatically
on scene changes in TP's game code.
```
u8 mPriority;
u8 mVolume; // Converted to float: mVolume * (1.0/127.0)
u16 mStreamPanParameters; // Bitpacked, two bits per channel determining whether a channel is center (01), left (10), or right (11).
char* mStreamFilePath[] : u32; // File path to the .ast on disc.
```
## Further reading & credits
* https://www.lumasworkshop.com/wiki/SMR.szs (note that details like the exact layout of the BAA are not the same as TP)
* XAYRGA for doing much RE work and making [JAMTools](https://xayr.gay/tools/SoundModdingToolkit/)
* The decompiled source code, duh.
+510 -123
View File
@@ -1,35 +1,137 @@
# Dusklight Mod API
Mods are `.dusk` bundles: zip archives that can contain code (in the form of native libraries), resources, DVD overlay
Mods are `.dusk` bundles: zip archives that can contain code (native libraries or scripts), resources, DVD overlay
files, and texture replacements. Mods may be enabled, disabled and reloaded at runtime.
When code mods are loaded, they get dynamically linked by the operating system to the running game process. The mod
There are three types of mods:
- **Asset-only mods**: Mods that contain no code, and may replace files on the game disc ("overlays") and provide
replacement textures (texture packs).
- **Native mods (C++)**: Fully-featured, with the ability to interop with game code and hook functions. Must be compiled
for every supported platform. (See [mod-template](https://github.com/TwilitRealm/mod-template))
- **Script mods (Luau)**: Simple, widely-compatible, but can only access provided services.
## Table of Contents
1. [mod.json](#modjson)
2. [Asset-only Mods](#asset-only-mods)
3. [Native Mods (C++)](#native-mods)
4. [Script Mods (Luau)](#script-mods)
5. [Services](#services)
6. [Built-in Services](#built-in-services)
7. [Hooking Game Functions](#hooking-game-functions)
8. [Asset Overlays](#asset-overlays)
9. [Runtime Lifecycle](#runtime-lifecycle)
10. [Error Handling](#error-handling)
11. [Advanced](#advanced)
---
## mod.json
Every mod starts with a single file, a `mod.json`:
```json
{
"id": "com.example.my_mod",
"name": "My Mod",
"version": "1.0.0",
"author": "Your Name",
"description": "A short description shown in the mod manager.",
"icon": "res/icon.png",
"banner": "res/banner.png"
}
```
`id` is required: a unique, stable identifier (reverse-DNS style; periods, underscores, and lowercase alphanumerics).
Everything else is optional but recommended.
`icon` and `banner` are bundle paths to PNG images that display in the in-game mod manager and mod website. A square
icon (1:1), and a banner (~3.5:1, minimum 800px width). If omitted, `res/icon.png` and `res/banner.png` are used
automatically when present.
Simply create a zip file with a `mod.json`, and rename it to `.dusk`. That's it!
---
## Asset-only Mods
```
my_mod.dusk
├── mod.json
├── res/ (optional bundled resources)
├── overlay/ (optional game file overrides)
└── textures/ (optional texture replacements)
```
Place files in `overlay/` to replace the disc version of that file. Examples:
- `overlay/Movie/demo_movie98_00.thp`: Replaces `Movie/demo_movie98_00.thp` on disc.
- `overlay/res/Object/Kmdl/archive/bmwr/al.bmd`: Replaces `archive/bmwr/al.bmd` _within_ `res/Object/Kmdl.arc` without
overwriting the entire `.arc`.
Place textures in `textures/` to automatically register them as texture replacements when active. These follow the same
[Dolphin-compatible naming scheme](#textureservice-modssvctextureh) as the user `<data>/texture_replacements/`
directory. Directories are scanned recursively. Examples:
- `textures/tex1_256x128_e6a4c7be9bf48305_14.dds`: Replaces the Hero's Clothes texture.
Simply zip the `mod.json` and adjacent folders, then rename to `.dusk`. Then, copy the `.dusk` into the user mods
folder:
- Windows: `%APPDATA%\TwilitRealm\Dusklight\mods`
- Linux: `~/.local/share/TwilitRealm/Dusklight/mods`
- macOS: `~/Library/Application Support/TwilitRealm/Dusklight/mods`
---
## Native Mods
Mods built with [mod-template](https://github.com/TwilitRealm/mod-template) are native C++ mods. Native mods are very
powerful and can interact with and [hook](#hooking-game-functions) game code directly. All features are available to
native mods.
Example C++ mod:
```cpp
#include "mods/service.hpp"
#include "mods/svc/log.h"
DEFINE_MOD(); // once, in exactly one translation unit
IMPORT_SERVICE(LogService, svc_log); // resolved by the loader before mod_initialize
extern "C" {
MOD_EXPORT ModResult mod_initialize(ModError* error) {
svc_log->info(mod_ctx, "hello from my_mod");
return MOD_OK;
}
MOD_EXPORT ModResult mod_update(ModError* error) { // called every frame
return MOD_OK;
}
MOD_EXPORT ModResult mod_shutdown(ModError* error) {
return MOD_OK;
}
}
```
When native mods are loaded, they get dynamically linked by the operating system to the running game process. The mod
exports lifecycle functions that Dusklight calls into (`mod_initialize`, `mod_update`, `mod_shutdown`), and the mod
communicates with the host via **services**: plain C APIs, individually versioned. Dusklight exports several built-in
services, and mods may export services of their own, permitting framework mods and cross-mod integration.
Beyond services, mods have full access to the original game's code: include game headers, call directly into any public
function, read and write data fields, and hook the vast majority of game functions.
Beyond services, native mods have full access to the original game's code: include game headers, call directly into any
public function, read and write data fields, and hook the vast majority of game functions.
## Table of Contents
### Quick Start (Native Mods)
1. [Getting Started](#getting-started)
2. [mod.json](#modjson)
3. [Anatomy of a Code Mod](#anatomy-of-a-code-mod)
4. [Services](#services)
5. [Built-in Services](#built-in-services)
6. [Hooking Game Functions](#hooking-game-functions)
7. [Asset Overlays](#asset-overlays)
8. [Runtime Lifecycle](#runtime-lifecycle)
9. [Error Handling](#error-handling)
10. [Advanced](#advanced)
---
## Getting Started
Fork the [mod template](https://github.com/TwilitRealm/mod-template), a self-contained CMake project that uses the
Dusklight mod SDK.
Create a repository from
the [mod-template](https://github.com/new?template_name=mod-template&template_owner=TwilitRealm),
a self-contained CMake project that uses the Dusklight mod SDK. It includes a GitHub Actions CI workflow that builds the
mod for every supported platform.
```
my_mod/
@@ -65,10 +167,12 @@ add_mod(my_mod
Available features:
- `fmt`: Provides the header-only `{fmt}` library and the formatted logging helpers in `mods/svc/log.hpp`.
- `fmt`: Provides the header-only `{fmt}` library and the formatted logging helpers in
[`mods/svc/log.hpp`](../sdk/include/mods/svc/log.hpp).
- `game`: Allows calling into and hooking game code. Mods that **only** use services may omit it, providing a wider
range of compatibility with Dusklight versions and a slightly faster build process.
- `webgpu`: Allows importing the WebGPU API (`webgpu/webgpu.h`). Must be enabled when using
- `webgpu`: Allows importing the WebGPU API
([`webgpu/webgpu.h`](https://github.com/webgpu-native/webgpu-headers/blob/main/webgpu.h)). Must be enabled when using
[GfxService](#gfxservice-modssvcgfxh).
Building produces `my_mod.dusk` in `build/mods/`. Copy the `.dusk` into the user mods folder:
@@ -81,63 +185,101 @@ Passing `--mods <dir>` on the command line replaces the user directory with one
---
## mod.json
## Script Mods
For simpler use cases where direct game code access and hooks aren't necessary, Luau mods are also supported.
Luau mods do not need to be compiled, and are always supported on all platforms. However, they can only use services
that are provided as Luau modules.
Mods can utilize Luau to add UI elements to their mod panel, use configuration variables, and dynamically swap out
models/textures at runtime (e.g. to switch model variants or disable certain replacements) while remaining widely
compatible.
Example mod structure:
```
my_luau_mod.dusk
├── mod.json
└── res/
├── main.luau
└── lib/util.luau
```
Set the `runtime` to `dev.twilitrealm.luau@1.0` in `mod.json`:
```json
{
"id": "com.example.my_mod",
"name": "My Mod",
"id": "com.example.my_luau_mod",
"name": "My Script Mod",
"version": "1.0.0",
"author": "Your Name",
"description": "A short description shown in the mod manager.",
"icon": "res/my_icon.png",
"banner": "res/my_banner.png"
"runtime": "dev.twilitrealm.luau@1.0"
}
```
`id` is required: a unique, stable identifier (reverse-DNS style; periods, underscores, and alphanumerics). Everything
else is optional but recommended.
`res/main.luau` runs once when the mod activates. Register optional update and shutdown callbacks through
`dusklight.host`:
`icon` and `banner` are bundle-relative paths to PNG images for the in-game mod manager: the square icon (e.g.
512x512), the banner (~3.5:1). If omitted, `res/icon.png` and `res/banner.png` are used automatically when present.
---
## Anatomy of a Code Mod
```cpp
#include "mods/service.hpp"
#include "mods/svc/log.h"
DEFINE_MOD(); // once, in exactly one translation unit
IMPORT_SERVICE(LogService, svc_log); // resolved by the loader before mod_initialize
extern "C" {
MOD_EXPORT ModResult mod_initialize(ModError* error) {
svc_log->info(mod_ctx, "hello from my_mod");
return MOD_OK;
}
MOD_EXPORT ModResult mod_update(ModError* error) { // called every frame
return MOD_OK;
}
MOD_EXPORT ModResult mod_shutdown(ModError* error) {
return MOD_OK;
}
}
```lua
local host = require("dusklight.host")
host.on_update(function()
-- Runs every frame
end)
host.on_shutdown(function()
-- Runs on mod deactivation
end)
```
All three lifecycle exports are required. `mod_ctx` is your mod's identity token, set by the loader before
`mod_initialize` runs. Pass it as the first argument to every service call.
Require script modules with `./` or `../` paths relative to the requiring file. The runtime appends `.luau` and rejects
paths that escape `res/`.
The runtime provides these modules:
- `dusklight.log`: `write`, `trace`, `debug`, `info`, `warn`, and `error`.
- `dusklight.host`: host `version`, mod metadata and directories, lifecycle callbacks, and `fail`.
- `dusklight.config`: bool, integer, float, and string variables with `get`, `set`, and subscriptions.
- `dusklight.resource`: binary-safe reads from the mod's `res/` tree.
- `dusklight.overlay`: file and copied-buffer overlays with removable handles.
- `dusklight.texture`: encoded-file and raw-data replacements with unregisterable handles.
- `dusklight.ui`: Mods panels, controls, lists, windows, dialogs, styles, menu tabs, toasts, and clipboard access.
For completion and type checking, add `sdk/luau/dusklight.d.luau` to the `luau-lsp.types.definitionFiles` setting.
Configurable overlay example:
```lua
local config = require("dusklight.config")
local overlay = require("dusklight.overlay")
local hood = config.register({ name = "hood", type = "bool", default = true })
local current
local function apply(enabled)
if current then current:remove() end
current = overlay.add_file("/res/Object/Alink.arc",
enabled and "res/alink_hood.arc" or "res/alink_nohood.arc")
end
hood:subscribe(apply)
apply(hood:get())
```
To create a script mod, copy `sdk/luau/template`, edit its manifest and source, then zip the `mod.json` and adjacent
folders and rename to `.dusk`. Copy the `.dusk` into the user mods folder:
- Windows: `%APPDATA%\TwilitRealm\Dusklight\mods`
- Linux: `~/.local/share/TwilitRealm/Dusklight/mods`
- macOS: `~/Library/Application Support/TwilitRealm/Dusklight/mods`
**Restrictions:** The Luau VM has no raw filesystem, network, or game-code access. Each script mod has a 64 MiB memory
limit. Calls are interrupted after 250 ms for updates and UI callbacks or 5 seconds for lifecycle calls. An uncaught
error, timeout, or memory exhaustion fails and disables the mod.
---
## Services
A service is a struct of C function pointers with a version header. You declare what you use at file scope, and the
loader resolves it before your mod initializes:
A service is a struct of C function pointers with a version header. Import services at file scope, and the loader
resolves them before initializing the mod:
```cpp
IMPORT_SERVICE(LogService, svc_log); // required, latest minor version
@@ -145,7 +287,7 @@ IMPORT_SERVICE_VERSION(LogService, svc_log, 0); // required, minimum minor ver
IMPORT_OPTIONAL_SERVICE(SomeService, svc_maybe); // may be null
```
A service must be imported in only **one** file (usually your `mod.cpp`). Other files may simply use `svc_log` or
A service should be imported in only **one** file (usually your `mod.cpp`). Other files may simply use `svc_log` or
`mods::log::` after including the appropriate header.
Each service is individually versioned, and there may be multiple major versions of a service provided at once,
@@ -153,26 +295,19 @@ allowing backwards compatibility with older mods while still changing services f
bump is a breaking change, treated as a different service entirely. For **additive** changes, a service appends new
functions to the end of the struct without breaking existing callers and simply bumps the minor version.
`IMPORT_SERVICE` and `IMPORT_OPTIONAL_SERVICE` require the latest minor version compiled against, making every field in
the service safe to call. A mod can use `IMPORT_SERVICE_VERSION` (or its optional counterpart) with an older minor
version to remain compatible with older Dusklight versions, then use `SERVICE_HAS` to check at runtime for fields added
after that explicitly requested version.
The contract (see `sdk/include/mods/api.h` for the full version):
- **A required import is guaranteed valid.** If the service is missing or too old, the mod fails to load with a clear
error. No need to null check at call sites.
- **Anything at or below the minor version you imported can be called unconditionally.** The default macros import
the service type's current minor version; the versioned macros explicitly override that minimum.
- Optional imports may be null; check once in `mod_initialize`.
- Fields newer than your imported minor version must be gated behind `SERVICE_HAS(service, ServiceType, field)` plus a
null check.
`IMPORT_SERVICE` and `IMPORT_OPTIONAL_SERVICE` require the latest minor version compiled against, guaranteeing that
every function is present. If a mod doesn't use (or may operate without) functions added in later minor versions, and
wants to remain compatible with older Dusklight versions, it may use `IMPORT_SERVICE_VERSION` or
`IMPORT_OPTIONAL_SERVICE_VERSION` to require an older minor version. It can then check `SERVICE_HAS` at runtime to see
if a newer function is present (i.e. running on a new enough Dusklight version).
---
## Built-in Services
### LogService (`mods/svc/log.h`)
### LogService ([`mods/svc/log.h`](../sdk/include/mods/svc/log.h))
**C++**
```cpp
IMPORT_SERVICE(LogService, svc_log);
@@ -183,9 +318,16 @@ svc_log->error(mod_ctx, "very bad");
svc_log->write(mod_ctx, LOG_LEVEL_DEBUG, "verbose details");
```
**Luau**
```lua
local log = require("dusklight.log")
log.info("spawned the thing")
```
Messages appear in the console prefixed with your mod ID. Messages are plain UTF-8 strings and are copied before the
call returns. C++ mods can enable `add_mod(... FEATURES fmt)` and use the formatted logging helpers in
`mods/svc/log.hpp`:
[`mods/svc/log.hpp`](../sdk/include/mods/svc/log.hpp):
```cpp
#include <mods/svc/log.hpp>
@@ -194,11 +336,13 @@ mods::log::info("spawned actor {} at ({}, {})", actorName, x, y);
mods::log::warn("health is down to {:.1f}%", healthPercent);
```
### ResourceService (`mods/svc/resource.h`)
### ResourceService ([`mods/svc/resource.h`](../sdk/include/mods/svc/resource.h))
Loads files from the `res/` tree of your `.dusk` archive. Paths are relative to `res/` (pass `"config.txt"`, not
`"res/config.txt"`); absolute paths and `..` are rejected.
**C++**
```cpp
IMPORT_SERVICE(ResourceService, svc_resource);
@@ -209,10 +353,17 @@ if (svc_resource->load(mod_ctx, "config.txt", &buf) == MOD_OK) {
}
```
**Luau**
```lua
local resource = require("dusklight.resource")
local contents = resource.load("config.txt")
```
Missing files return `MOD_UNAVAILABLE`. Always `free` what you `load`. The bundle is read-only; use
`HostService::data_dir` for persistent storage.
### FileService (`mods/svc/file.h`)
### FileService ([`mods/svc/file.h`](../sdk/include/mods/svc/file.h))
Provides file and folder pickers, file I/O, exports and folder enumeration.
@@ -257,9 +408,10 @@ mods::file::export_file(location, "report.txt", [](mods::file::PickResult result
`export_file` copies an existing file to a user-selected destination and returns the destination location in its
callback. Mod-owned persistent files belong in `HostService::data_dir`.
### HttpService (`mods/svc/http.h`)
### HttpService ([`mods/svc/http.h`](../sdk/include/mods/svc/http.h))
Asynchronous HTTPS requests supporting HTTP/2 and TLS 1.2+. C++ mods should use the helpers in `mods/svc/http.hpp`:
Asynchronous HTTPS requests supporting HTTP/2 and TLS 1.2+. C++ mods should use the helpers in
[`mods/svc/http.hpp`](../sdk/include/mods/svc/http.hpp):
```cpp
#include "mods/svc/http.hpp"
@@ -299,9 +451,87 @@ For large responses, set `downloadPath` to an absolute path in the calling mod's
an empty `body` and the final path in `downloadPath`. Check `Response::ok()` before using the file.
`Pending::progress()` reports download progress when the server provides a total size.
### HostService (`mods/svc/host.h`)
### WebSocketService ([`mods/svc/websocket.h`](../sdk/include/mods/svc/websocket.h))
Mod metadata and runtime interaction with the loader:
WebSocket client connections with text or binary messages. Secure `wss://` URLs are supported everywhere. Insecure
`ws://` is limited to `localhost`, `127.0.0.1`, and `[::1]`.
```cpp
#include "mods/svc/websocket.hpp"
IMPORT_SERVICE(WebSocketService, svc_websocket);
mods::ws::Connection connection;
MOD_EXPORT ModResult mod_initialize(ModError*) {
connection = mods::ws::connect({.url = "wss://example.com/events"});
return connection ? MOD_OK : connection.result();
}
MOD_EXPORT ModResult mod_update(ModError*) {
mods::ws::Event event;
while (mods::ws::poll(event)) {
if (event.type == WEBSOCKET_EVENT_MESSAGE) {
consume(event.data);
} else if (event.type == WEBSOCKET_EVENT_CLOSED) {
schedule_reconnect(event.error);
}
}
return MOD_OK;
}
```
Keep the `Connection` alive and drain `mods::ws::poll()` regularly, usually on every `mod_update` tick. A connection
emits an (optional) `OPEN` event, zero to many `MESSAGE` events, and exactly one `CLOSED` event.
**Restrictions:** A mod may only open four connections at once. Messages have a 1 MiB limit by default, and may request
up to 16 MiB. Unread data is limited to 16 MiB and the outbound queue to 4 MiB. `send` returns `MOD_CONFLICT` when the
outbound queue is full. Dropping the `Connection` or deactivating the mod attempts to gracefully close with code 1001,
until the close deadline expires.
### NetService ([`mods/svc/net.h`](../sdk/include/mods/svc/net.h))
Asynchronous raw TCP and UDP networking. Endpoints can be `tcp://host:port` or `udp://host:port`. TCP connections and
`resolve` accept hostnames. Listeners and UDP endpoints require IP literals.
```cpp
#include "mods/svc/net.hpp"
IMPORT_SERVICE(NetService, svc_net);
mods::net::BindOutcome bound;
mods::net::Socket listener;
mods::net::Socket client;
MOD_EXPORT ModResult mod_initialize(ModError*) {
listener = mods::net::listen("tcp://127.0.0.1:0", &bound);
client = mods::net::connect(bound.local);
return listener && client ? MOD_OK : MOD_ERROR;
}
MOD_EXPORT ModResult mod_update(ModError*) {
mods::net::Event event;
while (mods::net::poll(event)) {
if (event.type == NET_EVENT_ACCEPTED) {
remember_client(mods::net::adopt(event.accepted));
} else if (event.type == NET_EVENT_STREAM_DATA) {
consume(event.data);
}
}
return MOD_OK;
}
```
`send` and `send_to` copy the payload and return `MOD_CONFLICT` when the socket's outbound queue is full. `stats`
reports queued bytes, traffic, dropped inbound datagrams, and asynchronous UDP send failures.
**Restrictions:** A mod may only have 32 streams, 4 listeners, 4 UDP sockets, and 8 DNS resolutions active at once.
### HostService ([`mods/svc/host.h`](../sdk/include/mods/svc/host.h))
Mod metadata and runtime interaction with the loader.
**C++**
```cpp
IMPORT_SERVICE(HostService, svc_host);
@@ -319,6 +549,20 @@ if (svc_host->data_dir(mod_ctx, &dataDir) == MOD_OK) {
svc_host->fail(mod_ctx, MOD_ERROR, "something unrecoverable happened");
```
**Luau**
```lua
local host = require("dusklight.host")
local dataDir = host.data_dir()
host.on_update(function()
-- Runs every frame
end)
host.on_shutdown(function()
-- Runs on mod deactivation
end)
host.fail("something unrecoverable happened")
```
`get_service`/`publish_service` provide dynamic service lookup; see [Exporting Services](#exporting-services).
**Lifecycle watches.** If your mod provides a service that hands out per-caller state (registrations, callbacks,
@@ -341,17 +585,19 @@ svc_host->watch_mod_lifecycle(mod_ctx, on_mod_lifecycle, nullptr, &watch);
`MOD_LIFECYCLE_DETACHED` fires on the game thread at a lifecycle safe point, after the subject's `mod_shutdown` ran and
every service dropped its state. For your own mod's teardown, use `mod_shutdown` instead.
### HookService (`mods/svc/hook.h`)
### HookService ([`mods/svc/hook.h`](../sdk/include/mods/svc/hook.h))
Installs hooks on game functions and resolves symbols by name. You'll rarely call it directly; use the typed helpers in
`mods/svc/hook.hpp` described in [Hooking Game Functions](#hooking-game-functions).
[`mods/svc/hook.hpp`](../sdk/include/mods/svc/hook.hpp) described in
[Hooking Game Functions](#hooking-game-functions).
### OverlayService (`mods/svc/overlay.h`)
### OverlayService ([`mods/svc/overlay.h`](../sdk/include/mods/svc/overlay.h))
Registers DVD file overlays at runtime: the dynamic counterpart to the static `overlay/` directory (see
[Asset Overlays](#asset-overlays)). Overlay a disc path with a file from your bundle, a file within an archive,
or with a caller-owned buffer
(copied on registration):
or with a caller-owned buffer (copied on registration).
**C++**
```cpp
IMPORT_SERVICE(OverlayService, svc_overlay);
@@ -363,6 +609,14 @@ svc_overlay->add_buffer(mod_ctx, "/generated.txt", data, size, nullptr);
svc_overlay->remove(mod_ctx, handle);
```
**Luau**
```lua
local overlay = require("dusklight.overlay")
local replacement = overlay.add_file("/Movie/demo_movie98_00.thp", "res/replacement.thp")
replacement:remove()
```
`disc_path` must be absolute (leading `/`) and is matched against the disc case-insensitively. Paths that don't exist
on the disc are added as new files. Changes are applied at the next frame boundary, and data the game already read
stays in memory until the file is re-read: sometimes a scene reload, and in the worst case, a full restart.
@@ -372,11 +626,13 @@ data get refreshed without a full restart.
See [Asset Overlays](#asset-overlays) for priority and conflict handling.
### TextureService (`mods/svc/texture.h`)
### TextureService ([`mods/svc/texture.h`](../sdk/include/mods/svc/texture.h))
Registers texture replacements at runtime: the dynamic counterpart to the static `textures/` directory (see
[Asset Overlays](#asset-overlays)). Two forms: raw texel data with an explicit key, or an encoded `.dds`/`.png` from
your bundle whose filename encodes the key:
your bundle whose filename encodes the key.
**C++**
```cpp
IMPORT_SERVICE(TextureService, svc_texture);
@@ -397,6 +653,14 @@ svc_texture->register_data(mod_ctx, &key, &data, nullptr);
svc_texture->unregister(mod_ctx, handle);
```
**Luau**
```lua
local texture = require("dusklight.texture")
local replacement = texture.register_file("res/tex1_32x32_$_6.png")
replacement:unregister()
```
Filenames use the same Dolphin-style convention as the user's `texture_replacements` directory:
`tex1_{w}x{h}_{texhash}[_{tluthash}]_{fmt}.dds|.png`, where hashes may be `$` (wildcard). `_mipN` sidecar files next to
a registered file are picked up automatically. Files are decoded lazily on first use by the renderer; raw data is copied
@@ -404,11 +668,13 @@ at registration. Registrations follow your mod's lifecycle.
See [Asset Overlays](#asset-overlays) for priority and conflict handling.
### ConfigService (`mods/svc/config.h`)
### ConfigService ([`mods/svc/config.h`](../sdk/include/mods/svc/config.h))
Persistent, mod-scoped configuration variables. Each var is stored in the user's `config.json` under
`mod.<escaped mod id>.<name>` (escaping: `.` → `_`, `_` → `__`, so `com.example.my_mod` becomes `com_example_my__mod`),
next to the host's own settings:
next to the host's own settings.
**C++**
```cpp
IMPORT_SERVICE(ConfigService, svc_config);
@@ -432,6 +698,17 @@ void on_speed_changed(ModContext* ctx, ConfigVarHandle var, const ConfigVarValue
svc_config->subscribe(mod_ctx, var, on_speed_changed, nullptr, nullptr);
```
**Luau**
```lua
local config = require("dusklight.config")
local speed = config.register({ name = "speedMultiplier", type = "float", default = 1.0 })
speed:subscribe(function(value, previous)
-- React to the new value.
end)
speed:set(2.0)
```
Types: `CONFIG_VAR_BOOL` (`bool`), `CONFIG_VAR_INT` (`int64_t`), `CONFIG_VAR_FLOAT` (`double`), `CONFIG_VAR_STRING`
(UTF-8; `get_string` copies into a caller buffer, pass a `NULL` buffer with size 0 to query the length). Accessors are
typed and must match the registration.
@@ -440,10 +717,10 @@ Change callbacks fire on the game thread whenever the value changes at runtime (
Writes that store the same value are silent. Values applied from `config.json` or `--cvar` at registration do
**not** fire callbacks; read the value after `register_var` for the starting state.
### SaveService (`mods/svc/save.h`)
### SaveService ([`mods/svc/save.h`](../sdk/include/mods/svc/save.h))
Stores named binary blobs for each save slot. Blob names are scoped to the calling mod, and each mod may store up to
`SAVE_BLOB_BUDGET_BYTES` per slot. The service copies data passed to `set_blob`.
Allows reading and writing binary blobs associated with save slots. Blobs are scoped to your mod and the active game
mode's save file. A mod may store up to `SAVE_BLOB_BUDGET_BYTES` per slot.
```cpp
IMPORT_SERVICE(SaveService, svc_save);
@@ -466,14 +743,14 @@ if (svc_save->get_blob(mod_ctx, "state", &loaded, &loadedSize) == MOD_OK &&
`set_blob`, `get_blob`, and `delete_blob` operate on the current slot, which is available after creating or loading a
save and unavailable at file select. Blob changes are written with the next game save. File-select copy and erase
operations update the blob data as well. Use `peek_blob` to read the calling mod's data from any slot; it uses the same
buffer contract as `get_blob`. Pass a `NULL` buffer to either read function to query the blob size.
operations update the blob data as well. Use `peek_blob` to read the calling mod's data from any slot in the active save
file. Pass a `NULL` buffer to either read function to query the blob size.
`observe_saves` registers callbacks for new, loaded, and written saves. New-save callbacks run after the slot's blobs
are cleared. Observers are removed automatically when the mod is detached, so the output handle is only needed for
manual unregistration. Save callbacks run on the game thread.
### StageService (`mods/svc/stage.h`)
### StageService ([`mods/svc/stage.h`](../sdk/include/mods/svc/stage.h))
Allows making changes to a stage's "stage info" (contents of .dzs/.dzr files).
(Currently only supports editing actor nodes.)
@@ -522,7 +799,7 @@ Stage names may contain up to 8 characters. For patches and deletions, room `0xf
layer; additions require a specific room. Edits are removed when the mod is detached. If multiple mods edit the same
record, the later-loaded mod wins.
### UiService (`mods/svc/ui.h`)
### UiService ([`mods/svc/ui.h`](../sdk/include/mods/svc/ui.h))
Integrate seamlessly with Dusklight's UI system: add controls and buttons to your mod's detail pane in the Mods window,
create custom windows and modal dialogs, apply custom RCSS stylesheets (anywhere!), and add menu bar tabs.
@@ -532,6 +809,8 @@ content is rebuilt, and `update` runs every frame while that mod is selected. Wh
pane carries your mod's id as a `mod-id` attribute (like custom window roots), so scoped RCSS can target it (e.g.
`[mod-id="com.example.mod"]`).
**C++**
```cpp
IMPORT_SERVICE(UiService, svc_ui);
@@ -555,14 +834,27 @@ panel.update = update;
svc_ui->register_mods_panel(mod_ctx, &panel);
```
**Luau**
```lua
local ui = require("dusklight.ui")
ui.register_mods_panel({
build = function(panel)
panel:add_section("Status")
panel:add_text("running")
end,
})
```
Element setters must match the element kind: `elem_set_text`/`elem_set_rml` on text rows, and `elem_set_progress` on
progress bars. `elem_set_class` sets or clears an RCSS class on any element handle, for styling via scoped or
per-window RCSS. A non-`MOD_OK` result from `build`/`update` fails your mod, as do exceptions thrown from any UI
callback.
**Controls:** `pane_add_control` adds an input row described by a `UiControlDesc`: `UI_CONTROL_BUTTON`,
`UI_CONTROL_GROUP`, `UI_CONTROL_TOGGLE`, `UI_CONTROL_NUMBER`, `UI_CONTROL_STRING`, `UI_CONTROL_SELECT`, or
`UI_CONTROL_COLOR`. Values bind with callbacks or directly to a config var.
`UI_CONTROL_GROUP`, `UI_CONTROL_TOGGLE`, `UI_CONTROL_NUMBER`, `UI_CONTROL_STRING`, `UI_CONTROL_SELECT`,
`UI_CONTROL_COLOR`, `UI_CONTROL_FILE_PICKER`, `UI_CONTROL_ICON_BUTTON`, or `UI_CONTROL_DROPDOWN`. Bind values with
callbacks or directly to a config var.
```cpp
UiControlDesc control = UI_CONTROL_DESC_INIT;
@@ -571,18 +863,32 @@ control.label = "Enable rainbows";
control.help_rml = "Shown in the help pane while focused.";
control.binding = UI_BINDING_CONFIG_VAR;
control.config_var = myBoolVar; // from svc_config->register_var
svc_ui->pane_add_control(mod_ctx, leftPane, &control, nullptr);
svc_ui->pane_add_control(mod_ctx, pane, &control, nullptr);
UiRowDesc rowDesc = UI_ROW_DESC_INIT;
rowDesc.align = UI_ROW_ALIGN_CENTER;
UiElementHandle row = 0;
svc_ui->pane_add_row(mod_ctx, pane, &rowDesc, &row);
UiControlDesc play = UI_CONTROL_DESC_INIT;
play.kind = UI_CONTROL_ICON_BUTTON;
play.icon = "play_arrow";
play.label = "Play";
play.on_pressed = play_track;
svc_ui->pane_add_control(mod_ctx, row, &play, nullptr);
```
`UI_BINDING_CONFIG_VAR` wires persistence, change notifications, and the modified indicator automatically. The var
type must match the control: `TOGGLE` = bool, `NUMBER` and `SELECT` = int, `STRING` and `COLOR` = string. Float vars
are not bindable; use callbacks and convert. `help_rml` and `SELECT` option lists render in a help pane, so `SELECT`
controls are only available inside window tabs.
type must match the control: `TOGGLE` = bool, `NUMBER`, `SELECT`, and `DROPDOWN` = int, `STRING`, `COLOR`, and
`FILE_PICKER` = string. Float vars are not bindable; use callbacks and convert. `help_rml` and `SELECT` option lists
render in a help pane, so `SELECT` controls are only available inside window tabs.
`pane_add_group` adds a category button to a window tab's left pane. Focusing the button clears the paired right pane
and calls the group's build callback with that pane, which is useful for organizing related controls without adding
more tabs.
`pane_add_row` adds a horizontal container that other controls may be nested inside.
**Lists:** `pane_add_list` adds a scrollable virtualized list of items that can be efficiently updated and filtered.
Keys must be unique and remain stable across replacements.
@@ -704,7 +1010,7 @@ existing documents restyle immediately, and future ones pick it up when created.
host styles and may override them. Scope selectors tightly (use `[mod-id="..."]`!), especially for `UI_SCOPE_WINDOW`,
unless changing host UI is intentional.
### WindowService (`mods/svc/window.h`)
### WindowService ([`mods/svc/window.h`](../sdk/include/mods/svc/window.h))
Allows creating new windows that can be rendered to via `GfxService`.
@@ -724,12 +1030,13 @@ one present target may be attached to a WindowService window at a time.
New windows are hidden by default so a mod can finish attaching graphics before calling `show_window`.
### GfxService (`mods/svc/gfx.h`)
### GfxService ([`mods/svc/gfx.h`](../sdk/include/mods/svc/gfx.h))
**Requires `add_mod(... FEATURES webgpu)`**
Direct WebGPU access at various stages of the rendering pipeline. Mods use the `wgpu*` C API (via `webgpu/webgpu.h`) for
custom draws and compute dispatches. Mods must manage their own WebGPU state, including pipelines and bind groups.
Direct WebGPU access at various stages of the rendering pipeline. Mods use the `wgpu*` C API (via
[`webgpu/webgpu.h`](https://github.com/webgpu-native/webgpu-headers/blob/main/webgpu.h)) for custom draws and compute
dispatches. Mods must manage their own WebGPU state, including pipelines and bind groups.
```cpp
IMPORT_SERVICE(GfxService, svc_gfx);
@@ -779,7 +1086,7 @@ To create a `WGPUSurface` manually, `GfxDeviceInfo` holds the `WGPUInstance` and
`push_present` must be called every frame from a GfxService stage callback. If surface was lost, `push_present` returns
`MOD_ERROR`. Unregister and re-register the target before trying again.
### CameraService (`mods/svc/camera.h`)
### CameraService ([`mods/svc/camera.h`](../sdk/include/mods/svc/camera.h))
Converts a game view provided by a render callback into WebGPU-convention camera data. Matrix fields are column-major
`float[16]` values using the matrix * column-vector convention (transpose of the game's row-major `Mtx`/`Mtx44` layout),
@@ -801,7 +1108,7 @@ first in-game frame. Projection matrices match the renderer's WebGPU clip conven
Camera operators allow overriding the main camera. When an operator callback returns true, its values replace the camera
state for the current frame. Register and unregister using `register_camera_operator` / `unregister_camera_operator`.
### GameModeService (`mods/svc/game_mode.h`)
### GameModeService ([`mods/svc/game_mode.h`](../sdk/include/mods/svc/game_mode.h))
Allows a mod to register a game mode with callbacks for key gameplay and save lifecycle events. Registered game modes
appear in the prelaunch menu. Game modes may use a unique set of saves by configuring `save_name`; leave it empty to use
@@ -920,6 +1227,82 @@ svc_game_mode->register_game_mode(mod_ctx, &gameModeDesc);
```
### ActorService (`mods/svc/actor.h`)
A service that manages registering and creating custom actors. These actors will be run by the game as if they are part of the engine. These actors can be created by the game either by its 16-bit actor name, or a 7-character long name that can
be loaded by a stage.
```cpp
#include "mods/svc/actor.h"
IMPORT_SERVICE(ActorService, svc_actor);
class myActor_c : public fopAc_ac_c {};
int myActor_Create(void* i_this) {
// Ran several times, until it returns cPhs_COMPLEATE_e to allow for async loading
return cPhs_COMPLEATE_e;
}
int myActor_Delete(void* i_this) {
// Free resources here
return 1;
}
int myActor_Execute(void* i_this) {
// Ran once per game tick
return 1;
}
int myActor_IsDelete(void* i_this) {
// Returns 1 when the actor can be deleted
return 1;
}
int myActor_Draw(void* i_this) {
// Code to draw the actor
return 1;
}
s16 actor_name; // The process name that can be used by the game to load the actor
ActorHandle actor_handle;
ActorProfileDesc profDesc = {
.name = "AUnique", // The name used by the stage loader to load the actor with.
// It has a character limit of 7 and must be unique among active
// mod actors. Matching a game actor name overrides stage lookup.
.priority_group = 7, // When, relative to other actors _Execute should run
// See: mods/svc/actor.h
.process_size = sizeof(myActor_c),
.draw_priority = fpcDwPi_OBJ_LBOX_e, // Defines when the actor should be drawn relative
// to other actors (see f_pc_draw_priority.h)
.status = fopAcStts_CULL_e | fopAcStts_UNK_0x4000_e | fopAcStts_UNK_0x40000_e,
.group = fopAc_ACTOR_e, // Can be fopAc_ACTOR_e, fopAc_PLAYER_e, fopAc_ENEMY_e, or fopAc_NPC_e
.cull_type = fopAc_CULLBOX_CUSTOM_e,
.create_function = myActor_Create,
.delete_function = myActor_Delete,
.execute_function = myActor_Execute,
.is_delete_function = myActor_IsDelete,
.draw_function = myActor_Draw,
};
svc_actor->register_actor(mod_ctx, &profDesc, &actor_name, &actor_handle);
// Spawn the actor at the player's position
fopAc_ac_c* plr = dComIfGp_getPlayer(0);
if (plr) {
ActorSpawnParams spawnParams = {
.parameters = 0,
.argument = 0,
.room_num = fopAcM_GetRoomNo(plr),
.position = {plr->current.pos.x, plr->current.pos.y, plr->current.pos.z},
.angle = {plr->current.angle.x, plr->current.angle.y, plr->current.angle.z},
.scale = {1.0f, 1.0f, 1.0f}
};
ActorId created_actor_id;
svc_actor->create_actor(mod_ctx, actor_name, &spawnParams, &created_actor_id);
}
```
See `mods/custom_actor_demo` for a more complete example.
---
## Hooking Game Functions
@@ -927,7 +1310,7 @@ svc_game_mode->register_game_mode(mod_ctx, &gameModeDesc);
**Requires `add_mod(... FEATURES game)`**
Mods may hook the vast majority of game functions, including file-local static, private and virtual functions.
`mods/svc/hook.hpp` provides typed helpers over the hook service:
[`mods/svc/hook.hpp`](../sdk/include/mods/svc/hook.hpp) provides typed helpers over the hook service:
```cpp
#include "mods/svc/hook.hpp"
@@ -1003,12 +1386,16 @@ HookshotHit::g_orig(link, atObjInf, target, tgObjInf); // call through to the o
Class member functions must include `Class*` as the first argument.
Two spellings work on every platform:
There are three ways to refer to a function by symbol:
- **Display names** (`daAlink_c::posMove`, `fapGm_Before`): the qualified name with no parameter list. They carry no
signature, so overload sets (and file-local statics sharing a name) return `MOD_CONFLICT`.
- **Decorated names** (`_ZN9daAlink_c7posMoveEv` / `?posMove@daAlink_c@@...`): the platform's mangled spelling in
dlsym convention (no Mach-O leading underscore). The escape hatch for overloads.
- **Display names** (`daAlink_c::posMove`, `fapGm_Before`): the qualified name with no parameter list. Since they have
no signature, overloads (and file-local statics sharing a name) return `MOD_CONFLICT`.
- **Decorated names** (`_ZN9daAlink_c7posMoveEv` / `?posMove@daAlink_c@@...`): the platform's mangled name, like you'd
pass to dlsym(). Useful for overloads, but must be specified separately for Windows (`#ifdef _MSVC_LANG`) and other
platforms.
- **Translation unit aliases** (`src/d/actor/d_a_b_gnd.cpp#action`): the source path relative to the repository root,
followed by `#` and then the function display name without parameters. This allows disambiguating static functions
with the same name across different source files.
Installing fails with `MOD_UNAVAILABLE` when it didn't resolve (missing, ambiguous, or no symbol manifest). Unlike
`DEFINE_HOOK`, the signature is **not** compiler-checked: a mismatched signature will corrupt the
+1 -1
+68 -2
View File
@@ -1422,6 +1422,8 @@ set(DUSK_FILES
src/dusk/achievements.cpp
src/dusk/action_bindings.cpp
src/dusk/action_bindings.h
src/dusk/archive.cpp
src/dusk/archive.hpp
src/dusk/asserts.cpp
src/dusk/autosave.cpp
src/dusk/config.cpp
@@ -1432,10 +1434,10 @@ set(DUSK_FILES
src/dusk/dvd_asset.cpp
src/dusk/dvd_asset.hpp
src/dusk/extras.c
src/dusk/frame_interpolation.cpp
src/dusk/commands.cpp
src/dusk/commands.hpp
src/dusk/game_clock.cpp
src/dusk/hash.hpp
src/dusk/game_mode.cpp
src/dusk/gamepad_color.cpp
src/dusk/globals.cpp
@@ -1462,6 +1464,13 @@ set(DUSK_FILES
src/dusk/imgui/ImGuiStateShare.cpp
src/dusk/imgui/ImGuiStateShare.hpp
src/dusk/imgui/ImGuiStubLog.cpp
src/dusk/interp/camera.cpp
src/dusk/interp/frame_interpolation.cpp
src/dusk/interp/line.cpp
src/dusk/interp/material.cpp
src/dusk/interp/particle.cpp
src/dusk/interp/samples.cpp
src/dusk/interp/vertex.cpp
src/dusk/io.cpp
src/dusk/iso_validate.cpp
src/dusk/language.cpp
@@ -1478,10 +1487,23 @@ set(DUSK_FILES
src/dusk/mods/loader/depgraph.hpp
src/dusk/mods/loader/loader.cpp
src/dusk/mods/loader/loader.hpp
src/dusk/mods/loader/manifest.cpp
src/dusk/mods/loader/manifest.hpp
src/dusk/mods/loader/natives.cpp
src/dusk/mods/loader/natives.hpp
src/dusk/mods/loader/packages.cpp
src/dusk/mods/loader/packages.hpp
src/dusk/mods/loader/native_module.cpp
src/dusk/mods/loader/native_module.hpp
src/dusk/mods/loader/prepatch.cpp
src/dusk/mods/loader/prepatch.hpp
src/dusk/mods/updates.cpp
src/dusk/mods/updates.hpp
src/dusk/mods/catalog.cpp
src/dusk/mods/catalog.hpp
src/dusk/mods/queue.cpp
src/dusk/mods/queue.hpp
src/dusk/mods/services.hpp
src/dusk/mods/item.hpp
src/dusk/mods/item_actor.cpp
src/dusk/mods/item_checks.cpp
@@ -1490,6 +1512,15 @@ set(DUSK_FILES
src/dusk/mods/log_buffer.hpp
src/dusk/mods/manifest.cpp
src/dusk/mods/manifest.hpp
src/dusk/mods/svc/actor.cpp
src/dusk/mods/svc/audio_res/audio_res.hpp
src/dusk/mods/svc/audio_res/audio_res.cpp
src/dusk/mods/svc/audio_res/bst.cpp
src/dusk/mods/svc/audio_res/bst.hpp
src/dusk/mods/svc/audio_res/wsys.cpp
src/dusk/mods/svc/audio_res/wsys.hpp
src/dusk/mods/svc/audio_res/wave.cpp
src/dusk/mods/svc/audio_res/opus.cpp
src/dusk/mods/svc/camera.cpp
src/dusk/mods/svc/config.cpp
src/dusk/mods/svc/config.hpp
@@ -1500,8 +1531,13 @@ set(DUSK_FILES
src/dusk/mods/svc/hook.cpp
src/dusk/mods/svc/host.cpp
src/dusk/mods/svc/http.cpp
src/dusk/mods/svc/net.cpp
src/dusk/mods/svc/net.hpp
src/dusk/mods/svc/websocket.cpp
src/dusk/mods/svc/item.cpp
src/dusk/mods/svc/item.hpp
src/dusk/mods/svc/id_allocator.cpp
src/dusk/mods/svc/id_allocator.hpp
src/dusk/mods/svc/log.cpp
src/dusk/mods/svc/overlay.cpp
src/dusk/mods/svc/registry.cpp
@@ -1521,6 +1557,8 @@ set(DUSK_FILES
src/dusk/presentation.cpp
src/dusk/presentation.hpp
src/dusk/scope_guard.hpp
src/dusk/save_manager.cpp
src/dusk/save_manager.hpp
src/dusk/settings.cpp
src/dusk/speedrun.cpp
src/dusk/stubs.cpp
@@ -1535,6 +1573,8 @@ set(DUSK_FILES
src/dusk/ui/bool_button.hpp
src/dusk/ui/button.cpp
src/dusk/ui/button.hpp
src/dusk/ui/clamped_text.cpp
src/dusk/ui/clamped_text.hpp
src/dusk/ui/color_input.cpp
src/dusk/ui/color_input.hpp
src/dusk/ui/component.cpp
@@ -1544,6 +1584,10 @@ set(DUSK_FILES
src/dusk/ui/controls.hpp
src/dusk/ui/document.cpp
src/dusk/ui/document.hpp
src/dusk/ui/drop_install_modal.cpp
src/dusk/ui/drop_install_modal.hpp
src/dusk/ui/dropdown_button.cpp
src/dusk/ui/dropdown_button.hpp
src/dusk/ui/editor.cpp
src/dusk/ui/editor.hpp
src/dusk/ui/event.cpp
@@ -1564,21 +1608,41 @@ set(DUSK_FILES
src/dusk/ui/list.hpp
src/dusk/ui/menu_bar.cpp
src/dusk/ui/menu_bar.hpp
src/dusk/ui/mod_browser.cpp
src/dusk/ui/mod_browser.hpp
src/dusk/ui/online_mods.cpp
src/dusk/ui/online_mods.hpp
src/dusk/ui/package_row.cpp
src/dusk/ui/package_row.hpp
src/dusk/ui/mod_texture_provider.cpp
src/dusk/ui/mod_texture_provider.hpp
src/dusk/ui/remote_texture_provider.cpp
src/dusk/ui/remote_texture_provider.hpp
src/dusk/ui/runtime_image.cpp
src/dusk/ui/runtime_image.hpp
src/dusk/ui/mod_window.cpp
src/dusk/ui/mod_window.hpp
src/dusk/ui/modal.cpp
src/dusk/ui/modal.hpp
src/dusk/ui/mod_updates.cpp
src/dusk/ui/mod_updates.hpp
src/dusk/ui/mods_window.cpp
src/dusk/ui/mods_window.hpp
src/dusk/ui/nav_types.hpp
src/dusk/ui/nav_group.cpp
src/dusk/ui/nav_group.hpp
src/dusk/ui/context_menu.cpp
src/dusk/ui/context_menu.hpp
src/dusk/ui/icon_button.cpp
src/dusk/ui/icon_button.hpp
src/dusk/ui/tooltip.cpp
src/dusk/ui/tooltip.hpp
src/dusk/ui/number_button.cpp
src/dusk/ui/number_button.hpp
src/dusk/ui/overlay.cpp
src/dusk/ui/overlay.hpp
src/dusk/ui/row.cpp
src/dusk/ui/row.hpp
src/dusk/ui/pane.cpp
src/dusk/ui/pane.hpp
src/dusk/ui/popover.cpp
@@ -1589,6 +1653,8 @@ set(DUSK_FILES
src/dusk/ui/preset.hpp
src/dusk/ui/reporting.cpp
src/dusk/ui/reporting.hpp
src/dusk/ui/saves_window.cpp
src/dusk/ui/saves_window.hpp
src/dusk/ui/select_button.cpp
src/dusk/ui/select_button.hpp
src/dusk/ui/settings.cpp
@@ -1612,7 +1678,7 @@ set(DUSK_FILES
src/dusk/version.cpp
src/dusk/utilities.cpp
src/helpers/batch.cpp
src/helpers/endian.cpp
src/helpers/offset_ptr.cpp
src/helpers/string.cpp
src/helpers/cast.cpp
)
-1
View File
@@ -5,7 +5,6 @@
#include "f_pc/f_pc_base.h"
#include "SSystem/SComponent/c_bg_s_grp_pass_chk.h"
#include "SSystem/SComponent/c_bg_s_poly_pass_chk.h"
#include "helpers/endian.h"
struct cBgD_Vtx_t : public Vec {};
-1
View File
@@ -2,7 +2,6 @@
#define C_M3D_G_TRI_H_
#include "SSystem/SComponent/c_m3d_g_pla.h"
#include "helpers/endian.h"
class cM3dGCyl;
-1
View File
@@ -13,7 +13,6 @@ public:
bool update(s32 chan);
void bzeroBuffer(s32 chan);
private:
/* 0x00 */ s16* mBuffer[4];
};
-1
View File
@@ -41,7 +41,6 @@ public:
static bool checkRadioSensitivity(s32 chan);
static bool isSubmitPlayByRadioSensitivity(s32 chan);
private:
};
#endif /* Z2AUDIOCS_SPKSPEAKERCTRL_H */
-1
View File
@@ -28,7 +28,6 @@ public:
inline SpkData* getData(void) const { return mData; }
inline SpkMixingBuffer* getMixingBuffer(void) const { return mMixingBuffer; }
private:
/* 0x00 */ JKRHeap* mHeap;
/* 0x04 */ SpkData* mData;
/* 0x08 */ SpkMixingBuffer* mMixingBuffer;
-1
View File
@@ -31,7 +31,6 @@ public:
return (SpkTableParams*)mEntryOffset + num;
}
// private:
/* 0x00 */ bool mIsInitialized;
/* 0x04 */ s32 mNumOfSound;
/* 0x08 */ u32 mEntryOffset;
-1
View File
@@ -25,7 +25,6 @@ public:
inline const void* getResource(void) const { return mWaveData; }
inline void* getResource(void) { return mWaveData; }
private:
/* 0x00 */ void* mWaveData;
};
+85 -45
View File
@@ -9,6 +9,8 @@
#include "JSystem/JAudio2/JAUAudibleParam.h"
#include "JSystem/TPosition3.h"
#define Z2_AUDIO_PLAYERS 1
struct Z2Audible;
struct Z2AudibleAbsPos {
@@ -49,10 +51,10 @@ struct Z2AudioCamera {
f32 getCamDist() const { return mCamDist; }
/* 0x00 */ JGeometry::TPosition3f32 field_0x0;
/* 0x00 */ JGeometry::TPosition3f32 mViewMatrix;
/* 0x30 */ JGeometry::TVec3<f32> mVel;
/* 0x3C */ JGeometry::TVec3<f32> mPos;
/* 0x48 */ JGeometry::TVec3<f32> field_0x48;
/* 0x48 */ JGeometry::TVec3<f32> mLastPos;
/* 0x54 */ f32 mFovySin;
/* 0x58 */ f32 mVolCenterZ;
/* 0x5C */ f32 mTargetVolume;
@@ -83,14 +85,14 @@ struct Z2SpotMic {
/* 0x04 */ f32 field_0x4;
/* 0x08 */ f32 field_0x8;
/* 0x0C */ f32 field_0xc;
/* 0x10 */ Z2AudioCamera* field_0x10[1];
/* 0x10 */ Z2AudioCamera* field_0x10[Z2_AUDIO_PLAYERS];
/* 0x14 */ Vec* mPosPtr;
/* 0x18 */ f32 field_0x18[1];
/* 0x18 */ f32 field_0x18[Z2_AUDIO_PLAYERS];
/* 0x1C */ f32 field_0x1c;
/* 0x20 */ f32 field_0x20[1];
/* 0x20 */ f32 field_0x20[Z2_AUDIO_PLAYERS];
/* 0x24 */ bool mIgnoreIfOut;
/* 0x25 */ bool mMicOn;
/* 0x26 */ bool field_0x26[1];
/* 0x26 */ bool field_0x26[Z2_AUDIO_PLAYERS];
}; // Size: 0x28
struct Z2Audience3DSetting {
@@ -102,62 +104,99 @@ struct Z2Audience3DSetting {
void updateDolbyDist(f32, f32);
void calcVolumeFactorAll() {
field_0x0[1] = 1.25f * field_0x0[0];
field_0x0[2] = 1.5f * field_0x0[0];
field_0x0[3] = 2.0f * field_0x0[0];
field_0x0[4] = 3.0f * field_0x0[0];
field_0x0[5] = 4.0f * field_0x0[0];
field_0x0[6] = 6.0f * field_0x0[0];
field_0x0[7] = 8.0f * field_0x0[0];
field_0x0[8] = 0.9f * field_0x0[0];
field_0x0[9] = 0.8f * field_0x0[0];
field_0x0[10] = 0.7f * field_0x0[0];
field_0x0[11] = 0.6f * field_0x0[0];
field_0x0[12] = 0.5f * field_0x0[0];
field_0x0[13] = 0.4f * field_0x0[0];
field_0x0[14] = 0.3f * field_0x0[0];
mDistanceMaxes[1] = 1.25f * mDistanceMaxes[0];
mDistanceMaxes[2] = 1.5f * mDistanceMaxes[0];
mDistanceMaxes[3] = 2.0f * mDistanceMaxes[0];
mDistanceMaxes[4] = 3.0f * mDistanceMaxes[0];
mDistanceMaxes[5] = 4.0f * mDistanceMaxes[0];
mDistanceMaxes[6] = 6.0f * mDistanceMaxes[0];
mDistanceMaxes[7] = 8.0f * mDistanceMaxes[0];
mDistanceMaxes[8] = 0.9f * mDistanceMaxes[0];
mDistanceMaxes[9] = 0.8f * mDistanceMaxes[0];
mDistanceMaxes[10] = 0.7f * mDistanceMaxes[0];
mDistanceMaxes[11] = 0.6f * mDistanceMaxes[0];
mDistanceMaxes[12] = 0.5f * mDistanceMaxes[0];
mDistanceMaxes[13] = 0.4f * mDistanceMaxes[0];
mDistanceMaxes[14] = 0.3f * mDistanceMaxes[0];
for (int i = 0; i < 15; i++) {
field_0x70[i] = (field_0x40 - 1.0f) / (field_0x0[i] - field_0x3c);
mVolumeFactor[i] = (mMinDistanceVolume - 1.0f) / (mDistanceMaxes[i] - mMaxVolumeDistance);
}
}
void calcPriorityFactorAll() {
for (int i = 0; i < 15; i++) {
field_0xac[i] = field_0x64 / (field_0x0[i] - field_0x3c);
mPriorityFactor[i] = mMaxDistancePriority / (mDistanceMaxes[i] - mMaxVolumeDistance);
}
}
void calcFxMixFactorAll() {
for (int i = 0; i < 15; i++) {
field_0xe8[i] = (field_0x54 - field_0x50) / (field_0x0[i] - field_0x3c);
mFxMixFactor[i] = (mMaxDistanceFxMix - mMinDistanceFxMix) / (mDistanceMaxes[i] - mMaxVolumeDistance);
}
}
/* 0x000 */ f32 field_0x0[15];
/* 0x03C */ f32 field_0x3c;
/* 0x040 */ f32 field_0x40;
/* 0x044 */ f32 field_0x44;
/* 0x048 */ f32 field_0x48;
/* 0x04C */ f32 field_0x4c;
/* 0x050 */ f32 field_0x50;
/* 0x054 */ f32 field_0x54;
/* 0x058 */ f32 field_0x58;
/* 0x05C */ f32 field_0x5c;
/**
* Maximum distance a sound can reach before being "far away"
* Being far away affects stuff like culling, lowering its priority, forcibly stopping it, etc.
* Sounds select which entry they use based on their VolBits.
*/
/* 0x000 */ f32 mDistanceMaxes[15];
/**
* Distance at which the max volume of a sound is reached.
* i.e. sounds do *not* get louder if they get closer than this.
*/
/* 0x03C */ f32 mMaxVolumeDistance;
/**
* FX Mix value at maximum distance (@ref mDistanceMaxes)
*/
/* 0x040 */ f32 mMinDistanceVolume;
/* 0x044 */ f32 mDolbyFrontDistanceMax;
/* 0x048 */ f32 mDolbyBehindDistanceMax;
/* 0x04C */ f32 mDolbyCenterValue;
/**
* FX Mix value at minimum distance (@ref mMaxVolumeDistance)
*/
/* 0x050 */ f32 mMinDistanceFxMix;
/**
* FX Mix value at maximum distance (@ref mDistanceMaxes)
*/
/* 0x054 */ f32 mMaxDistanceFxMix;
/* 0x058 */ f32 mPanFactor;
/* 0x05C */ f32 mSonicSpeed; // Used for doppler effect calculations.
/* 0x060 */ f32 field_0x60;
/* 0x064 */ u32 field_0x64;
/**
* Priority that sounds receive when "far away".
* @see mDistanceMaxes
*/
/* 0x064 */ u32 mMaxDistancePriority;
/* 0x068 */ f32 field_0x68;
/* 0x06C */ f32 field_0x6c;
/* 0x070 */ f32 field_0x70[15];
/* 0x0AC */ f32 field_0xac[15];
/* 0x0E8 */ f32 field_0xe8[15];
/* 0x070 */ f32 mVolumeFactor[15];
/* 0x0AC */ f32 mPriorityFactor[15];
/* 0x0E8 */ f32 mFxMixFactor[15];
/* 0x124 */ bool mVolumeDistInit;
/* 0x125 */ bool mDolbyDistInit;
}; // Size: 0x128
struct Z2AudibleRelPos {
/* 0x00 */ JGeometry::TVec3<f32> field_0x00;
/* 0x0C */ f32 field_0xC;
/* 0x10 */ f32 field_0x10;
/* 0x00 */ JGeometry::TVec3<f32> mCameraRelative;
/**
* Distance from mCameraRelative. This is from the object root and not the
* exact distance used for volume/priority calculations.
*/
/* 0x0C */ f32 mTrueDistance;
/**
* Distance from mCameraRelative but offset by mVolCenterZ.
* This presumably means the distance is more centered on the object than mTrueDistance.
*/
/* 0x10 */ f32 mCenterDistance;
};
struct Z2AudibleChannel {
@@ -171,7 +210,7 @@ struct Z2AudibleChannel {
}
/* 0x00 */ JASSoundParams mParams;
/* 0x14 */ Z2AudibleRelPos field_0x14;
/* 0x14 */ Z2AudibleRelPos mRelPos;
/* 0x28 */ f32 field_0x28;
/* 0x2c */ f32 mPan;
/* 0x30 */ f32 mDolby;
@@ -200,8 +239,8 @@ struct Z2Audible : public JAIAudible, public JASPoolAllocObject<Z2Audible> {
/* 0x10 */ JAUAudibleParam mParam;
/* 0x14 */ Z2AudibleAbsPos mAbsPos;
/* 0x2C */ Z2AudibleChannel mChannel[1];
/* 0x64 */ f32 field_0x64[1];
/* 0x2C */ Z2AudibleChannel mChannel[Z2_AUDIO_PLAYERS];
/* 0x64 */ f32 mMicDistances[Z2_AUDIO_PLAYERS];
};
struct Z2Audience : public JAIAudience, public JASGlobalInstance<Z2Audience> {
@@ -223,7 +262,8 @@ struct Z2Audience : public JAIAudience, public JASGlobalInstance<Z2Audience> {
virtual ~Z2Audience();
virtual JAIAudible* newAudible(const JGeometry::TVec3<f32>& pos, JAISoundID soundID,
const JGeometry::TVec3<f32>*, u32);
const JGeometry::TVec3<f32>*, u32
IF_DUSK_ARG(dusk::mods::svc::audio_res::bst::SoundTableReplacementSlot const*));
virtual int getMaxChannels();
virtual void deleteAudible(JAIAudible* audible);
virtual u32 calcPriority(JAIAudible* audible);
@@ -237,7 +277,7 @@ struct Z2Audience : public JAIAudience, public JASGlobalInstance<Z2Audience> {
}
Z2Audience3DSetting* getSetting() { return &mSetting; }
const Z2AudioCamera* getAudioCamera(int camID) const { return &mAudioCamera[camID]; }
const Z2AudioCamera* getAudioCamera(int camID) const { return &mAudioCamera[camID]; }
void setUsingOffMicVol(bool value) { mUsingOffMicVol = value; }
-1
View File
@@ -67,7 +67,6 @@ public:
void playVoice(int);
virtual Z2SoundHandlePool* startCreatureVoice(JAISoundID soundID, s8 reverb);
private:
/* 0xA0 */ s8 mCitizenID;
/* 0xA1 */ s8 field_0xa1;
/* 0xA2 */ bool mLinkSearch;
-3
View File
@@ -63,7 +63,6 @@ public:
friend class Z2LinkSoundStarter;
friend struct Z2RideSoundStarter;
private:
/* 0x90 Z2LinkSoundStarter */
/* 0x94 */ Z2SoundObjSimple mKantera;
/* 0xB4 */ Vec field_0xb4;
@@ -123,7 +122,6 @@ public:
virtual void deleteObject();
private:
/* 0x90 */ // Z2RideSoundStarter mSoundStarter;
/* 0x98 */ bool mLinkRiding;
}; // Size: 0x9C
@@ -136,7 +134,6 @@ public:
Z2SoundHandlePool* startFireSound(u16);
Z2SoundHandlePool* startSound(JAISoundID soundID, u32 mapinfo, s8 reverb);
private:
/* 0x20 */ f32 field_0x20;
};
-1
View File
@@ -47,7 +47,6 @@ public:
s32 getBgmLoadStatus(u32 wave) { return getWaveLoadStatus(wave, 1); }
u8 getDemoSeWaveNum() { return loadedDemoWave; }
// private:
/* 0x00 */ JAISoundID BGM_ID;
/* 0x04 */ int sceneNum;
/* 0x08 */ int timer;
-1
View File
@@ -84,7 +84,6 @@ public:
void homeMenuSeCallback(s32);
#endif
private:
/* 0x000 */ JAISoundHandle mSoundHandle[24];
/* 0x060 */ JAISoundHandles mSoundHandles;
#if VERSION >= VERSION_WII_USA_R0
-1
View File
@@ -44,7 +44,6 @@ public:
return (Z2SoundHandlePool*)getNth(index);
}
private:
/* 0xC */ u8 handleNum_;
};
+14 -8
View File
@@ -6,23 +6,29 @@
#include "JSystem/JAudio2/JAUSoundInfo.h"
#include "JSystem/JAudio2/JAUSoundTable.h"
#define STRM_CH_SHIFT_ 2
#define STRM_CH_CENTER 1
#define STRM_CH_LEFT 2
#define STRM_CH_RIGHT 3
class Z2SoundInfo : public JAISoundInfo, public JAUSoundInfo, public JAIStreamDataMgr, public JASGlobalInstance<Z2SoundInfo> {
public:
Z2SoundInfo() : JAISoundInfo(true), JAUSoundInfo(true), JASGlobalInstance<Z2SoundInfo>(true) {}
virtual u16 getAudibleSw(JAISoundID soundID) const;
virtual u16 getAudibleSw(JAISoundID soundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) const;
virtual u16 getBgmSeqResourceID(JAISoundID soundID) const;
virtual s32 getStreamFileEntry(JAISoundID soundID);
virtual s32 getStreamFileEntry(JAISoundID soundID IF_DUSK_ARG(StreamReplacementSlot const* replacement));
virtual int getSoundType(JAISoundID soundID) const;
virtual int getCategory(JAISoundID soundID) const;
virtual u32 getPriority(JAISoundID soundID) const;
virtual void getSeInfo(JAISoundID soundID, JAISe* sePtr) const;
virtual u32 getPriority(JAISoundID soundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) const;
virtual void getSeInfo(JAISoundID soundID, JAISe* sePtr IF_DUSK_ARG(SoundEffectReplacementSlot const* replacement)) const;
virtual void getSeqInfo(JAISoundID soundID, JAISeq* seqPtr) const;
virtual void getStreamInfo(JAISoundID soundID, JAIStream* streamPtr) const;
virtual void getStreamInfo(JAISoundID soundID, JAIStream* streamPtr IF_DUSK_ARG(StreamReplacementSlot const* replacement)) const;
virtual ~Z2SoundInfo() {}
JAUAudibleParam getAudibleSwFull(JAISoundID soundID);
const char* getStreamFilePath(JAISoundID soundID);
int getSwBit(JAISoundID soundID) const;
JAUAudibleParam getAudibleSwFull(JAISoundID soundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement));
const char* getStreamFilePath(JAISoundID soundID IF_DUSK_ARG(StreamReplacementSlot const* replacement));
int getSwBit(JAISoundID soundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) const;
void getSoundInfo_(JAISoundID soundID, JAISound* soundPtr) const;
BOOL isValid() const {
+1 -2
View File
@@ -38,11 +38,10 @@ public:
const JAISeqMgr* getSeqMgr() const { return &seqMgr_; }
JAIStreamMgr* getStreamMgr() { return &streamMgr_; }
private:
/* 0x004 */ JAISeMgr seMgr_;
/* 0x728 */ JAISeqMgr seqMgr_;
/* 0x79C */ JAIStreamMgr streamMgr_;
/* 0x80C */ JAISoundID soundID_;
/* 0x80C */ JAISoundID bgmMuter;
}; // Size: 0x810
#if VERSION != VERSION_SHIELD_DEBUG
-1
View File
@@ -104,7 +104,6 @@ public:
JSUList<Z2SoundObjBase>* getAllList() { return &allList_; }
#endif
private:
/* 0x00 */ JSUList<Z2CreatureEnemy> field_0x0;
#if PARTIAL_DEBUG || DEBUG
/* 0x0C */ JSUList<Z2SoundObjBase> allList_;
-1
View File
@@ -70,7 +70,6 @@ public:
u8 getReleaseTimer() { return mReleaseTimer; }
u8 getCorrectCurveID() { return mCorrectCurveID; }
private:
/* 0x00 */ JAISoundHandle mWolfHowlHandle;
/* 0x04 */ JAISoundHandle mWindStoneHandle;
/* 0x08 */ JAISoundHandle mGuideHandle;
+4 -25
View File
@@ -77,7 +77,6 @@ public:
virtual void draw();
virtual ~daAlink_blur_c() {}
// private:
/* 0x010 */ ResTIMG* m_blurTex;
/* 0x014 */ int field_0x14;
/* 0x018 */ u8 field_0x18[4];
@@ -113,7 +112,6 @@ public:
void onAppearFlg() { mAppearFlg = true; }
private:
/* 0x04 */ s16 mHitFlg;
/* 0x06 */ s16 mAppearFlg;
/* 0x08 */ f32 mKeepMinY;
@@ -126,7 +124,11 @@ public:
BOOL create();
void update();
virtual void draw();
#if TARGET_PC
virtual ~daAlink_lockCursor_c();
#else
virtual ~daAlink_lockCursor_c() {}
#endif
void initFrame() {
field_0x4 = 0;
@@ -4558,29 +4560,6 @@ public:
bool checkAimContext();
bool checkAimInputContext();
void onIronBallChainInterpCallback();
static const int IRON_BALL_CHAIN_COUNT = 102;
cXyz mIBChainInterpPrevPos[IRON_BALL_CHAIN_COUNT];
cXyz mIBChainInterpCurrPos[IRON_BALL_CHAIN_COUNT];
csXyz mIBChainInterpPrevAngle[IRON_BALL_CHAIN_COUNT];
csXyz mIBChainInterpCurrAngle[IRON_BALL_CHAIN_COUNT];
cXyz mIBChainInterpPrevHandRoot;
cXyz mIBChainInterpCurrHandRoot;
bool mIBChainInterpPrevValid;
bool mIBChainInterpCurrValid;
cXyz mHsChainInterpPrevTop;
cXyz mHsChainInterpCurrTop;
cXyz mHsChainInterpPrevRoot;
cXyz mHsChainInterpCurrRoot;
cXyz mHsChainInterpPrevSubRoot;
cXyz mHsChainInterpCurrSubRoot;
cXyz mHsChainInterpPrevSubTop;
cXyz mHsChainInterpCurrSubTop;
bool mHsChainInterpPrevValid;
bool mHsChainInterpCurrValid;
bool mIsRollstab = false;
#endif
}; // Size: 0x385C
-1
View File
@@ -110,7 +110,6 @@ public:
void setModelMatrix(MtxP mtx) { mpModel->setBaseTRMtx(mtx); }
private:
/* 0x568 */ J3DModel* mpModel;
/* 0x56C */ dBgS_ArrowLinChk field_0x56c;
/* 0x5DC */ dBgS_ObjLinChk field_0x5dc;
-1
View File
@@ -82,7 +82,6 @@ public:
u8 onTarget() { return mTarget = true; }
u8 isBack() { return arg0; }
private:
/* 0x05AC */ request_of_phase_process_class mPhase;
/* 0x05B4 */ mDoExt_McaMorfSO* mpModelMorf;
/* 0x05B8 */ J3DModel* mpPartModel;
-1
View File
@@ -189,7 +189,6 @@ public:
void onDemo() { mIsDemo = true; }
void offDemo() { mIsDemo = false; }
private:
/* 0x05AC */ request_of_phase_process_class mPhase;
/* 0x05B4 */ mDoExt_McaMorfSO* mpMorf;
/* 0x05B8 */ mDoExt_McaMorfSO* mpSwordMorf;
+3
View File
@@ -110,6 +110,9 @@ public:
/* 0x1CFC */ int field_0x1cfc;
/* 0x1D00 */ f32 mKankyoBlend;
/* 0x1D04 */ u8 mInitHIO;
#if TARGET_PC
s8 mDemoCamSyncTicks;
#endif
};
STATIC_ASSERT(sizeof(b_gm_class) == 0x1d08);
-6
View File
@@ -189,12 +189,6 @@ public:
/* 0x2740 */ u8 field_0x2740;
/* 0x2744 */ dMsgFlow_c mMsgFlow;
#if TARGET_PC
cXyz mReinsInterpPrev[2][16];
cXyz mReinsInterpCurr[2][16];
cXyz mReinsTexInterpPrev[2];
cXyz mReinsTexInterpCurr[2];
bool mReinsInterpPrevValid;
bool mReinsInterpCurrValid;
s8 mDemoCamSyncTicks;
#endif
};
-1
View File
@@ -92,7 +92,6 @@ public:
bool isDown() { return mDownFlag != 0; }
bool isAppear() { return mAppearFlag != 0; }
private:
/* 0x05AC */ request_of_phase_process_class mMgnPhase;
/* 0x05B4 */ request_of_phase_process_class mMgnePhase;
/* 0x05BC */ mDoExt_McaMorfSO* mpMgnModelMorf;
-1
View File
@@ -131,7 +131,6 @@ public:
int CreateHeap();
int create();
private:
/* 0x05AC */ request_of_phase_process_class mPhaseReq1;
/* 0x05B4 */ request_of_phase_process_class mPhaseReq2;
/* 0x05BC */ J3DModel* mpPartModels[16];
-1
View File
@@ -80,7 +80,6 @@ public:
void setDrawOff() { mIsInactive = 1; }
bool isEnemyDemoEnd() { return (u8)mIsEnemyDemoEnd != 0; }
private:
/* 0x05AC */ request_of_phase_process_class mPhase1;
/* 0x05B4 */ request_of_phase_process_class mPhase2;
/* 0x05BC */ request_of_phase_process_class mPhase3;
-1
View File
@@ -51,7 +51,6 @@ public:
void setSubNumber(int i_subNumber) { mSubNumber = i_subNumber; }
private:
/* 0x5AC */ request_of_phase_process_class mPhase;
/* 0x5B4 */ J3DModel* mpModel;
/* 0x5B8 */ Z2Creature mCreatureSound;
-1
View File
@@ -24,7 +24,6 @@ public:
int _delete();
int create();
private:
/* 0x5AC */ Mtx field_0x5ac;
/* 0x5DC */ cXyz field_0x5dc;
/* 0x5E8 */ f32 field_0x5e8;
-1
View File
@@ -33,7 +33,6 @@ public:
bool isSearchContinue() { return mSearchContinue != false; }
void offSearchContinue() { mSearchContinue = false; }
private:
/* 0x5AC */ request_of_phase_process_class mPhase;
/* 0x5B4 */ mDoExt_McaMorfSO* mpMorf;
/* 0x5B8 */ mDoExt_brkAnm* mpBrk;
+1 -1
View File
@@ -72,7 +72,7 @@ public:
struct ScoreCount {
cXyz field_0x0;
u16 field_0xc;
u8 field_0xe;
DUSK_IF_ELSE(f32, u8) field_0xe;
u8 field_0xf;
};
-1
View File
@@ -57,7 +57,6 @@ public:
inline int execute();
inline int isDelete();
private:
/* 0x568 */ u8 field_0x568[0x570 - 0x568];
/* 0x570 */ daBg_Part mBgParts[6];
/* 0x5E8 */ dBgW* mpBgW;
+4 -2
View File
@@ -17,7 +17,11 @@ public:
void setSight(cXyz const*, int);
virtual void draw();
#if TARGET_PC
virtual ~daBoomerang_sight_c();
#else
virtual ~daBoomerang_sight_c() {}
#endif
u8 getReserve() const { return mReserve; }
u8 getAlpha(int i_index) { return m_alpha[i_index]; }
@@ -25,7 +29,6 @@ public:
void onReserve() { mReserve = 1; }
void offReserve() { mReserve = 0; }
private:
/* 0x04 */ J2DScreen* m_cursorYellowScrn;
/* 0x08 */ J2DPane* m_cursorYellowAllPane;
/* 0x0C */ J2DPane* m_cursorYellow0Pane;
@@ -126,7 +129,6 @@ public:
bool getLockCntMax() { return m_lockCnt >= BOOMERANG_LOCK_MAX; }
void onLockDistanceCancel() { onStateFlg0(FLG0_LOCK_DIST_CANCEL); }
private:
/* 0x568 */ J3DModel* mp_boomModel;
/* 0x56C */ J3DModel* mp_shippuModel;
/* 0x570 */ J3DAnmTextureSRTKey* m_windBtk;
-1
View File
@@ -65,7 +65,6 @@ public:
field_0x1456 = 15;
}
private:
/* 0x0568 */ request_of_phase_process_class mPhaseReq;
/* 0x0570 */ J3DModel* mpModel;
/* 0x0574 */ J3DModel* mpPaddleModel;
-1
View File
@@ -42,7 +42,6 @@ public:
void setNoHitTimer() { noHitTimer = 20; }
inline int execute();
private:
/* 0x568 */ LIGHT_INFLUENCE mLightInfluence;
/* 0x588 */ dCcD_Stts mStts;
/* 0x5C4 */ dCcD_Sph mSph;
-1
View File
@@ -208,7 +208,6 @@ public:
u8 getCowIn() { return mCowIn; }
u8 getNoNearCheckTimer() { return mNoNearCheckTimer; }
private:
/* 0x568 */ u16 mFlags;
/* 0x56c */ request_of_phase_process_class mPhase;
/* 0x574 */ mDoExt_McaMorfSO* mpMorf;
-1
View File
@@ -48,7 +48,6 @@ public:
static f32 getFlyInitY() { return 40.0f; }
static f32 getFlyInitZ() { return 50.0f; }
private:
/* 0x568 */ J3DModel* mpBallModel;
/* 0x56C */ mDoExt_bckAnm mBck;
/* 0x588 */ J3DAnmTevRegKey* mpBallBrk;
-1
View File
@@ -40,7 +40,6 @@ public:
};
static DUSK_GAME_DATA const BckTbl m_bckIdxTable[];
private:
/* 0x5A0 */ const char* m_arcName;
/* 0x5A4 */ request_of_phase_process_class m_phase;
/* 0x5AC */ J3DModel* mp_model;
-1
View File
@@ -101,7 +101,6 @@ public:
static DUSK_GAME_DATA u16 const m_bckIdxTable[daCstatueType_N][7];
private:
/* 0x568 */ const char* mResName;
/* 0x56C */ request_of_phase_process_class mPhaseReq;
/* 0x574 */ J3DModel* mModel;
-1
View File
@@ -55,7 +55,6 @@ public:
void setOffsetPos(cXyz i_pos) { mOffsetPos = i_pos; }
void setMaxScale(f32 i_scale) { mMaxScale = i_scale; }
private:
/* 0x92C */ cXyz mOffsetPos;
/* 0x938 */ f32 mMaxScale;
/* 0x93C */ u8 field_0x93c;
-1
View File
@@ -50,7 +50,6 @@ public:
void setAction(u8 i_action) { mAction = i_action; }
private:
/* 0x568 */ request_of_phase_process_class mPhaseReq;
/* 0x570 */ J3DModel* mpDoorModel;
/* 0x574 */ J3DModel* mpLockModel;
-1
View File
@@ -76,7 +76,6 @@ public:
void setAction(u8 action) { mAction = action; }
private:
/* 0x568 */ request_of_phase_process_class mPhase1;
/* 0x570 */ request_of_phase_process_class mPhase2;
/* 0x578 */ request_of_phase_process_class mPhase3;
-1
View File
@@ -72,7 +72,6 @@ public:
return 1;
}
private:
/* 0x568 */ request_of_phase_process_class mPhase1;
/* 0x570 */ request_of_phase_process_class mPhase2;
/* 0x578 */ request_of_phase_process_class mPhase3;
-1
View File
@@ -41,7 +41,6 @@ public:
void setAction(u8 i_action) { mAction = i_action; }
// private:
/* 0x568 */ request_of_phase_process_class mPhaseReq;
/* 0x570 */ request_of_phase_process_class mPhaseReq2;
/* 0x578 */ J3DModel* mpModel;
-1
View File
@@ -73,7 +73,6 @@ public:
void onFlag(u16 flag) { field_0x60c |= flag; }
int checkFlag(u16 flag) { return field_0x60c & flag; }
private:
/* 0x568 */ request_of_phase_process_class mPhase1;
/* 0x570 */ request_of_phase_process_class mPhase2;
/* 0x578 */ J3DModel* mModel1;
-1
View File
@@ -121,7 +121,6 @@ public:
mAction = action;
}
private:
/* 0x568 */ request_of_phase_process_class mPhase1;
/* 0x570 */ request_of_phase_process_class mPhase2;
/* 0x578 */ request_of_phase_process_class mPhase3;
-1
View File
@@ -49,7 +49,6 @@ public:
void setAction(u8 i_action) { mAction = i_action; }
u32 getSceneNo() { return fopAcM_GetParamBit(this, 4, 6); }
// private:
/* 0x5A0 */ request_of_phase_process_class mPhaseReq;
/* 0x5A8 */ J3DModel* mpModel[2];
/* 0x5B0 */ dBgW* mpDoorBgW;
-1
View File
@@ -123,7 +123,6 @@ public:
bool checkFlag(u16 flag) { return field_0x68e & flag; }
void setAction(u8 action) { mAction = action; }
// private:
/* 0x56C */ request_of_phase_process_class mPhase1;
/* 0x574 */ request_of_phase_process_class mPhase2;
/* 0x57C */ J3DModel* mModel1;
-1
View File
@@ -48,7 +48,6 @@ public:
int CreateHeap();
int Create();
private:
/* 0x5AC */ JPABaseEmitter* mpEmitter;
/* 0x5B0 */ request_of_phase_process_class m_phase;
/* 0x5B8 */ u8 field_0x5b8;
-1
View File
@@ -45,7 +45,6 @@ public:
void setBgId(unsigned int i_bgId) { mBgId = i_bgId; }
bool isBomb() { return mIsBomb; }
private:
/* 0x5AC */ request_of_phase_process_class mPhaseReq;
/* 0x5B4 */ mDoExt_McaMorfSO* mpMorfSO;
/* 0x5B8 */ mDoExt_brkAnm* mpBrkAnm;
-6
View File
@@ -80,12 +80,6 @@ public:
/* 0x125C */ u32 field_0x125c;
/* 0x1260 */ u8 field_0x1260[0x126C - 0x1260];
/* 0x126C */ u8 HIOInit;
#if TARGET_PC
cXyz mStalkLineInterpPrev[12];
cXyz mStalkLineInterpCurr[12];
bool mStalkLineInterpPrevValid;
bool mStalkLineInterpCurrValid;
#endif
};
STATIC_ASSERT(sizeof(e_db_class) == 0x1270);
-1
View File
@@ -45,7 +45,6 @@ public:
int create();
daE_DK_c();
private:
/* 0x5AC */ request_of_phase_process_class mPhaseReq;
/* 0x5B4 */ mDoExt_McaMorfSO* mpMorfSO;
/* 0x5B8 */ mDoExt_McaMorfSO* mpCoreMorfSO;
-1
View File
@@ -83,7 +83,6 @@ public:
MtxP getBackMtx() { return mpMorf->getModel()->getAnmMtx(1); }
fpc_ProcID getDemoId() { return mDemoID; }
private:
/* 0x05AC */ request_of_phase_process_class mPhase[3];
/* 0x05C4 */ J3DModel* mpChestModel;
/* 0x05C8 */ J3DModel* mpSpitModel;
-1
View File
@@ -40,7 +40,6 @@ public:
cPhs_Step create();
daE_FB_c();
private:
/* 0x5AC */ request_of_phase_process_class mPhaseReq;
/* 0x5B4 */ mDoExt_McaMorfSO* mpMorf;
/* 0x5B8 */ mDoExt_invisibleModel mInvisibleModel;
-1
View File
@@ -52,7 +52,6 @@ public:
void CreateChk();
int Create();
private:
/* 0x5AC */ u8 field_0x5AC[0x5B1 - 0x5AC];
/* 0x5B1 */ u8 mUpDownMode;
/* 0x5B2 */ u8 field_0x5B2[0x5B6 - 0x5B2];
-1
View File
@@ -63,7 +63,6 @@ public:
s32 CreateHeap();
s32 create();
private:
/* 0x5AC */ request_of_phase_process_class mPhaseReq; /**< Phase request used when creating the actor. */
/* 0x5B4 */ J3DModel* mpModel; /**< Pointer to the Mini Freezard's model. */
/* 0x5B8 */ mDoExt_invisibleModel mInvisibleModel; /**< Invisible model used for the Mini Freezard. */
-1
View File
@@ -61,7 +61,6 @@ public:
u8 getGroupNo() { return mGroupNo; }
private:
/* 0x5AC */ request_of_phase_process_class mPhaseReq;
/* 0x5B4 */ mDoExt_McaMorfSO* mpMorfSO;
/* 0x5B8 */ Z2CreatureEnemy mSound;
-1
View File
@@ -47,7 +47,6 @@ public:
bool isBattleOn() { return mIsBattleOn; }
bool isAttackStart() { return mIsAttackStart; }
private:
/* 0x05AC */ request_of_phase_process_class mPhase;
/* 0x05B4 */ mDoExt_McaMorfSO* mpModelMorf;
/* 0x05B8 */ J3DModel* mpSwordModel;
-1
View File
@@ -62,7 +62,6 @@ public:
BOOL checkAction(actionFunc action) { return mAction == action; }
BOOL checkOldAction(actionFunc action) { return mOldAction == action; }
private:
/* 0x5AC */ request_of_phase_process_class mPhase;
/* 0x5B4 */ dBgS_AcchCir mAcchCir;
/* 0x5F4 */ dBgS_ObjAcch mObjAcch;
-6
View File
@@ -73,12 +73,6 @@ public:
/* 0x124C */ f32 field_0x124c;
/* 0x1250 */ u8 field_0x1250[0x1264 - 0x1250];
/* 0x1264 */ u8 HIOInit;
#if TARGET_PC
cXyz mStalkLineInterpPrev[12];
cXyz mStalkLineInterpCurr[12];
bool mStalkLineInterpPrevValid;
bool mStalkLineInterpCurrValid;
#endif
};
STATIC_ASSERT(sizeof(e_hb_class) == 0x1268);
-1
View File
@@ -65,7 +65,6 @@ public:
void CheckWall();
void CreateStyle();
int Create();
private:
/* 0x5AC */ u8 field_0x5ac;
/* 0x5AD */ u8 field_0x5ad;
/* 0x5AE */ u8 field_0x5ae;
-1
View File
@@ -64,7 +64,6 @@ public:
void setInitPos();
int create();
private:
/* 0x5AC */ request_of_phase_process_class mPhaseReq;
/* 0x5B4 */ request_of_phase_process_class mPhaseReq2;
/* 0x5BC */ mDoExt_McaMorfSO* mpMorfSO;
-1
View File
@@ -49,7 +49,6 @@ public:
int CreateHeap();
int create();
private:
/* 0x05AC */ request_of_phase_process_class mPhaseReq;
/* 0x05B4 */ mDoExt_McaMorfSO* mpMorfSO;
/* 0x05B8 */ mDoExt_McaMorfSO* mpWeaponMorfSO;
-6
View File
@@ -44,12 +44,6 @@ public:
/* 0x88C */ u8 field_0x88C[0x8C8 - 0x88C];
/* 0x8C8 */ s8 field_0x8c8;
/* 0x8C9 */ u8 mInitHIO;
#if TARGET_PC
cXyz mRopeInterpPrev[16];
cXyz mRopeInterpCurr[16];
bool mRopeInterpPrevValid;
bool mRopeInterpCurrValid;
#endif
};
STATIC_ASSERT(sizeof(e_mb_class) == 0x8cc);
-1
View File
@@ -87,7 +87,6 @@ public:
daE_OC_c* getTalkOc() { return mpTalk; }
J3DModel* getOcModel() { return mpMorf->getModel(); }
private:
/* 0x5a0 */ request_of_phase_process_class mPhaseReqs[2];
/* 0x5bc */ mDoExt_McaMorfSO* mpMorf;
/* 0x5c0 */ J3DModel* mpModel;
-1
View File
@@ -54,7 +54,6 @@ public:
u32 checkAction(actionFunc func) { return field_0xb58 == func; }
bool checkNormalAttk() { return checkAction(&daE_OctBg_c::normal_attack); }
private:
/* 0x5AC */ request_of_phase_process_class mPhase;
/* 0x5B4 */ mDoExt_McaMorfSO* field_0x5b4;
/* 0x5B8 */ mDoExt_brkAnm* field_0x5b8;
-1
View File
@@ -54,7 +54,6 @@ public:
/* 0x4 */ ACT_DAMAGE,
};
private:
/* 0x5AC */ request_of_phase_process_class mPhase;
/* 0x5B4 */ mDoExt_McaMorfSO* mpMorf;
/* 0x5B8 */ J3DModel* mpEggModel;
-1
View File
@@ -84,7 +84,6 @@ public:
u8 SwitchChk() { return mStage; }
u8 DoorChk() { return mDoorAction; }
private:
/* 0x5AC */ fpc_ProcID mPuppetID[4];
/* 0x5BC */ u8 field_0x5bc[0x5DC - 0x5BC];
/* 0x5DC */ u8 mDoorAction;
-9
View File
@@ -81,15 +81,6 @@ public:
/* 0x306D */ u8 field_0x306D[0x307C - 0x306D];
/* 0x307C */ u32 mBodyEffEmtrID;
/* 0x3080 */ u8 mInitHIO;
#if TARGET_PC
static const int HAIR_STRAND_COUNT = 22;
static const int HAIR_SEGMENT_COUNT = 16;
cXyz mHairInterpPrev[HAIR_STRAND_COUNT * HAIR_SEGMENT_COUNT];
cXyz mHairInterpCurr[HAIR_STRAND_COUNT * HAIR_SEGMENT_COUNT];
bool mHairInterpPrevValid;
bool mHairInterpCurrValid;
#endif
};
STATIC_ASSERT(sizeof(e_s1_class) == 0x3084);
-2
View File
@@ -57,7 +57,6 @@ public:
int Delete();
void setBaseMtx();
cPhs_Step Create();
private:
/* 0x5AC */ int field_0x5ac;
/* 0x5B0 */ int field_0x5b0;
/* 0x5B4 */ int field_0x5b4;
@@ -78,7 +77,6 @@ private:
public:
/* 0x5EC */ cXyz* field_0x5ec;
/* 0x5F0 */ f32 field_0x5f0;
private:
/* 0x5F4 */ cXyz field_0x5f4;
/* 0x600 */ s16 field_0x600;
/* 0x602 */ u8 field_0x602;
-1
View File
@@ -82,7 +82,6 @@ public:
bool d_checkOldAction(void (daE_SW_c::*action)()) {
return field_0xb0c == action;
}
private:
/* 0x5AC */ request_of_phase_process_class mPhase;
/* 0x5B4 */ mDoExt_McaMorfSO* mpModelMorf;
/* 0x5B8 */ Z2CreatureEnemy mSound;
-1
View File
@@ -47,7 +47,6 @@ public:
int CreateHeap();
int create();
private:
/* 0x5AC */ request_of_phase_process_class mPhaseReq;
/* 0x5B4 */ request_of_phase_process_class mPhaseReq2;
/* 0x5BC */ mDoExt_McaMorfSO* mpMorfSO;
-1
View File
@@ -146,7 +146,6 @@ public:
int create();
daE_VA_c();
private:
/* 0x005AC */ request_of_phase_process_class mPhase;
/* 0x005B4 */ mDoExt_McaMorfSO* mpMorf;
/* 0x005B8 */ mDoExt_McaMorfSO* mpEndEfMorf;
-6
View File
@@ -221,12 +221,6 @@ public:
/* 0x17E4 */ u8 field_0x17e4[0x17e8 - 0x17e4];
/* 0x17E8 */ f32 ride_speed_max; ///< @brief Speed rate for riding calculations.
#if TARGET_PC
cXyz himo_mat_interp_prev[2][16];
cXyz himo_mat_interp_curr[2][16];
cXyz himo_tex_interp_prev[2];
cXyz himo_tex_interp_curr[2];
bool himo_interp_prev_valid;
bool himo_interp_curr_valid;
s8 demo_cam_sync_ticks;
#endif
};
-1
View File
@@ -59,7 +59,6 @@ public:
void setAttack() { mActionMode = 10; }
f32 const getSpeedF() { return speedF; }
private:
/* 0x5AC */ request_of_phase_process_class mPhase;
/* 0x5B4 */ mDoExt_McaMorfSO* mpModelMorf;
/* 0x5B8 */ Z2CreatureEnemy mSound;
-6
View File
@@ -74,12 +74,6 @@ public:
/* 0x1250 */ f32 field_0x1250;
/* 0x1254 */ u8 field_0x1254[0x1268 - 0x1254];
/* 0x1268 */ u8 field_0x1268;
#if TARGET_PC
cXyz mLineMatInterpPrev[12];
cXyz mLineMatInterpCurr[12];
bool mLineMatInterpPrevValid;
bool mLineMatInterpCurrValid;
#endif
};
STATIC_ASSERT(sizeof(e_yd_class) == 0x126c);
-9
View File
@@ -63,15 +63,6 @@ public:
/* 0x0BB4 */ yg_ke_s mYgKes[13];
/* 0x1880 */ mDoExt_3DlineMat0_c mLineMat;
/* 0x189C */ u8 mIsFirstSpawn;
#if TARGET_PC
static const int TENTACLE_STRAND_COUNT = 13;
static const int TENTACLE_SEGMENT_COUNT = 10;
cXyz mTentacleInterpPrev[TENTACLE_STRAND_COUNT * TENTACLE_SEGMENT_COUNT];
cXyz mTentacleInterpCurr[TENTACLE_STRAND_COUNT * TENTACLE_SEGMENT_COUNT];
bool mTentacleInterpPrevValid;
bool mTentacleInterpCurrValid;
#endif
};
STATIC_ASSERT(sizeof(e_yg_class) == 0x18a0);
-6
View File
@@ -77,12 +77,6 @@ public:
/* 0x1260 */ u32 field_0x1260;
/* 0x1260 */ u8 field_0x1264[0x1270 - 0x1264];
/* 0x1270 */ bool mIsHIOOwner;
#if TARGET_PC
cXyz mLineInterpPrev[12];
cXyz mLineInterpCurr[12];
bool mLineInterpPrevValid;
bool mLineInterpCurrValid;
#endif
};
STATIC_ASSERT(sizeof(e_yh_class) == 0x1274);
-1
View File
@@ -122,7 +122,6 @@ public:
u8 getSwitchBit() { return mSwitchBit; }
u8 isHide() { return mIsHide; }
private:
/* 0x5AC */ request_of_phase_process_class mPhase;
/* 0x5B4 */ mDoExt_McaMorfSO* mpMorf;
/* 0x5B8 */ mDoExt_brkAnm* mpBrk;
-1
View File
@@ -39,7 +39,6 @@ public:
int CreateHeap();
int create();
private:
/* 0x5ac */ request_of_phase_process_class mPhase;
/* 0x5b4 */ mDoExt_McaMorfSO* mpMorf;
/* 0x5b8 */ Z2CreatureEnemy mSound;
-3
View File
@@ -196,9 +196,6 @@ public:
void copyReinPos();
void setReinPosHandSubstance(int);
void setReinPosNormalSubstance();
#if TARGET_PC
void lerpControlPoints(f32 alpha);
#endif
void bgCheck();
bool checkSpecialWallHitSubstance(cXyz const&) const;
void setServiceWaitTimer();
-1
View File
@@ -140,7 +140,6 @@ public:
void setEatYm() { field_0x6d8 |= (u8) 4; }
MtxP getMouthMtx() { return mAnm_p->getModel()->getAnmMtx(7); }
private:
/* 0x568 */ request_of_phase_process_class mPhase;
/* 0x570 */ mDoExt_McaMorfSO* mAnm_p;
/* 0x574 */ Z2CreatureEnemy mSound;

Some files were not shown because too many files have changed in this diff Show More