Compare commits

..

1 Commits

Author SHA1 Message Date
Luke Street 625f752fb9 Try Android CI 2026-05-10 00:26:00 -06:00
140 changed files with 1230 additions and 6927 deletions
+12 -12
View File
@@ -10,7 +10,7 @@ on:
env:
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
# SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
jobs:
build-linux:
@@ -50,7 +50,7 @@ jobs:
libxss-dev libfuse2 libusb-1.0-0-dev libdecor-0-dev libpipewire-0.3-dev libunwind-dev
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.10
uses: mozilla-actions/sccache-action@v0.0.9
- name: Print sccache stats
run: sccache --show-stats
@@ -67,9 +67,9 @@ jobs:
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: dusklight-${{env.DUSK_VERSION}}-linux-${{matrix.preset}}-${{matrix.artifact_arch}}
name: dusk-${{env.DUSK_VERSION}}-linux-${{matrix.preset}}-${{matrix.artifact_arch}}
path: |
build/install/Dusklight-*.AppImage
build/install/Dusk-*.AppImage
build/install/debug.tar.*
build-apple:
@@ -124,7 +124,7 @@ jobs:
rustup target add x86_64-apple-darwin
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.10
uses: mozilla-actions/sccache-action@v0.0.9
- name: Configure CMake
run: cmake --preset ${{matrix.preset}}
@@ -135,9 +135,9 @@ jobs:
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: dusklight-${{env.DUSK_VERSION}}-${{matrix.artifact_name}}
name: dusk-${{env.DUSK_VERSION}}-${{matrix.artifact_name}}
path: |
build/install/Dusklight.app
build/install/Dusk.app
build/install/debug.tar.*
build-android:
@@ -175,7 +175,7 @@ jobs:
java-version: 17
- name: Setup Android SDK
uses: android-actions/setup-android@v4
uses: android-actions/setup-android@v3
- name: Install Android SDK packages
run: sdkmanager "platforms;android-36" "build-tools;36.1.0" "ndk;${ANDROID_NDK_VERSION}"
@@ -186,13 +186,13 @@ jobs:
rustup target add ${{matrix.rust_target}}
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.10
uses: mozilla-actions/sccache-action@v0.0.9
- name: Configure CMake
run: cmake --preset ${{matrix.preset}}
- name: Build native library
run: cmake --build --preset ${{matrix.preset}} --target dusklight
run: cmake --build --preset ${{matrix.preset}} --target dusk
- name: Stage stripped JNI library
run: ANDROID_STAGE_ABIS="${{matrix.abi}}" platforms/android/scripts/stage-jni-libs.sh
@@ -204,7 +204,7 @@ jobs:
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: dusklight-${{env.DUSK_VERSION}}-android-${{matrix.artifact_arch}}
name: dusk-${{env.DUSK_VERSION}}-android-${{matrix.artifact_arch}}
path: platforms/android/app/build/outputs/apk/release/app-${{matrix.abi}}-release-unsigned.apk
build-windows:
@@ -266,7 +266,7 @@ jobs:
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: dusklight-${{env.DUSK_VERSION}}-win32-msvc-${{matrix.artifact_arch}}
name: dusk-${{env.DUSK_VERSION}}-win32-msvc-${{matrix.artifact_arch}}
path: |
build/install/*.exe
build/install/*.dll
-4
View File
@@ -41,10 +41,6 @@ compile_commands.json
# MacOS
.DS_Store
# direnv / nix
.direnv/
.envrc
# ISOs
*.iso
+1 -1
View File
@@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch Dusklight MSVC",
"name": "(gdb) Launch Dusk MSVC",
"type": "cppvsdbg",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
+1 -1
View File
@@ -1,5 +1,5 @@
{
"cmake.buildDirectory": "${workspaceFolder}/build/dusklight/${buildType}/${variant:tp_version}",
"cmake.buildDirectory": "${workspaceFolder}/build/dusk/${buildType}/${variant:tp_version}",
"cmake.generator": "Ninja",
"cmake.configureSettings": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
+53 -76
View File
@@ -5,19 +5,8 @@ if (NOT CMAKE_BUILD_TYPE)
"Build type options: Debug Release RelWithDebInfo MinSizeRel" FORCE)
endif ()
set(DUSK_VERSION_OVERRIDE "" CACHE STRING "Override version string (skips git detection and format validation)")
if (DUSK_VERSION_OVERRIDE)
set(DUSK_WC_DESCRIBE "${DUSK_VERSION_OVERRIDE}")
set(DUSK_VERSION_STRING "0.0.0.0")
set(DUSK_SHORT_VERSION_STRING "0.0.0")
set(DUSK_WC_REVISION "")
set(DUSK_WC_BRANCH "")
set(DUSK_WC_DATE "")
message(STATUS "Dusklight version overridden to ${DUSK_WC_DESCRIBE}")
else ()
# obtain revision info from git
find_package(Git)
# obtain revision info from git
find_package(Git)
if (GIT_FOUND)
# make sure version information gets re-run when the current Git HEAD changes
execute_process(WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} rev-parse --git-path HEAD
@@ -74,15 +63,13 @@ else ()
set(DUSK_SHORT_VERSION_STRING "0.0.0")
endif ()
endif ()
# Add version information to CI environment variables
if(DEFINED ENV{GITHUB_ENV})
file(APPEND "$ENV{GITHUB_ENV}" "DUSK_VERSION=${DUSK_WC_DESCRIBE}\n")
endif()
message(STATUS "Dusklight version set to ${DUSK_WC_DESCRIBE}")
message(STATUS "Dusk version set to ${DUSK_WC_DESCRIBE}")
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
project(dusklight LANGUAGES C CXX VERSION ${DUSK_VERSION_STRING})
project(dusk LANGUAGES C CXX VERSION ${DUSK_VERSION_STRING})
if (APPLE)
enable_language(OBJC OBJCXX)
endif ()
@@ -125,6 +112,11 @@ 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_ENABLE_UPDATE_CHECKER "Enable update checking support" ON)
if(ANDROID)
set(DUSK_MOVIE_SUPPORT OFF)
endif ()
option(DUSK_ENABLE_SENTRY_NATIVE "Enable sentry-native crash reporting support" OFF)
set(DUSK_SENTRY_DSN "" CACHE STRING "Sentry DSN")
set(DUSK_SENTRY_ENVIRONMENT "development" CACHE STRING "Sentry environment")
@@ -142,9 +134,9 @@ endif ()
if (DUSK_MOVIE_SUPPORT)
find_package(libjpeg-turbo 3.0 CONFIG QUIET)
if (libjpeg-turbo_FOUND)
message(STATUS "dusklight: Using system libjpeg-turbo")
message(STATUS "dusk: Using system libjpeg-turbo")
else ()
message(STATUS "dusklight: Fetching libjpeg-turbo")
message(STATUS "dusk: Fetching libjpeg-turbo")
include(ExternalProject)
set(_jpeg_install_dir ${CMAKE_BINARY_DIR}/libjpeg-turbo-install)
if (WIN32)
@@ -163,8 +155,6 @@ if (DUSK_MOVIE_SUPPORT)
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
@@ -236,13 +226,13 @@ endif ()
include(FetchContent)
# Declare all dependencies first so CMake can download them in parallel
message(STATUS "dusklight: Fetching cxxopts")
message(STATUS "dusk: Fetching cxxopts")
FetchContent_Declare(cxxopts
URL https://github.com/jarro2783/cxxopts/archive/refs/tags/v3.3.1.tar.gz
URL_HASH SHA256=3bfc70542c521d4b55a46429d808178916a579b28d048bd8c727ee76c39e2072
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
)
message(STATUS "dusklight: Fetching nlohmann/json")
message(STATUS "dusk: Fetching nlohmann/json")
FetchContent_Declare(json
URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz
URL_HASH SHA256=42f6e95cad6ec532fd372391373363b62a14af6d771056dbfc86160e6dfff7aa
@@ -251,7 +241,7 @@ FetchContent_Declare(json
FetchContent_MakeAvailable(cxxopts json)
if (DUSK_ENABLE_SENTRY_NATIVE)
message(STATUS "dusklight: Fetching sentry-native")
message(STATUS "dusk: Fetching sentry-native")
set(SENTRY_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set(SENTRY_BACKEND crashpad CACHE STRING "" FORCE)
if (WIN32)
@@ -296,15 +286,15 @@ include(files.cmake)
# TODO: version handling for res includes
set(DUSK_BUNDLE_NAME Dusklight)
set(DUSK_BUNDLE_NAME Dusk)
set(DUSK_BUNDLE_IDENTIFIER dev.twilitrealm.dusk)
set(DUSK_COMPANY_NAME "Twilit Realm")
set(DUSK_FILE_DESCRIPTION "Dusklight")
set(DUSK_PRODUCT_NAME "Dusklight")
set(DUSK_FILE_DESCRIPTION "Dusk")
set(DUSK_PRODUCT_NAME "Dusk")
set(DUSK_COPYRIGHT "Copyright (C) Twilit Realm contributors")
source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES})
source_group("dusklight" FILES ${DUSK_FILES} ${DUSK_HTTP_BACKEND_FILES})
source_group("dusk" FILES ${DUSK_FILES} ${DUSK_HTTP_BACKEND_FILES})
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 MTX_USE_PS=1)
@@ -341,30 +331,30 @@ if (DUSK_ENABLE_UPDATE_CHECKER)
set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/winhttp.cpp)
list(APPEND GAME_LIBS winhttp)
list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_WINHTTP=1)
message(STATUS "dusklight: Enabled update checker (WinHTTP)")
message(STATUS "dusk: Enabled update checker (WinHTTP)")
elseif (ANDROID)
set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/android.cpp)
list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_ANDROID=1)
message(STATUS "dusklight: Enabled update checker (Android)")
message(STATUS "dusk: Enabled update checker (Android)")
elseif (APPLE)
find_library(FOUNDATION_FRAMEWORK Foundation REQUIRED)
set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/url_session.mm)
set_source_files_properties(src/dusk/http/url_session.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
list(APPEND GAME_LIBS ${FOUNDATION_FRAMEWORK})
list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_URLSESSION=1)
message(STATUS "dusklight: Enabled update checker (NSURLSession)")
message(STATUS "dusk: Enabled update checker (NSURLSession)")
elseif (CMAKE_SYSTEM_NAME STREQUAL Linux)
find_package(CURL QUIET OPTIONAL_COMPONENTS HTTPS SSL)
if (CURL_FOUND AND CURL_HTTPS_FOUND AND CURL_SSL_FOUND)
set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/curl.cpp)
list(APPEND GAME_LIBS CURL::libcurl)
list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_LIBCURL=1)
message(STATUS "dusklight: Enabled update checker (libcurl)")
message(STATUS "dusk: Enabled update checker (libcurl)")
else ()
message(STATUS "dusklight: Disabled update checker (libcurl + HTTPS/SSL not found)")
message(STATUS "dusk: Disabled update checker (libcurl + HTTPS/SSL not found)")
endif ()
else ()
message(STATUS "dusklight: Disabled update checker (unsupported platform)")
message(STATUS "dusk: Disabled update checker (unsupported platform)")
endif ()
endif ()
list(APPEND DUSK_FILES ${DUSK_HTTP_BACKEND_SOURCE})
@@ -442,37 +432,31 @@ endif ()
set(DUSK_FILES src/dusk/main.cpp ${GAME_BASE_FILES} ${GAME_DEBUG_FILES})
if(ANDROID)
add_library(dusklight SHARED ${DUSK_FILES})
set_target_properties(dusklight PROPERTIES OUTPUT_NAME main)
add_library(dusk SHARED ${DUSK_FILES})
set_target_properties(dusk PROPERTIES OUTPUT_NAME main)
else ()
add_executable(dusklight ${DUSK_FILES})
add_executable(dusk ${DUSK_FILES})
endif ()
target_compile_definitions(dusklight PRIVATE ${GAME_COMPILE_DEFS})
target_include_directories(dusklight PRIVATE ${GAME_INCLUDE_DIRS})
target_link_libraries(dusklight PRIVATE aurora::main ${GAME_LIBS} ${JSYSTEM_LINK_LIBRARIES})
target_precompile_headers(dusklight PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_SOURCE_DIR}/include/dusk_pch.hpp>")
target_compile_definitions(dusk PRIVATE ${GAME_COMPILE_DEFS})
target_include_directories(dusk PRIVATE ${GAME_INCLUDE_DIRS})
target_link_libraries(dusk PRIVATE aurora::main ${GAME_LIBS} ${JSYSTEM_LINK_LIBRARIES})
target_precompile_headers(dusk PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_SOURCE_DIR}/include/dusk_pch.hpp>")
if (TARGET crashpad_handler)
add_dependencies(dusklight crashpad_handler)
add_custom_command(TARGET dusklight POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_FILE:crashpad_handler>"
"$<TARGET_FILE_DIR:dusklight>"
COMMENT "Copying crashpad handler"
)
add_dependencies(dusk crashpad_handler)
endif ()
if (ANDROID)
# SDLActivity loads SDL_main via dlsym on Android. Since aurora::main is a static
# archive, force an undefined reference so the linker keeps the SDL_main object.
target_link_options(dusklight PRIVATE "-Wl,-u,SDL_main")
target_link_options(dusk PRIVATE "-Wl,-u,SDL_main")
endif ()
if (NOT APPLE)
add_custom_command(TARGET dusklight POST_BUILD
add_custom_command(TARGET dusk POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/res"
"$<TARGET_FILE_DIR:dusklight>/res"
"$<TARGET_FILE_DIR:dusk>/res"
COMMENT "Copying resources"
)
endif ()
@@ -480,9 +464,9 @@ endif ()
if (WIN32)
set(DUSK_WINDOWS_RESOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/platforms/windows)
set(DUSK_WINDOWS_ICON_PNG ${CMAKE_CURRENT_SOURCE_DIR}/res/icon.png)
set(DUSK_WINDOWS_ICON_ICO ${CMAKE_CURRENT_BINARY_DIR}/dusklight.ico)
set(DUSK_WINDOWS_RC ${CMAKE_CURRENT_BINARY_DIR}/dusklight.rc)
set(DUSK_WINDOWS_MANIFEST ${CMAKE_CURRENT_BINARY_DIR}/dusklight.manifest)
set(DUSK_WINDOWS_ICON_ICO ${CMAKE_CURRENT_BINARY_DIR}/dusk.ico)
set(DUSK_WINDOWS_RC ${CMAKE_CURRENT_BINARY_DIR}/dusk.rc)
set(DUSK_WINDOWS_MANIFEST ${CMAKE_CURRENT_BINARY_DIR}/dusk.manifest)
add_custom_command(
OUTPUT ${DUSK_WINDOWS_ICON_ICO}
@@ -495,14 +479,14 @@ if (WIN32)
COMMENT "Generating Windows icon"
)
configure_file(${DUSK_WINDOWS_RESOURCE_DIR}/dusklight.manifest.in ${DUSK_WINDOWS_MANIFEST} @ONLY)
configure_file(${DUSK_WINDOWS_RESOURCE_DIR}/dusklight.rc.in ${DUSK_WINDOWS_RC} @ONLY)
configure_file(${DUSK_WINDOWS_RESOURCE_DIR}/dusk.manifest.in ${DUSK_WINDOWS_MANIFEST} @ONLY)
configure_file(${DUSK_WINDOWS_RESOURCE_DIR}/dusk.rc.in ${DUSK_WINDOWS_RC} @ONLY)
target_sources(dusklight PRIVATE ${DUSK_WINDOWS_ICON_ICO} ${DUSK_WINDOWS_RC})
set_target_properties(dusklight PROPERTIES WIN32_EXECUTABLE TRUE)
target_sources(dusk PRIVATE ${DUSK_WINDOWS_ICON_ICO} ${DUSK_WINDOWS_RC})
set_target_properties(dusk PROPERTIES WIN32_EXECUTABLE TRUE)
if (MSVC)
target_link_options(dusklight PRIVATE /MANIFEST:NO)
target_link_options(dusk PRIVATE /MANIFEST:NO)
endif ()
endif ()
@@ -518,10 +502,10 @@ if (APPLE)
file(GLOB_RECURSE DUSK_RESOURCE_FILES
"${DUSK_RESOURCE_DIR}/Assets.car"
"${DUSK_RESOURCE_DIR}/Base.lproj/*"
"${DUSK_RESOURCE_DIR}/Dusklight.icns")
"${DUSK_RESOURCE_DIR}/Dusk.icns")
file(GLOB_RECURSE DUSK_APP_RESOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/res/*")
target_sources(dusklight PRIVATE ${DUSK_RESOURCE_FILES})
target_sources(dusklight PRIVATE ${DUSK_APP_RESOURCE_FILES})
target_sources(dusk PRIVATE ${DUSK_RESOURCE_FILES})
target_sources(dusk PRIVATE ${DUSK_APP_RESOURCE_FILES})
foreach (FILE ${DUSK_RESOURCE_FILES})
file(RELATIVE_PATH NEW_FILE "${DUSK_RESOURCE_DIR}" ${FILE})
get_filename_component(NEW_FILE_PATH ${NEW_FILE} DIRECTORY)
@@ -533,36 +517,29 @@ if (APPLE)
set_property(SOURCE ${FILE} PROPERTY MACOSX_PACKAGE_LOCATION "Resources/${NEW_FILE_PATH}")
endforeach ()
set_target_properties(
dusklight PROPERTIES
dusk PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_BUNDLE_NAME ${DUSK_BUNDLE_NAME}
MACOSX_BUNDLE_GUI_IDENTIFIER ${DUSK_BUNDLE_IDENTIFIER}
MACOSX_BUNDLE_BUNDLE_VERSION ${DUSK_VERSION_STRING}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${DUSK_SHORT_VERSION_STRING}
MACOSX_BUNDLE_INFO_PLIST ${DUSK_INFO_PLIST}
OUTPUT_NAME Dusklight
OUTPUT_NAME Dusk
XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "YES"
XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "YES"
)
endif ()
if (APPLE AND NOT IOS AND NOT TVOS)
find_library(APPKIT_FRAMEWORK AppKit REQUIRED)
target_sources(dusklight PRIVATE src/dusk/file_select_macos.mm)
set_source_files_properties(src/dusk/file_select_macos.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
target_link_libraries(dusklight PRIVATE ${APPKIT_FRAMEWORK})
endif ()
if (IOS)
find_library(UIKIT_FRAMEWORK UIKit REQUIRED)
find_library(UNIFORM_TYPE_IDENTIFIERS_FRAMEWORK UniformTypeIdentifiers REQUIRED)
target_sources(dusklight PRIVATE src/dusk/ios/FileSelectDialog.m)
target_sources(dusk PRIVATE src/dusk/ios/FileSelectDialog.m)
set_source_files_properties(src/dusk/ios/FileSelectDialog.m PROPERTIES COMPILE_FLAGS -fobjc-arc)
target_link_libraries(dusklight PRIVATE ${UIKIT_FRAMEWORK} ${UNIFORM_TYPE_IDENTIFIERS_FRAMEWORK})
target_link_libraries(dusk PRIVATE ${UIKIT_FRAMEWORK} ${UNIFORM_TYPE_IDENTIFIERS_FRAMEWORK})
endif ()
include(extern/aurora/cmake/AuroraCopyRuntimeDLLs.cmake)
aurora_copy_runtime_dlls(dusklight)
aurora_copy_runtime_dlls(dusk)
if (DUSK_SELECTED_OPT)
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
@@ -600,13 +577,13 @@ function(get_target_prefix target result_var)
endif ()
endif ()
endfunction()
list(APPEND BINARY_TARGETS dusklight)
list(APPEND BINARY_TARGETS dusk)
set(EXTRA_TARGETS "")
if (TARGET crashpad_handler)
list(APPEND EXTRA_TARGETS crashpad_handler)
endif ()
install(TARGETS ${BINARY_TARGETS} ${EXTRA_TARGETS} DESTINATION ${CMAKE_INSTALL_PREFIX})
aurora_install_runtime_dlls(dusklight ${CMAKE_INSTALL_PREFIX})
aurora_install_runtime_dlls(dusk ${CMAKE_INSTALL_PREFIX})
if (NOT APPLE)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/res DESTINATION ${CMAKE_INSTALL_PREFIX})
endif ()
+32 -23
View File
@@ -30,7 +30,7 @@
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache",
"DUSK_ENABLE_SENTRY_NATIVE": {
"type": "BOOL",
"value": true
"value": false
},
"DUSK_SENTRY_DSN": "$env{SENTRY_DSN}",
"DUSK_SENTRY_ENVIRONMENT": "production"
@@ -249,11 +249,22 @@
"type": "BOOL",
"value": false
},
"CMAKE_DISABLE_FIND_PACKAGE_PkgConfig": {
"CMAKE_DISABLE_FIND_PACKAGE_BZip2": {
"type": "BOOL",
"value": true
},
"CMAKE_IGNORE_PREFIX_PATH": "/opt/homebrew"
"CMAKE_DISABLE_FIND_PACKAGE_LibLZMA": {
"type": "BOOL",
"value": true
},
"CMAKE_DISABLE_FIND_PACKAGE_zstd": {
"type": "BOOL",
"value": true
},
"CMAKE_DISABLE_FIND_PACKAGE_Freetype": {
"type": "BOOL",
"value": true
}
},
"vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": {
@@ -318,11 +329,7 @@
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install",
"CMAKE_TOOLCHAIN_FILE": "$env{ANDROID_HOME}/ndk/$env{ANDROID_NDK_VERSION}/build/cmake/android.toolchain.cmake",
"ANDROID_PLATFORM": "android-28",
"BUILD_SHARED_LIBS": {
"type": "BOOL",
"value": false
}
"ANDROID_PLATFORM": "android-28"
}
},
{
@@ -351,13 +358,7 @@
"inherits": [
"android-base",
"ci"
],
"cacheVariables": {
"DUSK_ENABLE_SENTRY_NATIVE": {
"type": "BOOL",
"value": false
}
}
]
},
{
"name": "x-android-ci-arm64",
@@ -409,7 +410,7 @@
},
"CMAKE_OSX_DEPLOYMENT_TARGET": "11.0",
"CMAKE_IGNORE_PREFIX_PATH": "/opt/homebrew",
"BUILD_SHARED_LIBS": {
"DUSK_MOVIE_SUPPORT": {
"type": "BOOL",
"value": false
}
@@ -442,7 +443,11 @@
],
"cacheVariables": {
"CMAKE_C_COMPILER_LAUNCHER": "sccache",
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache"
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache",
"DUSK_MOVIE_SUPPORT": {
"type": "BOOL",
"value": false
}
}
},
{
@@ -452,7 +457,11 @@
],
"cacheVariables": {
"CMAKE_C_COMPILER_LAUNCHER": "sccache",
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache"
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache",
"DUSK_MOVIE_SUPPORT": {
"type": "BOOL",
"value": false
}
}
},
{
@@ -536,7 +545,7 @@
"description": "iOS release build with debug info",
"displayName": "iOS RelWithDebInfo",
"targets": [
"dusklight"
"dusk"
]
},
{
@@ -545,7 +554,7 @@
"description": "tvOS release build with debug info",
"displayName": "tvOS RelWithDebInfo",
"targets": [
"dusklight"
"dusk"
]
},
{
@@ -554,7 +563,7 @@
"description": "Android arm64-v8a release build with debug info",
"displayName": "Android arm64-v8a RelWithDebInfo",
"targets": [
"dusklight"
"dusk"
]
},
{
@@ -563,7 +572,7 @@
"description": "Android x86_64 release build with debug info",
"displayName": "Android x86_64 RelWithDebInfo",
"targets": [
"dusklight"
"dusk"
]
},
{
@@ -572,7 +581,7 @@
"description": "(Internal) Android CI arm64-v8a",
"displayName": "(Internal) Android CI arm64-v8a",
"targets": [
"dusklight"
"dusk"
]
},
{
+12 -15
View File
@@ -1,30 +1,27 @@
<div align="center">
<img src="res/logo.png" alt="Logo" width="640">
<img src="res/logo-mascot.png" alt="Logo" width="640">
<p align="center">
<a href="https://twilitrealm.dev">Official Website</a>
<a href="https://discord.gg/6NpMhefCK9">Discord</a>
<a href="https://discord.gg/dusktp">Discord</a>
</p>
</div>
# Overview
Dusklight is a reverse-engineered reimplementation of Twilight Princess.
Dusk 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.
# Setup
> [!IMPORTANT]
> Dusklight does *not* provide any copyrighted assets. You must provide your own copy of the original game.
> [!IMPORTANT]
> At a minimum, Dusklight requires a GPU with support for either D3D12, Vulkan, or Metal. Your experience with specific hardware, operating systems, and drivers may vary. In particular, older Intel iGPUs have a high likelihood of incompatibility. We are also aware of a number of issues on devices with Adreno GPUs and are working to resolve them.
> Dusk does *not* provide any copyrighted assets. You must provide your own copy of the original game.
### 1. Verify your dump
First, make sure your dump of the game is clean and supported by Dusklight. You can do this by checking the SHA-1 hash of your dump against this list of supported versions:
First, make sure your dump of the game is clean and supported by Dusk. You can do this by checking the SHA-1 hash of your dump against this list of supported versions:
| Version | SHA-1 hash |
|--------------| ------------------------------------------ |
@@ -33,12 +30,12 @@ First, make sure your dump of the game is clean and supported by Dusklight. You
*Support for other versions of the game is planned in the future.
### 2. Download [Dusklight](https://github.com/TwilitRealm/dusklight/releases)
### 2. Download [Dusk](https://github.com/TwilitRealm/dusk/releases)
### 3. Setup the game
**Windows / macOS / Linux**
- Extract the .zip file
- Launch Dusklight
- Launch Dusk
- Press **Select Disc Image** and provide the path to your supported game dump
- Press **Play**!
@@ -46,20 +43,20 @@ First, make sure your dump of the game is clean and supported by Dusklight. You
- Follow the [iOS setup guide](docs/ios-install-altstore.md)
**Android**
- Install the Dusklight APK
- Launch Dusklight
- Install the Dusk apk
- Launch Dusk
- Press **Select Disc Image** and provide the path to your supported game dump
- Press **Play**!
# Building
If you'd like to build Dusklight from source, please read the [build instructions](docs/building.md).
If you'd like to build Dusk from source, please read the [build instructions](docs/building.md).
Pull requests are welcomed! Note that we do not accept contributions that are primarily AI-generated and will close your PR if we suspect as much. Please also see the [code conventions](docs/code-conventions.md).
Pull requests are welcomed! Note that we do not accept contributions that are primarily AI-generated and will close your PR if we suspect as much.
# Credits
Special thanks to the [TP decompilation](https://github.com/zeldaret/tp) team, the GC/Wii decompilation community, the [Aurora](https://github.com/encounter/aurora) developers, the [TP speedrunning community](https://zsrtp.link), and all [contributors](https://github.com/TwilitRealm/dusklight/graphs/contributors).
Special thanks to the [TP decompilation](https://github.com/zeldaret/tp) team, the GC/Wii decompilation community, the [Aurora](https://github.com/encounter/aurora) developers, the [TP speedrunning community](https://zsrtp.link), and all [contributors](https://github.com/TwilitRealm/dusk/graphs/contributors).
<br/>
<div align="center">
+9 -17
View File
@@ -1,26 +1,18 @@
#!/bin/bash -ex
if [[ -n "${GITHUB_WORKSPACE:-}" ]]; then
cd "$GITHUB_WORKSPACE"
fi
build_dir="$PWD/build"
linuxdeploy="$build_dir/linuxdeploy-$(uname -m).AppImage"
shopt -s extglob
# Get linuxdeploy
mkdir -p "$build_dir"
curl -fL "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-$(uname -m).AppImage" -o "$linuxdeploy"
chmod +x "$linuxdeploy"
cd "$RUNNER_WORKSPACE"
curl -fOL https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-$(uname -m).AppImage
chmod +x linuxdeploy-$(uname -m).AppImage
# Build AppImage
cd "$GITHUB_WORKSPACE"
mkdir -p build/appdir/usr/{bin,share/{applications,icons/hicolor}}
for install_path in build/install/*; do
[[ "$(basename "$install_path")" == *.* ]] && continue
cp -r "$install_path" build/appdir/usr/bin
done
cp -r build/install/!(*.*) build/appdir/usr/bin
cp -r platforms/freedesktop/{16x16,32x32,48x48,64x64,128x128,256x256,512x512,1024x1024} build/appdir/usr/share/icons/hicolor
cp platforms/freedesktop/dusklight.desktop build/appdir/usr/share/applications
cp platforms/freedesktop/dusk.desktop build/appdir/usr/share/applications
cd build/install
VERSION="$DUSK_VERSION" NO_STRIP=1 "$linuxdeploy" \
-l /usr/lib/x86_64-linux-gnu/libusb-1.0.so --appdir "$build_dir/appdir" --output appimage
VERSION="$DUSK_VERSION" NO_STRIP=1 "$RUNNER_WORKSPACE"/linuxdeploy-$(uname -m).AppImage \
-l /usr/lib/x86_64-linux-gnu/libusb-1.0.so --appdir "$GITHUB_WORKSPACE"/build/appdir --output appimage
+5 -5
View File
@@ -36,10 +36,10 @@
sudo dnf groupinstall "Development Tools" "Development Libraries"
```
#### Setup
Clone and initialize the Dusklight repository
Clone and initialize the Dusk repository
```sh
git clone --recursive https://github.com/TwilitRealm/dusklight.git
cd dusklight
git clone --recursive https://github.com/TwilitRealm/dusk.git
cd dusk
git pull
git submodule update --init --recursive
```
@@ -93,6 +93,6 @@ Alternate presets available:
#### Running
Pass the disc image as a positional argument. Supported formats: ISO (GCM), RVZ, WIA, WBFS, CISO, GCZ
```sh
build/{preset}/dusklight/path/to/game.rvz
build/{preset}/dusk /path/to/game.rvz
```
If no path is specified, Dusklight defaults to `game.iso` in the current working directory.
If no path is specified, Dusk defaults to `game.iso` in the current working directory.
-13
View File
@@ -1,13 +0,0 @@
# Code conventions for Dusk
## Upstream when appropriate
Bug fixes, documentation improvements, code cleanup, etc that also apply to the [original decompilation project](https://github.com/zeldaret/tp) should preferably be PR'd there.
## Properly indicate Dusk-modified code
When modifying original game code (i.e. in decomp) for Dusk's purposes, please clearly delineate such code as being Dusk-specific. Generally, this can be done by using `#if TARGET_PC` and keeping the original code in place. Use `#if AVOID_UB` for Undefined Behavior fixes to the original codebase.
## Miscellaneous things
* The original codebase makes heavy use of global `operator new` and similar overloads to allocate into a strict tree of heaps. This would cause many linkage headaches for us, so effectively all uses of `new` or `delete` in the original game code have been replaced with `JKR_NEW`, `JKR_DELETE`, or similar macros. See `JKRHeap.h` for the full list.
+2 -2
View File
@@ -1,10 +1,10 @@
# Installing Dusklight on iOS via AltStore
# Installing Dusk on iOS via AltStore
## Prerequisites
- Mac with Homebrew installed
- iPhone connected via USB
- Dusklight IPA file (download the latest `Dusklight-vX.X.X-ios-arm64.ipa` from the [releases page](https://github.com/TwilitRealm/dusk/releases))
- Dusk IPA file (download the latest `Dusk-vX.X.X-ios-arm64.ipa` from the [releases page](https://github.com/TwilitRealm/dusk/releases))
- Game disc - `GZ2E01` (Gamecube USA) or `GZ2PE01` (Gamecube PAL)
## 1. Install AltServer
+1 -1
+3 -10
View File
@@ -1411,7 +1411,6 @@ set(DOLPHIN_FILES
)
set(DUSK_FILES
include/dusk/action_bindings.h
include/dusk/endian_gx.hpp
include/dusk/config.hpp
include/dusk/dvd_asset.hpp
@@ -1421,8 +1420,6 @@ set(DUSK_FILES
src/dusk/asserts.cpp
src/dusk/config.cpp
src/dusk/crash_reporting.cpp
src/dusk/data.cpp
src/dusk/data.hpp
src/dusk/endian.cpp
src/dusk/extras.c
src/dusk/file_select.cpp
@@ -1438,7 +1435,6 @@ set(DUSK_FILES
src/dusk/layout.cpp
src/dusk/logging.cpp
src/dusk/settings.cpp
src/dusk/speedrun.cpp
src/dusk/stubs.cpp
src/dusk/update_check.cpp
src/dusk/update_check.hpp
@@ -1448,16 +1444,18 @@ set(DUSK_FILES
src/dusk/imgui/ImGuiConsole.cpp
src/dusk/imgui/ImGuiEngine.cpp
src/dusk/imgui/ImGuiEngine.hpp
src/dusk/imgui/ImGuiMenuGame.cpp
src/dusk/imgui/ImGuiMenuGame.hpp
src/dusk/imgui/ImGuiBloomWindow.cpp
src/dusk/imgui/ImGuiBloomWindow.hpp
src/dusk/imgui/ImGuiMenuTools.cpp
src/dusk/imgui/ImGuiMenuTools.hpp
src/dusk/imgui/ImGuiActorSpawner.cpp
src/dusk/imgui/ImGuiProcessOverlay.cpp
src/dusk/imgui/ImGuiCameraOverlay.cpp
src/dusk/imgui/ImGuiHeapOverlay.cpp
src/dusk/imgui/ImGuiControllerOverlay.cpp
src/dusk/imgui/ImGuiStubLog.cpp
src/dusk/imgui/ImGuiMapLoader.cpp
src/dusk/imgui/ImGuiSaveEditor.cpp
src/dusk/imgui/ImGuiStateShare.hpp
src/dusk/imgui/ImGuiStateShare.cpp
@@ -1496,8 +1494,6 @@ set(DUSK_FILES
src/dusk/ui/prelaunch.hpp
src/dusk/ui/preset.cpp
src/dusk/ui/preset.hpp
src/dusk/ui/reporting.cpp
src/dusk/ui/reporting.hpp
src/dusk/ui/select_button.cpp
src/dusk/ui/select_button.hpp
src/dusk/ui/settings.cpp
@@ -1508,8 +1504,6 @@ set(DUSK_FILES
src/dusk/ui/tab_bar.hpp
src/dusk/ui/ui.cpp
src/dusk/ui/ui.hpp
src/dusk/ui/warp.cpp
src/dusk/ui/warp.hpp
src/dusk/ui/window.cpp
src/dusk/ui/window.hpp
src/dusk/achievements.cpp
@@ -1524,7 +1518,6 @@ set(DUSK_FILES
src/dusk/discord.hpp
src/dusk/discord_presence.cpp
src/dusk/version.cpp
src/dusk/action_bindings.cpp
)
set(DUSK_HTTP_BACKEND_FILES
+24 -219
View File
@@ -4,225 +4,30 @@
};
outputs = { self, nixpkgs }:
let
supportedSystems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
pkgsFor = system: import nixpkgs { inherit system; };
# Dependencies that are not packaged in nixpkgs (used by the Linux package build):
buildSources = pkgs: {
aurora-src = pkgs.fetchFromGitHub {
owner = "encounter";
repo = "aurora";
rev = "63606a43265a3bc18dafd500ab4d7a2108f109e6";
hash = "sha256-xBvnAwGwNzav67Ac6oUz7RqDUwqgL2bsME3OOMn8Tqw=";
};
dawn-src = pkgs.fetchzip {
url = "https://github.com/encounter/dawn-build/releases/download/v20260423.175430/dawn-linux-x86_64.tar.gz";
hash = "sha256-HXfKTLHtMPwupnFnaflCARtXVPuS/0PoCePXidjE5xs=";
stripRoot = false;
};
nod-src = pkgs.fetchzip {
url = "https://github.com/encounter/nod/releases/download/v2.0.0-alpha.8/libnod-linux-x86_64.tar.gz";
hash = "sha256-mUqvLsbsqaZ+HAjMmHYPYO+MgtanGRTw7Gzn5uXR5rE=";
stripRoot = false;
};
# The version of imgui on nixpkgs does not map cleanly.
imgui-src = pkgs.fetchFromGitHub {
owner = "ocornut";
repo = "imgui";
rev = "v1.91.9b-docking";
hash = "sha256-mQOJ6jCN+7VopgZ61yzaCnt4R1QLrW7+47xxMhFRHLQ=";
};
sqlite-src = pkgs.fetchzip {
url = "https://sqlite.org/2026/sqlite-amalgamation-3510300.zip";
hash = "sha256-pNMR8zxaaqfAzQ0AQBOXMct4usdjey1Q0Gnitg06UhM=";
};
rmlui-src = pkgs.fetchzip {
url = "https://github.com/mikke89/RmlUi/archive/f9b8c9e2935d5df2c7dff2c190d3968e99b0c3dc.tar.gz";
hash = "sha256-g4O/JZUrrcseOz8o2QJRt+2CeuiLnVeuDJc906xvuIg=";
};
pkgs = import nixpkgs { system = "x86_64-linux"; };
dusk = pkgs.stdenv.mkDerivation {
name = "dusk";
src = ./.;
nativeBuildInputs = [
pkgs.cmake
pkgs.pkg-config
pkgs.wayland
];
buildInputs = [
pkgs.libGL
pkgs.libX11
pkgs.libXcursor
pkgs.libxi
pkgs.libxcb
pkgs.libxrandr
pkgs.libxscrnsaver
pkgs.libxtst
pkgs.libjpeg8
pkgs.libxkbcommon
pkgs.libglvnd
];
};
# Dusklight Actual (Linux x86_64 only — relies on prebuilt dawn/nod binaries)
mkDusklight = pkgs:
let srcs = buildSources pkgs;
versionSuffix = if self ? shortRev && self.shortRev != null
then "nix-${self.shortRev}"
else "nix-dirty";
in
pkgs.stdenv.mkDerivation {
name = "dusklight";
src = ./.;
postUnpack = ''
mkdir -p $sourceRoot/extern/aurora
cp -r ${srcs.aurora-src}/. $sourceRoot/extern/aurora/
chmod -R u+w $sourceRoot/extern/aurora
sed -i '/add_subdirectory(tests)/d' $sourceRoot/extern/aurora/CMakeLists.txt
'';
# Remove last line to re-enable tests
cmakeFlags = [
"-DDUSK_VERSION_OVERRIDE=${versionSuffix}"
"-DFETCHCONTENT_FULLY_DISCONNECTED=ON"
"-DFETCHCONTENT_SOURCE_DIR_CXXOPTS=${pkgs.cxxopts.src}"
"-DFETCHCONTENT_SOURCE_DIR_JSON=${pkgs.nlohmann_json.src}"
"-DFETCHCONTENT_SOURCE_DIR_DAWN_PREBUILT=${srcs.dawn-src}"
"-DFETCHCONTENT_SOURCE_DIR_XXHASH=${pkgs.xxHash.src}"
"-DFETCHCONTENT_SOURCE_DIR_FMT=${pkgs.fmt.src}"
"-DFETCHCONTENT_SOURCE_DIR_TRACY=${pkgs.tracy.src}"
"-DAURORA_SDL3_PROVIDER=system"
"-DFETCHCONTENT_SOURCE_DIR_NOD_PREBUILT=${srcs.nod-src}"
"-DAURORA_NOD_PROVIDER=package"
"-DFETCHCONTENT_SOURCE_DIR_FREETYPE=${pkgs.freetype.src}"
"-DFETCHCONTENT_SOURCE_DIR_ZSTD=${pkgs.zstd.src}"
"-DFETCHCONTENT_SOURCE_DIR_SQLITE3=${srcs.sqlite-src}"
"-DFETCHCONTENT_SOURCE_DIR_IMGUI=${srcs.imgui-src}"
"-DFETCHCONTENT_SOURCE_DIR_RMLUI=${srcs.rmlui-src}"
"-DCMAKE_CROSSCOMPILING=ON" # Tests are not working as I didn't want to work through getting google's test suite working as well. This is the only guard I could find to disable it.
];
installPhase = ''
mkdir -p $out/bin
cp dusklight $out/bin/dusklight
cp -r ./res $out/bin/res
mkdir -p $out/share/applications
cp $src/platforms/freedesktop/dusklight.desktop $out/share/applications/dusklight.desktop
for size in 16 32 48 64 128 256 512 1024; do
install -Dm644 $src/platforms/freedesktop/''${size}x''${size}/apps/dusklight.png \
$out/share/icons/hicolor/''${size}x''${size}/apps/dusklight.png
done
'';
nativeBuildInputs = [
pkgs.cmake
pkgs.pkg-config
pkgs.wayland
];
buildInputs = [
pkgs.libGL
pkgs.libX11
pkgs.libXcursor
pkgs.libxi
pkgs.libxcb
pkgs.libxrandr
pkgs.libxscrnsaver
pkgs.libxtst
pkgs.libjpeg8
pkgs.libxkbcommon
pkgs.libglvnd
pkgs.cxxopts
pkgs.abseil-cpp
pkgs.sdl3
pkgs.fmt
pkgs.tracy
pkgs.freetype
pkgs.zstd
];
};
# Tooling common to every supported host (Linux and macOS).
commonDevTools = pkgs: [
pkgs.cmake
pkgs.ninja
pkgs.pkg-config
pkgs.git
pkgs.python3
pkgs.python3Packages.markupsafe
pkgs.rustc
pkgs.cargo
pkgs.sccache
];
# Linux-only system libraries — mirrors the apt deps from .github/workflows/build.yml
# so the cmake presets resolve the same set of headers as CI.
linuxDevDeps = pkgs: [
# Compilers / linkers
pkgs.clang
pkgs.lld
# C/C++ utilities
pkgs.curl
pkgs.openssl
pkgs.zlib
pkgs.libpng
pkgs.libjpeg_turbo
pkgs.freetype
pkgs.zstd
pkgs.fmt
pkgs.tracy
pkgs.cxxopts
pkgs.abseil-cpp
pkgs.sdl3
pkgs.ncurses
pkgs.libunwind
pkgs.libusb1
pkgs.fuse
# Wayland / display server
pkgs.wayland
pkgs.wayland-protocols
pkgs.libxkbcommon
pkgs.libdecor
# OpenGL / Vulkan
pkgs.libGL
pkgs.libGLU
pkgs.libglvnd
pkgs.vulkan-headers
pkgs.vulkan-loader
# X11
pkgs.libX11
pkgs.libxcb
pkgs.libXcursor
pkgs.libxi
pkgs.libxrandr
pkgs.libxscrnsaver
pkgs.libxtst
pkgs.libxinerama
# Audio
pkgs.alsa-lib
pkgs.libpulseaudio
pkgs.pipewire
# System integration
pkgs.dbus
pkgs.udev
pkgs.gtk3
];
# On macOS we deliberately avoid pulling Nix's cc-wrapper so CMake picks up
# Apple Clang and the Xcode SDK directly, matching the macOS CI workflow.
mkDarwinShell = pkgs:
pkgs.mkShellNoCC {
packages = commonDevTools pkgs;
shellHook = ''
echo "Dusklight dev shell (macOS)"
echo "Requires Xcode Command Line Tools for Apple Clang and the macOS SDK."
echo "Configure: cmake --preset macos-default-relwithdebinfo"
echo "Build: cmake --build --preset macos-default-relwithdebinfo"
'';
};
mkLinuxShell = pkgs:
pkgs.mkShell {
packages = (commonDevTools pkgs) ++ (linuxDevDeps pkgs);
shellHook = ''
echo "Dusklight dev shell (Linux)"
echo "Configure: cmake --preset linux-default-relwithdebinfo"
echo " cmake --preset linux-clang-relwithdebinfo"
echo "Build: cmake --build --preset <preset>"
'';
};
mkDevShell = pkgs:
if pkgs.stdenv.isDarwin
then mkDarwinShell pkgs
else mkLinuxShell pkgs;
in {
packages.x86_64-linux.default = mkDusklight (pkgsFor "x86_64-linux");
devShells = forAllSystems (system: {
default = mkDevShell (pkgsFor system);
});
packages.x86_64-linux.default = dusk;
};
}
}
+1 -1
View File
@@ -4059,7 +4059,7 @@ public:
/* 0x02180 */ daAlink_matAnm_c* field_0x2180[2];
/* 0x02188 */ dEyeHL_c mEyeHL1;
/* 0x0219C */ dEyeHL_c mEyeHL2;
/* 0x021B0 */ daPy_anmHeap_c mItemHeap[3];
/* 0x021B0 */ daPy_anmHeap_c mItemHeap[2];
/* 0x021D8 */ daPy_anmHeap_c mAnmHeap9;
/* 0x021EC */ daAlinkHIO_c* mpHIO;
/* 0x021F0 */ daAlink_blur_c m_swordBlur;
-5
View File
@@ -47,7 +47,6 @@ enum dEvt_type_e {
/* 0x5 */ dEvt_type_ITEM_e,
/* 0x6 */ dEvt_type_SHOWITEM_X_e,
/* 0x7 */ dEvt_type_SHOWITEM_Y_e,
/* 0x8 */ dEvt_type_SHOWITEM_Z_e,
/* 0xA */ dEvt_type_CATCH_e = 10,
/* 0xB */ dEvt_type_TREASURE_e,
};
@@ -197,11 +196,7 @@ public:
/* 0x108 */ int mSkipTimer;
/* 0x10C */ int mSkipParameter;
/* 0x110 */ BOOL mIsSkipFade;
#if TARGET_PC
/* 0x114 */ char mSkipEventName[21];
#else
/* 0x114 */ char mSkipEventName[20];
#endif
/* 0x128 */ u8 mCompulsory;
/* 0x129 */ bool mRoomInfoSet;
/* 0x12C */ int mRoomNo;
-3
View File
@@ -223,9 +223,6 @@ private:
/* 0x8F */ u8 field_0x8f;
/* 0x90 */ u8 field_0x90;
/* 0x91 */ u8 field_0x91;
#if TARGET_PC
bool previousMirror;
#endif
}; // Size: 0x94
class dMap_HIO_list_c : public dMpath_HIO_n::hioList_c {
+1 -1
View File
@@ -172,7 +172,7 @@ private:
/* 0x6A9 */ u8 field_0x6a9; // unused
/* 0x6AA */ u8 mXButtonSlot;
/* 0x6AB */ u8 mYButtonSlot;
/* 0x6AC */ u8 mZButtonSlot;
/* 0x6AC */ u8 field_0x6ac;
/* 0x6AD */ u8 field_0x6ad;
/* 0x6AE */ u8 mItemsTotal; // Contains the amount of items which are actually obtained and in
// the item wheel
+1 -1
View File
@@ -160,7 +160,7 @@ private:
/* 0x078 */ J2DScreen* mpScreen;
/* 0x07C */ J2DScreen* mpKanteraScreen;
/* 0x080 */ J2DScreen* mpPikariScreen;
/* 0x084 */ J2DPicture* mpItemNumTex[3][3];
/* 0x084 */ J2DPicture* mpItemNumTex[2][3];
/* 0x09C */ CPaneMgr* field_0x9c[3];
/* 0x0A8 */ int field_0xa8;
/* 0x0AC */ dKantera_icon_c* mpKanteraMeter[2];
+1 -2
View File
@@ -12,7 +12,7 @@
static const int DEFAULT_SELECT_ITEM_INDEX = 0;
static const int MAX_SELECT_ITEM = 4;
static const int SELECT_ITEM_NUM = 3;
static const int SELECT_ITEM_NUM = 2;
static const int MAX_EQUIPMENT = 6;
static const int MAX_EVENTS = 256;
static const int MAX_ITEM_SLOTS = 24;
@@ -123,7 +123,6 @@ enum {
/* 0x3 */ SELECT_ITEM_B,
/* 0x0 */ SELECT_ITEM_X = SELECT_ITEM_LEFT,
/* 0x1 */ SELECT_ITEM_Y = SELECT_ITEM_RIGHT,
/* 0x2 */ SELECT_ITEM_Z = SELECT_ITEM_DOWN,
};
enum {
-43
View File
@@ -1,43 +0,0 @@
#pragma once
#include <unordered_map>
#include "dusk/config_var.hpp"
namespace dusk {
enum class ActionBinds {
FIRST_PERSON_CAMERA,
CALL_MIDNA,
OPEN_DUSKLIGHT_MENU,
TURBO_SPEED_BUTTON,
COUNT,
};
struct ActionBindData {
std::array<config::ActionBindConfigVar, 4>* configVars{};
std::string actionName{};
};
struct ActionBindPressData {
bool pressedCurFrame{false};
bool pressedPrevFrame{false};
};
using ActionBindsMap = std::unordered_map<ActionBinds, ActionBindData>;
ActionBindsMap& getActionBinds();
bool isActionBound(ActionBinds action, u32 port);
void updateActionBindings();
bool getActionBindTrig(ActionBinds action, u32 port);
bool getActionBindHold(ActionBinds action, u32 port);
bool getActionBindHoldAnyPort(ActionBinds action);
int getActionBindButton(ActionBinds action, u32 port);
}
+1 -6
View File
@@ -7,12 +7,7 @@ namespace dusk {
*
* This gets used for file paths and such, and cannot be changed!
*/
constexpr auto AppName = "Dusklight";
/**
* Previous AppName to migrate data from.
*/
constexpr auto LegacyAppName = "Dusk";
constexpr auto AppName = "Dusk";
/**
* \brief The internal organization name for the game.
-11
View File
@@ -1,19 +1,8 @@
#pragma once
#include <cmath>
#include <dolphin/types.h>
namespace dusk::audio {
// Converts a 0-1 volume to a linear amplitude multiplier.
// The curve is -4 dB per 10% step: 100% = 0 dB, 90% = -4 dB, ..., 0% = -inf dB
inline f32 MasterVolumeToLinear(f32 v) {
if (v <= 0.0f) {
return 0.0f;
}
return std::pow(10.0f, (v - 1.0f) * 2.0f);
}
/**
* Initialize the audio system and start playing audio.
*/
-1
View File
@@ -13,6 +13,5 @@ void enterAutoSave();
void autoSaving();
void waitingForWrite();
void endAutoSave();
void toggleAutoSave(bool enabled);
#endif
-13
View File
@@ -1,7 +1,6 @@
#ifndef DUSK_CONFIG_HPP
#define DUSK_CONFIG_HPP
#include <functional>
#include <stdexcept>
#include "nlohmann/json.hpp"
#include "config_var.hpp"
@@ -112,18 +111,6 @@ void Save();
*/
ConfigVarBase* GetConfigVar(std::string_view name);
/**
* \brief Resets all custom action bindings for a specific port to nothing
*
* @param port The port to be cleared of action bindings
*/
void ClearAllActionBindings(int port);
/**
* \brief Call a function on every registered CVar.
*/
void EnumerateRegistered(std::function<void(ConfigVarBase&)> callback);
template <ConfigValue T>
const ConfigImplBase* GetConfigImpl() {
static ConfigImpl<T> config;
-61
View File
@@ -48,13 +48,6 @@ enum class ConfigVarLayer : u8 {
* Will not get saved to config.
*/
Override,
/**
* The CVar is temporarily overridden by speedrun mode.
* Will not get saved to config. Cleared when speedrun mode is disabled.
* Lower priority than Override, so launch args still win.
*/
Speedrun,
};
class ConfigImplBase;
@@ -120,12 +113,6 @@ public:
* This is necessary to make it legal to access.
*/
void markRegistered();
/**
* Clear a speedrun-mode override if one is active on this CVar.
* Safe to call on any CVar, no-op if not at the Speedrun layer.
*/
virtual void clearSpeedrunOverride() {}
};
template <typename T>
@@ -175,7 +162,6 @@ class ConfigVar : public ConfigVarBase {
T defaultValue;
T value;
T overrideValue;
ConfigVarLayer priorLayer = ConfigVarLayer::Default;
public:
/**
@@ -203,7 +189,6 @@ public:
case ConfigVarLayer::Value:
return value;
case ConfigVarLayer::Override:
case ConfigVarLayer::Speedrun:
return overrideValue;
default:
abort();
@@ -254,54 +239,8 @@ public:
overrideValue = std::move(newValue);
layer = ConfigVarLayer::Override;
}
/**
* \brief Give a CVar a speedrun-mode override value.
*
* Lower priority than a launch-arg override. Cleared when speedrun mode is disabled.
* The overridden value will not get saved to config.
*
* @param newValue The new value the CVar will get.
*/
void setSpeedrunValue(T newValue) {
checkRegistered();
if (layer != ConfigVarLayer::Override) {
priorLayer = layer;
overrideValue = std::move(newValue);
layer = ConfigVarLayer::Speedrun;
}
}
void clearOverride() {
checkRegistered();
if (layer == ConfigVarLayer::Override) {
overrideValue = {};
layer = ConfigVarLayer::Value;
}
}
void clearSpeedrunOverride() override {
checkRegistered();
if (layer == ConfigVarLayer::Speedrun) {
overrideValue = {};
layer = priorLayer;
}
}
/**
* \brief Get the user-persisted value, ignoring any temporary overrides.
*
* Used by Save() to write the correct value even when a speedrun override is active.
*/
[[nodiscard]] constexpr const T& getValueForSave() const noexcept {
checkRegistered();
const ConfigVarLayer effectiveLayer = (layer == ConfigVarLayer::Speedrun) ? priorLayer : layer;
return effectiveLayer == ConfigVarLayer::Default ? defaultValue : value;
}
};
using ActionBindConfigVar = ConfigVar<int>;
}
#endif // DUSK_CONFIG_VAR_HPP
+4 -13
View File
@@ -1,17 +1,8 @@
#pragma once
namespace dusk::crash_reporting {
namespace dusk {
enum class Consent {
Unavailable,
Unknown,
Given,
Revoked,
};
void InitializeCrashReporting();
void ShutdownCrashReporting();
void initialize();
void shutdown();
Consent get_consent();
void set_consent(bool enabled);
} // namespace dusk::crash_reporting
} // namespace dusk
+1
View File
@@ -14,6 +14,7 @@ constexpr const char* SHOW_DEBUG_OVERLAY = "F3";
constexpr const char* SHOW_HEAP_VIEWER = "F4";
constexpr const char* SHOW_PLAYER_INFO = "F5";
constexpr const char* SHOW_SAVE_EDITOR = "F6";
constexpr const char* SHOW_MAP_LOADER = "F7";
constexpr const char* SHOW_STATE_SHARE = "F8";
constexpr const char* SHOW_DEBUG_CAMERA = "F9";
constexpr const char* SHOW_AUDIO_DEBUG = "F10";
+5 -9
View File
@@ -1,13 +1,14 @@
#ifndef DUSK_IO_HPP
#define DUSK_IO_HPP
#include <filesystem>
#include <vector>
#include <filesystem>
// I can't believe it's 2026 and neither SDL (no error codes) nor
// C++ (no error codes) have a file system API functional enough for me to use.
// Here you go, this one's inspired by C#. I only wrote the functions I need.
namespace dusk::io {
/**
@@ -82,7 +83,9 @@ public:
/**
* Get direct access to the underlying FILE* handle.
*/
[[nodiscard]] void* GetFileHandle() const noexcept { return file; }
[[nodiscard]] void* GetFileHandle() const noexcept {
return file;
}
/**
* Write data to the file.
@@ -92,14 +95,7 @@ public:
FILE* ToInner();
};
/**
* Converts a std::filesystem::path to a std::string, UTF-8, without exploding on Windows.
*/
inline std::string fs_path_to_string(const std::filesystem::path& path) {
const auto u8str = path.u8string();
return {reinterpret_cast<const char*>(u8str.c_str())};
}
} // namespace dusk::io
#endif // DUSK_IO_HPP
+28 -18
View File
@@ -1,26 +1,36 @@
#ifndef DUSK_MAIN_H
#define DUSK_MAIN_H
#include <filesystem>
namespace dusk {
extern bool IsRunning;
extern bool IsShuttingDown;
extern bool IsGameLaunched;
extern bool RestartRequested;
extern std::filesystem::path ConfigPath;
extern std::filesystem::path CachePath;
#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS) || \
(defined(TARGET_OS_TV) && TARGET_OS_TV)
inline constexpr bool SupportsProcessRestart = false;
#else
inline constexpr bool SupportsProcessRestart = true;
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
void RequestRestart() noexcept;
#include <filesystem>
} // namespace dusk
#if defined(_WIN32) || \
(defined(__APPLE__) && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_MACCATALYST) || \
(defined(__linux__) && !defined(__ANDROID__))
#define DUSK_CAN_OPEN_DATA_FOLDER 1
#else
#define DUSK_CAN_OPEN_DATA_FOLDER 0
#endif
namespace dusk {
extern bool IsRunning;
extern bool IsShuttingDown;
extern bool IsGameLaunched;
extern bool RestartRequested;
extern std::filesystem::path ConfigPath;
#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS) || \
(defined(TARGET_OS_TV) && TARGET_OS_TV)
inline constexpr bool SupportsProcessRestart = false;
#else
inline constexpr bool SupportsProcessRestart = true;
#endif
void RequestRestart() noexcept;
bool OpenDataFolder();
}
#endif // DUSK_MAIN_H
+1 -21
View File
@@ -1,8 +1,6 @@
#ifndef DUSK_CONFIG_H
#define DUSK_CONFIG_H
#include <array>
#include "dusk/config_var.hpp"
namespace dusk {
@@ -117,7 +115,6 @@ struct UserSettings {
ConfigVar<bool> enableLinkDollRotation;
ConfigVar<bool> enableAchievementToasts;
ConfigVar<bool> enableControllerToasts;
ConfigVar<bool> enableDiscordPresence;
// Graphics
ConfigVar<BloomMode> bloomMode;
@@ -128,7 +125,6 @@ struct UserSettings {
ConfigVar<int> shadowResolutionMultiplier;
ConfigVar<bool> enableDepthOfField;
ConfigVar<bool> enableMapBackground;
ConfigVar<bool> disableCutscenePillarboxing;
// Audio
ConfigVar<bool> noLowHpSound;
@@ -148,8 +144,6 @@ struct UserSettings {
ConfigVar<bool> freeCamera;
ConfigVar<bool> invertCameraXAxis;
ConfigVar<bool> invertCameraYAxis;
ConfigVar<bool> invertFirstPersonXAxis;
ConfigVar<bool> invertFirstPersonYAxis;
ConfigVar<float> freeCameraSensitivity;
ConfigVar<bool> debugFlyCam;
ConfigVar<bool> debugFlyCamLockEvents;
@@ -158,7 +152,6 @@ struct UserSettings {
// Cheats
ConfigVar<bool> infiniteHearts;
ConfigVar<bool> infiniteArrows;
ConfigVar<bool> infiniteSeeds;
ConfigVar<bool> infiniteBombs;
ConfigVar<bool> infiniteOil;
ConfigVar<bool> infiniteOxygen;
@@ -169,25 +162,19 @@ struct UserSettings {
ConfigVar<bool> alwaysGreatspin;
ConfigVar<bool> enableFastIronBoots;
ConfigVar<bool> canTransformAnywhere;
ConfigVar<bool> fastRoll;
ConfigVar<bool> fastSpinner;
ConfigVar<bool> freeMagicArmor;
ConfigVar<bool> invincibleEnemies;
// Technical
ConfigVar<bool> restoreWiiGlitches;
// Controls
ConfigVar<bool> enableTurboKeybind;
ConfigVar<bool> enableResetKeybind;
// Tools
ConfigVar<bool> speedrunMode;
ConfigVar<bool> liveSplitEnabled;
ConfigVar<bool> showSpeedrunRTATimer;
ConfigVar<bool> recordingMode;
ConfigVar<bool> showInputViewer;
ConfigVar<bool> showInputViewerGyro;
} game;
struct {
@@ -197,18 +184,11 @@ struct UserSettings {
ConfigVar<bool> skipPreLaunchUI;
ConfigVar<bool> showPipelineCompilation;
ConfigVar<bool> wasPresetChosen;
ConfigVar<bool> enableCrashReporting;
ConfigVar<bool> checkForUpdates;
ConfigVar<int> cardFileType;
ConfigVar<bool> enableAdvancedSettings;
} backend;
// Arrays of size 4 for 4 ports
struct {
std::array<ActionBindConfigVar, 4> firstPersonCamera;
std::array<ActionBindConfigVar, 4> callMidna;
std::array<ActionBindConfigVar, 4> openDusklightMenu;
std::array<ActionBindConfigVar, 4> turboSpeedButton;
} actionBindings;
};
UserSettings& getSettings();
-41
View File
@@ -1,41 +0,0 @@
#pragma once
#include <aurora/aurora.h>
namespace dusk {
struct SpeedrunInfo {
void startRun() {
m_isRunStarted = true;
m_startTimestamp = OSGetTime();
}
void stopRun() {
m_isRunStarted = false;
m_endTimestamp = OSGetTime() - m_startTimestamp;
}
void reset() {
m_isRunStarted = false;
m_startTimestamp = 0;
m_endTimestamp = 0;
m_isPauseIGT = false;
m_loadStartTimestamp = 0;
m_totalLoadTime = 0;
m_igtTimer = 0;
}
bool m_isRunStarted = false;
OSTime m_startTimestamp = 0;
OSTime m_endTimestamp = 0;
bool m_isPauseIGT = false;
OSTime m_loadStartTimestamp = 0;
OSTime m_totalLoadTime = 0;
OSTime m_igtTimer = 0;
};
extern SpeedrunInfo m_speedrunInfo;
void resetForSpeedrunMode();
} // namespace dusk
-7
View File
@@ -4,10 +4,6 @@
#include <cmath>
#include "os_report.h"
#if TARGET_PC
#include "dusk/action_bindings.h"
#endif
u32 JUTGamePad::CRumble::sChannelMask[4] = {
PAD_CHAN0_BIT,
PAD_CHAN1_BIT,
@@ -89,9 +85,6 @@ u32 JUTGamePad::sRumbleSupported;
u32 JUTGamePad::read() {
sRumbleSupported = PADRead(mPadStatus);
#if TARGET_PC
dusk::updateActionBindings();
#endif
switch (sClampMode) {
case EClampStick:
+1 -1
View File
@@ -1,6 +1,6 @@
# Android Shell
This directory contains a minimal SDLActivity-based Android app wrapper for Dusklight.
This directory contains a minimal SDLActivity-based Android app wrapper for Dusk.
## Prerequisites
+1 -1
View File
@@ -3,7 +3,7 @@ plugins {
}
def duskRepoDir = rootProject.projectDir.parentFile.parentFile
def duskGeneratedAssetsDir = layout.buildDirectory.dir('generated/assets/dusklight').get().asFile
def duskGeneratedAssetsDir = layout.buildDirectory.dir('generated/assets/dusk').get().asFile
def syncDuskAssets = tasks.register('syncDuskAssets', Sync) {
from(new File(duskRepoDir, 'res')) {
into 'res'
@@ -1,16 +1,12 @@
package dev.twilitrealm.dusk;
import android.app.ActionBar;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.OpenableColumns;
import android.util.Log;
import android.view.View;
@@ -26,13 +22,6 @@ import java.util.List;
public class DuskActivity extends SDLActivity {
private static final String TAG = "DuskActivity";
private static final int FOLDER_DIALOG_REQUEST_CODE = 0x4455;
private static final String EXTERNAL_STORAGE_AUTHORITY =
"com.android.externalstorage.documents";
private long folderDialogUserdata = 0;
private static native void nativeFolderDialogResult(long userdata, String path, String error);
private static String[] splitArgs(String raw) {
List<String> out = new ArrayList<>();
@@ -158,154 +147,9 @@ public class DuskActivity extends SDLActivity {
if (resultCode == RESULT_OK) {
persistUriPermissions(data);
}
if (requestCode == FOLDER_DIALOG_REQUEST_CODE) {
finishFolderDialog(resultCode, data);
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
public boolean showFolderDialog(long userdata) {
if (userdata == 0 || folderDialogUserdata != 0) {
return false;
}
folderDialogUserdata = userdata;
runOnUiThread(() -> {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION |
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
try {
startActivityForResult(intent, FOLDER_DIALOG_REQUEST_CODE);
} catch (ActivityNotFoundException e) {
Log.w(TAG, "Unable to open folder dialog.", e);
finishFolderDialog(Activity.RESULT_CANCELED, null);
}
});
return true;
}
private void finishFolderDialog(int resultCode, Intent data) {
long userdata = folderDialogUserdata;
folderDialogUserdata = 0;
if (userdata == 0) {
return;
}
if (resultCode == RESULT_OK && data != null && data.getData() != null) {
String path = getRealPathForUri(data.getData());
if (path != null && !path.isEmpty()) {
nativeFolderDialogResult(userdata, path, null);
} else {
nativeFolderDialogResult(
userdata, null, "Selected folder is not available as a filesystem path");
}
return;
}
nativeFolderDialogResult(userdata, null, null);
}
private String getRealPathForUri(Uri uri) {
if (uri == null) {
return null;
}
String scheme = uri.getScheme();
if ("file".equals(scheme)) {
return uri.getPath();
}
if (!"content".equals(scheme) ||
!EXTERNAL_STORAGE_AUTHORITY.equals(uri.getAuthority()) ||
Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
{
return null;
}
try {
return getExternalStoragePathForDocumentId(getExternalStorageDocumentId(uri));
} catch (IllegalArgumentException e) {
Log.w(TAG, "Unable to resolve URI: " + uri, e);
return null;
}
}
private static String getExternalStorageDocumentId(Uri uri) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && isTreeDocumentUri(uri)) {
return DocumentsContract.getTreeDocumentId(uri);
}
return DocumentsContract.getDocumentId(uri);
}
private static boolean isTreeDocumentUri(Uri uri) {
List<String> segments = uri.getPathSegments();
return segments.size() >= 2 && "tree".equals(segments.get(0));
}
private String getExternalStoragePathForDocumentId(String documentId) {
if (documentId == null || documentId.isEmpty()) {
return null;
}
if (documentId.startsWith("raw:")) {
return documentId.substring("raw:".length());
}
String[] parts = documentId.split(":", 2);
String volumeId = parts[0];
String relativePath = parts.length > 1 ? parts[1] : "";
File root = getExternalStorageRoot(volumeId);
if (root == null) {
return null;
}
return relativePath.isEmpty()
? root.getAbsolutePath()
: new File(root, relativePath).getAbsolutePath();
}
private File getExternalStorageRoot(String volumeId) {
if ("primary".equalsIgnoreCase(volumeId)) {
return Environment.getExternalStorageDirectory();
}
if ("home".equalsIgnoreCase(volumeId)) {
return new File(
Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DOCUMENTS);
}
File[] externalFilesDirs = getExternalFilesDirs(null);
if (externalFilesDirs != null) {
for (File externalFilesDir : externalFilesDirs) {
File root = getStorageRootForExternalFilesDir(externalFilesDir);
if (root != null && volumeId.equalsIgnoreCase(root.getName())) {
return root;
}
}
}
File fallback = new File("/storage", volumeId);
return fallback.exists() ? fallback : null;
}
private File getStorageRootForExternalFilesDir(File externalFilesDir) {
if (externalFilesDir == null) {
return null;
}
String path = externalFilesDir.getAbsolutePath();
int androidDir = path.indexOf("/Android/");
if (androidDir <= 0) {
return null;
}
return new File(path.substring(0, androidDir));
}
private void persistUriPermissions(Intent data) {
if (data == null) {
return;
@@ -14,22 +14,15 @@ import android.provider.DocumentsContract.Root;
import android.provider.DocumentsProvider;
import android.webkit.MimeTypeMap;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class DuskDocumentsProvider extends DocumentsProvider {
public static final String AUTHORITY = "dev.twilitrealm.dusk.documents";
private static final String ROOT_ID = "dusk";
private static final String ROOT_DOCUMENT_ID = "root";
private static final String LOCATION_DESCRIPTOR_NAME = "data_location.json";
private static final String DIRECTORY_MIME_TYPE = Document.MIME_TYPE_DIR;
private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
@@ -53,19 +46,13 @@ public class DuskDocumentsProvider extends DocumentsProvider {
@Override
public boolean onCreate() {
if (!isCustomDataPathEnabled()) {
ensureUserDirectories();
}
ensureUserDirectories();
return true;
}
@Override
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
if (isCustomDataPathEnabled()) {
return result;
}
final File root = getRootDirectory();
final MatrixCursor.RowBuilder row = result.newRow();
@@ -235,14 +222,9 @@ public class DuskDocumentsProvider extends DocumentsProvider {
}
private File getRootDirectory() throws FileNotFoundException {
if (isCustomDataPathEnabled()) {
throw new FileNotFoundException(
"Dusk DocumentsProvider is disabled while a custom data path is configured");
}
final File root = getContext().getFilesDir();
if (root == null) {
throw new FileNotFoundException("Dusklight files directory is unavailable");
throw new FileNotFoundException("Dusk files directory is unavailable");
}
return root;
}
@@ -259,7 +241,7 @@ public class DuskDocumentsProvider extends DocumentsProvider {
final String relativePath = documentId.substring(ROOT_DOCUMENT_ID.length() + 1);
final File file = new File(root, relativePath);
if (!isInside(root, file)) {
throw new FileNotFoundException("Document escapes Dusklight files directory: " + documentId);
throw new FileNotFoundException("Document escapes Dusk files directory: " + documentId);
}
if (!file.exists()) {
throw new FileNotFoundException("Document does not exist: " + documentId);
@@ -273,7 +255,7 @@ public class DuskDocumentsProvider extends DocumentsProvider {
return ROOT_DOCUMENT_ID;
}
if (!isInside(root, file)) {
throw new FileNotFoundException("File escapes Dusklight files directory: " + file);
throw new FileNotFoundException("File escapes Dusk files directory: " + file);
}
final String rootPath = canonicalPath(root);
@@ -291,42 +273,6 @@ public class DuskDocumentsProvider extends DocumentsProvider {
new File(root, "EUR/Card A").mkdirs();
}
private boolean isCustomDataPathEnabled() {
if (getContext() == null) {
return false;
}
final File filesDir = getContext().getFilesDir();
if (filesDir == null) {
return false;
}
final File descriptor = new File(filesDir, LOCATION_DESCRIPTOR_NAME);
if (!descriptor.isFile()) {
return false;
}
try {
final JSONObject json = new JSONObject(readText(descriptor));
return "custom".equals(json.optString("mode", "default"));
} catch (IOException | JSONException e) {
return false;
}
}
private static String readText(File file) throws IOException {
try (FileInputStream input = new FileInputStream(file);
ByteArrayOutputStream output = new ByteArrayOutputStream())
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
return output.toString(StandardCharsets.UTF_8.name());
}
}
private static String[] resolveRootProjection(String[] projection) {
return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
}
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Dusklight</string>
<string name="documents_provider_root_name">Dusklight Data</string>
<string name="app_name">Dusk</string>
<string name="documents_provider_root_name">Dusk Data</string>
<string name="documents_provider_summary">Saves, texture packs, settings, and logs</string>
</resources>
Vendored Executable → Regular
View File
+1 -1
View File
@@ -14,5 +14,5 @@ dependencyResolutionManagement {
}
}
rootProject.name = "dusklight-android"
rootProject.name = "dusk-android"
include ':app'

Before

Width:  |  Height:  |  Size: 928 KiB

After

Width:  |  Height:  |  Size: 928 KiB

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before

Width:  |  Height:  |  Size: 1014 B

After

Width:  |  Height:  |  Size: 1014 B

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Before

Width:  |  Height:  |  Size: 279 KiB

After

Width:  |  Height:  |  Size: 279 KiB

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

+9
View File
@@ -0,0 +1,9 @@
[Desktop Entry]
Name=Dusk
GenericName=Dusk
Comment=The Legend of Zelda: Twilight Princess
Exec=dusk
Icon=dusk
Terminal=false
Type=Application
Categories=Game;
-9
View File
@@ -1,9 +0,0 @@
[Desktop Entry]
Name=Dusklight
GenericName=Dusklight
Comment=PC port of a classic adventure game
Exec=dusklight
Icon=dusklight
Terminal=false
Type=Application
Categories=Game;
-2
View File
@@ -83,7 +83,5 @@
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>LSSupportsGameMode</key>
<true/>
</dict>
</plist>
+1 -3
View File
@@ -13,7 +13,7 @@
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string>Dusklight</string>
<string>Dusk</string>
<key>CFBundleIconName</key>
<string>Dusk</string>
<key>CFBundleIdentifier</key>
@@ -28,7 +28,5 @@
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>LSSupportsGameMode</key>
<true/>
</dict>
</plist>
-2
View File
@@ -45,7 +45,5 @@
<string>LaunchScreen</string>
<key>UIUserInterfaceStyle</key>
<string>Automatic</string>
<key>LSSupportsGameMode</key>
<true />
</dict>
</plist>
@@ -24,9 +24,9 @@ BEGIN
VALUE "CompanyName", "@DUSK_COMPANY_NAME@\0"
VALUE "FileDescription", "@DUSK_FILE_DESCRIPTION@\0"
VALUE "FileVersion", "@DUSK_VERSION_STRING@\0"
VALUE "InternalName", "dusklight\0"
VALUE "InternalName", "dusk\0"
VALUE "LegalCopyright", "@DUSK_COPYRIGHT@\0"
VALUE "OriginalFilename", "dusklight.exe\0"
VALUE "OriginalFilename", "dusk.exe\0"
VALUE "ProductName", "@DUSK_PRODUCT_NAME@\0"
VALUE "ProductVersion", "@DUSK_VERSION_STRING@\0"
END
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 457 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 642 KiB

After

Width:  |  Height:  |  Size: 340 KiB

-31
View File
@@ -201,37 +201,6 @@ fps {
white-space: nowrap;
}
speedrun-timer {
display: none;
position: absolute;
bottom: 0;
right: 0;
z-index: 99;
background-color: rgba(0, 0, 0, 65%);
padding: 2dp 4dp;
pointer-events: none;
font-family: "Noto Mono";
font-size: 16dp;
color: #ffffff;
white-space: nowrap;
}
speedrun-timer[open] {
display: block;
}
speedrun-rta {
display: none;
}
speedrun-rta[open] {
display: block;
}
speedrun-igt {
display: block;
}
fps[open] {
display: block;
}
+9 -8
View File
@@ -65,10 +65,10 @@ menu {
right: auto;
top: 50%;
transform: translateY(-50%);
/* Scale based on a reference screen width, 856/1216 */
width: 70.394736vw;
/* Scale based on a reference screen width, 428/1216 */
width: 35.230264vw;
min-width: 428dp;
max-width: 50vw;
max-width: 856dp;
height: auto;
display: flex;
flex-direction: column;
@@ -83,8 +83,9 @@ body.mirrored menu {
hero {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 4dp;
gap: 8dp;
}
body.mirrored hero {
@@ -95,19 +96,19 @@ hero img {
width: 100%;
}
eyebrow {
.eyebrow {
font-family: "Alegreya SC";
font-size: 32dp;
}
@media (min-width: 1216dp) {
eyebrow {
.eyebrow {
/* Same logic as .menu, 32/1216 */
font-size: 2.631579vw;
}
}
eyebrow span {
.eyebrow span {
font-weight: bold;
}
@@ -436,7 +437,7 @@ body.animate-in .intro-item {
decorator: horizontal-gradient(#FEE685FF #FEE68500);
}
eyebrow {
.eyebrow {
display: none;
}
-11
View File
@@ -105,12 +105,6 @@ window content pane:last-of-type > div {
line-height: 1.625;
}
.data-folder-current {
display: block;
font-size: 16dp;
color: rgba(224, 219, 200, 65%);
}
window content pane > spacer {
display: block;
/* Completes the 24dp bottom inset after the pane's 8dp gap. */
@@ -205,11 +199,6 @@ button:not(:disabled):active {
box-shadow: #C2A42D 0 0 0 2dp;
}
button:disabled {
opacity: 0.35;
cursor: default;
}
button.modal-btn {
flex: 1 1 0;
text-align: center;
+27 -75
View File
@@ -51,13 +51,10 @@
#include "d/actor/d_a_ni.h"
#include "d/d_s_play.h"
#if TARGET_PC
#include "dusk/action_bindings.h"
#include "dusk/frame_interpolation.h"
#include "dusk/settings.h"
#include "res/Object/Alink.h"
#include <cstring>
#endif
static int daAlink_Create(fopAc_ac_c* i_this);
static int daAlink_Delete(daAlink_c* i_this);
@@ -4552,7 +4549,7 @@ void daAlink_c::playerInit() {
PLAYER_CREATE_ANM_HEAP(mFaceBtkHeap, daPy_anmHeap_c::HEAP_TYPE_2, "daAlink_c::mFaceBtkHeap");
PLAYER_CREATE_ANM_HEAP(mFaceBckHeap, daPy_anmHeap_c::HEAP_TYPE_3, "daAlink_c::mFaceBckHeap");
for (i = 0; i < SELECT_ITEM_NUM; i++) {
for (i = 0; i < 2; i++) {
mItemHeap[i].setBufferSize(0x13200);
PLAYER_CREATE_ANM_HEAP_F(mItemHeap[i], daPy_anmHeap_c::HEAP_TYPE_4, "daAlink_c::mItemHeap[%d]", i);
}
@@ -9366,12 +9363,6 @@ BOOL daAlink_c::spActionTrigger() {
}
BOOL daAlink_c::midnaTalkTrigger() const {
#if TARGET_PC
// If we have a custom bind for Midna, check that instead
if (dusk::isActionBound(dusk::ActionBinds::CALL_MIDNA, 0)) {
return dusk::getActionBindTrig(dusk::ActionBinds::CALL_MIDNA, 0);
}
#endif
return mItemTrigger & BTN_Z;
}
@@ -9494,7 +9485,7 @@ void daAlink_c::setStickData() {
if (mDoCPd_c::getTrigY(PAD_1)) {
mItemTrigger |= (daAlink_ITEM_BTN)BTN_Y;
}
if (mDoCPd_c::getTrigZ(PAD_1) && !mDoCPd_c::getHoldR(PAD_1)) {
if (mDoCPd_c::getTrigZ(PAD_1)) {
mItemTrigger |= (daAlink_ITEM_BTN)BTN_Z;
}
if (mDoCPd_c::getTrigL(PAD_1)) {
@@ -11297,8 +11288,8 @@ BOOL daAlink_c::checkUpperItemActionFly() {
void daAlink_c::checkItemButtonChange() {
if (mProcID != PROC_CANOE_PADDLE_PUT && mEquipItem != dItemNo_NONE_e && !checkEquipAnime()) {
u8 temp_r0;
for (u8 i = 0; i < SELECT_ITEM_NUM; i++) {
temp_r0 = (i + 1) % SELECT_ITEM_NUM;
for (u8 i = 0; i < 2; i++) {
temp_r0 = (i + 1) % 2;
if (mEquipItem == dComIfGp_getSelectItem(i) &&
(mEquipItem != dComIfGp_getSelectItem(temp_r0) || mSelectItemId != temp_r0))
{
@@ -11468,8 +11459,8 @@ int daAlink_c::orderTalk(int i_checkZTalk) {
}
if (!checkWolf() && checkRequestTalkActor(mAttList2, field_0x27f8)) {
for (int i = 0; i < 3; i++) {
// check if pressed X or Y or Z and if item on button is a trade item
for (int i = 0; i < 2; i++) {
// check if pressed X or Y and if item on button is a trade item
if (checkTradeItem(dComIfGp_getSelectItem(i)) && itemTriggerCheck(1 << i)) {
fopAcM_orderTalkItemBtnEvent(itemTalkType[i], this, field_0x27f8, 0, 0);
return 1;
@@ -12107,7 +12098,7 @@ void daAlink_c::allUnequip(BOOL param_0) {
if (checkNoResetFlg2(FLG2_UNK_1) && param_0 && !checkCanoeRide() &&
mEquipItem != dItemNo_KANTERA_e)
{
for (u8 i = 0; i < SELECT_ITEM_NUM; i++) {
for (u8 i = 0; i < 2; i++) {
if (dComIfGp_getSelectItem(i) == dItemNo_KANTERA_e) {
mSelectItemId = i;
}
@@ -12159,7 +12150,7 @@ BOOL daAlink_c::checkItemChangeFromButton() {
itemEquip(0x105);
} else {
u8 i;
for (i = 0; i < SELECT_ITEM_NUM; i++) {
for (i = 0; i < 2; i++) {
int proc_type = checkNewItemChange(i);
if (proc_type != 0 && itemTriggerCheck(1 << i)) {
BOOL var_r27 = changeItemTriggerKeepProc(i, proc_type);
@@ -12180,7 +12171,7 @@ BOOL daAlink_c::checkItemChangeFromButton() {
} else if (mEquipItem == dItemNo_NONE_e && mThrowBoomerangAcKeep.getActor() == NULL &&
!checkCanoeRide() && checkNoUpperAnime() && checkNoResetFlg2(FLG2_UNK_1))
{
for (i = 0; i < SELECT_ITEM_NUM; i++) {
for (i = 0; i < 2; i++) {
if (dComIfGp_getSelectItem(i) == dItemNo_KANTERA_e) {
mSelectItemId = i;
}
@@ -12192,7 +12183,7 @@ BOOL daAlink_c::checkItemChangeFromButton() {
mEquipItem != 0x102 && (!checkCanoeRide() || !checkFisingRodLure()))
{
if (!checkEventRun() || strcmp(dComIfGp_getEventManager().getRunEventName(), "ANGER") != 0) {
if (strcmp(dComIfGp_getEventManager().getRunEventName(), "ANGER2") != 0 && checkItemSetButton(mEquipItem) == 3) {
if (strcmp(dComIfGp_getEventManager().getRunEventName(), "ANGER2") != 0 && checkItemSetButton(mEquipItem) == 2) {
allUnequip(1);
}
}
@@ -14386,7 +14377,7 @@ BOOL daAlink_c::checkGroupItem(int i_itemNo, int i_selItem) const {
}
int daAlink_c::checkSetItemTrigger(int i_itemNo) {
for (u8 i = 0; i < SELECT_ITEM_NUM; i++) {
for (u8 i = 0; i < 2; i++) {
if (checkGroupItem(i_itemNo, dComIfGp_getSelectItem(i)) && itemTriggerCheck(1 << i)) {
if (i_itemNo != dItemNo_HVY_BOOTS_e) {
mSelectItemId = i;
@@ -14399,13 +14390,13 @@ int daAlink_c::checkSetItemTrigger(int i_itemNo) {
}
int daAlink_c::checkItemSetButton(int i_itemNo) {
for (u8 i = 0; i < SELECT_ITEM_NUM; i++) {
for (u8 i = 0; i < 2; i++) {
if (checkGroupItem(i_itemNo, dComIfGp_getSelectItem(i))) {
return i;
}
}
return 3;
return 2;
}
bool daAlink_c::checkField() {
@@ -14605,7 +14596,7 @@ int daAlink_c::checkNewItemChange(u8 i_selItemIdx) {
return ITEM_PROC_BOTTLE_DRINK;
}
if (checkOilBottleItem(sel_item) && checkItemSetButton(dItemNo_KANTERA_e) != 3) {
if (checkOilBottleItem(sel_item) && checkItemSetButton(dItemNo_KANTERA_e) != 2) {
return ITEM_PROC_KANDELAAR_POUR;
}
} else if (sel_item == dItemNo_HVY_BOOTS_e) {
@@ -14650,7 +14641,7 @@ int daAlink_c::checkNewItemChange(u8 i_selItemIdx) {
return ITEM_PROC_SPINNER_READY;
} else if (checkDungeonWarpItem(sel_item)) {
return ITEM_PROC_DUNGEON_WARP_READY;
} else if (checkItemSetButton(0x108) != 3 &&
} else if (checkItemSetButton(0x108) != 2 &&
(sel_item == dItemNo_WORM_e || sel_item == dItemNo_BEE_CHILD_e))
{
int itemNo = dComIfGp_getSelectItem(checkItemSetButton(0x108));
@@ -14674,7 +14665,7 @@ int daAlink_c::checkNewItemChange(u8 i_selItemIdx) {
return ITEM_PROC_NOT_USE_ITEM;
} else if (sel_item == dItemNo_HORSE_FLUTE_e) {
return ITEM_PROC_GRASS_WHISTLE;
} else if (checkOilBottleItem(sel_item) && checkItemSetButton(0x48) != 3) {
} else if (checkOilBottleItem(sel_item) && checkItemSetButton(0x48) != 2) {
return ITEM_PROC_KANDELAAR_POUR;
} else if (sel_item == dItemNo_HAWK_EYE_e) {
if (acceptSubjectModeChange()) {
@@ -16123,9 +16114,6 @@ int daAlink_c::procSlideLand() {
int daAlink_c::procFrontRollInit() {
BOOL is_guard_anime = checkUpperGuardAnime();
#ifdef TARGET_PC
const f32 fastRollMultiplier = dusk::getSettings().game.fastRoll ? 2.0f : 1.0f;
#endif
if (mProcID == PROC_FRONT_ROLL && mDemo.getDemoMode() == daPy_demo_c::DEMO_FRONT_ROLL_e) {
return 0;
@@ -16141,16 +16129,10 @@ int daAlink_c::procFrontRollInit() {
roll_anm_speed = mpHIO->mFrontRoll.m.mRollAnm.mStartFrame;
}
setSingleAnime(ANM_FRONT_ROLL,
#ifdef TARGET_PC
mpHIO->mFrontRoll.m.mRollAnm.mSpeed * fastRollMultiplier,
#else
mpHIO->mFrontRoll.m.mRollAnm.mSpeed,
#endif
roll_anm_speed,
setSingleAnime(ANM_FRONT_ROLL, mpHIO->mFrontRoll.m.mRollAnm.mSpeed, roll_anm_speed,
mpHIO->mFrontRoll.m.mRollAnm.mEndFrame,
mpHIO->mFrontRoll.m.mRollAnm.mInterpolation);
mNormalSpeed = speedF * mpHIO->mFrontRoll.m.mSpeedRate + mpHIO->mFrontRoll.m.mInitSpeed;
f32 max_speed = mpHIO->mFrontRoll.m.mInitSpeed + mpHIO->mMove.m.mMaxSpeed * mpHIO->mFrontRoll.m.mSpeedRate;
@@ -16163,20 +16145,11 @@ int daAlink_c::procFrontRollInit() {
}
if (checkNoResetFlg0(FLG0_WATER_IN_MOVE)) {
#if TARGET_PC
if (!(dusk::getSettings().game.enableFastIronBoots))
#endif
{
mNormalSpeed *= mpHIO->mItem.mIronBoots.m.mWaterVelocityX;
}
mNormalSpeed *= mpHIO->mItem.mIronBoots.m.mWaterVelocityX;
} else if (checkHeavyStateOn(TRUE, TRUE)) {
mNormalSpeed *= mHeavySpeedMultiplier;
}
#ifdef TARGET_PC
mNormalSpeed *= fastRollMultiplier;
#endif
current.angle.y = shape_angle.y;
voiceStart(Z2SE_AL_V_BACKTEN);
mProcVar2.field_0x300c = 0;
@@ -16307,13 +16280,8 @@ int daAlink_c::procFrontRollCrashInit() {
speed.y = mpHIO->mFrontRoll.m.mCrashSpeedV;
if (checkNoResetFlg0(FLG0_WATER_IN_MOVE)) {
#if TARGET_PC
if (!(dusk::getSettings().game.enableFastIronBoots))
#endif
{
mNormalSpeed *= mpHIO->mItem.mIronBoots.m.mWaterVelocityX;
speed.y *= mpHIO->mItem.mIronBoots.m.mWaterVelocityY;
}
mNormalSpeed *= mpHIO->mItem.mIronBoots.m.mWaterVelocityX;
speed.y *= mpHIO->mItem.mIronBoots.m.mWaterVelocityY;
}
ANGLE_ADD_2(current.angle.y, 0x8000);
@@ -16407,9 +16375,6 @@ int daAlink_c::procFrontRollSuccess() {
int daAlink_c::procSideRollInit(int param_0) {
BOOL is_prev_guardAnm = checkUpperGuardAnime();
#ifdef TARGET_PC
const f32 fastRollMultiplier = dusk::getSettings().game.fastRoll ? 2.0f : 1.0f;
#endif
if (!commonProcInitNotSameProc(PROC_SIDE_ROLL)) {
return 0;
@@ -16426,30 +16391,17 @@ int daAlink_c::procSideRollInit(int param_0) {
current.angle.y = shape_angle.y + -0x4000;
}
setSingleAnime(anmID,
#ifdef TARGET_PC
mpHIO->mGuard.mTurnMove.m.mSideRollAnmSpeed * fastRollMultiplier,
#else
mpHIO->mGuard.mTurnMove.m.mSideRollAnmSpeed,
#endif
setSingleAnime(anmID, mpHIO->mGuard.mTurnMove.m.mSideRollAnmSpeed,
mpHIO->mGuard.mTurnMove.m.mTurnAnm.mStartFrame,
mpHIO->mGuard.mTurnMove.m.mTurnAnm.mEndFrame,
mpHIO->mGuard.mTurnMove.m.mTurnAnm.mInterpolation);
mNormalSpeed = mpHIO->mGuard.mTurnMove.m.mSideRollSpeed;
if (checkNoResetFlg0(FLG0_WATER_IN_MOVE)) {
#if TARGET_PC
if (!(dusk::getSettings().game.enableFastIronBoots))
#endif
{
mNormalSpeed *= mpHIO->mItem.mIronBoots.m.mWaterVelocityX;
}
mNormalSpeed *= mpHIO->mItem.mIronBoots.m.mWaterVelocityX;
} else if (checkHeavyStateOn(TRUE, TRUE)) {
mNormalSpeed *= mHeavySpeedMultiplier;
}
#ifdef TARGET_PC
mNormalSpeed *= fastRollMultiplier;
#endif
setFootEffectProcType(0);
field_0x2f9d = 4;
@@ -17826,7 +17778,7 @@ int daAlink_c::execute() {
if (checkNoResetFlg2(FLG2_UNK_1) != FALSE &&
mEquipItem != dItemNo_KANTERA_e &&
checkItemSetButton(dItemNo_KANTERA_e) == 3) {
checkItemSetButton(dItemNo_KANTERA_e) == 2) {
offKandelaarModel();
}
@@ -18215,7 +18167,7 @@ int daAlink_c::execute() {
if (checkEquipHeavyBoots()) {
int itemButton = checkItemSetButton(dItemNo_HVY_BOOTS_e);
if (itemButton == 3 || checkNotHeavyBootsStage()) {
if (itemButton == 2 || checkNotHeavyBootsStage()) {
if (!dComIfGp_checkPlayerStatus1(0, 0x10000) || !checkHookshotRoofLv7Boss()) {
setHeavyBoots(0);
}
@@ -18737,7 +18689,7 @@ int daAlink_c::execute() {
if (!checkWolf()) {
u8 tmp;
for (u8 i = 0; i < SELECT_ITEM_NUM; i++) {
for (u8 i = 0; i < 2; i++) {
tmp = (i + 1) % 2;
if (dComIfGp_getSelectItem(i) == dItemNo_EMPTY_BOTTLE_e && (mUseButtonFlags & (1 << i)) &&
dComIfGp_getSelectItem(tmp) == dItemNo_EMPTY_BOTTLE_e)
@@ -18747,7 +18699,7 @@ int daAlink_c::execute() {
}
}
for (int i = 0; i < SELECT_ITEM_NUM; i++) {
for (int i = 0; i < 2; i++) {
if (!(mUseButtonFlags & (1 << i)) && !(field_0x2faf & (1 << i))) {
dMeter2Info_offUseButton(METER2_USEBUTTON_X << i);
}
+1 -2
View File
@@ -25,7 +25,6 @@
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/settings.h"
#include "dusk/speedrun.h"
BOOL daAlink_c::checkEventRun() const {
return dComIfGp_event_runCheck() || checkPlayerDemoMode();
@@ -4121,7 +4120,7 @@ int daAlink_c::procDungeonWarpReadyInit() {
}
fpc_ProcID id;
if (checkItemSetButton(dItemNo_DUNGEON_EXIT_e) != 3) {
if (checkItemSetButton(dItemNo_DUNGEON_EXIT_e) != 2) {
id = fopAcM_create(fpcNm_OBJ_TKS_e, 0, &current.pos, fopAcM_GetRoomNo(this), &shape_angle,
NULL, -1);
} else {
+3 -6
View File
@@ -12,7 +12,6 @@
#if TARGET_PC
#include "dusk/gyro.h"
#include "dusk/action_bindings.h"
#endif
bool daAlink_c::checkNoSubjectModeCamera() {
@@ -120,8 +119,8 @@ BOOL daAlink_c::setBodyAngleToCamera() {
var_f31 /= dComIfGp_getCameraZoomScale(field_0x317c);
}
shape_angle.y = shape_angle.y + (var_f31 * cM_ssin(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonXAxis ? -1.0f : 1.0f)));
sp8 = mBodyAngle.x + (var_f31 * cM_scos(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonYAxis ? -1.0f : 1.0f)));
shape_angle.y = shape_angle.y + (var_f31 * cM_ssin(mStickAngle));
sp8 = mBodyAngle.x + (var_f31 * cM_scos(mStickAngle));
if (checkNotItemSinkLimit() && sp8 > 0 && sp8 > mBodyAngle.x) {
sp8 = mBodyAngle.x;
@@ -193,9 +192,7 @@ BOOL daAlink_c::subjectCancelTrigger() {
BOOL daAlink_c::checkSubjectEnd(BOOL i_isPlaySe) {
setDoStatus(BUTTON_STATUS_BACK);
// Allow pressing the first person binding to also leave first person
if (IF_DUSK(dusk::getActionBindTrig(dusk::ActionBinds::FIRST_PERSON_CAMERA, 0)) ||
checkEventRun() || checkEquipAnime() || doTrigger() || checkSetItemTrigger(dItemNo_HAWK_EYE_e) || subjectCancelTrigger() || checkEndResetFlg0(ERFLG0_FORCE_SUBJECT_CANCEL) || dComIfGp_checkCameraAttentionStatus(field_0x317c, 0x2000)) {
if (checkEventRun() || checkEquipAnime() || doTrigger() || checkSetItemTrigger(dItemNo_HAWK_EYE_e) || subjectCancelTrigger() || checkEndResetFlg0(ERFLG0_FORCE_SUBJECT_CANCEL) || dComIfGp_checkCameraAttentionStatus(field_0x317c, 0x2000)) {
if (i_isPlaySe) {
seStartSystem(Z2SE_SUBJ_VIEW_OUT);
}
+1 -1
View File
@@ -211,7 +211,7 @@ int daAlink_c::procSpinnerWait() {
mProcVar3.field_0x300e = shape_angle.y;
}
} else {
if (checkSetItemTrigger(dItemNo_SPINNER_e) || swordSwingTrigger() || itemSetBtn == SELECT_ITEM_NUM) {
if (checkSetItemTrigger(dItemNo_SPINNER_e) || swordSwingTrigger() || itemSetBtn == 2) {
if (swordSwingTrigger()) {
swordEquip(0);
}
+1 -6
View File
@@ -77,12 +77,7 @@ int daAlink_c::loadModelDVD() {
mpWlMidnaHairModel = NULL;
if (!checkNoResetFlg2(FLG2_UNK_280000)) {
if (!dComIfG_resDelete(&mPhaseReq, mArcName)) {
#if TARGET_PC
// resDelete no-ops if load was in-progress; force-unregister before freeAll
dComIfG_deleteObjectResMain(mArcName);
#endif
}
dComIfG_resDelete(&mPhaseReq, mArcName);
cPhs_Reset(&mPhaseReq);
mpArcHeap->freeAll();
-6
View File
@@ -8723,12 +8723,6 @@ int daAlink_c::procWolfCargoCarry() {
return checkNextActionWolf(0);
}
#if TARGET_PC
if (field_0x280c.getActor() == NULL) {
return checkNextActionWolf(0);
}
#endif
mDoMtx_stack_c::copy(((e_yc_class*)field_0x280c.getActor())->getLegR3Mtx());
mDoMtx_stack_c::transM(-9.0f, -7.0f, -30.0f);
mDoMtx_stack_c::multVecZero(&current.pos);
-6
View File
@@ -7053,12 +7053,6 @@ static int daE_RD_IsDelete(e_rd_class*) {
}
static int daE_RD_Delete(e_rd_class* i_this) {
#if TARGET_PC
if (boss == i_this) {
boss = NULL;
}
#endif
fopEn_enemy_c* enemy = (fopEn_enemy_c*)&i_this->enemy;
fopAcM_RegisterDeleteID(i_this, "E_RD");
+1 -5
View File
@@ -11,9 +11,7 @@
#include "d/d_msg_string.h"
#include "dusk/livesplit.h"
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/speedrun.h"
#include "m_Do/m_Do_controller_pad.h"
#include <dusk/autosave.h>
dBrightCheck_c::dBrightCheck_c(JKRArchive* i_archive) {
mArchive = i_archive;
@@ -148,12 +146,10 @@ void dBrightCheck_c::modeMove() {
if (dusk::getSettings().game.speedrunMode && !dusk::getSettings().game.hideTvSettingsScreen) {
// start a new run if a run isn't already in progress
if (!dusk::m_speedrunInfo.m_isRunStarted) {
dusk::resetForSpeedrunMode();
dusk::ImGuiMenuGame::resetForSpeedrunMode();
dusk::m_speedrunInfo.startRun();
}
}
toggleAutoSave(true);
#endif
mCompleteCheck = true;
mMode = MODE_WAIT_e;
+59 -96
View File
@@ -31,7 +31,6 @@
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#include "dusk/logging.h"
#include "dusk/action_bindings.h"
#include "imgui.h"
#endif
@@ -839,12 +838,6 @@ void dCamera_c::updatePad() {
mTrigB = mDoCPd_c::getTrigB(mPadID) ? true : false;
#if TARGET_PC
// If our custom action binding is triggered, and we're not already in first person, go into first person
if (dusk::getActionBindTrig(dusk::ActionBinds::FIRST_PERSON_CAMERA, mPadID) && mGear != -1) {
setComStat(0x1000);
mGear = 0;
}
if (mCamParam.mManualMode) {
return;
}
@@ -884,8 +877,7 @@ void dCamera_c::updatePad() {
if (mPadInfo.mCStick.mLastPosY < -mCamSetup.mCStick.SwTHH()) {
if (mCStickYState != -1) {
// Don't use regular first person trigger if custom mapping is set
if (mGear == -1 && mCurMode == 4 IF_DUSK(&& !dusk::isActionBound(dusk::ActionBinds::FIRST_PERSON_CAMERA, mPadID))) {
if (mGear == -1 && mCurMode == 4) {
mGear = 0;
setComStat(0x2000);
} else if (mGear == 0 && sp6C) {
@@ -896,8 +888,7 @@ void dCamera_c::updatePad() {
mCStickYState = -1;
} else if (mPadInfo.mCStick.mLastPosY > mCamSetup.mCStick.SwTHH()) {
if (mCStickYState != 1) {
// Don't use regular first person trigger if custom mapping is set
if (mGear == 0 && sp6B IF_DUSK(&& !dusk::isActionBound(dusk::ActionBinds::FIRST_PERSON_CAMERA, mPadID))) {
if (mGear == 0 && sp6B) {
setComStat(0x1000);
} else if (mGear == 1) {
mGear = 0;
@@ -7657,11 +7648,7 @@ bool dCamera_c::freeCamera() {
cXyz camMovement = {mPadInfo.mCStick.mLastPosX, mPadInfo.mCStick.mLastPosY, 0.0f};
f32 magnitude = sqrt(mPadInfo.mCStick.mLastPosX * mPadInfo.mCStick.mLastPosX + mPadInfo.mCStick.mLastPosY * mPadInfo.mCStick.mLastPosY);
// If we aren't in manual cam mode, don't trigger it if the player tries to hit C-up
// for first person unless they have first person bound to a custom binding
if ((dusk::isActionBound(dusk::ActionBinds::FIRST_PERSON_CAMERA, mPadID) && mPadInfo.mCStick.mLastPosY != 0) ||
mPadInfo.mCStick.mLastPosX != 0 || mPadInfo.mCStick.mLastPosY < 0 || (mCamParam.mManualMode == 1 && mPadInfo.mCStick.mLastPosY != 0))
{
if (mPadInfo.mCStick.mLastPosX != 0 || mPadInfo.mCStick.mLastPosY != 0) {
mCamParam.mManualMode = 1;
camMovement = camMovement.normalize();
camMovement.y *= dusk::getSettings().game.invertCameraYAxis ? 1.0f : -1.0f;
@@ -11244,62 +11231,6 @@ cXyz dCamera_c::Center() {
return mCenter + mShake.field_0x24;
}
#ifdef TARGET_PC
f32 get_target_trim_height(camera_process_class* i_this) {
const auto camera = &i_this->mCamera;
if (camera->mCurState != 2) {
switch (camera->mTrimSize) {
case 0:
case 4:
return 0.0f;
case 1:
return camera->mCamSetup.VistaTrimHeight();
case 2:
case 3:
return camera->mCamSetup.CinemaScopeTrimHeight();
default:
return camera->mTrimHeight;
}
}
return camera->mTrimHeight;
}
void widezoom_correction(camera_process_class* i_this, float trim_height) {
camera_class* camera = (camera_class*)i_this;
dDlst_window_c* window = get_window(camera);
view_port_class* viewport = window->getViewPort();
auto trim_width = 0.0f;
if (mDoGph_gInf_c::isWideZoom()) {
const auto target_ar = FB_WIDTH_BASE / (FB_HEIGHT_BASE - trim_height * 2.0f);
const auto target_ar_real =
FB_WIDTH_BASE / (FB_HEIGHT_BASE - get_target_trim_height(i_this) * 2.0f);
const auto current_ar = camera->view.aspect;
if (current_ar < target_ar) {
trim_height = FB_HEIGHT_BASE / 2.0f * (1.0f - current_ar / target_ar);
} else {
trim_height = 0.0f;
trim_width = FB_WIDTH_BASE / 2.0f * (1.0f - target_ar_real / current_ar);
}
if (dusk::frame_interp::is_sim_frame()) {
constexpr auto base_ar =
static_cast<f32>(FB_WIDTH_BASE) / static_cast<f32>(FB_HEIGHT_BASE);
const auto ar_corr = base_ar / std::min(current_ar, target_ar_real);
camera->view.fovy =
MTXRadToDeg(2.0f * atanf(tanf(MTXDegToRad(camera->view.fovy) * 0.5f) * ar_corr));
}
}
trim_width *= viewport->width / FB_WIDTH_BASE;
trim_height *= viewport->height / FB_HEIGHT_BASE;
window->setScissor(trim_width, trim_height, viewport->width - trim_width * 2.0f,
viewport->height - trim_height * 2.0f);
}
#endif
static int camera_execute(camera_process_class* i_this) {
preparation(i_this);
@@ -11320,28 +11251,6 @@ static int camera_execute(camera_process_class* i_this) {
store(i_this);
#ifdef TARGET_PC
widezoom_correction(i_this, i_this->mCamera.TrimHeight());
if (dusk::getSettings().game.enableFrameInterpolation) {
dusk::frame_interp::add_interpolation_callback([](bool _, void* pUserWork) {
const auto i_this = static_cast<camera_process_class*>(pUserWork);
const auto camera = &i_this->mCamera;
const auto trim_size = camera->mTrimSize;
if (camera->mCurState != 2 && trim_size >= 0 && trim_size <= 3) {
// derive trim height at previous tick using current camera state
const auto target = get_target_trim_height(i_this);
const auto step = dusk::frame_interp::get_interpolation_step();
const auto cur = camera->TrimHeight();
const auto prev = (4.0f * cur - target) / 3.0f;
const auto trim_height = prev + (cur - prev) * step;
widezoom_correction(i_this, trim_height);
}
}, i_this);
}
// record new camera for our sim frame
dusk::frame_interp::record_camera(i_this, get_camera_id(i_this));
// interpolate the view now so that this sim frame's view matrix matches what
@@ -11353,6 +11262,26 @@ static int camera_execute(camera_process_class* i_this) {
return 1;
}
#ifdef TARGET_PC
void set_ar_corrected_trim(dDlst_window_c* window, float trim_height) {
const auto viewport = window->getViewPort();
if (mDoGph_gInf_c::isWideZoom()) {
const auto target_ar = FB_WIDTH / (FB_HEIGHT - trim_height * 2.0f);
const auto current_ar = mDoGph_gInf_c::m_safeWidthF / mDoGph_gInf_c::m_safeHeightF;
if (current_ar < target_ar) {
trim_height = FB_HEIGHT / 2.0f * (1.0f - current_ar / target_ar);
} else {
trim_height = 0.0f;
}
}
trim_height *= viewport->height / FB_HEIGHT;
window->setScissor(0.0f, trim_height, viewport->width, viewport->height - trim_height * 2.0f);
}
#endif
static int camera_draw(camera_process_class* i_this) {
camera_class* a_this = (camera_class*)i_this;
dCamera_c* body = &i_this->mCamera;
@@ -11405,8 +11334,42 @@ static int camera_draw(camera_process_class* i_this) {
}
#endif
#if !TARGET_PC
// trim handling moved to camera_execute for PC
#if TARGET_PC
set_ar_corrected_trim(window, body->TrimHeight());
if (dusk::getSettings().game.enableFrameInterpolation) {
dusk::frame_interp::add_interpolation_callback([](bool _, void* pUserWork) {
const auto i_this = static_cast<camera_process_class*>(pUserWork);
const auto camera = &i_this->mCamera;
const auto trim_size = camera->mTrimSize;
if (camera->mCurState != 2 && trim_size >= 0 && trim_size <= 3) {
// derive trim height at previous tick using current camera state
f32 target;
switch (trim_size) {
case 0:
target = 0.0f;
break;
case 1:
target = camera->mCamSetup.VistaTrimHeight();
break;
case 2:
case 3:
target = camera->mCamSetup.CinemaScopeTrimHeight();
break;
}
const auto step = dusk::frame_interp::get_interpolation_step();
const auto cur = camera->TrimHeight();
const auto prev = (4.0f * cur - target) / 3.0f;
const auto trim_height = prev + (cur - prev) * step;
set_ar_corrected_trim(get_window((camera_class*)i_this), trim_height);
}
}, i_this);
}
#else
int trim_height = body->TrimHeight();
window->setScissor(0.0f, trim_height, FB_WIDTH, FB_HEIGHT - trim_height * 2.0f);
-8
View File
@@ -15,7 +15,6 @@
#include "f_op/f_op_actor_mng.h"
#if TARGET_PC
#include "dusk/achievements.h"
#include "dusk/settings.h"
#endif
static int plCutLRC[58] = {
@@ -430,13 +429,6 @@ fopAc_ac_c* cc_at_check(fopAc_ac_c* i_enemy, dCcU_AtInfo* i_AtInfo) {
}
}
#if TARGET_PC
if (dusk::getSettings().game.invincibleEnemies &&
fopAcM_GetGroup(i_enemy) == fopAc_ENEMY_e) {
i_AtInfo->mAttackPower = 0;
}
#endif
if (i_AtInfo->mAttackPower != 0) {
i_enemy->health -= i_AtInfo->mAttackPower;
}
+13 -3
View File
@@ -1952,7 +1952,18 @@ u8 dComIfGs_getMixItemIndex(int i_no) {
}
void dComIfGp_setSelectItem(int i_selItemIdx) {
if (dComIfGs_getSelectItemIndex(i_selItemIdx) != 0xFF) {
if (i_selItemIdx == SELECT_ITEM_DOWN) {
if (dComIfGs_getSelectItemIndex(i_selItemIdx) != 0xFF) {
u8 selItem_slotNo = dComIfGs_getSelectItemIndex(i_selItemIdx);
g_dComIfG_gameInfo.play.setSelectItem(i_selItemIdx, selItem_slotNo);
if (selItem_slotNo == 0xFF) {
dComIfGs_setSelectItemIndex(i_selItemIdx, 0xFF);
}
} else {
g_dComIfG_gameInfo.play.setSelectItem(i_selItemIdx, dItemNo_NONE_e);
}
} else if (dComIfGs_getSelectItemIndex(i_selItemIdx) != 0xFF) {
u8 item = dComIfGs_getItem(dComIfGs_getSelectItemIndex(i_selItemIdx), false);
g_dComIfG_gameInfo.play.setSelectItem(i_selItemIdx, item);
@@ -1967,8 +1978,7 @@ void dComIfGp_setSelectItem(int i_selItemIdx) {
u8 dComIfGp_getSelectItem(int i_selItemIdx) {
u8 playItem = g_dComIfG_gameInfo.play.getSelectItem(i_selItemIdx);
if ((i_selItemIdx == SELECT_ITEM_X || i_selItemIdx == SELECT_ITEM_Y ||
i_selItemIdx == SELECT_ITEM_Z) &&
if ((i_selItemIdx == SELECT_ITEM_X || i_selItemIdx == SELECT_ITEM_Y) &&
dComIfGs_getMixItemIndex(i_selItemIdx) != 0xFF)
{
u8 saveItem = dComIfGs_getItem(dComIfGs_getMixItemIndex(i_selItemIdx), false);
-4
View File
@@ -3882,11 +3882,7 @@ bool dCamera_c::hintTalkEvCamera() {
cSAngle acStack_1fc(20.0f);
for (i = 0; i < 2; i++) {
#if AVOID_UB
for (j = 0; j < 10; j++) {
#else
for (j = 0; j < 12; j++) {
#endif
cSAngle acStack_200(local_b0[j] * fVar22);
hintTalk->mDirection.U(acStack_1f8 + acStack_200);
hintTalk->mDirection.V(((hintTalk->field_0x28.V() * acStack_200.Cos()) * 0.2f) + acStack_1fc);
-4
View File
@@ -287,10 +287,6 @@ int dEvt_control_c::talkXyCheck(dEvt_order_c* order) {
mTalkXyType = 2;
itemIndex = SELECT_ITEM_Y;
break;
case dEvt_type_SHOWITEM_Z_e:
mTalkXyType = 3;
itemIndex = SELECT_ITEM_Z;
break;
#if PLATFORM_WII || PLATFORM_SHIELD
case 8:
mTalkXyType = 3;
+1 -10
View File
@@ -36,7 +36,6 @@
#include "dusk/imgui/ImGuiBloomWindow.hpp"
#include "dusk/settings.h"
#include "dusk/frame_interpolation.h"
#include "dusk/game_clock.h"
#endif
static void GxXFog_set();
@@ -2269,7 +2268,6 @@ void dKy_calc_color_set(GXColorS10* out_color_p, color_RGB_class* color_a_start_
color_b_start_p->b, color_b_end_p->b, blend_ratio, add_col.b, scale);
}
void dScnKy_env_light_c::setLight() {
f32 color_ratio;
@@ -2515,14 +2513,7 @@ void dScnKy_env_light_c::setLight() {
static s16 S_fuwan_sin;
f32 sin = cM_ssin(S_fuwan_sin);
#if TARGET_PC
const f32 deltaTime = dusk::game_clock::consume_interval(this);
const f32 timeScale = deltaTime / dusk::game_clock::period_for_original_frames(1.0f);
S_fuwan_sin += (s16)((cM_rndF(2000.0f) + 500) * timeScale);
#else
S_fuwan_sin += (s16)cM_rndF(2000.0f) + 500;
#endif
S_fuwan_sin += (s16)cM_rndF(2000.0f) + 500;
blure_size += (u8)(sin * (0.2f * blure_size));
}
+1 -26
View File
@@ -152,7 +152,7 @@ u8 STControl::checkTrigger() {
field_0x22 = -field_0x24;
}
}
#if !TARGET_PC
if (!(mDirectionTrig & 3)) {
Xinit();
}
@@ -160,35 +160,10 @@ u8 STControl::checkTrigger() {
if (!(mDirectionTrig & 0xC)) {
Yinit();
}
#endif
} else {
mDirectionTrig = 0;
#if !TARGET_PC
Xinit();
Yinit();
#endif
#if TARGET_PC
if (mDoCPd_c::getHoldLeft(PAD_1)) {
mDirectionTrig |= TRIG_LEFT;
}
if (mDoCPd_c::getHoldRight(PAD_1)) {
mDirectionTrig |= TRIG_RIGHT;
}
if (mDoCPd_c::getHoldUp(PAD_1)) {
mDirectionTrig |= TRIG_UP;
}
if (mDoCPd_c::getHoldDown(PAD_1)) {
mDirectionTrig |= TRIG_DOWN;
}
}
if (!(mDirectionTrig & 3)) {
Xinit();
}
if (!(mDirectionTrig & 0xC)) {
Yinit();
#endif
}
if ((field_0x0d & mDirectionTrig & 3) && field_0x0e > 0) {
-14
View File
@@ -1141,9 +1141,6 @@ dMap_c::dMap_c(int width, int height, int param_2, int param_3) {
field_0x91 = 0;
m_mySelfPointer = this;
#endif
#if TARGET_PC
previousMirror = dusk::getSettings().game.enableMirrorMode;
#endif
m_res = JKR_NEW_ARGS (0x20) dMap_prm_res_s;
JUT_ASSERT(2559, m_res != NULL);
@@ -1582,17 +1579,6 @@ bool dMap_c::isDrawRoomIcon(int param_0, int param_1) const {
}
void dMap_c::_move(f32 i_centerX, f32 i_centerZ, int i_roomNo, f32 param_3) {
#if TARGET_PC
bool currentMirror = dusk::getSettings().game.enableMirrorMode;
if (currentMirror != previousMirror) {
previousMirror = currentMirror;
if (currentMirror) {
mCenterX -= 2.0f * mPackX;
} else {
mCenterX += 2.0f * mPackX;
}
}
#endif
if (mStayRoomNo == -1) {
mStayRoomNo = i_roomNo;
field_0x80 = mStayRoomNo;
+1 -1
View File
@@ -139,7 +139,7 @@ bool dMenu_Fishing_c::isSync() {
void dMenu_Fishing_c::init() {
#if TARGET_PC || VERSION == VERSION_GCN_PAL
BOOL isEnglish = FALSE;
if (dusk::version::isRegionPal() && dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) {
if (dusk::version::isRegionUsa() || (dusk::version::isRegionPal() && dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH)) {
isEnglish = TRUE;
}
#endif
+1 -3
View File
@@ -446,7 +446,7 @@ void dMenu_ItemExplain_c::move_proc() {
if (field_0xe7 == 0) {
return;
}
if (!mDoCPd_c::getTrigX(PAD_1) && !mDoCPd_c::getTrigY(PAD_1) && !mDoCPd_c::getTrigZ(PAD_1)) {
if (!mDoCPd_c::getTrigX(PAD_1) && !mDoCPd_c::getTrigY(PAD_1)) {
return;
}
}
@@ -460,8 +460,6 @@ void dMenu_ItemExplain_c::move_proc() {
mEndButton = 3;
} else if (mDoCPd_c::getTrigY(PAD_1)) {
mEndButton = 4;
} else if (mDoCPd_c::getTrigZ(PAD_1)) {
mEndButton = 5;
}
mStatus = 5;
Z2GetAudioMgr()->seStart(Z2SE_SY_EXP_WIN_CLOSE, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0);
+15 -45
View File
@@ -134,7 +134,7 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i
field_0x6a9 = 0;
mXButtonSlot = 0xff;
mYButtonSlot = 0xff;
mZButtonSlot = 0xff;
field_0x6ac = 0xff;
field_0x6ad = 0xff;
field_0x670 = 0;
field_0x67e = 0;
@@ -244,8 +244,8 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i
if (dComIfGs_getSelectItemIndex(1) == dComIfGs_getLineUpItem(i)) {
mYButtonSlot = i;
}
if (dComIfGs_getSelectItemIndex(2) == dComIfGs_getLineUpItem(i)) {
mZButtonSlot = i;
if (dComIfGs_getSelectItemIndex(2) == dComIfGs_getWolfAbility(i)) {
field_0x6ac = i;
}
}
mRingRadiusH = g_ringHIO.mRingRadiusH;
@@ -259,7 +259,7 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i
}
}
field_0x6be[i] = 0;
if (i == MAX_SELECT_ITEM) {
if (i == 2) {
setSelectItem(i, 0);
} else {
setSelectItem(i, 0x43);
@@ -977,8 +977,8 @@ void dMenu_Ring_c::setItem() {
} else {
uVar2 = dItemNo_NONE_e;
}
if (mZButtonSlot != dItemNo_NONE_e) {
uVar3 = mItemSlots[mZButtonSlot];
if (field_0x6ac != dItemNo_NONE_e) {
uVar3 = mItemSlots[field_0x6ac];
} else {
uVar3 = dItemNo_NONE_e;
}
@@ -1058,9 +1058,6 @@ void dMenu_Ring_c::setItem() {
mixItemIndex1 = dItemNo_NONE_e;
}
}
} else if (field_0x6b3 == 2) {
mZButtonSlot = mCurrentSlot;
uVar3 = mItemSlots[mZButtonSlot];
}
field_0x6b4[0] = uVar1;
field_0x6b4[1] = uVar2;
@@ -1076,7 +1073,7 @@ void dMenu_Ring_c::setItem() {
void dMenu_Ring_c::setJumpItem(bool i_useVibrationM) {
for (int i = 0; i < 4; i++) {
if (i == 4) {
if (i == 2) {
setSelectItem(i, field_0x6b4[i]);
} else if (i == field_0x6cd) {
setSelectItem(i, getItem(field_0x6cb, 0));
@@ -1092,9 +1089,9 @@ void dMenu_Ring_c::setJumpItem(bool i_useVibrationM) {
field_0x518[1] = mItemSlotPosX[mYButtonSlot];
field_0x528[1] = mItemSlotPosY[mYButtonSlot];
}
if (mZButtonSlot != dItemNo_NONE_e) {
field_0x518[2] = mItemSlotPosX[mZButtonSlot];
field_0x528[2] = mItemSlotPosY[mZButtonSlot];
if (field_0x6ac != dItemNo_NONE_e) {
field_0x518[2] = mItemSlotPosX[field_0x6ac];
field_0x528[2] = mItemSlotPosY[field_0x6ac];
}
if (field_0x6ad != dItemNo_NONE_e) {
field_0x518[3] = mItemSlotPosX[field_0x6ad];
@@ -1120,21 +1117,9 @@ void dMenu_Ring_c::setJumpItem(bool i_useVibrationM) {
field_0x674[1] = 1;
#if TARGET_PC
mSelectItemSlideElapsed[1] = 0.0f;
#endif
}
} else if (field_0x6b3 == 2) {
field_0x538[0] = g_ringHIO.mUnselectItemScale;
field_0x538[1] = g_ringHIO.mSelectItemScale;
if (field_0x6b4[2] != dComIfGs_getSelectItemIndex(2) ||
field_0x6b8[2] != dComIfGs_getMixItemIndex(2))
{
field_0x674[2] = 1;
#if TARGET_PC
mSelectItemSlideElapsed[2] = 0.0f;
#endif
}
}
if (field_0x674[0] == 1) {
if (i_useVibrationM) {
dMeter2Info_set2DVibrationM();
@@ -1175,7 +1160,7 @@ void dMenu_Ring_c::setScale() {
}
setNameString(itemId);
setItemScale(i, g_ringHIO.mUnselectItemScale);
for (int j = 0; j < SELECT_ITEM_NUM; j++) {
for (int j = 0; j < 2; j++) {
if (j == field_0x6cf) {
setButtonScale(j, g_ringHIO.mSelectButtonScale);
} else {
@@ -1195,7 +1180,7 @@ void dMenu_Ring_c::setScale() {
} else {
setItemScale(i, g_ringHIO.mUnselectItemScale);
}
for (int j = 0; j < SELECT_ITEM_NUM; j++) {
for (int j = 0; j < 2; j++) {
setButtonScale(j, g_ringHIO.mUnselectButtonScale);
}
}
@@ -1229,7 +1214,6 @@ void dMenu_Ring_c::setNameString(u32 i_stringID) {
void dMenu_Ring_c::setActiveCursor() {
u8 item = dComIfGs_getItem(mItemSlots[mCurrentSlot], false);
if (mStatus == STATUS_WAIT && mOldStatus != STATUS_EXPLAIN_FORCE && mOldStatus != STATUS_EXPLAIN && mpItemExplain->getStatus() == 0) {
if (mDoCPd_c::getTrigR(PAD_1) && !mPlayerIsWolf && item != dItemNo_NONE_e) {
for (int i = 0; i < MAX_SELECT_ITEM; i++) {
@@ -1260,21 +1244,7 @@ void dMenu_Ring_c::setActiveCursor() {
(this->*stick_init[mStatus])();
}
}
} else if (mDoCPd_c::getTrigZ(PAD_1) && !mPlayerIsWolf && item != dItemNo_NONE_e) {
for (int i = 0; i < MAX_SELECT_ITEM; i++) {
setSelectItemForce(i);
}
field_0x6b3 = 2;
if (!checkCombineBomb(field_0x6b3)) {
setItem();
if (mpItemExplain->getStatus() == 0) {
setStatus(STATUS_WAIT);
(this->*stick_init[mStatus])();
}
}
} else if (mDoCPd_c::getTrigX(PAD_1) || mDoCPd_c::getTrigY(PAD_1) ||
mDoCPd_c::getTrigZ(PAD_1))
{
} else if (mDoCPd_c::getTrigX(PAD_1) || mDoCPd_c::getTrigY(PAD_1)) {
// If the player is a wolf or somehow manages to access an item slot with no item, error
Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0);
}
@@ -1690,7 +1660,7 @@ void dMenu_Ring_c::drawSelectItem() {
}
void dMenu_Ring_c::setSelectItemForce(int i_idx) {
if (i_idx == SELECT_ITEM_NUM) {
if (i_idx == 2) {
if (field_0x674[i_idx] != 0) {
dComIfGs_setSelectItemIndex(i_idx, field_0x6b4[i_idx]);
field_0x674[i_idx] = 0;
@@ -1699,7 +1669,7 @@ void dMenu_Ring_c::setSelectItemForce(int i_idx) {
#endif
}
} else if (field_0x674[i_idx] != 0) {
for (int i = 0; i < SELECT_ITEM_NUM; i++) {
for (int i = 0; i < 2; i++) {
dComIfGs_setMixItemIndex(i, field_0x6b8[i]);
dComIfGs_setSelectItemIndex(i, field_0x6b4[i]);
}
-2
View File
@@ -1533,8 +1533,6 @@ void dMeter2Info_c::setMiniGameItem(u8 i_minigameFlag) {
if (mMiniGameItemSetFlag != 3) {
dComIfGs_setItem(SLOT_4, dItemNo_BOW_e);
dComIfGp_setItem(SLOT_4, dItemNo_BOW_e);
dComIfGs_setMixItemIndex(SELECT_ITEM_Z, 0xFF);
dComIfGs_setSelectItemIndex(SELECT_ITEM_Z, 0xFF);
dComIfGs_setMixItemIndex(SELECT_ITEM_Y, 0xFF);
dComIfGs_setSelectItemIndex(SELECT_ITEM_Y, 0xFF);
dComIfGs_setMixItemIndex(SELECT_ITEM_X, SLOT_4);
+1 -5
View File
@@ -11,7 +11,6 @@
#include "d/d_s_name.h"
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/memory.h"
#include "dusk/speedrun.h"
#include "dusk/settings.h"
#include "f_op/f_op_overlap_mng.h"
#include "f_op/f_op_scene_mng.h"
@@ -20,7 +19,6 @@
#include "m_Do/m_Do_machine.h"
#include "m_Do/m_Do_main.h"
#include "m_Do/m_Do_mtx.h"
#include <dusk/autosave.h>
#if TARGET_PC
#define SHOW_TV_SETTINGS_SCREEN (this->mShowTvSettingsScreen)
@@ -420,12 +418,10 @@ void dScnName_c::changeGameScene() {
if (dusk::getSettings().game.speedrunMode && dusk::getSettings().game.hideTvSettingsScreen) {
// start a new run on file load if a run isn't already in progress
if (!dusk::m_speedrunInfo.m_isRunStarted) {
dusk::resetForSpeedrunMode();
dusk::ImGuiMenuGame::resetForSpeedrunMode();
dusk::m_speedrunInfo.startRun();
}
}
toggleAutoSave(true);
#endif
}
}
-4
View File
@@ -1042,10 +1042,6 @@ static BOOL heapSizeCheck() {
bool dScnPly_c::resetGame() {
if (fpcM_GetName(this) == fpcNm_OPENING_SCENE_e) {
#if TARGET_PC
toggleAutoSave(false);
#endif
if (!dStage_roomControl_c::resetArchiveBank(0)) {
return false;
}
-5
View File
@@ -53,11 +53,6 @@ static std::string FormatToString(const char* msg, va_list list) {
size *= 2;
}
}
while (!str.empty() && str[str.size()-1] == '\n') {
str.pop_back();
}
return str;
}
-6
View File
@@ -692,12 +692,6 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
return;
}
// prevent stuff like https://github.com/TwilitRealm/dusklight/issues/949
if (link->getDemoMode() != 0) {
inJump = false;
return;
}
if (!inJump) {
if (link->mProcID == daAlink_c::PROC_CUT_JUMP) {
inJump = true;
-96
View File
@@ -1,96 +0,0 @@
#include "dusk/action_bindings.h"
#include "aurora/lib/input.hpp"
#include "dusk/settings.h"
#include "dusk/ui/ui.hpp"
namespace dusk {
static std::array<std::array<ActionBindPressData, static_cast<int>(ActionBinds::COUNT)>, PAD_CHANMAX> actionPressData{};
ActionBindsMap& getActionBinds() {
static ActionBindsMap actionBinds = {
{ActionBinds::FIRST_PERSON_CAMERA, {&getSettings().actionBindings.firstPersonCamera, "First Person Camera"}},
{ActionBinds::CALL_MIDNA, {&getSettings().actionBindings.callMidna, "Call Midna"}},
{ActionBinds::OPEN_DUSKLIGHT_MENU, {&getSettings().actionBindings.openDusklightMenu, "Open Dusklight Menu"}},
{ActionBinds::TURBO_SPEED_BUTTON, {&getSettings().actionBindings.turboSpeedButton, "Turbo Speed Button"}},
};
return actionBinds;
}
bool isActionBound(ActionBinds action, u32 port) {
auto& actionBinds = getActionBinds();
// Check to make sure action is properly bound
if (!actionBinds.contains(action)) {
return false;
}
return getActionBindButton(action, port) != PAD_NATIVE_BUTTON_INVALID;
}
void updateActionBindings() {
for (u32 port = 0; port < PAD_CHANMAX; ++port) {
// Move the current press to the previous frame
for (auto& pressData : actionPressData[port]) {
pressData.pressedPrevFrame = pressData.pressedCurFrame;
pressData.pressedCurFrame = false;
}
// Update current frame with whether action button is pressed
for (auto& [action, boundAction] : getActionBinds()) {
// If the action isn't bound, or if documents are visible and the action isn't
// opening the dusklight menu, don't update. Otherwise, we may accidentally
// perform actions while the dusklight menu is open.
if (!isActionBound(action, port) ||
(ui::any_document_visible() && action != ActionBinds::OPEN_DUSKLIGHT_MENU)) {
continue;
}
int button = boundAction.configVars->at(port);
// If keyboard is active for this port
u32 count = 0;
if (PADGetKeyButtonBindings(port, &count) != nullptr) {
int numKeys = 0;
const bool* kbState = SDL_GetKeyboardState(&numKeys);
if (kbState[button]) {
actionPressData[port][static_cast<int>(action)].pressedCurFrame = true;
}
} else {
// If controller is active
auto controller = aurora::input::get_controller_for_player(port);
if (controller) {
if (SDL_GetGamepadButton(controller->m_controller, static_cast<SDL_GamepadButton>(button))) {
actionPressData[port][static_cast<int>(action)].pressedCurFrame = true;
}
}
}
}
}
}
bool getActionBindTrig(ActionBinds action, u32 port) {
return isActionBound(action, port) &&
actionPressData[port][static_cast<int>(action)].pressedCurFrame &&
!actionPressData[port][static_cast<int>(action)].pressedPrevFrame;
}
bool getActionBindHold(ActionBinds action, u32 port) {
return isActionBound(action, port) &&
actionPressData[port][static_cast<int>(action)].pressedCurFrame &&
actionPressData[port][static_cast<int>(action)].pressedPrevFrame;
}
bool getActionBindHoldAnyPort(ActionBinds action) {
for (u32 port = 0; port < PAD_CHANMAX; ++port) {
if (getActionBindHold(action, port)) {
return true;
}
}
return false;
}
int getActionBindButton(ActionBinds action, u32 port) {
return (*getActionBinds()[action].configVars)[port];
}
}
+5 -16
View File
@@ -2,7 +2,6 @@
#include "dusk/ui/ui.hpp"
#include "imgui/ImGuiConsole.hpp"
bool shouldAutoSave = false;
u8 mSaveBuffer[QUEST_LOG_SIZE * 3];
u8 mAutoSaveProc = 0;
int autoSaveWriteState = 0;
@@ -15,7 +14,7 @@ static AutoSaveFuncs AutoSaveFuncsProc[] = {
void noAutoSave() {}
void triggerAutoSave() {
if (dusk::getSettings().game.autoSave && shouldAutoSave && mAutoSaveProc == 0 &&
if (dusk::getSettings().game.autoSave && mAutoSaveProc == 0 &&
strcmp(dComIfGp_getStartStageName(), "F_SP102") != 0)
{
mAutoSaveProc = 1;
@@ -26,12 +25,8 @@ void updateAutoSave() {
(AutoSaveFuncsProc[mAutoSaveProc])();
}
bool writeAutoSave() {
stage_stag_info_class* stagInfo = dComIfGp_getStageStagInfo();
if (stagInfo == nullptr) {
return false;
}
int stageNo = dStage_stagInfo_GetSaveTbl(stagInfo);
void writeAutoSave() {
int stageNo = dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo());
dComIfGs_putSave(stageNo);
dComIfGs_setMemoryToCard(mSaveBuffer, dComIfGs_getDataNum());
@@ -44,7 +39,6 @@ bool writeAutoSave() {
}
g_mDoMemCd_control.save(mSaveBuffer, sizeof(mSaveBuffer), 0);
return true;
}
void autoSaving() {
@@ -53,9 +47,8 @@ void autoSaving() {
if (cardState == 2) {
mAutoSaveProc = 1;
} else if (cardState == 1) {
if (writeAutoSave()) {
mAutoSaveProc = 3;
}
writeAutoSave();
mAutoSaveProc = 3;
}
}
}
@@ -96,8 +89,4 @@ void endAutoSave() {
.duration = std::chrono::milliseconds(1500),
});
mAutoSaveProc = 0;
}
void toggleAutoSave(bool enabled) {
shouldAutoSave = enabled;
}
+2 -17
View File
@@ -11,7 +11,6 @@
#include <string>
#include "dusk/main.h"
#include "dusk/action_bindings.h"
using namespace dusk::config;
@@ -61,7 +60,7 @@ void ConfigImpl<T>::loadFromJson(ConfigVar<T>& cVar, const json& jsonValue) {
template<ConfigValue T>
nlohmann::json ConfigImpl<T>::dumpToJson(const ConfigVar<T>& cVar) {
return cVar.getValueForSave();
return cVar.getValue();
}
template<ConfigValue T> requires std::is_integral_v<T> && std::is_signed_v<T>
@@ -249,8 +248,7 @@ void dusk::config::Save() {
json j;
for (const auto& pair : RegisteredConfigVars) {
const auto layer = pair.second->getLayer();
if (layer == ConfigVarLayer::Value || layer == ConfigVarLayer::Speedrun) {
if (pair.second->getLayer() == ConfigVarLayer::Value) {
j[pair.first] = pair.second->getImpl()->dumpToJson(*pair.second);
}
}
@@ -258,13 +256,6 @@ void dusk::config::Save() {
io::FileStream::WriteAllText(reinterpret_cast<const char*>(configJsonPath.c_str()), j.dump(4));
}
void dusk::config::ClearAllActionBindings(int port) {
for (auto& actionBinding : getActionBinds() | std::views::values) {
actionBinding.configVars->at(port).setValue(PAD_NATIVE_BUTTON_INVALID);
}
Save();
}
ConfigVarBase* dusk::config::GetConfigVar(std::string_view name) {
const auto configVar = RegisteredConfigVars.find(name);
if (configVar != RegisteredConfigVars.end()) {
@@ -273,9 +264,3 @@ ConfigVarBase* dusk::config::GetConfigVar(std::string_view name) {
return nullptr;
}
void dusk::config::EnumerateRegistered(std::function<void(ConfigVarBase&)> callback) {
for (auto& pair : RegisteredConfigVars) {
callback(*pair.second);
}
}
+66 -67
View File
@@ -4,6 +4,7 @@
#include "dusk/dusk.h"
#include "dusk/logging.h"
#include "dusk/main.h"
#include "dusk/settings.h"
#include "version.h"
#include <cstdlib>
@@ -12,83 +13,114 @@
#include <string_view>
#include <system_error>
#include "SDL3/SDL_filesystem.h"
#if DUSK_ENABLE_SENTRY_NATIVE
#include <sentry.h>
#endif
namespace dusk::crash_reporting {
namespace dusk {
namespace {
#if DUSK_ENABLE_SENTRY_NATIVE
bool g_sentryInitialized = false;
bool truthy(std::string_view value) {
return value == "1" || value == "true" || value == "TRUE" || value == "yes" || value == "YES" ||
value == "on" || value == "ON";
bool IsTruthy(std::string_view value) {
return value == "1" || value == "true" || value == "TRUE" || value == "yes"
|| value == "YES" || value == "on" || value == "ON";
}
std::string env_or_empty(const char* name) {
std::string GetEnvOrEmpty(const char* name) {
if (const char* value = std::getenv(name)) {
return value;
}
return {};
}
bool disabled_by_env() {
const std::string env = env_or_empty("DUSK_SENTRY_ENABLED");
return !env.empty() && !truthy(env);
bool GetEffectiveEnabled() {
const std::string env = GetEnvOrEmpty("DUSK_SENTRY_ENABLED");
if (!env.empty()) {
return IsTruthy(env);
}
return getSettings().backend.enableCrashReporting;
}
std::string effective_dsn() {
const std::string env = env_or_empty("DUSK_SENTRY_DSN");
std::string GetEffectiveDsn() {
const std::string env = GetEnvOrEmpty("DUSK_SENTRY_DSN");
if (!env.empty()) {
return env;
}
return DUSK_SENTRY_DSN;
}
bool effective_debug() {
const std::string env = env_or_empty("DUSK_SENTRY_DEBUG");
bool GetEffectiveDebug() {
const std::string env = GetEnvOrEmpty("DUSK_SENTRY_DEBUG");
if (!env.empty()) {
return truthy(env);
return IsTruthy(env);
}
return false;
}
std::string release_name() {
std::string GetReleaseName() {
return std::string(AppName) + "@" DUSK_WC_DESCRIBE;
}
std::filesystem::path sentry_database_path() {
return dusk::CachePath / "sentry";
std::filesystem::path GetSentryDatabasePath() {
return dusk::ConfigPath / "sentry";
}
std::filesystem::path log_attachment_path() {
std::filesystem::path GetLogAttachmentPath() {
if (const char* logPath = GetLogFilePath()) {
return logPath;
}
return {};
}
void configure_path_options(sentry_options_t* options) {
const auto databasePath = sentry_database_path();
std::filesystem::path GetCrashpadHandlerPath() {
const char* basePath = SDL_GetBasePath();
if (!basePath) {
return {};
}
const std::filesystem::path handlerDir(basePath);
#if _WIN32
return handlerDir / "crashpad_handler.exe";
#else
return handlerDir / "crashpad_handler";
#endif
}
void ConfigurePathOptions(sentry_options_t* options) {
const auto databasePath = GetSentryDatabasePath();
std::error_code ec;
std::filesystem::create_directories(databasePath, ec);
if (ec) {
DuskLog.warn(
"Unable to create Sentry database path '{}': {}", databasePath.string(), ec.message());
DuskLog.warn("Unable to create Sentry database path '{}': {}",
databasePath.string(), ec.message());
}
#if _WIN32
const std::wstring databasePathWide = databasePath.wstring();
sentry_options_set_database_pathw(options, databasePathWide.c_str());
const auto handlerPath = GetCrashpadHandlerPath();
if (!handlerPath.empty()) {
const std::wstring handlerPathWide = handlerPath.wstring();
sentry_options_set_handler_pathw(options, handlerPathWide.c_str());
}
#else
const std::string databasePathUtf8 = databasePath.string();
sentry_options_set_database_path(options, databasePathUtf8.c_str());
const auto handlerPath = GetCrashpadHandlerPath();
if (!handlerPath.empty()) {
const std::string handlerPathUtf8 = handlerPath.string();
sentry_options_set_handler_path(options, handlerPathUtf8.c_str());
}
#endif
const auto logPath = log_attachment_path();
const auto logPath = GetLogAttachmentPath();
if (!logPath.empty()) {
#if _WIN32
sentry_options_add_attachmentw(options, logPath.wstring().c_str());
@@ -101,29 +133,32 @@ void configure_path_options(sentry_options_t* options) {
} // namespace
void initialize() {
void InitializeCrashReporting() {
#if DUSK_ENABLE_SENTRY_NATIVE
if (g_sentryInitialized || disabled_by_env()) {
if (g_sentryInitialized) {
return;
}
const std::string dsn = effective_dsn();
if (!GetEffectiveEnabled()) {
return;
}
const std::string dsn = GetEffectiveDsn();
if (dsn.empty()) {
DuskLog.warn("Crash reporting is enabled but no Sentry DSN is configured");
return;
}
const std::string release = release_name();
const std::string release = GetReleaseName();
sentry_options_t* options = sentry_options_new();
sentry_options_set_dsn(options, dsn.c_str());
sentry_options_set_release(options, release.c_str());
sentry_options_set_environment(options, DUSK_SENTRY_ENVIRONMENT);
sentry_options_set_debug(options, effective_debug() ? 1 : 0);
sentry_options_set_require_user_consent(options, 1);
sentry_options_set_debug(options, GetEffectiveDebug() ? 1 : 0);
sentry_options_set_cache_keep(options, 1);
sentry_options_set_max_breadcrumbs(options, 100);
configure_path_options(options);
ConfigurePathOptions(options);
if (sentry_init(options) != 0) {
DuskLog.warn("Failed to initialize Sentry crash reporting");
@@ -138,7 +173,7 @@ void initialize() {
#endif
}
void shutdown() {
void ShutdownCrashReporting() {
#if DUSK_ENABLE_SENTRY_NATIVE
if (!g_sentryInitialized) {
return;
@@ -149,40 +184,4 @@ void shutdown() {
#endif
}
Consent get_consent() {
#if DUSK_ENABLE_SENTRY_NATIVE
if (!g_sentryInitialized) {
return Consent::Unavailable;
}
switch (sentry_user_consent_get()) {
case SENTRY_USER_CONSENT_GIVEN:
return Consent::Given;
case SENTRY_USER_CONSENT_REVOKED:
return Consent::Revoked;
case SENTRY_USER_CONSENT_UNKNOWN:
default:
return Consent::Unknown;
}
#else
return Consent::Unavailable;
#endif
}
void set_consent(bool enabled) {
#if DUSK_ENABLE_SENTRY_NATIVE
if (!g_sentryInitialized) {
return;
}
if (enabled) {
sentry_user_consent_give();
} else {
sentry_user_consent_revoke();
}
#else
(void)enabled;
#endif
}
} // namespace dusk::crash_reporting
} // namespace dusk
-1100
View File
File diff suppressed because it is too large Load Diff
-42
View File
@@ -1,42 +0,0 @@
#pragma once
#include <filesystem>
#include <string>
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#if defined(_WIN32) || \
(defined(__APPLE__) && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_MACCATALYST) || \
(defined(__linux__) && !defined(__ANDROID__))
#define DUSK_CAN_OPEN_DATA_FOLDER 1
#else
#define DUSK_CAN_OPEN_DATA_FOLDER 0
#endif
#if (defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST) || defined(__ANDROID__)
#define DUSK_CAN_CHANGE_DATA_FOLDER 0
#else
#define DUSK_CAN_CHANGE_DATA_FOLDER 1
#endif
namespace dusk::data {
struct Paths {
std::filesystem::path userPath;
std::filesystem::path cachePath;
};
Paths initialize_data();
std::filesystem::path configured_data_path();
std::filesystem::path cache_path();
bool open_data_path();
bool set_custom_data_path(const char* path, std::string* errorOut);
bool set_custom_data_path(const std::filesystem::path& path, std::string* errorOut);
bool set_portable_data_path();
bool reset_data_path();
bool is_default_data_path();
bool is_data_path_restart_pending();
} // namespace dusk::data
+1 -1
View File
@@ -81,7 +81,7 @@ void update_presence() {
rpc::Presence presence{};
presence.startTimestamp = g_startTime;
presence.largeImageKey = "icon";
presence.largeImageText = "Dusklight";
presence.largeImageText = "Dusk";
if (IsGameLaunched) {
const char* stageName = dComIfGp_getLastPlayStageName();
+6 -124
View File
@@ -5,7 +5,6 @@
#include <SDL3/SDL_dialog.h>
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_init.h>
#include <SDL3/SDL_stdinc.h>
#if defined(__ANDROID__) || defined(ANDROID)
@@ -17,12 +16,6 @@
#include <TargetConditionals.h>
#endif
#if defined(__APPLE__) && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_MACCATALYST
#define USE_MACOS_FOLDER_DIALOG 1
#else
#define USE_MACOS_FOLDER_DIALOG 0
#endif
#if defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST
#define USE_IOS_DIALOG 1
#include "ios/FileSelectDialog.h"
@@ -30,13 +23,6 @@
#define USE_IOS_DIALOG 0
#endif
#if USE_MACOS_FOLDER_DIALOG
namespace dusk {
bool ShowMacOSFolderSelect(
FileCallback callback, void* userdata, SDL_Window* window, const char* default_location);
} // namespace dusk
#endif
namespace dusk {
namespace {
@@ -46,10 +32,6 @@ std::string fallback_display_name(std::string_view path) {
}
std::string pathString(path);
while (pathString.size() > 1 && (pathString.back() == '/' || pathString.back() == '\\')) {
pathString.pop_back();
}
const std::size_t slash = pathString.find_last_of("/\\");
if (slash == std::string::npos || slash + 1 >= pathString.size()) {
return pathString;
@@ -116,7 +98,8 @@ std::string android_display_name(std::string_view path) {
return {};
}
auto* displayName = static_cast<jstring>(env->CallObjectMethod(activity, getDisplayName, uri));
auto* displayName =
static_cast<jstring>(env->CallObjectMethod(activity, getDisplayName, uri));
env->DeleteLocalRef(uri);
env->DeleteLocalRef(activity);
if (displayName == nullptr || clear_pending_exception(env)) {
@@ -127,76 +110,6 @@ std::string android_display_name(std::string_view path) {
env->DeleteLocalRef(displayName);
return result;
}
struct AndroidFolderDialogState {
FileCallback callback;
void* userdata;
std::string path;
std::string error;
};
void onAndroidFolderDialogFinished(void* userdata) {
std::unique_ptr<AndroidFolderDialogState> state(
static_cast<AndroidFolderDialogState*>(userdata));
const char* path = state->path.empty() ? nullptr : state->path.c_str();
const char* error = state->error.empty() ? nullptr : state->error.c_str();
state->callback(state->userdata, path, error);
}
bool show_android_folder_select(AndroidFolderDialogState* state) {
auto* env = static_cast<JNIEnv*>(SDL_GetAndroidJNIEnv());
if (env == nullptr) {
return false;
}
jobject activity = static_cast<jobject>(SDL_GetAndroidActivity());
if (activity == nullptr || clear_pending_exception(env)) {
if (activity != nullptr) {
env->DeleteLocalRef(activity);
}
return false;
}
jclass activityClass = env->GetObjectClass(activity);
if (activityClass == nullptr || clear_pending_exception(env)) {
env->DeleteLocalRef(activity);
return false;
}
jmethodID showFolderDialog =
env->GetMethodID(activityClass, "showFolderDialog", "(J)Z");
env->DeleteLocalRef(activityClass);
if (showFolderDialog == nullptr || clear_pending_exception(env)) {
env->DeleteLocalRef(activity);
return false;
}
const jboolean shown = env->CallBooleanMethod(
activity, showFolderDialog, reinterpret_cast<jlong>(state));
env->DeleteLocalRef(activity);
if (clear_pending_exception(env)) {
return false;
}
return shown == JNI_TRUE;
}
extern "C" JNIEXPORT void JNICALL
Java_dev_twilitrealm_dusk_DuskActivity_nativeFolderDialogResult(
JNIEnv* env, jclass, jlong userdata, jstring path, jstring error) {
auto* state = reinterpret_cast<AndroidFolderDialogState*>(userdata);
if (state == nullptr) {
return;
}
state->path = to_string(env, path);
state->error = to_string(env, error);
if (!SDL_RunOnMainThread(&onAndroidFolderDialogFinished, state, false)) {
onAndroidFolderDialogFinished(state);
}
}
#endif
#if USE_IOS_DIALOG
@@ -246,8 +159,8 @@ void onSDLDialogFinished(void* userdata, const char* const* filelist, [[maybe_un
} // namespace
void ShowFileSelect(FileCallback callback, void* userdata, SDL_Window* window,
const SDL_DialogFileFilter* filters, int nfilters, const char* default_location,
bool allow_many) {
const SDL_DialogFileFilter* filters, int nfilters, const char* default_location,
bool allow_many) {
if (callback == nullptr) {
return;
}
@@ -258,45 +171,14 @@ void ShowFileSelect(FileCallback callback, void* userdata, SDL_Window* window,
state->userdata = userdata;
Dusk_iOS_ShowFileSelect(&onIOSDialogFinished, state.release(), window, filters, nfilters,
default_location, allow_many);
default_location, allow_many);
#else
auto state = std::make_unique<SDLDialogCallbackState>();
state->callback = callback;
state->userdata = userdata;
SDL_ShowOpenFileDialog(&onSDLDialogFinished, state.release(), window, filters, nfilters,
default_location, allow_many);
#endif
}
void ShowFolderSelect(
FileCallback callback, void* userdata, SDL_Window* window, const char* default_location) {
if (callback == nullptr) {
return;
}
#if USE_IOS_DIALOG
callback(userdata, nullptr, "Folder selection is not supported on this platform");
#elif USE_MACOS_FOLDER_DIALOG
ShowMacOSFolderSelect(callback, userdata, window, default_location);
#elif defined(__ANDROID__) || defined(ANDROID)
auto state = std::make_unique<AndroidFolderDialogState>();
state->callback = callback;
state->userdata = userdata;
if (show_android_folder_select(state.get())) {
state.release();
return;
}
callback(userdata, nullptr, "Folder selection is not supported on this platform");
#else
auto state = std::make_unique<SDLDialogCallbackState>();
state->callback = callback;
state->userdata = userdata;
SDL_ShowOpenFolderDialog(
&onSDLDialogFinished, state.release(), window, default_location, false);
default_location, allow_many);
#endif
}
-2
View File
@@ -14,8 +14,6 @@ using FileCallback = void (*)(void* userdata, const char* path, const char* erro
void ShowFileSelect(FileCallback callback, void* userdata, SDL_Window* window,
const SDL_DialogFileFilter* filters, int nfilters, const char* default_location,
bool allow_many);
void ShowFolderSelect(
FileCallback callback, void* userdata, SDL_Window* window, const char* default_location);
std::string display_name_for_path(std::string_view path);
-102
View File
@@ -1,102 +0,0 @@
#include "file_select.hpp"
#include <SDL3/SDL_properties.h>
#include <SDL3/SDL_video.h>
#import <AppKit/AppKit.h>
namespace dusk {
namespace {
struct MacOSFolderDialogState {
FileCallback callback;
void* userdata;
};
void finish_folder_dialog(MacOSFolderDialogState* state, NSURL* url, const char* error) {
if (state == nullptr) {
return;
}
if (error != nullptr) {
state->callback(state->userdata, nullptr, error);
delete state;
return;
}
if (url == nil) {
state->callback(state->userdata, nullptr, nullptr);
delete state;
return;
}
state->callback(state->userdata, [[url path] UTF8String], nullptr);
delete state;
}
void configure_default_location(NSOpenPanel* panel, const char* defaultLocation) {
if (panel == nil || defaultLocation == nullptr || defaultLocation[0] == '\0') {
return;
}
NSString* path = [NSString stringWithUTF8String:defaultLocation];
if (path == nil) {
return;
}
BOOL isDirectory = NO;
NSFileManager* fileManager = [NSFileManager defaultManager];
NSURL* url = [NSURL fileURLWithPath:path];
if ([fileManager fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory) {
[panel setDirectoryURL:url];
} else {
[panel setDirectoryURL:[url URLByDeletingLastPathComponent]];
}
}
NSWindow* window_for_sdl_window(SDL_Window* window) {
if (window == nullptr) {
return nil;
}
auto props = SDL_GetWindowProperties(window);
return (__bridge NSWindow*)SDL_GetPointerProperty(
props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr);
}
} // namespace
bool ShowMacOSFolderSelect(
FileCallback callback, void* userdata, SDL_Window* window, const char* defaultLocation) {
if (callback == nullptr) {
return false;
}
auto* state = new MacOSFolderDialogState{
.callback = callback,
.userdata = userdata,
};
NSOpenPanel* panel = [NSOpenPanel openPanel];
[panel setCanChooseFiles:NO];
[panel setCanChooseDirectories:YES];
[panel setAllowsMultipleSelection:NO];
[panel setCanCreateDirectories:YES];
configure_default_location(panel, defaultLocation);
NSWindow* modalWindow = window_for_sdl_window(window);
if (modalWindow != nil) {
[panel beginSheetModalForWindow:modalWindow
completionHandler:^(NSModalResponse result) {
finish_folder_dialog(
state, result == NSModalResponseOK ? [panel URL] : nil, nullptr);
}];
return true;
}
const NSModalResponse result = [panel runModal];
finish_folder_dialog(state, result == NSModalResponseOK ? [panel URL] : nil, nullptr);
return true;
}
} // namespace dusk
-142
View File
@@ -1,142 +0,0 @@
#include "imgui.h"
#include "ImGuiMenuTools.hpp"
#include "d/actor/d_a_alink.h"
#include "d/d_com_inf_game.h"
#include "f_op/f_op_actor_mng.h"
#include "SSystem/SComponent/c_sxyz.h"
#include "SSystem/SComponent/c_xyz.h"
namespace dusk {
namespace {
struct ActorSpawnerState {
int actorId = 0;
int params = -1;
int argument = -1;
int angleX = 0;
int angleY = 0;
int angleZ = 0;
float scaleX = 1.0f;
float scaleY = 1.0f;
float scaleZ = 1.0f;
bool usePlayerRoom = true;
int manualRoom = 0;
int spawnCount = 1;
bool hasResult = false;
unsigned int lastResult = 0;
int lastAttempted = 0;
};
ActorSpawnerState s_state;
} // namespace
void ImGuiMenuTools::ShowActorSpawner() {
if (!m_showActorSpawner) {
return;
}
if (!ImGui::Begin("Actor Spawner", &m_showActorSpawner)) {
ImGui::End();
return;
}
daAlink_c* player = (daAlink_c*)dComIfGp_getPlayer(0);
ImGui::SeparatorText("Actor");
ImGui::InputInt("Actor ID", &s_state.actorId);
ImGui::InputInt("Params (hex)", &s_state.params, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
ImGui::InputInt("Argument", &s_state.argument);
s_state.argument = (s_state.argument < -128) ? -128 : (s_state.argument > 127) ? 127 : s_state.argument;
ImGui::SeparatorText("Angle");
ImGui::InputInt("Angle X", &s_state.angleX);
ImGui::InputInt("Angle Y", &s_state.angleY);
ImGui::InputInt("Angle Z", &s_state.angleZ);
ImGui::SeparatorText("Scale");
ImGui::InputFloat("Scale X", &s_state.scaleX, 0.1f, 1.0f);
ImGui::InputFloat("Scale Y", &s_state.scaleY, 0.1f, 1.0f);
ImGui::InputFloat("Scale Z", &s_state.scaleZ, 0.1f, 1.0f);
ImGui::SeparatorText("Spawn");
ImGui::InputInt("Count", &s_state.spawnCount);
if (s_state.spawnCount < 1) {
s_state.spawnCount = 1;
}
ImGui::SeparatorText("Position");
ImGui::Checkbox("Use player room", &s_state.usePlayerRoom);
if (!s_state.usePlayerRoom) {
ImGui::InputInt("Room No", &s_state.manualRoom);
}
if (player != nullptr) {
ImGui::Text("Spawn pos: %.2f, %.2f, %.2f",
player->current.pos.x, player->current.pos.y, player->current.pos.z);
} else {
ImGui::TextDisabled("Player not available");
}
ImGui::Separator();
bool canSpawn = player != nullptr;
if (!canSpawn) {
ImGui::BeginDisabled();
}
if (ImGui::Button("Spawn", ImVec2(-1, 0))) {
cXyz pos = player->current.pos;
csXyz angle;
angle.set((s16)s_state.angleX, (s16)s_state.angleY, (s16)s_state.angleZ);
cXyz scale(s_state.scaleX, s_state.scaleY, s_state.scaleZ);
int roomNo = s_state.usePlayerRoom ? player->current.roomNo : s_state.manualRoom;
layer_class* savedLayer = fpcLy_CurrentLayer();
base_process_class* playScene = fpcM_SearchByName(fpcNm_PLAY_SCENE_e);
if (playScene != nullptr) {
fpcLy_SetCurrentLayer(&((process_node_class*)playScene)->layer);
}
s_state.lastResult = 0;
s_state.lastAttempted = s_state.spawnCount;
for (int i = 0; i < s_state.spawnCount; ++i) {
unsigned int result = fopAcM_create(
(s16)s_state.actorId,
(u32)s_state.params,
&pos,
roomNo,
&angle,
&scale,
(s8)s_state.argument
);
if (result != 0) {
s_state.lastResult = result;
}
}
s_state.hasResult = true;
fpcLy_SetCurrentLayer(savedLayer);
}
if (!canSpawn) {
ImGui::EndDisabled();
}
if (s_state.hasResult) {
if (s_state.lastResult != 0) {
if (s_state.lastAttempted == 1) {
ImGui::Text("Spawned: proc ID %u", s_state.lastResult);
} else {
ImGui::Text("Spawned %d (last proc ID %u)", s_state.lastAttempted, s_state.lastResult);
}
} else {
ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), "Spawn failed (returned 0)");
}
}
ImGui::End();
}
} // namespace dusk
+16 -17
View File
@@ -13,10 +13,8 @@
#include "ImGuiEngine.hpp"
#include "JSystem/JUtility/JUTGamePad.h"
#include "SDL3/SDL_mouse.h"
#include "dusk/action_bindings.h"
#include "dusk/audio/DuskAudioSystem.h"
#include "dusk/config.hpp"
#include "dusk/data.hpp"
#include "dusk/dusk.h"
#include "dusk/frame_interpolation.h"
#include "dusk/livesplit.h"
@@ -240,8 +238,7 @@ namespace dusk {
}
void ImGuiConsole::UpdateSettings() {
getTransientSettings().skipFrameRateLimit = getSettings().game.enableTurboKeybind &&
(ImGui::IsKeyDown(ImGuiKey_Tab) || getActionBindHoldAnyPort(ActionBinds::TURBO_SPEED_BUTTON));
getTransientSettings().skipFrameRateLimit = getSettings().game.enableTurboKeybind && ImGui::IsKeyDown(ImGuiKey_Tab);
if (dusk::frame_interp::get_ui_tick_pending() && mDoMain::developmentMode == 1 && (mDoCPd_c::getHold(PAD_1) & (PAD_TRIGGER_R | PAD_TRIGGER_L)) == (PAD_TRIGGER_R | PAD_TRIGGER_L) && mDoCPd_c::getTrigY(PAD_1)) {
getTransientSettings().moveLinkActive = !getTransientSettings().moveLinkActive;
@@ -262,12 +259,6 @@ namespace dusk {
config::Save();
}
if (getSettings().game.enableResetKeybind && ImGui::GetIO().KeyCtrl &&
ImGui::IsKeyPressed(ImGuiKey_R) && !fpcM_SearchByName(fpcNm_LOGO_SCENE_e))
{
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
}
if (ImGui::GetIO().KeyShift && ImGui::IsKeyPressed(ImGuiKey_F1)) {
if (getSettings().backend.enableAdvancedSettings) {
m_isHidden = !m_isHidden;
@@ -282,6 +273,7 @@ namespace dusk {
// so make the window bg fully transparent temporarily
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
if (showMenu && ImGui::BeginMainMenuBar()) {
m_menuGame.draw();
m_menuTools.draw();
ImGui::EndMainMenuBar();
@@ -290,7 +282,7 @@ namespace dusk {
if (dusk::IsGameLaunched && !m_isLaunchInitialized) {
m_isLaunchInitialized = true;
if (getSettings().game.speedrunMode && getSettings().game.liveSplitEnabled) {
if (getSettings().game.liveSplitEnabled) {
dusk::speedrun::connectLiveSplit();
}
}
@@ -317,13 +309,11 @@ namespace dusk {
ImGui::Image(ImGuiEngine::duskLogo, ImVec2{width, iconSize});
} else {
ImGui::PushFont(ImGuiEngine::fontExtraLarge);
ImGuiTextCenter("Dusklight");
ImGuiTextCenter("Dusk");
ImGui::PopFont();
}
ImGui::PushFont(ImGuiEngine::fontLarge);
ImGuiTextCenter("Failed to initialize any graphics backend.");
ImGuiTextCenter("\nYour system may be misconfigured, or your hardware may not support the required versions of any of the available backends.");
ImGuiTextCenter("\nA clean reinstall of Dusklight may help. For further assistance, please visit #tech-support on the Twilit Realm Discord server.");
ImGuiTextCenter("Failed to initialize any graphics backend");
const auto& style = ImGui::GetStyle();
const auto retrySize = ImGui::CalcTextSize("Retry (Auto backend)");
const auto quitSize = ImGui::CalcTextSize("Quit");
@@ -349,7 +339,7 @@ namespace dusk {
}
#if DUSK_CAN_OPEN_DATA_FOLDER
if (ImGui::Button("Open Data Folder")) {
data::open_data_path();
OpenDataFolder();
}
ImGui::SameLine();
#endif
@@ -361,6 +351,15 @@ namespace dusk {
}
m_menuTools.ShowInputViewer();
m_menuGame.drawSpeedrunTimerOverlay();
if (getSettings().game.liveSplitEnabled) {
dusk::speedrun::updateLiveSplit();
if (dusk::speedrun::consumeConnectedEvent())
AddToast("LiveSplit connected");
else if (dusk::speedrun::consumeDisconnectedEvent())
AddToast("LiveSplit disconnected");
}
if (dusk::IsGameLaunched && !dusk::getSettings().game.speedrunMode) {
m_menuTools.ShowDebugOverlay();
@@ -368,12 +367,12 @@ namespace dusk {
m_menuTools.ShowProcessManager();
m_menuTools.ShowHeapOverlay();
m_menuTools.ShowStubLog();
m_menuTools.ShowMapLoader();
m_menuTools.ShowBloomWindow();
m_menuTools.ShowPlayerInfo();
m_menuTools.ShowAudioDebug();
m_menuTools.ShowSaveEditor();
m_menuTools.ShowStateShare();
m_menuTools.ShowActorSpawner();
}
// Hide mouse cursor if the F1 menu is not open and the cursor is idle for 3 seconds.
+3
View File
@@ -7,6 +7,7 @@
#include <aurora/aurora.h>
#include "ImGuiMenuGame.hpp"
#include "ImGuiMenuTools.hpp"
#include "dusk/main.h"
#include "imgui.h"
@@ -43,6 +44,8 @@ private:
ImVec2 m_dragScrollLastMousePos = {};
std::deque<Toast> m_toasts;
ImGuiMenuGame m_menuGame;
// Keep always last
ImGuiMenuTools m_menuTools;
+4 -5
View File
@@ -3,13 +3,12 @@
#include "imgui.h"
#include <imgui_internal.h>
#include "ImGuiConsole.hpp"
#include "dusk/settings.h"
#include <dolphin/pad.h>
namespace dusk {
void ImGuiMenuTools::ShowInputViewer() {
if (!getSettings().game.showInputViewer) {
if (!m_showInputViewer) {
return;
}
@@ -260,10 +259,10 @@ namespace dusk {
size.y = 130 * scale;
ImGui::Dummy(size);
if (getSettings().game.showInputViewerGyro)
{
if (PADHasSensor(PAD_1, PAD_SENSOR_GYRO) == TRUE) {
ImGui::Separator();
{
ImGui::Checkbox("Gyro Values", &m_showInputViewerGyro);
if (m_showInputViewerGyro) {
ImGui::TextUnformatted("Gyro");
constexpr float kBarScale = 4.0f;

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