Merge branch 'better-tools' of https://github.com/TakaRikka/dusk into better-tools

This commit is contained in:
madeline
2026-08-08 19:21:07 -07:00
61 changed files with 1485 additions and 2708 deletions
+17 -6
View File
@@ -76,15 +76,12 @@ template<ConfigValue T>
void ConfigImpl<T>::loadFromJson(ConfigVar<T>& cVar, const json& jsonValue) {
if constexpr (std::is_enum_v<T>) {
if (jsonValue.is_boolean()) {
DuskConfigLog.error("Doing default migration of CVar {} from bool, enum values may not be what is expected!", cVar.getName());
using Underlying = std::underlying_type_t<T>;
const bool b = jsonValue.get<bool>();
Underlying raw;
if constexpr (std::is_same_v<T, dusk::FrameInterpMode>) {
raw = b ? static_cast<Underlying>(2) : static_cast<Underlying>(0);
} else {
raw = b ? static_cast<Underlying>(1) : static_cast<Underlying>(0);
}
const Underlying raw = b ? static_cast<Underlying>(1) : static_cast<Underlying>(0);
cVar.setValue(sanitizeEnumValue(cVar, static_cast<T>(raw)), false);
return;
@@ -194,9 +191,23 @@ namespace dusk::config {
template class ConfigImpl<dusk::DiscVerificationState>;
template class ConfigImpl<dusk::GameLanguage>;
template class ConfigImpl<dusk::GyroMode>;
template<> void ConfigImpl<FrameInterpMode>::loadFromJson(ConfigVar<FrameInterpMode>& cVar, const json& jsonValue) {
if (jsonValue.is_boolean()) {
const bool b = jsonValue.get<bool>();
const FrameInterpMode mode = b ? FrameInterpMode::Unlimited : FrameInterpMode::Off;
cVar.setValue(sanitizeEnumValue(cVar, mode), false);
return;
}
cVar.setValue(sanitizeEnumValue(cVar, jsonValue.get<FrameInterpMode>()), false);
}
template class ConfigImpl<dusk::FrameInterpMode>;
template class ConfigImpl<dusk::MenuScaling>;
template class ConfigImpl<dusk::Resampler>;
template class ConfigImpl<dusk::MagicArmorMode>;
}
void dusk::config::Register(ConfigVarBase& configVar) {
+2 -1
View File
@@ -34,6 +34,7 @@
#if defined(__APPLE__)
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#include <TargetConditionals.h>
#else
#include <elf.h>
#include <link.h>
@@ -929,7 +930,7 @@ void install() {
SymInitialize(GetCurrentProcess(), nullptr, TRUE);
#endif
g_prevFilter = SetUnhandledExceptionFilter(&windowsHandler);
#else
#elif !defined(__APPLE__) || !TARGET_OS_TV
Dl_info moduleInfo;
if (dladdr(reinterpret_cast<void*>(&install), &moduleInfo) != 0) {
g_ctx.moduleBase = reinterpret_cast<uintptr_t>(moduleInfo.dli_fbase);
+2 -101
View File
@@ -16,7 +16,6 @@
#include <vector>
#include <SDL3/SDL_filesystem.h>
#include <SDL3/SDL_iostream.h>
#include <SDL3/SDL_misc.h>
#include <SDL3/SDL_stdinc.h>
@@ -28,8 +27,6 @@ namespace {
aurora::Module Log{"dusk::data"};
constexpr auto kLocationDescriptorName = "data_location.json";
constexpr auto kPipelineCacheName = "pipeline_cache.db";
constexpr auto kInitialPipelineCacheName = "initial_pipeline_cache.db";
constexpr std::array<std::string_view, 4> kUserDataDirectories = {
"texture_replacements",
@@ -37,10 +34,11 @@ constexpr std::array<std::string_view, 4> kUserDataDirectories = {
"EUR",
"JAP",
};
constexpr std::array<std::string_view, 6> kUserDataFiles = {
constexpr std::array<std::string_view, 7> kUserDataFiles = {
"achievements.json",
"config.json",
"controller_ports.dat",
"gamecontrollerdb.txt",
"imgui.ini",
"keyboard_bindings.dat",
"states.json",
@@ -888,102 +886,6 @@ void ensure_data_directory(const std::filesystem::path& dataPath) {
}
}
SDL_IOStream* open_initial_pipeline_cache_source(std::string& sourcePathString) {
const auto basePath = base_path_relative(kInitialPipelineCacheName);
sourcePathString = io::fs_path_to_string(basePath);
auto* source = SDL_IOFromFile(sourcePathString.c_str(), "rb");
if (source != nullptr) {
return source;
}
sourcePathString = std::string{kInitialPipelineCacheName};
return SDL_IOFromFile(sourcePathString.c_str(), "rb");
}
void ensure_initial_pipeline_cache(const std::filesystem::path& configDir) {
if (configDir.empty()) {
return;
}
std::error_code ec;
std::filesystem::create_directories(configDir, ec);
if (ec) {
Log.warn("Failed to create config directory '{}' for pipeline cache: {}",
io::fs_path_to_string(configDir), ec.message());
return;
}
const auto pipelineCachePath = configDir / kPipelineCacheName;
if (std::filesystem::exists(pipelineCachePath, ec)) {
return;
}
std::string sourcePathString;
SDL_IOStream* source = open_initial_pipeline_cache_source(sourcePathString);
if (source == nullptr) {
Log.info("No bundled initial pipeline cache found");
return;
}
const auto pipelineCacheString = io::fs_path_to_string(pipelineCachePath);
SDL_IOStream* destination = SDL_IOFromFile(pipelineCacheString.c_str(), "wb");
if (destination == nullptr) {
Log.warn("Failed to open '{}' for seeded pipeline cache: {}", pipelineCacheString,
SDL_GetError());
SDL_CloseIO(source);
return;
}
bool copied = true;
std::array<char, 64 * 1024> buffer{};
while (true) {
const size_t bytesRead = SDL_ReadIO(source, buffer.data(), buffer.size());
if (bytesRead > 0) {
size_t bytesWritten = 0;
while (bytesWritten < bytesRead) {
const size_t written = SDL_WriteIO(
destination, buffer.data() + bytesWritten, bytesRead - bytesWritten);
if (written == 0) {
Log.warn("Failed to write seeded pipeline cache '{}': {}", pipelineCacheString,
SDL_GetError());
copied = false;
break;
}
bytesWritten += written;
}
}
if (!copied) {
break;
}
if (bytesRead < buffer.size()) {
if (SDL_GetIOStatus(source) == SDL_IO_STATUS_EOF) {
break;
}
Log.warn(
"Failed to read bundled pipeline cache '{}': {}", sourcePathString, SDL_GetError());
copied = false;
break;
}
}
if (!SDL_CloseIO(destination)) {
Log.warn(
"Failed to close seeded pipeline cache '{}': {}", pipelineCacheString, SDL_GetError());
copied = false;
}
SDL_CloseIO(source);
if (!copied) {
std::filesystem::remove(pipelineCachePath, ec);
return;
}
Log.info("Seeded pipeline cache from '{}'", sourcePathString);
}
} // namespace
bool open_data_path() {
@@ -1096,7 +998,6 @@ Paths initialize_data() {
migrate_data(prefPath, dataPath, descriptor ? &descriptor->descriptor : nullptr);
ensure_data_directory(dataPath);
ensure_data_directory(prefPath);
ensure_initial_pipeline_cache(prefPath);
return Paths{
.userPath = dataPath,
+5 -3
View File
@@ -49,7 +49,9 @@ namespace dusk {
dCam->Reset(center, eye);
}
ImGui::InputFloat("Camera FOV", &dCam->mFovy);
if (ImGui::InputFloat("Camera FOV", &dCam->mFovy)) {
dCam->mFovy = std::clamp(dCam->mFovy, 0.1f, 179.9f);
}
ImGui::SeparatorText("Options");
@@ -75,12 +77,12 @@ namespace dusk {
if (!getSettings().game.debugFlyCam) {
ImGui::BeginDisabled();
}
config::ImGuiCheckbox("Lock Events", getSettings().game.debugFlyCamLockEvents);
config::ImGuiCheckbox("Freeze Time", getSettings().game.debugFlyCamLockEvents);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
if (!getSettings().game.debugFlyCam) {
ImGui::SetTooltip("Enable Fly Mode first.");
} else {
ImGui::SetTooltip("Freeze game events while flying.");
ImGui::SetTooltip("Freezes the game while flying.");
}
}
if (!getSettings().game.debugFlyCam) {
+6 -2
View File
@@ -41,6 +41,7 @@ UserSettings g_userSettings = {
.noMissClimbing {"game.noMissClimbing", false},
.fastTears {"game.fastTears", false},
.no2ndFishForCat {"game.no2ndFishForCat", false},
.buttonFishing {"game.buttonFishing", false},
.instantSaves {"game.instantSaves", false},
.instantText {"game.instantText", false},
.sunsSong {"game.sunsSong", false},
@@ -50,6 +51,7 @@ UserSettings g_userSettings = {
// Preferences
.enableMirrorMode {"game.enableMirrorMode", false},
.minimalHUD {"game.minimalHUD", false},
.hudScale {"game.hudScale", 1.0f},
.pauseOnFocusLost {"game.pauseOnFocusLost", false},
.enableLinkDollRotation {"game.enableLinkDollRotation", false},
.enableAchievementToasts {"game.enableAchievementToasts", true},
@@ -125,7 +127,7 @@ UserSettings g_userSettings = {
.canTransformAnywhere {"game.canTransformAnywhere", false},
.fastRoll {"game.fastRoll", false},
.fastSpinner {"game.fastSpinner", false},
.freeMagicArmor {"game.freeMagicArmor", false},
.armorRupeeDrain {"game.armorRupeeDrain", MagicArmorMode::NORMAL},
.invincibleEnemies {"game.invincibleEnemies", false},
// Technical
@@ -225,6 +227,7 @@ void registerSettings() {
Register(g_userSettings.game.fastClimbing);
Register(g_userSettings.game.fastTears);
Register(g_userSettings.game.no2ndFishForCat);
Register(g_userSettings.game.buttonFishing);
Register(g_userSettings.game.instantSaves);
Register(g_userSettings.game.instantText);
Register(g_userSettings.game.sunsSong);
@@ -240,6 +243,7 @@ void registerSettings() {
Register(g_userSettings.game.freeCameraXSensitivity);
Register(g_userSettings.game.freeCameraYSensitivity);
Register(g_userSettings.game.minimalHUD);
Register(g_userSettings.game.hudScale);
Register(g_userSettings.game.pauseOnFocusLost);
Register(g_userSettings.game.enableDiscordPresence);
Register(g_userSettings.game.bloomMode);
@@ -255,7 +259,7 @@ void registerSettings() {
Register(g_userSettings.game.enableFastIronBoots);
Register(g_userSettings.game.canTransformAnywhere);
Register(g_userSettings.game.fastRoll);
Register(g_userSettings.game.freeMagicArmor);
Register(g_userSettings.game.armorRupeeDrain);
Register(g_userSettings.game.restoreWiiGlitches);
Register(g_userSettings.game.enableLinkDollRotation);
Register(g_userSettings.game.enableAchievementToasts);
+1 -1
View File
@@ -33,7 +33,7 @@ void resetForSpeedrunMode() {
getSettings().game.canTransformAnywhere.setSpeedrunValue(false);
getSettings().game.fastRoll.setSpeedrunValue(false);
getSettings().game.fastSpinner.setSpeedrunValue(false);
getSettings().game.freeMagicArmor.setSpeedrunValue(false);
getSettings().game.armorRupeeDrain.setSpeedrunValue(MagicArmorMode::NORMAL);
getSettings().game.pauseOnFocusLost.setSpeedrunValue(false);
aurora_set_pause_on_focus_lost(false);
+1 -1
View File
@@ -217,7 +217,7 @@ void AchievementsWindow::updateTotal() {
return;
}
const auto all = AchievementSystem::get().getAchievements();
int total = static_cast<int>(all.size());
const int total = std::count_if(all.begin(), all.end(), [](const Achievement& achievement){ return achievement.category != AchievementCategory::Glitched;});
int unlocked = 0;
for (const auto& a : all) {
if (a.unlocked) {
+1
View File
@@ -37,6 +37,7 @@ void applyPresetDusk() {
s.game.invertCameraXAxis.setValue(true);
s.game.invertFirstPersonYAxis.setValue(true);
s.game.no2ndFishForCat.setValue(true);
s.game.buttonFishing.setValue(true);
s.game.enableAchievementToasts.setValue(true);
s.game.enableControllerToasts.setValue(true);
s.game.enableQuickTransform.setValue(true);
+48 -3
View File
@@ -75,6 +75,14 @@ constexpr std::array kMenuScalingModeLabels = {
"Dusklight",
};
constexpr std::array kMagicArmorModes = {
"Normal",
"On Damage",
"Double Defense",
"Invincible",
"Cosmetic",
};
bool try_parse_backend(std::string_view backend, AuroraBackend& outBackend) {
if (backend == "auto") {
outBackend = BACKEND_AUTO;
@@ -211,7 +219,7 @@ void reset_for_speedrun_mode() {
getSettings().game.canTransformAnywhere.setSpeedrunValue(false);
getSettings().game.fastRoll.setSpeedrunValue(false);
getSettings().game.fastSpinner.setSpeedrunValue(false);
getSettings().game.freeMagicArmor.setSpeedrunValue(false);
getSettings().game.armorRupeeDrain.setSpeedrunValue(MagicArmorMode::NORMAL);
getSettings().game.invincibleEnemies.setSpeedrunValue(false);
getSettings().game.pauseOnFocusLost.setSpeedrunValue(false);
@@ -1113,6 +1121,11 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
addOption("Minimal HUD", getSettings().game.minimalHUD,
"Disables the elements of the main HUD of the game.<br/>Useful for a more immersive "
"experience.");
config_percent_select(leftPane, rightPane, getSettings().game.hudScale,
"HUD Scale",
"Scales the size of the gameplay HUD (hearts, buttons, mini-map, etc.). Does not affect dialog boxes or menus.",
50, 200, 5,
[] { return getSettings().game.minimalHUD.getValue(); });
addOption("Restore Wii 1.0 Glitches", getSettings().game.restoreWiiGlitches,
"Restores patched glitches from Wii USA 1.0, the first released version.");
addOption("Enable Rotating Link Doll", getSettings().game.enableLinkDollRotation,
@@ -1173,6 +1186,8 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
"Link will not recoil when his sword hits walls.");
addOption("No 2nd Fish for Cat", getSettings().game.no2ndFishForCat,
"Skip needing to catch a second fish for Sera's cat.");
addOption("Button Fishing", getSettings().game.buttonFishing,
"Allow fishing with the Fishing Rod using the button the item is assigned to.");
addOption("Show Poe Count on Map", getSettings().game.enhancedMapMenus,
"Displays collected/total number of Poe Souls for a region on the map.");
addSpeedrunDisabledOption("Sun's Song (R+X)", getSettings().game.sunsSong,
@@ -1265,8 +1280,38 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
"Makes Link's roll animation and movement twice as fast.");
addCheat("Fast Spinner", getSettings().game.fastSpinner,
"Speeds up Spinner movement while holding R.");
addCheat("Free Magic Armor", getSettings().game.freeMagicArmor,
"Lets the magic armor work without consuming rupees.");
leftPane.register_control(
leftPane.add_select_button({
.key = "Magic Armor Behavior",
.getValue =
[] {
return kMagicArmorModes[static_cast<u8>(getSettings().game.armorRupeeDrain.getValue())];
},
.isDisabled = [] { return getSettings().game.speedrunMode; },
.isModified =
[] {
return getSettings().game.armorRupeeDrain.getValue() !=
getSettings().game.armorRupeeDrain.getDefaultValue();
},
}),
rightPane, [](Pane& pane) {
for (int i = 0; i < kMagicArmorModes.size(); i++) {
pane.add_button({
.text = kMagicArmorModes[i],
.isSelected =
[i] {
return getSettings().game.armorRupeeDrain.getValue() == static_cast<MagicArmorMode>(i);
},
})
.on_pressed([i] {
mDoAud_seStartMenu(kSoundItemChange);
getSettings().game.armorRupeeDrain.setValue(static_cast<MagicArmorMode>(i));
config::Save();
});
}
pane.add_rml(
"<br/>Control the behavior of the Magic Armor.");
});
addCheat("Invincible Enemies", getSettings().game.invincibleEnemies,
"Prevents enemies from taking damage.");
});