Good stuff

This commit is contained in:
Luke Street
2026-09-10 01:32:12 -06:00
parent b84f8f56de
commit a7171c1956
64 changed files with 2626 additions and 1271 deletions
+9 -1
View File
@@ -223,6 +223,14 @@ if (DUSK_HAS_FUNCHOOK)
endif ()
FetchContent_MakeAvailable(${_fetch_content_deps})
if (DUSK_HAS_FUNCHOOK AND APPLE)
target_sources(funchook-static PRIVATE src/dusk/mods/loader/code_patch_macos.cpp)
target_include_directories(funchook-static PRIVATE src/dusk/mods/loader)
set_source_files_properties(src/dusk/mods/loader/code_patch_macos.cpp
TARGET_DIRECTORY funchook-static PROPERTIES
COMPILE_OPTIONS "-O2;-fno-sanitize=all;-fno-stack-protector")
endif ()
# Use signed char on ARM to match the original game (and x86)
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" _arch)
if(_arch MATCHES "^(arm|aarch64)" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
@@ -249,7 +257,7 @@ find_package(Threads REQUIRED)
set(GAME_COMPILE_DEFS DUSK_BUILDING_GAME=1)
set(GAME_LIBS aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd aurora::thp
aurora::card borealis::http borealis::cli borealis::crash borealis::data borealis::disc borealis::discord borealis::file_select borealis::io borealis::log borealis::net borealis::presentation borealis::sentry borealis::update borealis::ws freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json TracyClient fmt::fmt
Threads::Threads zstd::libzstd dusklight_game_headers picosha2)
Threads::Threads zstd::libzstd dusklight_game_headers picosha2 PNG::PNG)
if (DUSK_HAS_FUNCHOOK)
list(APPEND GAME_LIBS funchook-static)
endif ()
+49 -53
View File
@@ -2,59 +2,55 @@ file(READ "${SOURCE_DIR}/cmake/capstone.cmake.in" _content)
# Insert PATCH_COMMAND before CONFIGURE_COMMAND in the ExternalProject_Add.
# Bracket args prevent cmake from substituting ${...} while writing this file.
string(REPLACE
" CONFIGURE_COMMAND \"\""
[=[ PATCH_COMMAND "${CMAKE_COMMAND}" -DDIR=${CMAKE_CURRENT_BINARY_DIR}/capstone-src -P "${CAPSTONE_FIX_SCRIPT}"
if (NOT _content MATCHES "CAPSTONE_FIX_SCRIPT")
string(REPLACE
" CONFIGURE_COMMAND \"\""
[=[ PATCH_COMMAND "${CMAKE_COMMAND}" -DDIR=${CMAKE_CURRENT_BINARY_DIR}/capstone-src -P "${CAPSTONE_FIX_SCRIPT}"
CONFIGURE_COMMAND ""]=]
_content "${_content}")
file(WRITE "${SOURCE_DIR}/cmake/capstone.cmake.in" "${_content}")
file(READ "${SOURCE_DIR}/src/funchook_unix.c" _unix_content)
# macOS rejects the POSIX mprotect RWX/RW transition for executable image pages on arm64.
# Use Mach VM_PROT_COPY for the short patch window, then restore RX permissions.
if (NOT _unix_content MATCHES "VM_PROT_READ \\| VM_PROT_WRITE \\| VM_PROT_COPY")
string(REPLACE
[=[ rv = mprotect(mstate->addr, mstate->size, prot);]=]
[=[#ifdef __APPLE__
kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)mstate->addr,
(vm_size_t)mstate->size, FALSE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY);
if (kr == KERN_SUCCESS) {
funchook_log(funchook, " unprotect memory %p (size=%"PRIuPTR", prot=read,write,copy) <- %p (size=%"PRIuPTR")\n",
mstate->addr, mstate->size, start, len);
return 0;
}
funchook_set_error_message(funchook, "Failed to unprotect memory %p (size=%"PRIuPTR", prot=read,write,copy) <- %p (size=%"PRIuPTR", error=%s)",
mstate->addr, mstate->size, start, len,
mach_error_string(kr));
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
#endif
rv = mprotect(mstate->addr, mstate->size, prot);]=]
_unix_content "${_unix_content}")
string(REPLACE
[=[ char errbuf[128];
int rv = mprotect(mstate->addr, mstate->size, PROT_READ | PROT_EXEC);]=]
[=[ char errbuf[128];
#ifdef __APPLE__
kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)mstate->addr,
(vm_size_t)mstate->size, FALSE,
VM_PROT_READ | VM_PROT_EXECUTE);
if (kr == KERN_SUCCESS) {
funchook_log(funchook, " protect memory %p (size=%"PRIuPTR", prot=read,exec)\n",
mstate->addr, mstate->size);
return 0;
}
funchook_set_error_message(funchook, "Failed to protect memory %p (size=%"PRIuPTR", prot=read,exec, error=%s)",
mstate->addr, mstate->size,
mach_error_string(kr));
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
#endif
int rv = mprotect(mstate->addr, mstate->size, PROT_READ | PROT_EXEC);]=]
_unix_content "${_unix_content}")
_content "${_content}")
file(WRITE "${SOURCE_DIR}/cmake/capstone.cmake.in" "${_content}")
endif ()
file(WRITE "${SOURCE_DIR}/src/funchook_unix.c" "${_unix_content}")
file(READ "${SOURCE_DIR}/src/funchook.c" _content)
if (NOT _content MATCHES "commit_code_patch")
string(REPLACE "#include \"funchook_internal.h\""
"#include \"funchook_internal.h\"\n#ifdef __APPLE__\n#include \"code_patch_macos.hpp\"\n#endif"
_content "${_content}")
foreach(_operation install uninstall)
if (_operation STREQUAL "install")
set(_expected old_code)
set(_replacement new_code)
else ()
set(_expected new_code)
set(_replacement old_code)
endif ()
set(_original " mem_state_t mstate;
int rv = funchook_unprotect_begin(funchook, &mstate, entry->target_func, JUMP32_BYTE_SIZE);
if (rv != 0) {
return rv;
}
memcpy(entry->target_func, entry->${_replacement}, JUMP32_BYTE_SIZE);
rv = funchook_unprotect_end(funchook, &mstate);
if (rv != 0) {
return rv;
}
flush_instruction_cache(entry->target_func, JUMP32_BYTE_SIZE);")
string(FIND "${_content}" "${_original}" _position)
if (_position EQUAL -1)
message(FATAL_ERROR "Funchook ${_operation} patch site changed")
endif ()
string(REPLACE "${_original}" "#ifdef __APPLE__
int rv = commit_code_patch(entry->target_func, entry->${_expected},
entry->${_replacement}, JUMP32_BYTE_SIZE);
if (rv != 0) {
funchook_set_error_message(funchook, \"Code patch commit failed (Mach error %d)\", rv);
return FUNCHOOK_ERROR_MEMORY_FUNCTION;
}
#else
${_original}
#endif" _content "${_content}")
endforeach ()
file(WRITE "${SOURCE_DIR}/src/funchook.c" "${_content}")
endif ()
+12
View File
@@ -1484,6 +1484,12 @@ set(DUSK_FILES
src/dusk/mods/loader/depgraph.hpp
src/dusk/mods/loader/loader.cpp
src/dusk/mods/loader/loader.hpp
src/dusk/mods/loader/manifest.cpp
src/dusk/mods/loader/manifest.hpp
src/dusk/mods/loader/natives.cpp
src/dusk/mods/loader/natives.hpp
src/dusk/mods/loader/packages.cpp
src/dusk/mods/loader/packages.hpp
src/dusk/mods/loader/native_module.cpp
src/dusk/mods/loader/native_module.hpp
src/dusk/mods/loader/prepatch.cpp
@@ -1601,6 +1607,12 @@ set(DUSK_FILES
src/dusk/ui/nav_types.hpp
src/dusk/ui/nav_group.cpp
src/dusk/ui/nav_group.hpp
src/dusk/ui/context_menu.cpp
src/dusk/ui/context_menu.hpp
src/dusk/ui/icon_button.cpp
src/dusk/ui/icon_button.hpp
src/dusk/ui/tooltip.cpp
src/dusk/ui/tooltip.hpp
src/dusk/ui/number_button.cpp
src/dusk/ui/number_button.hpp
src/dusk/ui/overlay.cpp
+36 -33
View File
@@ -118,10 +118,9 @@ catalog-card-art {
position: relative;
flex: 0 0 118dp;
min-height: 118dp;
background-color: rgba(var(--color-border-rgb), 12%);
}
catalog-card-art-shadow {
catalog-card-art-image {
display: block;
position: absolute;
top: 0;
@@ -129,7 +128,7 @@ catalog-card-art-shadow {
bottom: 0;
left: 0;
pointer-events: none;
decorator: linear-gradient(180deg, rgba(var(--color-surface-rgb), 0%) 45%, rgba(var(--color-surface-rgb), 85%));
mask-image: linear-gradient(180deg, #fff 45%, transparent);
}
catalog-card-body {
@@ -182,7 +181,6 @@ catalog-card-body > small {
height: 56dp;
border-radius: var(--radius-panel);
overflow: hidden;
background-color: rgba(var(--color-border-rgb), 18%);
box-shadow: rgba(var(--color-black-rgb), 60%) 0 6dp 16dp;
}
@@ -235,8 +233,10 @@ catalog-card-body > footer {
catalog-card-body > footer stat {
display: flex;
flex: 0 0 auto;
align-items: center;
gap: 3dp;
white-space: nowrap;
}
catalog-card-body > footer icon {
@@ -329,10 +329,9 @@ catalog-detail-hero {
flex: 0 0 220dp;
min-height: 220dp;
padding: 18dp var(--space-xl) 20dp var(--space-xl);
background-color: rgba(var(--color-control-rgb), 75%);
}
catalog-detail-hero-shadow {
catalog-detail-hero-image {
display: block;
position: absolute;
top: 0;
@@ -340,7 +339,7 @@ catalog-detail-hero-shadow {
bottom: 0;
left: 0;
pointer-events: none;
decorator: linear-gradient(180deg, rgba(var(--color-surface-rgb), 25%) 40%, rgba(var(--color-surface-rgb), 92%));
mask-image: linear-gradient(180deg, #fff 40%, transparent);
}
catalog-detail-actions {
@@ -403,10 +402,11 @@ catalog-source-actions button {
}
.catalog-install-action.idle {
--button-background: rgba(var(--color-interactive-rgb), 40%);
--button-background-hover: rgba(var(--color-interactive-rgb), 55%);
--button-background-selected: rgba(var(--color-interactive-rgb), 55%);
--button-background-active: rgba(var(--color-interactive-rgb), 55%);
--button-background: rgba(var(--color-interactive-rgb), 18%);
--button-background-hover: rgba(var(--color-interactive-rgb), 42%);
--button-background-selected: rgba(var(--color-interactive-rgb), 42%);
--button-background-active: rgba(var(--color-interactive-rgb), 65%);
box-shadow: rgba(var(--color-accent-rgb), 65%) 0 0 0 1dp;
}
.catalog-install-action.paused {
@@ -467,10 +467,6 @@ catalog-source-actions button {
box-shadow: rgba(var(--color-success-rgb), 50%) 0 0 0 2dp;
}
.catalog-install-action.installed:disabled {
opacity: 1;
}
.catalog-install-action.installing progress fill {
background-color: rgba(var(--color-info-rgb), 80%);
}
@@ -513,7 +509,6 @@ catalog-detail-identity mod-icon {
height: 70dp;
border-radius: var(--radius-panel);
overflow: hidden;
background-color: rgba(var(--color-border-rgb), 25%);
box-shadow: rgba(var(--color-black-rgb), 65%) 0 8dp 20dp;
}
@@ -561,11 +556,7 @@ catalog-detail-stats {
flex-flow: row;
align-items: center;
gap: 28dp;
padding: 13dp 28dp;
border-top-width: 1dp;
border-top-color: rgba(var(--color-border-rgb), 30%);
border-bottom-width: 1dp;
border-bottom-color: rgba(var(--color-border-rgb), 30%);
margin: 0 var(--space-xl);
font-size: var(--font-size-2xs);
color: rgba(var(--color-text-rgb), 58%);
}
@@ -582,11 +573,6 @@ catalog-detail-stats icon {
line-height: 1;
}
catalog-detail-stats > stat > b {
color: var(--color-text);
font-weight: bold;
}
catalog-detail-body {
display: flex;
flex-flow: row;
@@ -705,6 +691,8 @@ catalog-gallery {
}
.catalog-screenshot {
position: relative;
overflow: hidden;
flex: 1 1 0;
height: 100%;
min-width: 0;
@@ -718,6 +706,25 @@ catalog-gallery {
flex: 2 1 0;
}
catalog-screenshot-image,
catalog-screenshot-more {
display: block;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
pointer-events: none;
}
catalog-screenshot-more {
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(var(--color-black-rgb), 60%);
color: var(--color-white);
}
catalog-dependencies {
display: flex;
flex-flow: column;
@@ -759,13 +766,14 @@ catalog-detail-body dl {
display: flex;
flex-flow: row wrap;
margin: 0;
font-size: var(--font-size-2xs);
font-size: var(--font-size-sm);
}
catalog-detail-body dt {
flex: 0 0 42%;
padding: 5dp 0;
opacity: 0.5;
font-weight: bold;
opacity: 0.8;
}
catalog-detail-body dd {
@@ -775,11 +783,6 @@ catalog-detail-body dd {
text-align: right;
}
catalog-source-actions {
display: flex;
flex-flow: column;
}
window.screenshot-viewer > content {
flex-flow: column;
padding: 18dp;
+20 -3
View File
@@ -199,6 +199,22 @@ mod-header.has-banner {
margin: -24dp -24dp 0dp -24dp;
}
mod-header-image {
display: block;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
pointer-events: none;
mask-image: linear-gradient(180deg, #fff 40%, transparent);
filter: grayscale(0);
}
mod-header.inactive mod-header-image {
filter: grayscale(1);
}
mod-actions {
position: absolute;
top: 24dp;
@@ -209,9 +225,10 @@ mod-actions {
}
mod-actions button {
font-size: var(--font-size-md);
padding: 6dp 14dp;
background-color: rgba(var(--color-surface-rgb), 80%);
--button-background: rgba(var(--color-surface-rgb), 80%);
--button-background-hover: rgba(var(--color-control-rgb), 90%);
--button-background-selected: rgba(var(--color-control-rgb), 90%);
--button-background-active: rgba(var(--color-surface-rgb), 90%);
box-shadow: rgba(var(--color-border-rgb), 60%) 0 0 0 1dp;
}
+62
View File
@@ -186,3 +186,65 @@ color-value:hover,
color-value:focus-visible {
color: var(--color-accent);
}
popover.context-menu {
min-width: 200dp;
max-width: 90%;
max-height: 90%;
overflow-y: auto;
padding: 6dp;
gap: 2dp;
transform-origin: left top;
}
.context-menu button {
display: flex;
align-items: center;
gap: 10dp;
padding: 8dp 12dp;
flex: 0 0 auto;
white-space: nowrap;
--button-background: transparent;
background-color: var(--button-background);
box-shadow: none;
transition: background-color 0.1s linear-in-out;
}
.context-menu button:not(:disabled):hover,
.context-menu button:not(:disabled):focus-visible {
background-color: var(--button-background-hover);
box-shadow: none;
}
.context-menu button:not(:disabled):active {
background-color: var(--button-background-active);
}
.context-menu button:disabled {
background-color: transparent;
box-shadow: none;
opacity: 0.4;
cursor: unavailable;
}
.context-menu button.destructive {
color: var(--color-error);
}
.context-menu icon {
display: block;
flex: 0 0 1em;
width: 1em;
height: 1em;
font-family: var(--font-family-icons);
font-weight: normal;
line-height: 1;
}
menu-separator {
display: block;
flex: 0 0 1dp;
height: 1dp;
margin: 4dp 6dp;
background-color: var(--color-border);
}
+1 -1
View File
@@ -57,7 +57,7 @@ window > close {
position: fixed;
top: 8dp;
right: 8dp;
z-index: 1;
z-index: 2;
width: 48dp;
height: 48dp;
font-family: var(--font-family-icons);
+39
View File
@@ -940,3 +940,42 @@ modal-actions.vertical button.modal-btn {
width: 100%;
}
}
button.icon-button {
display: flex;
align-items: center;
justify-content: center;
width: 44dp;
height: 44dp;
padding: var(--space-sm);
box-sizing: border-box;
flex-shrink: 0;
font-size: var(--font-size-5xl);
}
button.icon-button icon {
display: block;
flex-shrink: 0;
line-height: 1;
pointer-events: none;
}
ui-tooltip {
display: none;
position: absolute;
z-index: 1000;
max-width: 240dp;
padding: 6dp 10dp;
border: 1dp var(--color-border);
border-radius: var(--radius-panel);
background-color: rgba(var(--color-surface-rgb), 96%);
color: var(--color-text);
font-size: var(--font-size-md);
word-break: break-word;
pointer-events: none;
focus: none;
}
ui-tooltip.visible {
display: block;
}
+2
View File
@@ -42,6 +42,8 @@ extern "C" {
#define MOD_ABI_VERSION 1u
#define MOD_ERROR_MESSAGE_SIZE 512u
#define DUSKLIGHT_SERVICE_ID_PREFIX "dev.twilitrealm.dusklight."
typedef struct ModContext ModContext;
typedef enum ModResult {
+1 -1
View File
@@ -3,7 +3,7 @@
#include <mods/api.h>
#include <mods/svc/config.h>
#define ACTOR_SERVICE_ID "dev.twilitrealm.dusklight.actor"
#define ACTOR_SERVICE_ID DUSKLIGHT_SERVICE_ID_PREFIX "actor"
#define ACTOR_SERVICE_MAJOR 1u
#define ACTOR_SERVICE_MINOR 0u
+1 -1
View File
@@ -6,7 +6,7 @@
#include <mods/service.hpp>
#endif
#define CAMERA_SERVICE_ID "dev.twilitrealm.dusklight.camera"
#define CAMERA_SERVICE_ID DUSKLIGHT_SERVICE_ID_PREFIX "camera"
#define CAMERA_SERVICE_MAJOR 1u
#define CAMERA_SERVICE_MINOR 1u
+1 -1
View File
@@ -6,7 +6,7 @@
#include <mods/service.hpp>
#endif
#define CONFIG_SERVICE_ID "dev.twilitrealm.dusklight.config"
#define CONFIG_SERVICE_ID DUSKLIGHT_SERVICE_ID_PREFIX "config"
#define CONFIG_SERVICE_MAJOR 1u
#define CONFIG_SERVICE_MINOR 0u
+1 -1
View File
@@ -6,7 +6,7 @@
#include <mods/service.hpp>
#endif
#define FILE_SERVICE_ID "dev.twilitrealm.dusklight.file"
#define FILE_SERVICE_ID DUSKLIGHT_SERVICE_ID_PREFIX "file"
#define FILE_SERVICE_MAJOR 1u
#define FILE_SERVICE_MINOR 0u
+1 -1
View File
@@ -6,7 +6,7 @@
#include <mods/service.hpp>
#endif
#define FLOW_SERVICE_ID "dev.twilitrealm.dusklight.flow"
#define FLOW_SERVICE_ID DUSKLIGHT_SERVICE_ID_PREFIX "flow"
#define FLOW_SERVICE_MAJOR 1u
#define FLOW_SERVICE_MINOR 0u
+1 -1
View File
@@ -15,7 +15,7 @@
* ordinary version check then fails mods built against the old epoch with a clear message instead
* of letting them corrupt memory.
*/
#define GAME_SERVICE_ID "dev.twilitrealm.dusklight.game"
#define GAME_SERVICE_ID DUSKLIGHT_SERVICE_ID_PREFIX "game"
#define GAME_SERVICE_MAJOR 2u
#define GAME_SERVICE_MINOR 0u
+1 -1
View File
@@ -3,7 +3,7 @@
#include <mods/api.h>
#include <mods/svc/config.h>
#define GAME_MODE_SERVICE_ID "dev.twilitrealm.dusklight.gamemode"
#define GAME_MODE_SERVICE_ID DUSKLIGHT_SERVICE_ID_PREFIX "gamemode"
#define GAME_MODE_SERVICE_MAJOR 1u
#define GAME_MODE_SERVICE_MINOR 0u
+1 -1
View File
@@ -31,7 +31,7 @@
* should be released in mod_shutdown. The device outlives all mods.
*/
#define GFX_SERVICE_ID "dev.twilitrealm.dusklight.gfx"
#define GFX_SERVICE_ID DUSKLIGHT_SERVICE_ID_PREFIX "gfx"
#define GFX_SERVICE_MAJOR 1u
#define GFX_SERVICE_MINOR 2u
+1 -1
View File
@@ -20,7 +20,7 @@
* (file-local statics included).
*/
#define HOOK_SERVICE_ID "dev.twilitrealm.dusklight.hook"
#define HOOK_SERVICE_ID DUSKLIGHT_SERVICE_ID_PREFIX "hook"
#define HOOK_SERVICE_MAJOR 1u
#define HOOK_SERVICE_MINOR 1u
+1 -1
View File
@@ -11,7 +11,7 @@
* Always available; every other service can be reached from it.
*/
#define HOST_SERVICE_ID "dev.twilitrealm.dusklight.host"
#define HOST_SERVICE_ID DUSKLIGHT_SERVICE_ID_PREFIX "host"
#define HOST_SERVICE_MAJOR 2u
#define HOST_SERVICE_MINOR 2u

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