mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-10 04:46:48 -04:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3eeb9a19a1 | |||
| 060f0eb419 | |||
| e491d254f8 | |||
| 84c5729c4e | |||
| e0ab36b7d9 | |||
| d40a30ee13 | |||
| 074b43a089 | |||
| 8e8dc305e6 | |||
| 41389f4a8e | |||
| 8145dec2a1 | |||
| 4089a80a17 | |||
| b772b6d952 | |||
| 42910ab2fd | |||
| f54892b2c2 | |||
| f32e069c4b |
+5
-4
@@ -363,7 +363,8 @@ 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})
|
||||
|
||||
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 MTX_USE_PS=1)
|
||||
# PARTIAL_DEBUG makes debug and release share one struct/vtable ABI so a mod binary loads into either
|
||||
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 MTX_USE_PS=1 PARTIAL_DEBUG=1)
|
||||
|
||||
set(GAME_INCLUDE_DIRS
|
||||
include
|
||||
@@ -474,7 +475,7 @@ set(GAME_DEBUG_FILES
|
||||
set_source_files_properties(
|
||||
${GAME_DEBUG_FILES}
|
||||
PROPERTIES
|
||||
COMPILE_DEFINITIONS "$<$<CONFIG:Debug>:DEBUG=1>;$<$<CONFIG:Debug>:PARTIAL_DEBUG=1>"
|
||||
COMPILE_DEFINITIONS "$<$<CONFIG:Debug>:DEBUG=1>;PARTIAL_DEBUG=1"
|
||||
)
|
||||
|
||||
# game_base is for all other game code files
|
||||
@@ -488,14 +489,14 @@ set(GAME_BASE_FILES
|
||||
set_source_files_properties(
|
||||
${GAME_BASE_FILES}
|
||||
PROPERTIES
|
||||
COMPILE_DEFINITIONS "NDEBUG=1;NDEBUG_DEFINED=1;DEBUG_DEFINED=0;$<$<CONFIG:Debug>:PARTIAL_DEBUG=1>"
|
||||
COMPILE_DEFINITIONS "NDEBUG=1;NDEBUG_DEFINED=1;DEBUG_DEFINED=0;PARTIAL_DEBUG=1"
|
||||
)
|
||||
|
||||
foreach(jsystem_lib IN LISTS JSYSTEM_LIBRARIES)
|
||||
target_compile_definitions(${jsystem_lib} PRIVATE
|
||||
${GAME_COMPILE_DEFS}
|
||||
$<$<CONFIG:Debug>:DEBUG=1>
|
||||
$<$<CONFIG:Debug>:PARTIAL_DEBUG=1>
|
||||
PARTIAL_DEBUG=1
|
||||
)
|
||||
target_include_directories(${jsystem_lib} PRIVATE ${GAME_INCLUDE_DIRS})
|
||||
target_link_libraries(${jsystem_lib} PRIVATE ${GAME_LIBS})
|
||||
|
||||
Vendored
+1
-1
Submodule extern/aurora updated: 9087a409da...e6c3a4409c
@@ -20,7 +20,7 @@ public:
|
||||
|
||||
/* 0x14 */ cM3dGAab mM3dGAab;
|
||||
/* 0x30 */ cBgS_ShdwDraw_Callback mCallbackFun;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x34 */ int field_0x34;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -48,6 +48,8 @@ public:
|
||||
/* 0x1370 */ Z2FxLineMgr mFxLineMgr;
|
||||
#if DEBUG
|
||||
/* 0x13BC */ Z2DebugSys mDebugSys;
|
||||
#elif PARTIAL_DEBUG
|
||||
alignas(Z2DebugSys) u8 mDebugSys[sizeof(Z2DebugSys)];
|
||||
#endif
|
||||
}; // Size: 0x138C
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ public:
|
||||
JAISoundHandle* getMainBgmHandle() { return &mMainBgmHandle; }
|
||||
JAISoundHandle* getSubBgmHandle() { return &mSubBgmHandle; }
|
||||
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
f32 field_0x00_debug;
|
||||
u8 field_0x04_debug;
|
||||
#endif
|
||||
|
||||
@@ -100,13 +100,13 @@ public:
|
||||
bool isForceBattle() { return forceBattle_; }
|
||||
JSUList<Z2CreatureEnemy>* getEnemyList() { return &field_0x0; }
|
||||
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
JSUList<Z2SoundObjBase>* getAllList() { return &allList_; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
/* 0x00 */ JSUList<Z2CreatureEnemy> field_0x0;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x0C */ JSUList<Z2SoundObjBase> allList_;
|
||||
#endif
|
||||
/* 0x0C */ Z2EnemyArea enemyArea_;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
struct Z2SoundStarter;
|
||||
|
||||
class Z2SoundObjBase : public Z2SoundHandles
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
, public JSULink<Z2SoundObjBase>
|
||||
#endif
|
||||
{
|
||||
|
||||
@@ -45,7 +45,7 @@ private:
|
||||
|
||||
class dAttParam_c : public JORReflexible {
|
||||
public:
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x04 */ s8 mHIOChildNo;
|
||||
#endif
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
/* 0x35 */ u8 mAttnCursorDisappearFrames;
|
||||
/* 0x38 */ f32 field_0x38;
|
||||
/* 0x3C */ f32 field_0x3c;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x44 */ s32 mDebugDispPosX;
|
||||
/* 0x48 */ s32 mDebugDispPosY;
|
||||
#endif
|
||||
|
||||
@@ -201,7 +201,7 @@ private:
|
||||
/* 0x02C */ u32 m_flags;
|
||||
/* 0x030 */ cXyz* pm_pos;
|
||||
/* 0x034 */ cXyz* pm_old_pos;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x038 */ cXyz unk_0x38;
|
||||
#endif
|
||||
/* 0x038 */ cXyz* pm_speed;
|
||||
@@ -229,7 +229,7 @@ private:
|
||||
/* 0x0CC */ f32 field_0xcc;
|
||||
/* 0x0D0 */ f32 m_wtr_chk_offset;
|
||||
/* 0x0D4 */ cBgS_PolyInfo* pm_out_poly_info;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x0E4 */ cXyz unk_0xe4;
|
||||
#endif
|
||||
/* 0x0D8 */ f32 field_0xd8;
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ public:
|
||||
|
||||
// /* 0x0000 */ cCcS mCCcS;
|
||||
/* 0x284C */ dCcMassS_Mng mMass_Mng;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x2AD0 */ u8 m_is_mass_all_timer;
|
||||
#endif
|
||||
}; // Size = 0x2AC4
|
||||
|
||||
@@ -1037,7 +1037,7 @@ public:
|
||||
/* 0x1DE09 */ u8 field_0x1de09;
|
||||
/* 0x1DE0A */ u8 field_0x1de0a;
|
||||
/* 0x1DE0B */ u8 mIsDebugMode;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x1DE0C */ OSStopwatch mStopwatch;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
BASE_ROOM5,
|
||||
BASE_DEMO,
|
||||
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
BASE_DEBUG,
|
||||
#endif
|
||||
|
||||
|
||||
@@ -259,7 +259,7 @@ public:
|
||||
/* 0x09B8 */ DUNGEON_LIGHT dungeonlight[8];
|
||||
/* 0x0C18 */ BOSS_LIGHT field_0x0c18[8];
|
||||
/* 0x0D58 */ BOSS_LIGHT field_0x0d58[6];
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x0E48 */ NAVYCHAN navy;
|
||||
/* 0x0E58 */ u8 field_0xe58[0xE68 - 0xE58]; // part of NAVYCHAN?
|
||||
#endif
|
||||
|
||||
@@ -521,13 +521,13 @@ private:
|
||||
/* 0x019 */ u8 field_0x19;
|
||||
/* 0x01A */ u8 field_0x1a;
|
||||
/* 0x01B */ u8 field_0x1b;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x01C */ dPa_simpleEcallBack field_0x1c[48];
|
||||
#else
|
||||
/* 0x01C */ dPa_simpleEcallBack field_0x1c[25];
|
||||
#endif
|
||||
/* 0x210 */ level_c field_0x210;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
u8 mSceneCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -59,7 +59,7 @@ private:
|
||||
/* 0x18 */ JKRHeap* heap;
|
||||
/* 0x1C */ JKRSolidHeap* mDataHeap;
|
||||
/* 0x20 */ void** mRes;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x24 */ int mSize;
|
||||
#endif
|
||||
}; // Size: 0x24
|
||||
|
||||
+4
-1
@@ -1008,7 +1008,7 @@ public:
|
||||
|
||||
static const int ZONE_MAX = 0x20;
|
||||
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x000 */ u8 unk_0x0;
|
||||
/* 0x001 */ char unk_0x1;
|
||||
/* 0x000 */ u8 unk_0x2[0x48 - 0x2];
|
||||
@@ -1029,6 +1029,9 @@ public:
|
||||
/* 0xF30 */ s64 mSaveTotalTime;
|
||||
#if DEBUG
|
||||
/* 0xF80 */ flagFile_c mFlagFile;
|
||||
#elif PARTIAL_DEBUG
|
||||
// flagFile_c's ctor/virtuals are only defined under #if DEBUG (d_save.cpp)
|
||||
alignas(flagFile_c) u8 mFlagFile[sizeof(flagFile_c)];
|
||||
#endif
|
||||
}; // Size: 0xF38
|
||||
|
||||
|
||||
+4
-4
@@ -538,7 +538,7 @@ public:
|
||||
/* vt[86] */ virtual stage_tgsc_class* getDrTg(void) const = 0;
|
||||
/* vt[87] */ virtual void setDoor(stage_tgsc_class*) = 0;
|
||||
/* vt[88] */ virtual stage_tgsc_class* getDoor(void) const = 0;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
virtual void setUnit(void*) = 0;
|
||||
virtual void* getUnit() = 0;
|
||||
#endif
|
||||
@@ -796,7 +796,7 @@ public:
|
||||
virtual stage_tgsc_class* getDrTg(void) const { return mDrTg; }
|
||||
virtual void setDoor(stage_tgsc_class* i_Door) { mDoor = i_Door; }
|
||||
virtual stage_tgsc_class* getDoor(void) const { return mDoor; }
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
virtual void setUnit(void* i_Unit) { mUnit = i_Unit; }
|
||||
virtual void* getUnit() { return mUnit; }
|
||||
#endif
|
||||
@@ -845,7 +845,7 @@ public:
|
||||
/* 0x54 */ stage_tgsc_class* mDrTg;
|
||||
/* 0x58 */ stage_tgsc_class* mDoor;
|
||||
/* 0x5C */ dStage_FloorInfo_c* mFloorInfo;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x60 */ void* mUnit;
|
||||
#endif
|
||||
/* 0x60 */ u16 mPlayerNum;
|
||||
@@ -990,7 +990,7 @@ public:
|
||||
/* vt[86] */ virtual stage_tgsc_class* getDrTg(void) const { return mDrTg; }
|
||||
/* vt[87] */ virtual void setDoor(stage_tgsc_class* i_Door) { mDoor = i_Door; }
|
||||
/* vt[88] */ virtual stage_tgsc_class* getDoor(void) const { return mDoor; }
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
virtual void setUnit(void* i_Unit) {
|
||||
UNUSED(i_Unit);
|
||||
OSReport("stage non unit list data !!\n");
|
||||
|
||||
@@ -97,6 +97,9 @@ public:
|
||||
private:
|
||||
#if DEBUG
|
||||
/* 0x00 */ dVibTest_c mVibTest;
|
||||
#elif PARTIAL_DEBUG
|
||||
// dVibTest_c's ctor/virtuals are only defined under #if DEBUG (d_vibration.cpp)
|
||||
alignas(dVibTest_c) u8 mVibTest[sizeof(dVibTest_c)];
|
||||
#endif
|
||||
|
||||
class {
|
||||
|
||||
+70
-7
@@ -1,9 +1,11 @@
|
||||
#ifndef DUSK_CONFIG_HPP
|
||||
#define DUSK_CONFIG_HPP
|
||||
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <stdexcept>
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include "config_var.hpp"
|
||||
|
||||
namespace dusk::config {
|
||||
@@ -40,7 +42,7 @@ public:
|
||||
[[nodiscard]] virtual nlohmann::json dumpToJson(const ConfigVarBase& cVar) const = 0;
|
||||
};
|
||||
|
||||
template<ConfigValue T>
|
||||
template <ConfigValue T>
|
||||
class ConfigImpl : public ConfigImplBase {
|
||||
// Just downcasting the references...
|
||||
void loadFromJson(ConfigVarBase& cVar, const nlohmann::json& jsonValue) const final {
|
||||
@@ -90,20 +92,28 @@ public:
|
||||
void Register(ConfigVarBase& configVar);
|
||||
|
||||
/**
|
||||
* \brief Indicate that all registrations have happened and everything should lock in.
|
||||
* \brief Unregister a CVar, detaching it from the config system.
|
||||
*
|
||||
* If the CVar carries a user-set value (Value or Speedrun layer), it is stashed as an
|
||||
* unregistered key: Save() keeps writing it, and a later Register() of the same name restores
|
||||
* it through the normal back-fill path. The CVar may be destroyed after this returns.
|
||||
*/
|
||||
void FinishRegistration();
|
||||
void unregister(ConfigVarBase& configVar);
|
||||
|
||||
/**
|
||||
* \brief Load config from the standard user preferences location.
|
||||
*/
|
||||
void LoadFromUserPreferences();
|
||||
void LoadFromFileName(const char* path);
|
||||
void load_from_user_preferences();
|
||||
void load_from_file_name(const char* path);
|
||||
|
||||
void load_arg_override(std::string_view name, std::string_view value);
|
||||
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* \brief Save the config to file.
|
||||
*/
|
||||
void Save();
|
||||
void save();
|
||||
|
||||
/**
|
||||
* \brief Get a registered CVar by name.
|
||||
@@ -124,6 +134,59 @@ void ClearAllActionBindings(int port);
|
||||
*/
|
||||
void EnumerateRegistered(std::function<void(ConfigVarBase&)> callback);
|
||||
|
||||
/**
|
||||
* \brief Type-erased change callback. previousValue points at the value before the mutation
|
||||
* (a `const T*` for a `ConfigVar<T>`) and is valid only for the duration of the call.
|
||||
*/
|
||||
using ChangeCallback = std::function<void(ConfigVarBase& cVar, const void* previousValue)>;
|
||||
|
||||
/**
|
||||
* \brief Token identifying a change subscription. 0 is never a valid token.
|
||||
*/
|
||||
using Subscription = u64;
|
||||
|
||||
/**
|
||||
* \brief Subscribe to changes of the named CVar (registered or not yet registered).
|
||||
*
|
||||
* Fired synchronously on the mutating thread (in practice the game thread) whenever the CVar's
|
||||
* effective value changes at runtime: setValue, override/speedrun setters and clears. Values
|
||||
* applied by config load or launch arguments do *not* notify: loads happen during startup
|
||||
* before the subsystems callbacks push values into are initialized, and each subsystem reads
|
||||
* its initial value itself at its own init. Callbacks may mutate other CVars; a nested
|
||||
* mutation of the same CVar applies but does not re-notify.
|
||||
*/
|
||||
Subscription subscribe(std::string_view name, ChangeCallback callback);
|
||||
|
||||
/**
|
||||
* \brief Typed convenience overload: the callback receives the current and previous values.
|
||||
*/
|
||||
template <ConfigValue T, typename Callback>
|
||||
requires std::invocable<Callback, const T&, const T&> Subscription subscribe(
|
||||
ConfigVar<T>& cVar, Callback&& callback) {
|
||||
return subscribe(cVar.getName(),
|
||||
[&cVar, cb = std::forward<Callback>(callback)](ConfigVarBase&, const void* previousValue) {
|
||||
cb(cVar.getValue(), *static_cast<const T*>(previousValue));
|
||||
});
|
||||
}
|
||||
|
||||
void unsubscribe(Subscription token);
|
||||
|
||||
/**
|
||||
* \brief Register a CVar and attach a change callback in one step.
|
||||
*
|
||||
* Useful for pushing settings into external systems (e.g. aurora) from one place instead of
|
||||
* every UI setter. The callback fires only for runtime changes (see subscribe); the value
|
||||
* loaded from config or launch arguments does not fire it — the external system reads its
|
||||
* initial value itself at its own initialization.
|
||||
*/
|
||||
template <ConfigValue T, typename Callback>
|
||||
requires std::invocable<Callback, const T&, const T&> Subscription Register(
|
||||
ConfigVar<T>& cVar, Callback&& onChange) {
|
||||
auto subscription = subscribe(cVar, std::forward<Callback>(onChange));
|
||||
Register(static_cast<ConfigVarBase&>(cVar));
|
||||
return subscription;
|
||||
}
|
||||
|
||||
template <ConfigValue T>
|
||||
const ConfigImplBase* GetConfigImpl() {
|
||||
static ConfigImpl<T> config;
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
#define DUSK_CONFIG_VAR_HPP
|
||||
|
||||
#include "dolphin/types.h"
|
||||
#include <type_traits>
|
||||
#include <concepts>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
/**
|
||||
* The configuration system.
|
||||
@@ -69,7 +71,7 @@ protected:
|
||||
/**
|
||||
* The name of this CVar, used in the configuration file.
|
||||
*/
|
||||
const char* name;
|
||||
std::string name;
|
||||
|
||||
/**
|
||||
* Whether this CVar has been registered with the global managing logic.
|
||||
@@ -87,8 +89,8 @@ protected:
|
||||
*/
|
||||
const ConfigImplBase* impl;
|
||||
|
||||
ConfigVarBase(const char* name, const ConfigImplBase* impl);
|
||||
virtual ~ConfigVarBase() = default;
|
||||
ConfigVarBase(const ConfigVarBase&) = delete;
|
||||
ConfigVarBase(std::string name, const ConfigImplBase* impl);
|
||||
|
||||
/**
|
||||
* Check that the CVar is registered, aborting if this is not the case.
|
||||
@@ -98,7 +100,22 @@ protected:
|
||||
abort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether any change subscriber (see config::subscribe) is attached to this CVar's name.
|
||||
*/
|
||||
[[nodiscard]] bool has_subscribers() const;
|
||||
|
||||
/**
|
||||
* Notify change subscribers (see config::subscribe) that the effective value of this CVar
|
||||
* changed. Called by mutators after the change has been applied; previousValue points at
|
||||
* the old value (a `const T*` for a `ConfigVar<T>`), valid only for the duration of the
|
||||
* call.
|
||||
*/
|
||||
void notify_changed(const void* previousValue);
|
||||
|
||||
public:
|
||||
virtual ~ConfigVarBase();
|
||||
|
||||
/**
|
||||
* Get the name of this CVar, used in the configuration file.
|
||||
*/
|
||||
@@ -121,6 +138,7 @@ public:
|
||||
* This is necessary to make it legal to access.
|
||||
*/
|
||||
void markRegistered();
|
||||
void unmarkRegistered();
|
||||
|
||||
/**
|
||||
* Clear a speedrun-mode override if one is active on this CVar.
|
||||
@@ -155,6 +173,7 @@ template <typename T>
|
||||
concept ConfigValue =
|
||||
!std::is_const_v<T>
|
||||
&& !std::is_volatile_v<T>
|
||||
&& std::equality_comparable<T>
|
||||
&& (std::is_same_v<T, bool>
|
||||
|| ConfigValueInteger<T>
|
||||
|| std::is_same_v<T, f32>
|
||||
@@ -166,6 +185,9 @@ concept ConfigValue =
|
||||
template <ConfigValue T>
|
||||
const ConfigImplBase* GetConfigImpl();
|
||||
|
||||
template <ConfigValue T>
|
||||
class ConfigImpl;
|
||||
|
||||
template <typename T>
|
||||
struct ConfigEnumRange {
|
||||
static constexpr auto min = std::numeric_limits<std::underlying_type_t<T>>::min();
|
||||
@@ -192,10 +214,12 @@ public:
|
||||
* @param arg Arguments to forward to construct the default value.
|
||||
*/
|
||||
template <typename... Args>
|
||||
ConfigVar(const char* name, Args&&... arg)
|
||||
: ConfigVarBase(name, GetConfigImpl<T>()), defaultValue(std::forward<Args>(arg)...),
|
||||
ConfigVar(std::string name, Args&&... arg)
|
||||
: ConfigVarBase(std::move(name), GetConfigImpl<T>()), defaultValue(std::forward<Args>(arg)...),
|
||||
value(), overrideValue() {}
|
||||
|
||||
ConfigVar(ConfigVar const&) = delete;
|
||||
|
||||
/**
|
||||
* \brief Get the current value of the CVar.
|
||||
*
|
||||
@@ -234,6 +258,7 @@ public:
|
||||
*/
|
||||
void setValue(T newValue, bool replaceOverride = true) {
|
||||
checkRegistered();
|
||||
const auto previous = previous_for_notify();
|
||||
value = std::move(newValue);
|
||||
|
||||
if (replaceOverride) {
|
||||
@@ -242,6 +267,7 @@ public:
|
||||
} else if (layer != ConfigVarLayer::Override) {
|
||||
layer = ConfigVarLayer::Value;
|
||||
}
|
||||
notify_if_changed(previous);
|
||||
}
|
||||
|
||||
operator const T&() {
|
||||
@@ -258,8 +284,10 @@ public:
|
||||
*/
|
||||
void setOverrideValue(T newValue) {
|
||||
checkRegistered();
|
||||
const auto previous = previous_for_notify();
|
||||
overrideValue = std::move(newValue);
|
||||
layer = ConfigVarLayer::Override;
|
||||
notify_if_changed(previous);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,25 +301,31 @@ public:
|
||||
void setSpeedrunValue(T newValue) {
|
||||
checkRegistered();
|
||||
if (layer != ConfigVarLayer::Override) {
|
||||
const auto previous = previous_for_notify();
|
||||
priorLayer = layer;
|
||||
overrideValue = std::move(newValue);
|
||||
layer = ConfigVarLayer::Speedrun;
|
||||
notify_if_changed(previous);
|
||||
}
|
||||
}
|
||||
|
||||
void clearOverride() {
|
||||
checkRegistered();
|
||||
if (layer == ConfigVarLayer::Override) {
|
||||
const auto previous = previous_for_notify();
|
||||
overrideValue = {};
|
||||
layer = ConfigVarLayer::Value;
|
||||
notify_if_changed(previous);
|
||||
}
|
||||
}
|
||||
|
||||
void clearSpeedrunOverride() override {
|
||||
checkRegistered();
|
||||
if (layer == ConfigVarLayer::Speedrun) {
|
||||
const auto previous = previous_for_notify();
|
||||
overrideValue = {};
|
||||
layer = priorLayer;
|
||||
notify_if_changed(previous);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,6 +339,48 @@ public:
|
||||
const ConfigVarLayer effectiveLayer = (layer == ConfigVarLayer::Speedrun) ? priorLayer : layer;
|
||||
return effectiveLayer == ConfigVarLayer::Default ? defaultValue : value;
|
||||
}
|
||||
|
||||
private:
|
||||
// The config loader applies values through the silent load_* methods below.
|
||||
friend class ConfigImpl<T>;
|
||||
|
||||
/**
|
||||
* Copy of the effective value before a mutation, taken only when someone is subscribed.
|
||||
*/
|
||||
[[nodiscard]] std::optional<T> previous_for_notify() const {
|
||||
return has_subscribers() ? std::optional<T>{getValue()} : std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify subscribers if the effective value actually changed across a mutation.
|
||||
*/
|
||||
void notify_if_changed(const std::optional<T>& previous) {
|
||||
if (previous.has_value() && !(getValue() == *previous)) {
|
||||
notify_changed(&*previous);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setValue(newValue, false) without notifying change subscribers. Used when loading config:
|
||||
* loads happen during startup before the subsystems change callbacks push values into are
|
||||
* initialized, and each subsystem applies the loaded value itself at its own init.
|
||||
*/
|
||||
void load_value(T newValue) {
|
||||
checkRegistered();
|
||||
value = std::move(newValue);
|
||||
if (layer != ConfigVarLayer::Override) {
|
||||
layer = ConfigVarLayer::Value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setOverrideValue without notifying change subscribers (see load_value).
|
||||
*/
|
||||
void load_override_value(T newValue) {
|
||||
checkRegistered();
|
||||
overrideValue = std::move(newValue);
|
||||
layer = ConfigVarLayer::Override;
|
||||
}
|
||||
};
|
||||
|
||||
using ActionBindConfigVar = ConfigVar<int>;
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
namespace dusk::mouse {
|
||||
void read();
|
||||
void getAimDeltas(float& out_yaw, float& out_pitch);
|
||||
void getCameraDeltas(float& out_yaw, float& out_pitch);
|
||||
void get_aim_deltas(float& out_yaw, float& out_pitch);
|
||||
void get_camera_deltas(float& out_yaw, float& out_pitch);
|
||||
void handle_event(const SDL_Event& event) noexcept;
|
||||
void onFocusLost();
|
||||
void onFocusGained();
|
||||
void on_focus_lost();
|
||||
void on_focus_gained();
|
||||
} // namespace dusk::mouse
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
|
||||
namespace dusk {
|
||||
|
||||
using namespace config;
|
||||
using config::ConfigVar;
|
||||
using config::ActionBindConfigVar;
|
||||
|
||||
enum class BloomMode : int {
|
||||
Off = 0,
|
||||
|
||||
@@ -36,7 +36,7 @@ typedef struct node_create_request {
|
||||
/* 0x58 */ s16 name;
|
||||
/* 0x5C */ void* data;
|
||||
/* 0x60 */ s16 unk_0x60;
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x64 */ int unk_0x64;
|
||||
/* 0x68 */ int unk_0x68;
|
||||
#endif
|
||||
|
||||
@@ -11,13 +11,13 @@ class mDoAud_zelAudio_c : public Z2AudioMgr {
|
||||
public:
|
||||
void reset();
|
||||
mDoAud_zelAudio_c() {
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
setMode(2);
|
||||
#endif
|
||||
}
|
||||
~mDoAud_zelAudio_c() {}
|
||||
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
u8 getMode() { return field_0x13bd; }
|
||||
void setMode(u8 mode) { field_0x13bd = mode; }
|
||||
|
||||
|
||||
@@ -35,6 +35,11 @@ public:
|
||||
/* 0x4 */ s8 mNo;
|
||||
/* 0x5 */ u8 mCount;
|
||||
#else
|
||||
#if PARTIAL_DEBUG
|
||||
// Initialized here since the DEBUG ctor doesn't run.
|
||||
/* 0x4 */ s8 mNo = -1;
|
||||
/* 0x5 */ u8 mCount = 0;
|
||||
#endif
|
||||
virtual ~mDoHIO_entry_c() {}
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -12,12 +12,23 @@ struct JORNodeEvent;
|
||||
class JORMContext;
|
||||
class JORServer;
|
||||
|
||||
// NOTE (stable game ABI): these classes stay non-polymorphic outside DEBUG
|
||||
// on purpose. Making them polymorphic under PARTIAL_DEBUG would give every one of the ~250
|
||||
// derived HIO classes a vptr and turn their plain `void genMessage(JORMContext*);`
|
||||
// declarations into implicit virtual overrides whose definitions are #if DEBUG-gated; every
|
||||
// instantiated one then fails to link (missing vtable). Closure types shared with DEBUG TUs
|
||||
// either declare their own unconditional virtuals (vptr in all TUs anyway) or add a
|
||||
// PARTIAL_DEBUG-only virtual dtor for vptr parity (see dAttParam_c).
|
||||
class JOREventListener {
|
||||
public:
|
||||
#if DEBUG
|
||||
JOREventListener() {}
|
||||
#if TARGET_PC
|
||||
virtual void listenPropertyEvent(const JORPropertyEvent*) {}
|
||||
#else
|
||||
virtual void listenPropertyEvent(const JORPropertyEvent*) = 0;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
class JORReflexible : public JOREventListener {
|
||||
@@ -30,7 +41,11 @@ public:
|
||||
virtual void listenPropertyEvent(const JORPropertyEvent*);
|
||||
virtual void listen(u32, const JOREvent*);
|
||||
virtual void genObjectInfo(const JORGenEvent*);
|
||||
#if TARGET_PC
|
||||
virtual void genMessage(JORMContext*) {}
|
||||
#else
|
||||
virtual void genMessage(JORMContext*) = 0;
|
||||
#endif
|
||||
virtual void listenNodeEvent(const JORNodeEvent*);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -314,7 +314,7 @@ public:
|
||||
>
|
||||
{
|
||||
TIterator_data_(const TFunctionValue_list_parameter& rParent, const f32* value) {
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
pOwn_ = &rParent;
|
||||
#endif
|
||||
pf_ = value;
|
||||
@@ -372,7 +372,7 @@ public:
|
||||
return (r1.pf_ - r2.pf_) / suData_size;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x00 */ const TFunctionValue_list_parameter* pOwn_;
|
||||
#endif
|
||||
/* 0x00 */ const f32* pf_;
|
||||
@@ -425,7 +425,7 @@ public:
|
||||
>
|
||||
{
|
||||
TIterator_data_(const TFunctionValue_hermite& rParent, const f32* value) {
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
pOwn_ = &rParent;
|
||||
#endif
|
||||
pf_ = value;
|
||||
@@ -491,7 +491,7 @@ public:
|
||||
return (r1.pf_ - r2.pf_) / r1.uSize_;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
/* 0x00 */ const TFunctionValue_hermite* pOwn_;
|
||||
/* 0x04 */ const f32* pf_;
|
||||
/* 0x08 */ u32 uSize_;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "os_report.h"
|
||||
|
||||
Z2SoundObjBase::Z2SoundObjBase()
|
||||
#if DEBUG
|
||||
#if PARTIAL_DEBUG || DEBUG
|
||||
: JSULink<Z2SoundObjBase>(this)
|
||||
#endif
|
||||
{
|
||||
|
||||
@@ -122,18 +122,11 @@ BOOL daAlink_c::setBodyAngleToCamera() {
|
||||
var_f31 /= dComIfGp_getCameraZoomScale(field_0x317c);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.enableMouseAim && checkAimInputContext()) {
|
||||
sp8 = mBodyAngle.x;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
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) 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)));
|
||||
|
||||
if (checkNotItemSinkLimit() && sp8 > 0 && sp8 > mBodyAngle.x) {
|
||||
sp8 = mBodyAngle.x;
|
||||
}
|
||||
if (checkNotItemSinkLimit() && sp8 > 0 && sp8 > mBodyAngle.x) {
|
||||
sp8 = mBodyAngle.x;
|
||||
}
|
||||
} else {
|
||||
sp8 = mBodyAngle.x;
|
||||
@@ -156,7 +149,7 @@ BOOL daAlink_c::setBodyAngleToCamera() {
|
||||
f32 final_yaw = 0.f;
|
||||
f32 final_pitch = 0.f;
|
||||
if (dusk::getSettings().game.enableMouseAim) {
|
||||
dusk::mouse::getAimDeltas(final_yaw, final_pitch);
|
||||
dusk::mouse::get_aim_deltas(final_yaw, final_pitch);
|
||||
}
|
||||
if (dusk::getSettings().game.enableGyroAim) {
|
||||
f32 gyro_yaw = 0.f;
|
||||
|
||||
+1
-1
@@ -7716,7 +7716,7 @@ bool dCamera_c::freeCamera() {
|
||||
|
||||
f32 yaw_rad = 0.0f;
|
||||
f32 pitch_rad = 0.0f;
|
||||
dusk::mouse::getCameraDeltas(yaw_rad, pitch_rad);
|
||||
dusk::mouse::get_camera_deltas(yaw_rad, pitch_rad);
|
||||
if (dusk::getSettings().game.enableMouseCamera && (yaw_rad != 0.0f || pitch_rad != 0.0f) &&
|
||||
!dComIfGp_checkCameraAttentionStatus(dComIfGp_getPlayerCameraID(0), 0x8))
|
||||
{
|
||||
|
||||
+1
-1
@@ -118,7 +118,7 @@ static int dKyeff_Create(kankyo_class* i_this) {
|
||||
|
||||
if (strcmp(dComIfGp_getStartStageName(), "Name") == 0) {
|
||||
camera_process_class* camera = dComIfGp_getCamera(0);
|
||||
OSTime time = OSGetTime();
|
||||
OSTime time = DUSK_IF_ELSE(OSGetSystemTime(), OSGetTime());
|
||||
OSTicksToCalendarTime(time, &calendar);
|
||||
|
||||
g_env_light.global_wind_influence.vec.x = 1.0f;
|
||||
|
||||
+6
-1
@@ -1640,7 +1640,7 @@ void dMap_c::_move(f32 i_centerX, f32 i_centerZ, int i_roomNo, f32 param_3) {
|
||||
|
||||
mCenterX += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -mPackX :) mPackX;
|
||||
mCenterZ -= mPackZ;
|
||||
mCenterX += field_0x64;
|
||||
mCenterX += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -field_0x64 : ) field_0x64;
|
||||
mCenterZ += mPackPlusZ;
|
||||
}
|
||||
|
||||
@@ -1649,6 +1649,8 @@ void dMap_c::_move(f32 i_centerX, f32 i_centerZ, int i_roomNo, f32 param_3) {
|
||||
{
|
||||
#if DEBUG
|
||||
field_0x64 = 33830.0f;
|
||||
#elif TARGET_PC
|
||||
field_0x64 = dusk::getSettings().game.enableMirrorMode ? 33830.0f : 0.0f;
|
||||
#else
|
||||
field_0x64 = 0.0f;
|
||||
#endif
|
||||
@@ -1657,6 +1659,9 @@ void dMap_c::_move(f32 i_centerX, f32 i_centerZ, int i_roomNo, f32 param_3) {
|
||||
f32 temp = (field_0x58 * (f32)(field_0x74 + 4)) * 0.5f;
|
||||
#if DEBUG
|
||||
mRightEdgePlus = -(((dMpath_c::getMinZ() - (-127103.67f)) - temp) / field_0x58);
|
||||
|
||||
#elif TARGET_PC
|
||||
mRightEdgePlus = dusk::getSettings().game.enableMirrorMode ? -(((dMpath_c::getMinX() - (-127103.67f)) - temp) / field_0x58) : 0.0f;
|
||||
#else
|
||||
mRightEdgePlus = 0.0f;
|
||||
#endif
|
||||
|
||||
+24
-1
@@ -914,6 +914,20 @@ void dMenu_DmapBg_c::dMapBgWide() {
|
||||
void dMenu_DmapBg_c::draw() {
|
||||
#if TARGET_PC
|
||||
dMapBgWide();
|
||||
|
||||
static bool prevMirror = false; // default state of panes is not mirrored
|
||||
if(prevMirror != dusk::getSettings().game.enableMirrorMode) {
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
static_cast<J2DPicture*>(mFloorScreen->search(MULTI_CHAR('rink')))->setMirror(J2DMirror_X);
|
||||
static_cast<J2DPicture*>(mBaseScreen->search(MULTI_CHAR('map000')))->setMirror(J2DMirror_X);
|
||||
}
|
||||
else {
|
||||
static_cast<J2DPicture*>(mFloorScreen->search(MULTI_CHAR('rink')))->setMirror(MIRROR0);
|
||||
static_cast<J2DPicture*>(mBaseScreen->search(MULTI_CHAR('map000')))->setMirror(MIRROR0);
|
||||
}
|
||||
|
||||
prevMirror = dusk::getSettings().game.enableMirrorMode;
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 scissor_left;
|
||||
@@ -960,6 +974,15 @@ void dMenu_DmapBg_c::draw() {
|
||||
mpBackTexture->setAlpha(dVar17 * (field_0xdbc * field_0xd9c));
|
||||
|
||||
f32 local_28c = mpBackTexture->getBounds().i.x;
|
||||
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
CPaneMgr mgr;
|
||||
Vec local_94 = mgr.getGlobalVtxCenter(mMapPane, true, 0);
|
||||
local_28c = (local_94.x * 2.0f) - (local_28c + 0.5f * mpBackTexture->getWidth()) - 0.5f * mpBackTexture->getWidth();
|
||||
}
|
||||
#endif
|
||||
|
||||
mpBackTexture->setBlackWhite(color_black, color_white);
|
||||
mpBackTexture->draw(local_28c, field_0xd94 + mpBackTexture->getBounds().i.y, mpBackTexture->getWidth(),
|
||||
mpBackTexture->getHeight(),
|
||||
@@ -1981,7 +2004,7 @@ void dMenu_Dmap_c::mapControl() {
|
||||
f32 temp_f28 = (var_f29 / 100.0f) * var_f31;
|
||||
f32 sp18 = temp_f28 * cM_ssin(stick_angle);
|
||||
f32 sp14 = temp_f28 * cM_scos(stick_angle);
|
||||
mMapCtrl->setPlusZoomCenterX(sp18);
|
||||
mMapCtrl->setPlusZoomCenterX(IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -sp18 :) sp18);
|
||||
mMapCtrl->setPlusZoomCenterZ(sp14);
|
||||
}
|
||||
|
||||
|
||||
@@ -359,14 +359,7 @@ f32 dMenu_StageMapCtrl_c::getPixelStageSizeZ() const {
|
||||
|
||||
f32 dMenu_StageMapCtrl_c::getPixelCenterX() const {
|
||||
f32 var_f31 = dMpath_c::getCenterX();
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.enableMirrorMode) {
|
||||
return (1.0f / field_0xbc) * (field_0x9c + var_f31);
|
||||
}
|
||||
else return (1.0f / field_0xbc) * (field_0x9c - var_f31);
|
||||
#else
|
||||
return (1.0f / field_0xbc) * (field_0x9c - var_f31);
|
||||
#endif
|
||||
}
|
||||
|
||||
f32 dMenu_StageMapCtrl_c::getPixelCenterZ() const {
|
||||
@@ -425,18 +418,7 @@ inline static f32 rightModeCnvPos(f32 param_0) {
|
||||
void dMenu_StageMapCtrl_c::cnvPosTo2Dpos(f32 param_0, f32 param_1, f32* param_2,
|
||||
f32* param_3) const {
|
||||
if (param_2 != NULL) {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.enableMirrorMode) {
|
||||
*param_2 =
|
||||
(0.5f * field_0x94) + rightModeCnvPos((1.0f / field_0xbc) * (field_0x9c + param_0));
|
||||
} else {
|
||||
*param_2 =
|
||||
(0.5f * field_0x94) + rightModeCnvPos((1.0f / field_0xbc) * (param_0 - field_0x9c));
|
||||
}
|
||||
#else
|
||||
*param_2 = (0.5f * field_0x94) + rightModeCnvPos((1.0f / field_0xbc) * (param_0 - field_0x9c));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (param_3 != NULL) {
|
||||
@@ -933,8 +915,7 @@ void dMenu_StageMapCtrl_c::move() {
|
||||
|
||||
void dMenu_DmapMapCtrl_c::draw() {
|
||||
if (field_0xef != 0) {
|
||||
setPos(field_0xeb, field_0xec,
|
||||
IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -field_0x9c :) field_0x9c,
|
||||
setPos(field_0xeb, field_0xec, field_0x9c,
|
||||
field_0xa0, field_0xbc, true, field_0xd8);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-15
@@ -931,17 +931,8 @@ void dMenu_Fmap_c::region_map_proc() {
|
||||
mpDraw2DBack->regionMapMove(mpStick);
|
||||
int stage_no, room_no;
|
||||
|
||||
#if TARGET_PC
|
||||
f32 arrow_pos_x = mpDraw2DBack->getArrowPos2DX();
|
||||
if (dusk::getSettings().game.enableMirrorMode) {
|
||||
arrow_pos_x = mpDraw2DBack->getMirrorPosX(arrow_pos_x, 0.0f);
|
||||
}
|
||||
|
||||
f32 pos_x = arrow_pos_x - mDoGph_gInf_c::getMinXF() - mDoGph_gInf_c::getWidthF() * 0.5f;
|
||||
#else
|
||||
f32 pos_x = mpDraw2DBack->getArrowPos2DX() - mDoGph_gInf_c::getMinXF()
|
||||
- mDoGph_gInf_c::getWidthF() * 0.5f;
|
||||
#endif
|
||||
f32 pos_y = mpDraw2DBack->getArrowPos2DY() - mDoGph_gInf_c::getHeightF() * 0.5f;
|
||||
|
||||
mpMenuFmapMap->getPointStagePathInnerNo(getNowFmapRegionData(), pos_x, pos_y,
|
||||
@@ -2486,12 +2477,6 @@ void dMenu_Fmap_c::portalWarpMapMove(STControl* i_stick) {
|
||||
f32 arrow_y = mpDraw2DBack->getArrowPos2DY();
|
||||
u8 uVar6 = 0xff;
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.enableMirrorMode) {
|
||||
arrow_x = mpDraw2DBack->getMirrorPosX(arrow_x, 0.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
for (int i = 0; i < portal_dat->mCount; i++) {
|
||||
if (portals[i].mRegionNo == mpDraw2DBack->getRegionCursor() + 1
|
||||
@@ -2561,6 +2546,11 @@ void dMenu_Fmap_c::drawIcon(f32 param_0, bool param_1) {
|
||||
if (mProcess == PROC_PORTAL_DEMO1) {
|
||||
is_portal_demo1 = 1;
|
||||
}
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
angle = 0x10000 - angle;
|
||||
}
|
||||
#endif
|
||||
mpDraw2DBack->setIcon2DPos(0x11, stage_name, pos.x, pos.z, cM_sht2d(angle),
|
||||
is_portal_demo1, param_1);
|
||||
|
||||
@@ -2649,6 +2639,11 @@ void dMenu_Fmap_c::drawPlayEnterIcon() {
|
||||
angle = dComIfGs_getPlayerFieldLastStayAngleY();
|
||||
SAFE_STRCPY(stage_name, dComIfGs_getPlayerFieldLastStayName());
|
||||
}
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
angle = 0x10000 - angle;
|
||||
}
|
||||
#endif
|
||||
mpDraw2DBack->setIcon2DPos(0x15, stage_name, pos.x, pos.z, cM_sht2d(angle), 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
+63
-17
@@ -1013,11 +1013,6 @@ void dMenu_Fmap2DBack_c::allmap_move2(STControl* param_0) {
|
||||
f32 stickValue = param_0->getValueStick();
|
||||
if (stickValue >= spC) {
|
||||
s16 angle = param_0->getAngleStick();
|
||||
#ifdef TARGET_PC
|
||||
if (dusk::getSettings().game.enableMirrorMode) {
|
||||
angle = -angle;
|
||||
}
|
||||
#endif
|
||||
f32 local_68 = (mTexMaxX - mTexMinX);
|
||||
f32 zoomRate = local_68 / getAllMapZoomRate();
|
||||
f32 sp24;
|
||||
@@ -1031,6 +1026,11 @@ void dMenu_Fmap2DBack_c::allmap_move2(STControl* param_0) {
|
||||
f32 delta_y = speed * cM_ssin(angle);
|
||||
f32 delta_x = speed * cM_scos(angle);
|
||||
|
||||
#ifdef TARGET_PC
|
||||
if (dusk::getSettings().game.enableMirrorMode) {
|
||||
delta_y = -delta_y;
|
||||
}
|
||||
#endif
|
||||
control_xpos = control_xpos + delta_y;
|
||||
control_ypos = control_ypos + delta_x;
|
||||
}
|
||||
@@ -1473,6 +1473,12 @@ void dMenu_Fmap2DBack_c::worldGridDraw() {
|
||||
f32 dVar8 = -mStageTransZ;
|
||||
calcAllMapPos2D(dVar9, dVar8, &local_74, &local_78);
|
||||
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
local_74 = getMirrorPosX(local_74, 0.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
J2DDrawLine(local_74, mDoGph_gInf_c::getMinYF(), local_74,
|
||||
mDoGph_gInf_c::getMinYF() + mDoGph_gInf_c::getHeightF(),
|
||||
JUtility::TColor(255, 255, 255, 255), 6);
|
||||
@@ -1481,6 +1487,11 @@ void dMenu_Fmap2DBack_c::worldGridDraw() {
|
||||
while (true) {
|
||||
calcAllMapPos2D(xPos, dVar8, &local_74, &local_78);
|
||||
if (local_74 >= getMapScissorAreaLX()) {
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
local_74 = getMirrorPosX(local_74, 0.0f);
|
||||
}
|
||||
#endif
|
||||
J2DDrawLine(local_74, mDoGph_gInf_c::getMinYF(), local_74,
|
||||
mDoGph_gInf_c::getMinYF() + mDoGph_gInf_c::getHeightF(),
|
||||
JUtility::TColor(255, 255, 255, 255), 6);
|
||||
@@ -1542,6 +1553,12 @@ void dMenu_Fmap2DBack_c::regionGridDraw() {
|
||||
f32 dVar8 = mRegionOriginZ[mRegionCursor] - mStageTransZ;
|
||||
calcAllMapPos2D(dVar9, dVar8, &local_74, &local_78);
|
||||
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
local_74 = getMirrorPosX(local_74, 0.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
J2DDrawLine(local_74, mDoGph_gInf_c::getMinYF(), local_74,
|
||||
mDoGph_gInf_c::getMinYF() + mDoGph_gInf_c::getHeightF(),
|
||||
JUtility::TColor(180, 0, 0, 255), 6);
|
||||
@@ -1550,6 +1567,12 @@ void dMenu_Fmap2DBack_c::regionGridDraw() {
|
||||
while (true) {
|
||||
calcAllMapPos2D(xPos, dVar8, &local_74, &local_78);
|
||||
if (local_74 >= getMapScissorAreaLX()) {
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
local_74 = getMirrorPosX(local_74, 0.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
J2DDrawLine(local_74, mDoGph_gInf_c::getMinYF(), local_74,
|
||||
mDoGph_gInf_c::getMinYF() + mDoGph_gInf_c::getHeightF(),
|
||||
JUtility::TColor(180, 0, 0, 255), 6);
|
||||
@@ -1612,6 +1635,12 @@ void dMenu_Fmap2DBack_c::worldOriginDraw() {
|
||||
f32 local_44, local_48;
|
||||
calcAllMapPos2D(-mStageTransX, -mStageTransZ, &local_44, &local_48);
|
||||
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
local_44 = getMirrorPosX(local_44, 0.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
J2DDrawLine(mDoGph_gInf_c::getMinXF(), local_48 - local_44 + mDoGph_gInf_c::getMinXF(),
|
||||
mDoGph_gInf_c::getMinXF() + mDoGph_gInf_c::getWidthF(),
|
||||
local_48 - local_44 + (mDoGph_gInf_c::getMinXF() + mDoGph_gInf_c::getWidthF()),
|
||||
@@ -1646,6 +1675,13 @@ void dMenu_Fmap2DBack_c::scrollAreaDraw() {
|
||||
calcAllMapPos2D(x_min - mStageTransX, z_min - mStageTransZ, &local_4c, &local_50);
|
||||
calcAllMapPos2D(x_max - mStageTransX, z_max - mStageTransZ, &local_54, &local_58);
|
||||
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
local_4c = getMirrorPosX(local_4c, 0.0f);
|
||||
local_54 = getMirrorPosX(local_54, 0.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
J2DDrawLine(local_4c, local_50, local_4c, local_58,
|
||||
JUtility::TColor(255, 255, 255, 255), 6);
|
||||
J2DDrawLine(local_54, local_50, local_54, local_58,
|
||||
@@ -1666,6 +1702,11 @@ void dMenu_Fmap2DBack_c::regionOriginDraw() {
|
||||
f32 center_x, center_y;
|
||||
calcAllMapPos2D(mRegionOriginX[i] - mStageTransX, mRegionOriginZ[i] - mStageTransZ,
|
||||
¢er_x, ¢er_y);
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
center_x = getMirrorPosX(center_x - 3.0f, 3.0f);
|
||||
}
|
||||
#endif
|
||||
J2DFillBox(center_x - 3.0f, center_y - 3.0f, 6.0f, 6.0f, JUtility::TColor(255, 0, 0, 255));
|
||||
}
|
||||
}
|
||||
@@ -1683,6 +1724,11 @@ void dMenu_Fmap2DBack_c::stageOriginDraw() {
|
||||
f32 v1 = mRegionOriginX[mRegionCursor] + stage_data[i].mOffsetX - mStageTransX;
|
||||
f32 v2 = mRegionOriginZ[mRegionCursor] + stage_data[i].mOffsetZ - mStageTransZ;
|
||||
calcAllMapPos2D(v1, v2, ¢er_x, ¢er_y);
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
center_x = getMirrorPosX(center_x - 3.0f, 3.0f);
|
||||
}
|
||||
#endif
|
||||
J2DFillBox(center_x - 3.0f, center_y - 3.0f, 6.0f, 6.0f,
|
||||
JUtility::TColor(0, 0, 255, 255));
|
||||
}
|
||||
@@ -1915,11 +1961,6 @@ void dMenu_Fmap2DBack_c::regionMapMove(STControl* i_stick) {
|
||||
f32 stick_value = i_stick->getValueStick();
|
||||
if (stick_value >= slow_bound) {
|
||||
s16 angle = i_stick->getAngleStick();
|
||||
#ifdef TARGET_PC
|
||||
if (dusk::getSettings().game.enableMirrorMode) {
|
||||
angle = -angle;
|
||||
}
|
||||
#endif
|
||||
f32 local_68 = mTexMaxX - mTexMinX;
|
||||
f32 spot_zoom = getSpotMapZoomRate();
|
||||
f32 region_zoom = getRegionMapZoomRate(mRegionCursor);
|
||||
@@ -1934,7 +1975,7 @@ void dMenu_Fmap2DBack_c::regionMapMove(STControl* i_stick) {
|
||||
f32 speed = base_speed / 100.0f * local_78;
|
||||
f32 speed_y = speed * cM_ssin(angle);
|
||||
f32 speed_x = speed * cM_scos(angle);
|
||||
control_xpos += speed_y;
|
||||
control_xpos += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -speed_y :) speed_y;
|
||||
control_ypos += speed_x;
|
||||
}
|
||||
}
|
||||
@@ -1990,11 +2031,6 @@ void dMenu_Fmap2DBack_c::stageMapMove(STControl* i_stick, u8 param_1, bool param
|
||||
if (stick_value >= slow_bound && param_2 && field_0x1238 != 2) {
|
||||
bVar6 = true;
|
||||
s16 angle = i_stick->getAngleStick();
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.enableMirrorMode) {
|
||||
angle = -angle;
|
||||
}
|
||||
#endif
|
||||
f32 local_68 = mTexMaxX - mTexMinX;
|
||||
f32 spot_zoom = getSpotMapZoomRate();
|
||||
f32 region_zoom = getRegionMapZoomRate(mRegionCursor);
|
||||
@@ -2009,7 +2045,7 @@ void dMenu_Fmap2DBack_c::stageMapMove(STControl* i_stick, u8 param_1, bool param
|
||||
f32 speed = base_speed / 100.0f * local_78;
|
||||
f32 speed_x = speed * cM_ssin(angle);
|
||||
f32 speed_z = speed * cM_scos(angle);
|
||||
mStageTransX += speed_x;
|
||||
mStageTransX += IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -speed_x :) speed_x;
|
||||
mStageTransZ += speed_z;
|
||||
} else if (!param_2) {
|
||||
return;
|
||||
@@ -2103,6 +2139,11 @@ void dMenu_Fmap2DBack_c::drawDebugStageArea() {
|
||||
if (stage_no >= 0) {
|
||||
f32 v = i + mDoGph_gInf_c::getMinXF();
|
||||
f32 v2 = j;
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
v = getMirrorPosX(v - 3.0f, 3.0f);
|
||||
}
|
||||
#endif
|
||||
J2DFillBox(v - 3.0f, v2 - 3.0f, 6.0f, 6.0f, colors[stage_no % 6]);
|
||||
}
|
||||
}
|
||||
@@ -2138,6 +2179,11 @@ void dMenu_Fmap2DBack_c::drawDebugRegionArea() {
|
||||
mRegionMapSizeX[region] * mZoom, mRegionMapSizeY[region] * mZoom,
|
||||
mpAreaTex[region]->getTexture(0)->getTexInfo());
|
||||
if (u) {
|
||||
#if TARGET_PC
|
||||
if(dusk::getSettings().game.enableMirrorMode) {
|
||||
pos_x = getMirrorPosX(pos_x - 3.0f, 3.0f);
|
||||
}
|
||||
#endif
|
||||
J2DFillBox(pos_x - 3.0f, pos_y - 3.0f, 6.0f, 6.0f, colors[region]);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -394,21 +394,8 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4
|
||||
icon_size_y *= _c7c;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
f32 rotation = mIconInfo[info_idx].rotation;
|
||||
if (dusk::getSettings().game.enableMirrorMode &&
|
||||
(mIconInfo[info_idx].icon_no == ICON_LINK_e ||
|
||||
mIconInfo[info_idx].icon_no == ICON_LINK_ENTER_e))
|
||||
{
|
||||
rotation = -rotation;
|
||||
}
|
||||
|
||||
mPictures[mIconInfo[info_idx].icon_no]->rotate(icon_size_x / 2, icon_size_y / 2, ROTATE_Z,
|
||||
rotation);
|
||||
#else
|
||||
mPictures[mIconInfo[info_idx].icon_no]->rotate(icon_size_x / 2, icon_size_y / 2, ROTATE_Z,
|
||||
mIconInfo[info_idx].rotation);
|
||||
#endif
|
||||
|
||||
if (mIconInfo[info_idx].icon_no == ICON_LIGHT_DROP_e) {
|
||||
mPictures[mIconInfo[info_idx].icon_no]->setAlpha((180.0f * _c80) / 255.0f);
|
||||
@@ -423,10 +410,15 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4
|
||||
}
|
||||
|
||||
f32 pos_x = i_posX + (icon_pos_x - (icon_size_x / 2));
|
||||
bool r4 = false;
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.enableMirrorMode) {
|
||||
pos_x = getMirrorCenterPosX(i_posX + (icon_pos_x - (icon_size_x / 2)), icon_size_x / 2);
|
||||
}
|
||||
|
||||
if(mIconInfo[info_idx].icon_no == ICON_GOLD_WOLF_e) {
|
||||
r4 = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
mPictures[mIconInfo[info_idx].icon_no]->draw(pos_x, (i_posY + (icon_pos_y - icon_size_y / 2)),
|
||||
@@ -435,7 +427,7 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4
|
||||
if (mIconInfo[info_idx].icon_no == ICON_LIGHT_DROP_e) {
|
||||
mLightDropPic->draw((pos_x + (icon_size_x / 2)) - (var_f29 / 2),
|
||||
((icon_size_y / 2) + (i_posY + (icon_pos_y - icon_size_y / 2))) - (var_f28 / 2),
|
||||
var_f29, var_f28, false, false, false);
|
||||
var_f29, var_f28, r4, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -869,4 +861,4 @@ void dMenuMapCommon_c::getFmapPoeCount(const int regionNo, int& nowCount, int& t
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -428,17 +428,6 @@ static void dummyStrings() {
|
||||
dMsgObject_HIO_c g_MsgObject_HIO_c;
|
||||
|
||||
int dMsgObject_c::_execute() {
|
||||
// TODO: enabling wii message overrides fixes direction text, but gives wrong item control text
|
||||
/*#if TARGET_PC
|
||||
if (dusk::getSettings().game.enableMirrorMode) {
|
||||
// enable wii message index override
|
||||
g_MsgObject_HIO_c.mMessageDisplay = 1;
|
||||
} else if (!dusk::getSettings().game.enableMirrorMode && g_MsgObject_HIO_c.mMessageDisplay == 1) {
|
||||
g_MsgObject_HIO_c.mMessageDisplay = 0;
|
||||
}
|
||||
#endif*/
|
||||
|
||||
|
||||
field_0x4c7 = 0;
|
||||
if (mpTalkHeap != NULL) {
|
||||
field_0x148 = mDoExt_setCurrentHeap(mpTalkHeap);
|
||||
|
||||
+1
-1
@@ -1823,7 +1823,7 @@ int dSv_info_c::memory_to_card(char* card_ptr, int dataNum) {
|
||||
savedata->getPlayer().getPlayerInfo().setTotalTime(play_time);
|
||||
}
|
||||
|
||||
savedata->getPlayer().getPlayerStatusB().setDateIpl(OSGetTime());
|
||||
savedata->getPlayer().getPlayerStatusB().setDateIpl(DUSK_IF_ELSE(OSGetSystemTime(), OSGetTime()));
|
||||
|
||||
memcpy(card_ptr, savedata, sizeof(dSv_save_c));
|
||||
card_ptr += 0x958;
|
||||
|
||||
+280
-151
@@ -7,6 +7,7 @@
|
||||
#include "dusk/io.hpp"
|
||||
#include "dusk/settings.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <filesystem>
|
||||
#include <limits>
|
||||
@@ -15,77 +16,90 @@
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "dusk/action_bindings.h"
|
||||
#include "dusk/logging.h"
|
||||
#include "dusk/main.h"
|
||||
|
||||
using namespace dusk::config;
|
||||
|
||||
namespace dusk::config {
|
||||
namespace {
|
||||
constexpr auto ConfigFileName = "config.json";
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
aurora::Module DuskConfigLog("dusk::config");
|
||||
|
||||
static absl::flat_hash_map<std::string_view, ConfigVarBase*> RegisteredConfigVars;
|
||||
static bool RegistrationDone = false;
|
||||
absl::flat_hash_map<std::string, ConfigVarBase*> RegisteredConfigVars;
|
||||
absl::flat_hash_map<std::string, nlohmann::json> UnregisteredConfigVars;
|
||||
absl::flat_hash_map<std::string, std::string> UnregisteredConfigVarOverrides;
|
||||
|
||||
static std::optional<dusk::ui::ControlAnchor> parse_control_anchor(std::string_view value) {
|
||||
struct ChangeSubscription {
|
||||
Subscription token;
|
||||
ChangeCallback callback;
|
||||
};
|
||||
absl::flat_hash_map<std::string, std::vector<ChangeSubscription> > s_changeSubscriptions;
|
||||
absl::flat_hash_map<Subscription, std::string> s_changeTokenNames;
|
||||
Subscription s_nextChangeToken = 1;
|
||||
// Names currently being notified; guards against a callback re-notifying its own CVar.
|
||||
std::vector<std::string> s_activeChangeNotifications;
|
||||
|
||||
std::optional<ui::ControlAnchor> parse_control_anchor(std::string_view value) {
|
||||
if (value == "none") {
|
||||
return dusk::ui::ControlAnchor::None;
|
||||
return ui::ControlAnchor::None;
|
||||
}
|
||||
if (value == "top") {
|
||||
return dusk::ui::ControlAnchor::Top;
|
||||
return ui::ControlAnchor::Top;
|
||||
}
|
||||
if (value == "left") {
|
||||
return dusk::ui::ControlAnchor::Left;
|
||||
return ui::ControlAnchor::Left;
|
||||
}
|
||||
if (value == "bottom") {
|
||||
return dusk::ui::ControlAnchor::Bottom;
|
||||
return ui::ControlAnchor::Bottom;
|
||||
}
|
||||
if (value == "right") {
|
||||
return dusk::ui::ControlAnchor::Right;
|
||||
return ui::ControlAnchor::Right;
|
||||
}
|
||||
if (value == "topLeft") {
|
||||
return dusk::ui::ControlAnchor::TopLeft;
|
||||
return ui::ControlAnchor::TopLeft;
|
||||
}
|
||||
if (value == "topRight") {
|
||||
return dusk::ui::ControlAnchor::TopRight;
|
||||
return ui::ControlAnchor::TopRight;
|
||||
}
|
||||
if (value == "bottomLeft") {
|
||||
return dusk::ui::ControlAnchor::BottomLeft;
|
||||
return ui::ControlAnchor::BottomLeft;
|
||||
}
|
||||
if (value == "bottomRight") {
|
||||
return dusk::ui::ControlAnchor::BottomRight;
|
||||
return ui::ControlAnchor::BottomRight;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static const char* control_anchor_value(dusk::ui::ControlAnchor anchor) {
|
||||
const char* control_anchor_value(ui::ControlAnchor anchor) {
|
||||
switch (anchor) {
|
||||
case dusk::ui::ControlAnchor::None:
|
||||
case ui::ControlAnchor::None:
|
||||
return "none";
|
||||
case dusk::ui::ControlAnchor::Top:
|
||||
case ui::ControlAnchor::Top:
|
||||
return "top";
|
||||
case dusk::ui::ControlAnchor::Left:
|
||||
case ui::ControlAnchor::Left:
|
||||
return "left";
|
||||
case dusk::ui::ControlAnchor::Bottom:
|
||||
case ui::ControlAnchor::Bottom:
|
||||
return "bottom";
|
||||
case dusk::ui::ControlAnchor::Right:
|
||||
case ui::ControlAnchor::Right:
|
||||
return "right";
|
||||
case dusk::ui::ControlAnchor::TopLeft:
|
||||
case ui::ControlAnchor::TopLeft:
|
||||
return "topLeft";
|
||||
case dusk::ui::ControlAnchor::TopRight:
|
||||
case ui::ControlAnchor::TopRight:
|
||||
return "topRight";
|
||||
case dusk::ui::ControlAnchor::BottomLeft:
|
||||
case ui::ControlAnchor::BottomLeft:
|
||||
return "bottomLeft";
|
||||
case dusk::ui::ControlAnchor::BottomRight:
|
||||
case ui::ControlAnchor::BottomRight:
|
||||
return "bottomRight";
|
||||
}
|
||||
return "none";
|
||||
}
|
||||
|
||||
static std::optional<float> json_finite_float(const json& object, const char* key) {
|
||||
std::optional<float> json_finite_float(const json& object, const char* key) {
|
||||
const auto iter = object.find(key);
|
||||
if (iter == object.end() || !iter->is_number()) {
|
||||
return std::nullopt;
|
||||
@@ -99,7 +113,7 @@ static std::optional<float> json_finite_float(const json& object, const char* ke
|
||||
return value;
|
||||
}
|
||||
|
||||
static std::optional<dusk::ui::ControlProps> parse_control_props(const json& value) {
|
||||
std::optional<ui::ControlProps> parse_control_props(const json& value) {
|
||||
if (!value.is_object()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -118,7 +132,7 @@ static std::optional<dusk::ui::ControlProps> parse_control_props(const json& val
|
||||
if (!anchor || *w <= 0.0f || *h <= 0.0f || *scale <= 0.0f) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return dusk::ui::ControlProps{
|
||||
return ui::ControlProps{
|
||||
.x = *x,
|
||||
.y = *y,
|
||||
.w = *w,
|
||||
@@ -128,17 +142,17 @@ static std::optional<dusk::ui::ControlProps> parse_control_props(const json& val
|
||||
};
|
||||
}
|
||||
|
||||
static std::filesystem::path GetConfigJsonPath() {
|
||||
return dusk::ConfigPath / ConfigFileName;
|
||||
std::filesystem::path GetConfigJsonPath() {
|
||||
return ConfigPath / ConfigFileName;
|
||||
}
|
||||
|
||||
static std::filesystem::path GetTempConfigJsonPath(const std::filesystem::path& configJsonPath) {
|
||||
std::filesystem::path GetTempConfigJsonPath(const std::filesystem::path& configJsonPath) {
|
||||
auto tempPath = configJsonPath;
|
||||
tempPath.replace_filename(fmt::format(".{}.tmp", configJsonPath.filename().string()));
|
||||
return tempPath;
|
||||
}
|
||||
|
||||
static void ReplaceFile(const std::filesystem::path& source, const std::filesystem::path& target) {
|
||||
void ReplaceFile(const std::filesystem::path& source, const std::filesystem::path& target) {
|
||||
std::error_code ec;
|
||||
std::filesystem::rename(source, target, ec);
|
||||
if (ec) {
|
||||
@@ -148,19 +162,8 @@ static void ReplaceFile(const std::filesystem::path& source, const std::filesyst
|
||||
}
|
||||
}
|
||||
|
||||
ConfigVarBase::ConfigVarBase(const char* name, const ConfigImplBase* impl)
|
||||
: name(name), registered(false), layer(ConfigVarLayer::Default), impl(impl) {}
|
||||
|
||||
const char* ConfigVarBase::getName() const noexcept {
|
||||
return name;
|
||||
}
|
||||
|
||||
const ConfigImplBase* ConfigVarBase::getImpl() const noexcept {
|
||||
return impl;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T sanitizeEnumValue(const ConfigVar<T>& cVar, T value) {
|
||||
T sanitizeEnumValue(const ConfigVar<T>& cVar, T value) {
|
||||
if constexpr (std::is_enum_v<T>) {
|
||||
using Underlying = std::underlying_type_t<T>;
|
||||
const Underlying raw = static_cast<Underlying>(value);
|
||||
@@ -174,6 +177,83 @@ static T sanitizeEnumValue(const ConfigVar<T>& cVar, T value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
template <ConfigValue T>
|
||||
requires std::is_integral_v<T>&& std::is_signed_v<T> T parse_arg_value(
|
||||
const ConfigVar<T>&, const std::string_view stringValue) {
|
||||
const std::string str(stringValue);
|
||||
const auto result = std::stoll(str);
|
||||
if (result >= std::numeric_limits<T>::min() && result <= std::numeric_limits<T>::max()) {
|
||||
return static_cast<T>(result);
|
||||
}
|
||||
throw std::out_of_range("Value is too large");
|
||||
}
|
||||
|
||||
template <ConfigValue T>
|
||||
requires std::is_integral_v<T>&& std::is_unsigned_v<T> T parse_arg_value(
|
||||
const ConfigVar<T>&, const std::string_view stringValue) {
|
||||
const std::string str(stringValue);
|
||||
const auto result = std::stoull(str);
|
||||
if (result <= std::numeric_limits<T>::max()) {
|
||||
return static_cast<T>(result);
|
||||
}
|
||||
throw std::out_of_range("Value is too large");
|
||||
}
|
||||
|
||||
f32 parse_arg_value(const ConfigVar<f32>&, const std::string_view stringValue) {
|
||||
const std::string str(stringValue);
|
||||
return std::stof(str);
|
||||
}
|
||||
|
||||
f64 parse_arg_value(const ConfigVar<f64>&, const std::string_view stringValue) {
|
||||
const std::string str(stringValue);
|
||||
return std::stod(str);
|
||||
}
|
||||
|
||||
std::string parse_arg_value(const ConfigVar<std::string>&, const std::string_view stringValue) {
|
||||
return std::string(stringValue);
|
||||
}
|
||||
|
||||
template <ConfigValue T>
|
||||
requires std::is_enum_v<T> T parse_arg_value(
|
||||
const ConfigVar<T>& cVar, const std::string_view stringValue) {
|
||||
using Underlying = std::underlying_type_t<T>;
|
||||
const std::string str(stringValue);
|
||||
|
||||
if constexpr (std::is_signed_v<Underlying>) {
|
||||
const auto result = std::stoll(str);
|
||||
if (result >= std::numeric_limits<Underlying>::min() &&
|
||||
result <= std::numeric_limits<Underlying>::max())
|
||||
{
|
||||
return sanitizeEnumValue(cVar, static_cast<T>(result));
|
||||
}
|
||||
throw std::out_of_range("Value is too large");
|
||||
} else {
|
||||
const auto result = std::stoull(str);
|
||||
if (result <= std::numeric_limits<Underlying>::max()) {
|
||||
return sanitizeEnumValue(cVar, static_cast<T>(result));
|
||||
}
|
||||
throw std::out_of_range("Value is too large");
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ConfigVarBase::ConfigVarBase(std::string name, const ConfigImplBase* impl)
|
||||
: name(std::move(name)), registered(false), layer(ConfigVarLayer::Default), impl(impl) {}
|
||||
|
||||
const char* ConfigVarBase::getName() const noexcept {
|
||||
return name.c_str();
|
||||
}
|
||||
|
||||
const ConfigImplBase* ConfigVarBase::getImpl() const noexcept {
|
||||
return impl;
|
||||
}
|
||||
|
||||
ConfigVarBase::~ConfigVarBase() {
|
||||
if (registered) {
|
||||
DuskLog.fatal("CVar '{}' was destroyed while still registered!", name);
|
||||
}
|
||||
}
|
||||
|
||||
template <ConfigValue T>
|
||||
void ConfigImpl<T>::loadFromJson(ConfigVar<T>& cVar, const json& jsonValue) {
|
||||
if constexpr (std::is_enum_v<T>) {
|
||||
@@ -187,12 +267,12 @@ void ConfigImpl<T>::loadFromJson(ConfigVar<T>& cVar, const json& jsonValue) {
|
||||
|
||||
const Underlying raw = b ? static_cast<Underlying>(1) : static_cast<Underlying>(0);
|
||||
|
||||
cVar.setValue(sanitizeEnumValue(cVar, static_cast<T>(raw)), false);
|
||||
cVar.load_value(sanitizeEnumValue(cVar, static_cast<T>(raw)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cVar.setValue(sanitizeEnumValue(cVar, jsonValue.get<T>()), false);
|
||||
cVar.load_value(sanitizeEnumValue(cVar, jsonValue.get<T>()));
|
||||
}
|
||||
|
||||
template <ConfigValue T>
|
||||
@@ -200,74 +280,9 @@ nlohmann::json ConfigImpl<T>::dumpToJson(const ConfigVar<T>& cVar) {
|
||||
return cVar.getValueForSave();
|
||||
}
|
||||
|
||||
template <ConfigValue T>
|
||||
requires std::is_integral_v<T>&& std::is_signed_v<T> static void loadFromArgImpl(
|
||||
ConfigVar<T>& cVar, const std::string_view stringValue) {
|
||||
const std::string str(stringValue);
|
||||
const auto result = std::stoll(str);
|
||||
if (result >= std::numeric_limits<T>::min() && result <= std::numeric_limits<T>::max()) {
|
||||
cVar.setOverrideValue(result);
|
||||
} else {
|
||||
throw std::out_of_range("Value is too large");
|
||||
}
|
||||
}
|
||||
|
||||
template <ConfigValue T>
|
||||
requires std::is_integral_v<T>&& std::is_unsigned_v<T> static void loadFromArgImpl(
|
||||
ConfigVar<T>& cVar, const std::string_view stringValue) {
|
||||
const std::string str(stringValue);
|
||||
const auto result = std::stoull(str);
|
||||
if (result <= std::numeric_limits<T>::max()) {
|
||||
cVar.setOverrideValue(result);
|
||||
} else {
|
||||
throw std::out_of_range("Value is too large");
|
||||
}
|
||||
}
|
||||
|
||||
static void loadFromArgImpl(ConfigVar<f32>& cVar, const std::string_view stringValue) {
|
||||
const std::string str(stringValue);
|
||||
const auto result = std::stof(str);
|
||||
cVar.setOverrideValue(result);
|
||||
}
|
||||
|
||||
static void loadFromArgImpl(ConfigVar<f64>& cVar, const std::string_view stringValue) {
|
||||
const std::string str(stringValue);
|
||||
const auto result = std::stod(str);
|
||||
cVar.setOverrideValue(result);
|
||||
}
|
||||
|
||||
static void loadFromArgImpl(ConfigVar<std::string>& cVar, const std::string_view stringValue) {
|
||||
cVar.setOverrideValue(std::string(stringValue));
|
||||
}
|
||||
|
||||
template <ConfigValue T>
|
||||
requires std::is_enum_v<T> static void loadFromArgImpl(
|
||||
ConfigVar<T>& cVar, const std::string_view stringValue) {
|
||||
using Underlying = std::underlying_type_t<T>;
|
||||
const std::string str(stringValue);
|
||||
|
||||
if constexpr (std::is_signed_v<Underlying>) {
|
||||
const auto result = std::stoll(str);
|
||||
if (result >= std::numeric_limits<Underlying>::min() &&
|
||||
result <= std::numeric_limits<Underlying>::max())
|
||||
{
|
||||
cVar.setOverrideValue(sanitizeEnumValue(cVar, static_cast<T>(result)));
|
||||
} else {
|
||||
throw std::out_of_range("Value is too large");
|
||||
}
|
||||
} else {
|
||||
const auto result = std::stoull(str);
|
||||
if (result <= std::numeric_limits<Underlying>::max()) {
|
||||
cVar.setOverrideValue(sanitizeEnumValue(cVar, static_cast<T>(result)));
|
||||
} else {
|
||||
throw std::out_of_range("Value is too large");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <ConfigValue T>
|
||||
void ConfigImpl<T>::loadFromArg(ConfigVar<T>& cVar, const std::string_view stringValue) {
|
||||
loadFromArgImpl(cVar, stringValue);
|
||||
cVar.load_override_value(parse_arg_value(cVar, stringValue));
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -275,18 +290,16 @@ void ConfigImpl<bool>::loadFromArg(ConfigVar<bool>& cVar, const std::string_view
|
||||
if (stringValue == "1" || stringValue == "TRUE" || stringValue == "true" ||
|
||||
stringValue == "True")
|
||||
{
|
||||
cVar.setOverrideValue(true);
|
||||
cVar.load_override_value(true);
|
||||
} else if (stringValue == "0" || stringValue == "FALSE" || stringValue == "false" ||
|
||||
stringValue == "False")
|
||||
{
|
||||
cVar.setOverrideValue(false);
|
||||
cVar.load_override_value(false);
|
||||
} else {
|
||||
throw InvalidConfigError("Value cannot be parsed as boolean");
|
||||
}
|
||||
}
|
||||
|
||||
// My IDE is convinced this namespace is necessary. It shouldn't be AFAICT?
|
||||
namespace dusk::config {
|
||||
template class ConfigImpl<bool>;
|
||||
template class ConfigImpl<s8>;
|
||||
template class ConfigImpl<u8>;
|
||||
@@ -299,10 +312,10 @@ template class ConfigImpl<u64>;
|
||||
template class ConfigImpl<f32>;
|
||||
template class ConfigImpl<f64>;
|
||||
template class ConfigImpl<std::string>;
|
||||
template class ConfigImpl<dusk::BloomMode>;
|
||||
template class ConfigImpl<dusk::DepthOfFieldMode>;
|
||||
template class ConfigImpl<dusk::DiscVerificationState>;
|
||||
template class ConfigImpl<dusk::GameLanguage>;
|
||||
template class ConfigImpl<BloomMode>;
|
||||
template class ConfigImpl<DepthOfFieldMode>;
|
||||
template class ConfigImpl<DiscVerificationState>;
|
||||
template class ConfigImpl<GameLanguage>;
|
||||
|
||||
template <>
|
||||
void ConfigImpl<FrameInterpMode>::loadFromJson(
|
||||
@@ -312,11 +325,11 @@ void ConfigImpl<FrameInterpMode>::loadFromJson(
|
||||
|
||||
const FrameInterpMode mode = b ? FrameInterpMode::Unlimited : FrameInterpMode::Off;
|
||||
|
||||
cVar.setValue(sanitizeEnumValue(cVar, mode), false);
|
||||
cVar.load_value(sanitizeEnumValue(cVar, mode));
|
||||
return;
|
||||
}
|
||||
|
||||
cVar.setValue(sanitizeEnumValue(cVar, jsonValue.get<FrameInterpMode>()), false);
|
||||
cVar.load_value(sanitizeEnumValue(cVar, jsonValue.get<FrameInterpMode>()));
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -347,7 +360,7 @@ void ConfigImpl<ui::ControlLayout>::loadFromJson(
|
||||
}
|
||||
}
|
||||
|
||||
cVar.setValue(std::move(layout), false);
|
||||
cVar.load_value(std::move(layout));
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -377,26 +390,59 @@ nlohmann::json ConfigImpl<ui::ControlLayout>::dumpToJson(const ConfigVar<ui::Con
|
||||
};
|
||||
}
|
||||
|
||||
template class ConfigImpl<dusk::FrameInterpMode>;
|
||||
template class ConfigImpl<dusk::TouchTargeting>;
|
||||
template class ConfigImpl<dusk::MenuScaling>;
|
||||
template class ConfigImpl<dusk::Resampler>;
|
||||
template class ConfigImpl<dusk::MagicArmorMode>;
|
||||
template class ConfigImpl<dusk::ui::ControlLayout>;
|
||||
} // namespace dusk::config
|
||||
|
||||
void dusk::config::Register(ConfigVarBase& configVar) {
|
||||
const auto& name = configVar.getName();
|
||||
if (RegistrationDone) {
|
||||
DuskConfigLog.fatal("Tried to register CVar {} after registrations closed!", name);
|
||||
}
|
||||
template class ConfigImpl<FrameInterpMode>;
|
||||
template class ConfigImpl<TouchTargeting>;
|
||||
template class ConfigImpl<MenuScaling>;
|
||||
template class ConfigImpl<Resampler>;
|
||||
template class ConfigImpl<MagicArmorMode>;
|
||||
template class ConfigImpl<ui::ControlLayout>;
|
||||
|
||||
void Register(ConfigVarBase& configVar) {
|
||||
const std::string_view name = configVar.getName();
|
||||
if (RegisteredConfigVars.contains(name)) {
|
||||
DuskConfigLog.fatal("Tried to register CVar {} twice!", name);
|
||||
}
|
||||
|
||||
RegisteredConfigVars[name] = &configVar;
|
||||
configVar.markRegistered();
|
||||
|
||||
const auto unregPair = UnregisteredConfigVars.find(name);
|
||||
if (unregPair != UnregisteredConfigVars.end()) {
|
||||
const auto value = std::move(unregPair->second);
|
||||
UnregisteredConfigVars.erase(name);
|
||||
|
||||
try {
|
||||
configVar.getImpl()->loadFromJson(configVar, value);
|
||||
} catch (std::exception& e) {
|
||||
DuskConfigLog.error("Failed to load key '{}' from config value: {}", name, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
const auto overridePair = UnregisteredConfigVarOverrides.find(name);
|
||||
if (overridePair != UnregisteredConfigVarOverrides.end()) {
|
||||
try {
|
||||
configVar.getImpl()->loadFromArg(configVar, overridePair->second);
|
||||
} catch (std::exception& e) {
|
||||
DuskConfigLog.error("Failed to load key '{}' from override arg: {}", name, e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unregister(ConfigVarBase& configVar) {
|
||||
const std::string_view name = configVar.getName();
|
||||
const auto it = RegisteredConfigVars.find(name);
|
||||
if (it == RegisteredConfigVars.end() || it->second != &configVar) {
|
||||
DuskConfigLog.fatal("Tried to unregister CVar '{}' that is not registered!", name);
|
||||
}
|
||||
|
||||
const auto layer = configVar.getLayer();
|
||||
if (layer == ConfigVarLayer::Value || layer == ConfigVarLayer::Speedrun) {
|
||||
UnregisteredConfigVars.insert_or_assign(
|
||||
std::string{name}, configVar.getImpl()->dumpToJson(configVar));
|
||||
}
|
||||
|
||||
RegisteredConfigVars.erase(it);
|
||||
configVar.unmarkRegistered();
|
||||
}
|
||||
|
||||
void ConfigVarBase::markRegistered() {
|
||||
@@ -406,21 +452,24 @@ void ConfigVarBase::markRegistered() {
|
||||
registered = true;
|
||||
}
|
||||
|
||||
void dusk::config::FinishRegistration() {
|
||||
RegistrationDone = true;
|
||||
void ConfigVarBase::unmarkRegistered() {
|
||||
if (!registered)
|
||||
abort();
|
||||
|
||||
registered = false;
|
||||
}
|
||||
|
||||
void dusk::config::LoadFromUserPreferences() {
|
||||
void load_from_user_preferences() {
|
||||
const auto configJsonPath = GetConfigJsonPath();
|
||||
if (configJsonPath.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto configPathString = io::fs_path_to_string(configJsonPath);
|
||||
LoadFromFileName(configPathString.c_str());
|
||||
load_from_file_name(configPathString.c_str());
|
||||
}
|
||||
|
||||
static void LoadFromPath(const char* path) {
|
||||
auto data = dusk::io::FileStream::ReadAllBytes(path);
|
||||
auto data = io::FileStream::ReadAllBytes(path);
|
||||
|
||||
json j = json::parse(data);
|
||||
if (!j.is_object()) {
|
||||
@@ -428,11 +477,16 @@ static void LoadFromPath(const char* path) {
|
||||
return;
|
||||
}
|
||||
|
||||
UnregisteredConfigVars.clear();
|
||||
|
||||
for (const auto& el : j.items()) {
|
||||
const auto& key = el.key();
|
||||
auto configVar = RegisteredConfigVars.find(key);
|
||||
if (configVar == RegisteredConfigVars.end()) {
|
||||
DuskConfigLog.error("Unknown key '{}' found in config!", key);
|
||||
DuskConfigLog.debug("Unknown key '{}' found in config! If this gets registered later, "
|
||||
"that's acceptable!",
|
||||
key);
|
||||
UnregisteredConfigVars.emplace(key, el.value());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -444,11 +498,7 @@ static void LoadFromPath(const char* path) {
|
||||
}
|
||||
}
|
||||
|
||||
void dusk::config::LoadFromFileName(const char* path) {
|
||||
if (!RegistrationDone) {
|
||||
DuskConfigLog.fatal("Registration not finished yet!");
|
||||
}
|
||||
|
||||
void load_from_file_name(const char* path) {
|
||||
DuskConfigLog.info("Loading config from '{}'", path);
|
||||
|
||||
try {
|
||||
@@ -466,7 +516,21 @@ void dusk::config::LoadFromFileName(const char* path) {
|
||||
}
|
||||
}
|
||||
|
||||
void dusk::config::Save() {
|
||||
void load_arg_override(std::string_view name, std::string_view value) {
|
||||
const auto cVar = GetConfigVar(name);
|
||||
if (!cVar) {
|
||||
UnregisteredConfigVarOverrides.emplace(name, value);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
cVar->getImpl()->loadFromArg(*cVar, value);
|
||||
} catch (const std::exception& e) {
|
||||
DuskLog.fatal("Unable to parse: '{}': {}", value, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void save() {
|
||||
const auto configJsonPath = GetConfigJsonPath();
|
||||
if (configJsonPath.empty()) {
|
||||
return;
|
||||
@@ -484,6 +548,10 @@ void dusk::config::Save() {
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& pair : UnregisteredConfigVars) {
|
||||
j[pair.first] = pair.second;
|
||||
}
|
||||
|
||||
try {
|
||||
const auto tempConfigJsonPath = GetTempConfigJsonPath(configJsonPath);
|
||||
io::FileStream::WriteAllText(tempConfigJsonPath, j.dump(4));
|
||||
@@ -493,14 +561,14 @@ void dusk::config::Save() {
|
||||
}
|
||||
}
|
||||
|
||||
void dusk::config::ClearAllActionBindings(int port) {
|
||||
void ClearAllActionBindings(int port) {
|
||||
for (auto& actionBinding : getActionBinds() | std::views::values) {
|
||||
actionBinding.configVars->at(port).setValue(PAD_NATIVE_BUTTON_INVALID);
|
||||
}
|
||||
Save();
|
||||
save();
|
||||
}
|
||||
|
||||
ConfigVarBase* dusk::config::GetConfigVar(std::string_view name) {
|
||||
ConfigVarBase* GetConfigVar(std::string_view name) {
|
||||
const auto configVar = RegisteredConfigVars.find(name);
|
||||
if (configVar != RegisteredConfigVars.end()) {
|
||||
return configVar->second;
|
||||
@@ -509,8 +577,69 @@ ConfigVarBase* dusk::config::GetConfigVar(std::string_view name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void dusk::config::EnumerateRegistered(std::function<void(ConfigVarBase&)> callback) {
|
||||
void EnumerateRegistered(std::function<void(ConfigVarBase&)> callback) {
|
||||
for (auto& pair : RegisteredConfigVars) {
|
||||
callback(*pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
Subscription subscribe(std::string_view name, ChangeCallback callback) {
|
||||
const auto token = s_nextChangeToken++;
|
||||
s_changeSubscriptions[std::string{name}].push_back({token, std::move(callback)});
|
||||
s_changeTokenNames.emplace(token, std::string{name});
|
||||
return token;
|
||||
}
|
||||
|
||||
void unsubscribe(Subscription token) {
|
||||
const auto nameIt = s_changeTokenNames.find(token);
|
||||
if (nameIt == s_changeTokenNames.end()) {
|
||||
DuskConfigLog.fatal("Tried to unsubscribe unknown change token {}!", token);
|
||||
}
|
||||
|
||||
const auto subsIt = s_changeSubscriptions.find(nameIt->second);
|
||||
auto& subscriptions = subsIt->second;
|
||||
std::erase_if(
|
||||
subscriptions, [token](const ChangeSubscription& sub) { return sub.token == token; });
|
||||
if (subscriptions.empty()) {
|
||||
s_changeSubscriptions.erase(subsIt);
|
||||
}
|
||||
s_changeTokenNames.erase(nameIt);
|
||||
}
|
||||
|
||||
bool ConfigVarBase::has_subscribers() const {
|
||||
return s_changeSubscriptions.contains(name);
|
||||
}
|
||||
|
||||
void ConfigVarBase::notify_changed(const void* previousValue) {
|
||||
const auto subsIt = s_changeSubscriptions.find(name);
|
||||
if (subsIt == s_changeSubscriptions.end()) {
|
||||
return;
|
||||
}
|
||||
if (std::ranges::find(s_activeChangeNotifications, name) != s_activeChangeNotifications.end()) {
|
||||
DuskConfigLog.error("Recursive change notification for CVar '{}' suppressed", name);
|
||||
return;
|
||||
}
|
||||
|
||||
s_activeChangeNotifications.push_back(name);
|
||||
// Copied so callbacks can subscribe/unsubscribe safely.
|
||||
const auto subscriptions = subsIt->second;
|
||||
for (const auto& sub : subscriptions) {
|
||||
sub.callback(*this, previousValue);
|
||||
}
|
||||
s_activeChangeNotifications.pop_back();
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
for (auto& pair : RegisteredConfigVars) {
|
||||
pair.second->unmarkRegistered();
|
||||
}
|
||||
|
||||
RegisteredConfigVars.clear();
|
||||
UnregisteredConfigVars.clear();
|
||||
UnregisteredConfigVarOverrides.clear();
|
||||
s_changeSubscriptions.clear();
|
||||
s_changeTokenNames.clear();
|
||||
s_activeChangeNotifications.clear();
|
||||
}
|
||||
|
||||
} // namespace dusk::config
|
||||
@@ -9,7 +9,7 @@ namespace dusk::config {
|
||||
bool copy = var.getValue();
|
||||
if (ImGui::Checkbox(title, ©)) {
|
||||
var.setValue(copy);
|
||||
Save();
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace dusk::config {
|
||||
float val = var;
|
||||
if (ImGui::SliderFloat(label, &val, v_min, v_max, format, flags)) {
|
||||
var.setValue(val);
|
||||
Save();
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace dusk::config {
|
||||
int val = var;
|
||||
if (ImGui::SliderInt(label, &val, v_min, v_max, format, flags)) {
|
||||
var.setValue(val);
|
||||
Save();
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace dusk::config {
|
||||
bool copy = p_selected.getValue();
|
||||
if (ImGui::MenuItem(label, shortcut, ©, enabled)) {
|
||||
p_selected.setValue(copy);
|
||||
Save();
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -254,7 +254,7 @@ namespace dusk {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_F11)) {
|
||||
getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen);
|
||||
VISetWindowFullscreen(getSettings().video.enableFullscreen);
|
||||
config::Save();
|
||||
config::save();
|
||||
}
|
||||
|
||||
if (getSettings().game.enableResetKeybind && ImGui::GetIO().KeyCtrl &&
|
||||
@@ -336,7 +336,7 @@ namespace dusk {
|
||||
if constexpr (SupportsProcessRestart) {
|
||||
if (ImGui::Button("Retry (Auto backend)")) {
|
||||
getSettings().backend.graphicsBackend.setValue("auto");
|
||||
config::Save();
|
||||
config::save();
|
||||
RestartRequested = true;
|
||||
IsRunning = false;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace dusk {
|
||||
bool disableWaterRefraction = getSettings().game.disableWaterRefraction;
|
||||
if (ImGui::Checkbox("Disable Water Refraction", &disableWaterRefraction)) {
|
||||
getSettings().game.disableWaterRefraction.setValue(disableWaterRefraction);
|
||||
config::Save();
|
||||
config::save();
|
||||
}
|
||||
ImGui::Checkbox("Enable LOD Bias", &aurora::gx::enableLodBias);
|
||||
ImGui::EndMenu();
|
||||
|
||||
@@ -314,7 +314,7 @@ void end_game_frame() noexcept {
|
||||
}
|
||||
|
||||
void begin_context(Context context) noexcept {
|
||||
if (context == Context::None) {
|
||||
if (context == Context::None || !enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+74
-52
@@ -1,54 +1,69 @@
|
||||
#include "dusk/mouse.h"
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "dusk/menu_pointer.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/ui/ui.hpp"
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
|
||||
#include <aurora/lib/window.hpp>
|
||||
#include <imgui.h>
|
||||
#include <SDL3/SDL_mouse.h>
|
||||
#include <SDL3/SDL_video.h>
|
||||
#include <aurora/lib/window.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace dusk::mouse {
|
||||
namespace {
|
||||
constexpr float kMousePixelToRad = 0.0025f;
|
||||
constexpr int kIdleHideFrames = 99; // Approx. 3 seconds with 33ms ticks
|
||||
using Clock = std::chrono::steady_clock;
|
||||
|
||||
float s_aim_yaw_rad = 0.0f;
|
||||
float s_aim_pitch_rad = 0.0f;
|
||||
float s_camera_yaw_rad = 0.0f;
|
||||
constexpr float kMousePixelToRad = 0.0025f;
|
||||
constexpr auto kCursorIdleDuration = std::chrono::seconds(1);
|
||||
|
||||
float s_aim_yaw_rad = 0.0f;
|
||||
float s_aim_pitch_rad = 0.0f;
|
||||
float s_camera_yaw_rad = 0.0f;
|
||||
float s_camera_pitch_rad = 0.0f;
|
||||
int s_idle_frames = 0;
|
||||
Clock::time_point s_last_cursor_motion = Clock::now();
|
||||
|
||||
void reset_deltas() {
|
||||
s_aim_yaw_rad = s_aim_pitch_rad = 0.0f;
|
||||
s_camera_yaw_rad = s_camera_pitch_rad = 0.0f;
|
||||
}
|
||||
|
||||
bool queryMouseAimContext() {
|
||||
bool query_mouse_aim_context() {
|
||||
return getSettings().game.enableMouseAim.getValue() && dCamera_c::isAimActive();
|
||||
}
|
||||
|
||||
bool wantMouseCapture() {
|
||||
return getSettings().game.enableMouseCamera.getValue() || queryMouseAimContext();
|
||||
bool want_mouse_capture() {
|
||||
return getSettings().game.enableMouseCamera.getValue() || query_mouse_aim_context();
|
||||
}
|
||||
|
||||
bool isWindowFocused(SDL_Window* window) {
|
||||
bool mouse_input_enabled() {
|
||||
const auto& game = getSettings().game;
|
||||
return game.enableMouseAim.getValue() || game.enableMouseCamera.getValue();
|
||||
}
|
||||
|
||||
bool is_window_focused(SDL_Window* window) {
|
||||
if (window == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return (SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS) != 0;
|
||||
}
|
||||
|
||||
bool shouldCaptureMouse(SDL_Window* window) {
|
||||
if (window == nullptr || ui::any_document_visible() || menu_pointer::active()) {
|
||||
return false;
|
||||
}
|
||||
return wantMouseCapture() && isWindowFocused(window);
|
||||
bool imgui_windows_visible() {
|
||||
return ImGui::GetIO().MetricsRenderWindows > 0;
|
||||
}
|
||||
|
||||
bool syncCaptureState(SDL_Window* window, bool should_capture) {
|
||||
bool should_capture_mouse(SDL_Window* window) {
|
||||
if (window == nullptr || ui::any_document_visible() || imgui_windows_visible() ||
|
||||
menu_pointer::active())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return want_mouse_capture() && is_window_focused(window);
|
||||
}
|
||||
|
||||
bool sync_capture_state(SDL_Window* window, bool should_capture) {
|
||||
if (window == nullptr) {
|
||||
reset_deltas();
|
||||
return false;
|
||||
@@ -78,7 +93,7 @@ bool syncCaptureState(SDL_Window* window, bool should_capture) {
|
||||
return is_captured;
|
||||
}
|
||||
|
||||
void accumulateDeltas(float mx_rel, float my_rel, bool camera_active, bool aim_active) {
|
||||
void accumulate_deltas(float mx_rel, float my_rel, bool camera_active, bool aim_active) {
|
||||
const auto& game = getSettings().game;
|
||||
const bool mirror_mode = game.enableMirrorMode.getValue();
|
||||
const bool invert_y = game.invertMouseY.getValue();
|
||||
@@ -114,57 +129,62 @@ void set_cursor_visible(bool visible) {
|
||||
}
|
||||
}
|
||||
|
||||
void update_cursor_visibility(SDL_Window* window, bool captured) {
|
||||
if (window == nullptr || !isWindowFocused(window)) {
|
||||
return;
|
||||
}
|
||||
bool cursor_idle() {
|
||||
return Clock::now() - s_last_cursor_motion >= kCursorIdleDuration;
|
||||
}
|
||||
|
||||
bool should_show_cursor(bool captured) {
|
||||
if (captured) {
|
||||
s_idle_frames = 0;
|
||||
set_cursor_visible(false);
|
||||
return false;
|
||||
}
|
||||
if (ui::any_document_visible()) {
|
||||
return true;
|
||||
}
|
||||
if (imgui_windows_visible()) {
|
||||
return true;
|
||||
}
|
||||
if (menu_pointer::enabled() && menu_pointer::active()) {
|
||||
return true;
|
||||
}
|
||||
if (mouse_input_enabled()) {
|
||||
return false;
|
||||
}
|
||||
return !cursor_idle();
|
||||
}
|
||||
|
||||
void update_cursor_visibility(SDL_Window* window, bool captured) {
|
||||
if (window == nullptr || !is_window_focused(window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) {
|
||||
s_idle_frames = 0;
|
||||
set_cursor_visible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_idle_frames < kIdleHideFrames) {
|
||||
++s_idle_frames;
|
||||
set_cursor_visible(true);
|
||||
} else {
|
||||
set_cursor_visible(false);
|
||||
}
|
||||
set_cursor_visible(should_show_cursor(captured));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void read() {
|
||||
SDL_Window* window = aurora::window::get_sdl_window();
|
||||
const bool capture_active = syncCaptureState(window, shouldCaptureMouse(window));
|
||||
const bool capture_active = sync_capture_state(window, should_capture_mouse(window));
|
||||
update_cursor_visibility(window, capture_active);
|
||||
|
||||
if (!capture_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool aim_active = capture_active && queryMouseAimContext();
|
||||
const bool aim_active = capture_active && query_mouse_aim_context();
|
||||
const bool camera_active = capture_active && getSettings().game.enableMouseCamera;
|
||||
|
||||
float mx_rel = 0.0f;
|
||||
float my_rel = 0.0f;
|
||||
SDL_GetRelativeMouseState(&mx_rel, &my_rel);
|
||||
accumulateDeltas(mx_rel, my_rel, camera_active, aim_active);
|
||||
accumulate_deltas(mx_rel, my_rel, camera_active, aim_active);
|
||||
}
|
||||
|
||||
void getAimDeltas(float& out_yaw, float& out_pitch) {
|
||||
void get_aim_deltas(float& out_yaw, float& out_pitch) {
|
||||
out_yaw = s_aim_yaw_rad;
|
||||
out_pitch = s_aim_pitch_rad;
|
||||
}
|
||||
|
||||
void getCameraDeltas(float& out_yaw, float& out_pitch) {
|
||||
void get_camera_deltas(float& out_yaw, float& out_pitch) {
|
||||
out_yaw = 0.0f;
|
||||
out_pitch = 0.0f;
|
||||
|
||||
@@ -178,26 +198,28 @@ void getCameraDeltas(float& out_yaw, float& out_pitch) {
|
||||
|
||||
void handle_event(const SDL_Event& event) noexcept {
|
||||
switch (event.type) {
|
||||
case SDL_EVENT_MOUSE_MOTION:
|
||||
s_last_cursor_motion = Clock::now();
|
||||
break;
|
||||
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
||||
onFocusLost();
|
||||
on_focus_lost();
|
||||
break;
|
||||
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
||||
onFocusGained();
|
||||
on_focus_gained();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void onFocusLost() {
|
||||
void on_focus_lost() {
|
||||
SDL_Window* window = aurora::window::get_sdl_window();
|
||||
if (window != nullptr) {
|
||||
syncCaptureState(window, false);
|
||||
sync_capture_state(window, false);
|
||||
}
|
||||
s_idle_frames = 0;
|
||||
set_cursor_visible(true);
|
||||
}
|
||||
|
||||
void onFocusGained() {
|
||||
void on_focus_gained() {
|
||||
SDL_Window* window = aurora::window::get_sdl_window();
|
||||
syncCaptureState(window, shouldCaptureMouse(window));
|
||||
sync_capture_state(window, should_capture_mouse(window));
|
||||
}
|
||||
} // namespace dusk::mouse
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/config.hpp"
|
||||
#include <aurora/aurora.h>
|
||||
|
||||
namespace dusk {
|
||||
|
||||
@@ -267,7 +268,8 @@ void registerSettings() {
|
||||
Register(g_userSettings.game.touchCameraYSensitivity);
|
||||
Register(g_userSettings.game.minimalHUD);
|
||||
Register(g_userSettings.game.hudScale);
|
||||
Register(g_userSettings.game.pauseOnFocusLost);
|
||||
Register(g_userSettings.game.pauseOnFocusLost,
|
||||
[](const bool& value, const bool&) { aurora_set_pause_on_focus_lost(value); });
|
||||
Register(g_userSettings.game.enableDiscordPresence);
|
||||
Register(g_userSettings.game.bloomMode);
|
||||
Register(g_userSettings.game.bloomMultiplier);
|
||||
|
||||
@@ -34,9 +34,9 @@ void resetForSpeedrunMode() {
|
||||
getSettings().game.fastRoll.setSpeedrunValue(false);
|
||||
getSettings().game.fastSpinner.setSpeedrunValue(false);
|
||||
getSettings().game.armorRupeeDrain.setSpeedrunValue(MagicArmorMode::NORMAL);
|
||||
getSettings().game.invincibleEnemies.setSpeedrunValue(false);
|
||||
|
||||
getSettings().game.pauseOnFocusLost.setSpeedrunValue(false);
|
||||
aurora_set_pause_on_focus_lost(false);
|
||||
|
||||
getSettings().backend.enableAdvancedSettings.setSpeedrunValue(false);
|
||||
getSettings().game.recordingMode.setSpeedrunValue(false);
|
||||
|
||||
@@ -278,7 +278,7 @@ ControllerConfigWindow::ControllerConfigWindow(bool prelaunch) {
|
||||
void ControllerConfigWindow::hide(bool close) {
|
||||
stop_rumble_test();
|
||||
cancel_pending_binding();
|
||||
config::Save();
|
||||
config::save();
|
||||
Window::hide(close);
|
||||
}
|
||||
|
||||
@@ -403,7 +403,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
|
||||
PADClearPort(port);
|
||||
PADSetKeyboardActive(static_cast<u32>(port), FALSE);
|
||||
PADSerializeMappings();
|
||||
ClearAllActionBindings(port);
|
||||
config::ClearAllActionBindings(port);
|
||||
refresh_controller_page();
|
||||
});
|
||||
|
||||
@@ -417,7 +417,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
|
||||
PADClearPort(port);
|
||||
PADSetKeyboardActive(static_cast<u32>(port), TRUE);
|
||||
PADSerializeMappings();
|
||||
ClearAllActionBindings(port);
|
||||
config::ClearAllActionBindings(port);
|
||||
});
|
||||
|
||||
const u32 controllerCount = PADCount();
|
||||
@@ -439,7 +439,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
|
||||
PADSetKeyboardActive(static_cast<u32>(port), FALSE);
|
||||
PADSetPortForIndex(i, port);
|
||||
PADSerializeMappings();
|
||||
ClearAllActionBindings(port);
|
||||
config::ClearAllActionBindings(port);
|
||||
});
|
||||
}
|
||||
break;
|
||||
@@ -1125,7 +1125,7 @@ void ControllerConfigWindow::poll_pending_binding() {
|
||||
return;
|
||||
}
|
||||
mPendingActionBinding->setValue(button);
|
||||
config::Save();
|
||||
config::save();
|
||||
finish_pending_binding(completedPort);
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -51,6 +51,8 @@ struct ControlProps {
|
||||
float h = 0.0f;
|
||||
float scale = 1.0f;
|
||||
ControlAnchor anchor = ControlAnchor::None;
|
||||
|
||||
bool operator==(const ControlProps&) const = default;
|
||||
};
|
||||
|
||||
struct ControlRect {
|
||||
@@ -76,6 +78,8 @@ struct ControlLayout {
|
||||
|
||||
int version = Version;
|
||||
std::map<std::string, ControlProps, std::less<> > controls;
|
||||
|
||||
bool operator==(const ControlLayout&) const = default;
|
||||
};
|
||||
|
||||
constexpr std::array<std::string_view, 9> kControlLayoutIds = {
|
||||
|
||||
@@ -300,7 +300,7 @@ void GraphicsTuner::show() {
|
||||
}
|
||||
|
||||
void GraphicsTuner::hide(bool close) {
|
||||
config::Save();
|
||||
config::save();
|
||||
mRoot->RemoveAttribute("open");
|
||||
if (close) {
|
||||
mPendingClose = true;
|
||||
|
||||
+15
-6
@@ -197,10 +197,19 @@ void remove_element(Rml::Element*& elem) noexcept {
|
||||
|
||||
} // namespace
|
||||
|
||||
static std::string FormatTime(OSTime ticks) {
|
||||
OSCalendarTime t;
|
||||
OSTicksToCalendarTime(ticks, &t);
|
||||
return fmt::format("{0:02}:{1:02}:{2:02}.{3:03}", t.hour, t.min, t.sec, t.msec);
|
||||
static std::string FormatElapsedTime(OSTime ticksElapsed) {
|
||||
using namespace std::chrono;
|
||||
|
||||
milliseconds ms{OSTicksToMilliseconds(ticksElapsed)};
|
||||
|
||||
const hours hr = duration_cast<hours>(ms);
|
||||
ms -= hr;
|
||||
const minutes min = duration_cast<minutes>(ms);
|
||||
ms -= min;
|
||||
const seconds sec = duration_cast<seconds>(ms);
|
||||
ms -= sec;
|
||||
|
||||
return fmt::format("{0:02}:{1:02}:{2:02}.{3:03}", hr.count(), min.count(), sec.count(), ms.count());
|
||||
}
|
||||
|
||||
Overlay::Overlay() : Document(kDocumentSource, true) {
|
||||
@@ -317,13 +326,13 @@ void Overlay::update() {
|
||||
|
||||
if (getSettings().game.showSpeedrunRTATimer) {
|
||||
mSpeedrunRta->SetAttribute("open", "");
|
||||
mSpeedrunRta->SetInnerRML(escape(fmt::format("RTA {}", FormatTime(elapsedTime))));
|
||||
mSpeedrunRta->SetInnerRML(escape(fmt::format("RTA {}", FormatElapsedTime(elapsedTime))));
|
||||
} else {
|
||||
mSpeedrunRta->RemoveAttribute("open");
|
||||
}
|
||||
|
||||
mSpeedrunIgt->SetInnerRML(
|
||||
escape(fmt::format("IGT {}", FormatTime(m_speedrunInfo.m_igtTimer))));
|
||||
escape(fmt::format("IGT {}", FormatElapsedTime(m_speedrunInfo.m_igtTimer))));
|
||||
} else {
|
||||
mSpeedrunTimer->RemoveAttribute("open");
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ void persist_disc_choice(const std::string& path, iso::ValidationError validatio
|
||||
|
||||
getSettings().backend.isoPath.setValue(path);
|
||||
getSettings().backend.isoVerification.setValue(verification);
|
||||
config::Save();
|
||||
config::save();
|
||||
|
||||
if (previousPath != path || previousVerification != verification) {
|
||||
iso::log_verification_state(path, verification);
|
||||
|
||||
@@ -106,7 +106,7 @@ PresetWindow::PresetWindow() : WindowSmall("modal", "modal-dialog") {
|
||||
if (cmd == NavCommand::Confirm) {
|
||||
apply();
|
||||
getSettings().backend.wasPresetChosen.setValue(true);
|
||||
config::Save();
|
||||
config::save();
|
||||
hide(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
+27
-32
@@ -248,7 +248,6 @@ void reset_for_speedrun_mode() {
|
||||
getSettings().game.invincibleEnemies.setSpeedrunValue(false);
|
||||
|
||||
getSettings().game.pauseOnFocusLost.setSpeedrunValue(false);
|
||||
aurora_set_pause_on_focus_lost(false);
|
||||
|
||||
getSettings().backend.enableAdvancedSettings.setSpeedrunValue(false);
|
||||
getSettings().game.recordingMode.setSpeedrunValue(false);
|
||||
@@ -263,7 +262,6 @@ void clear_speedrun_overrides() {
|
||||
|
||||
void restore_from_speedrun_mode() {
|
||||
clear_speedrun_overrides();
|
||||
aurora_set_pause_on_focus_lost(getSettings().game.pauseOnFocusLost.getValue());
|
||||
}
|
||||
|
||||
std::filesystem::path normalized_display_path(const std::filesystem::path& path) {
|
||||
@@ -447,7 +445,7 @@ SelectButton& config_bool_select(
|
||||
return;
|
||||
}
|
||||
var.setValue(value);
|
||||
config::Save();
|
||||
config::save();
|
||||
if (callback) {
|
||||
callback(value);
|
||||
}
|
||||
@@ -468,7 +466,7 @@ void add_speedrun_disabled_option(Pane& leftPane, Pane& rightPane, ConfigVar<boo
|
||||
config_bool_select(leftPane, rightPane, var, {
|
||||
.key = key,
|
||||
.helpText = helpText,
|
||||
.isDisabled = [] { return getSettings().game.speedrunMode; },
|
||||
.isDisabled = [] { return getSettings().game.speedrunMode.getValue(); },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -481,7 +479,7 @@ SelectButton& config_percent_select(Pane& leftPane, Pane& rightPane, ConfigVar<f
|
||||
.setValue =
|
||||
[&var, min, max](int value) {
|
||||
var.setValue(std::clamp(value, min, max) / 100.0f);
|
||||
config::Save();
|
||||
config::save();
|
||||
},
|
||||
.isDisabled = std::move(isDisabled),
|
||||
.isModified = [&var] { return var.getValue() != var.getDefaultValue(); },
|
||||
@@ -503,12 +501,12 @@ SelectButton& config_int_select(Pane& leftPane, Pane& rightPane, ConfigVar<int>&
|
||||
std::string suffix = "") {
|
||||
auto& button = leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = std::move(key),
|
||||
.getValue = [&var] { return var; },
|
||||
.getValue = [&var] { return var.getValue(); },
|
||||
.setValue =
|
||||
[&var, min, max, callback = std::move(onChange)](int value) {
|
||||
const int clampedValue = std::clamp(value, min, max);
|
||||
var.setValue(clampedValue);
|
||||
config::Save();
|
||||
config::save();
|
||||
if (callback) {
|
||||
callback(clampedValue);
|
||||
}
|
||||
@@ -680,7 +678,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
.on_pressed([i] {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().game.language.setValue(static_cast<GameLanguage>(i));
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
}
|
||||
pane.add_rml("<br/>Changes require a restart.");
|
||||
@@ -707,7 +705,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().backend.graphicsBackend.setValue(
|
||||
std::string{backend_id(backend)});
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
}
|
||||
pane.add_rml("<br/>Changes require a restart.");
|
||||
@@ -738,7 +736,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
.on_pressed([i] {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().backend.cardFileType.setValue(i);
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -755,7 +753,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen);
|
||||
VISetWindowFullscreen(getSettings().video.enableFullscreen);
|
||||
config::Save();
|
||||
config::save();
|
||||
}),
|
||||
rightPane, [](Pane& pane) { pane.clear(); });
|
||||
leftPane.register_control(leftPane.add_button("Restore Default Window Size").on_pressed([] {
|
||||
@@ -786,7 +784,6 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
{
|
||||
.key = "Pause on Focus Lost",
|
||||
.helpText = "Pause the game when window focus is lost.",
|
||||
.onChange = [](bool value) { aurora_set_pause_on_focus_lost(value); },
|
||||
.isDisabled = [] { return IsMobile || getSettings().game.speedrunMode; },
|
||||
});
|
||||
leftPane.register_control(
|
||||
@@ -818,7 +815,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
.on_pressed([] {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().video.enableFpsOverlay.setValue(false);
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
for (int i = 0; i < static_cast<int>(kFpsOverlayCornerNames.size()); ++i) {
|
||||
pane.add_button(
|
||||
@@ -834,7 +831,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().video.enableFpsOverlay.setValue(true);
|
||||
getSettings().video.fpsOverlayCorner.setValue(i);
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
}
|
||||
pane.add_rml(
|
||||
@@ -850,7 +847,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
const auto windowSize = aurora::window::get_window_size();
|
||||
dusk::getSettings().video.lastWindowWidth.setValue(windowSize.width);
|
||||
dusk::getSettings().video.lastWindowHeight.setValue(windowSize.height);
|
||||
dusk::config::Save();
|
||||
dusk::config::save();
|
||||
}
|
||||
},
|
||||
.isDisabled = [] { return IsMobile; },
|
||||
@@ -956,7 +953,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().game.enableFrameInterpolation.setValue(static_cast<FrameInterpMode>(i));
|
||||
android::update_surface_frame_rate();
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
}
|
||||
pane.add_rml(kUnlockFramerateHelpText);
|
||||
@@ -1055,7 +1052,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().game.touchTargeting.setValue(
|
||||
static_cast<TouchTargeting>(i));
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
}
|
||||
pane.add_rml(fmt::format("<br/>Hybrid: {}<br/>Hold: {}<br/>Switch: {}",
|
||||
@@ -1151,7 +1148,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
leftPane.add_section("Tools");
|
||||
addOption("Turbo Key", getSettings().game.enableTurboKeybind,
|
||||
"Hold Tab to increase game speed by up to 4x.",
|
||||
[] { return getSettings().game.speedrunMode; });
|
||||
[] { return getSettings().game.speedrunMode.getValue(); });
|
||||
addOption("Reset Key (" + Rml::String{hotkeys::DO_RESET} + ")",
|
||||
getSettings().game.enableResetKeybind,
|
||||
"Press " + Rml::String{hotkeys::DO_RESET} + " to reset the game.");
|
||||
@@ -1170,7 +1167,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
.setValue =
|
||||
[](int value) {
|
||||
getSettings().audio.masterVolume.setValue(value);
|
||||
config::Save();
|
||||
config::save();
|
||||
audio::SetMasterVolume(audio::MasterVolumeToLinear(value / 100.0f));
|
||||
},
|
||||
.isModified =
|
||||
@@ -1262,9 +1259,9 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
.setValue =
|
||||
[](int value) {
|
||||
getSettings().game.damageMultiplier.setValue(value);
|
||||
config::Save();
|
||||
config::save();
|
||||
},
|
||||
.isDisabled = [] { return getSettings().game.speedrunMode; },
|
||||
.isDisabled = [] { return getSettings().game.speedrunMode.getValue(); },
|
||||
.isModified =
|
||||
[] {
|
||||
return getSettings().game.damageMultiplier.getValue() !=
|
||||
@@ -1408,7 +1405,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
[] {
|
||||
return kMagicArmorModes[static_cast<u8>(getSettings().game.armorRupeeDrain.getValue())];
|
||||
},
|
||||
.isDisabled = [] { return getSettings().game.speedrunMode; },
|
||||
.isDisabled = [] { return getSettings().game.speedrunMode.getValue(); },
|
||||
.isModified =
|
||||
[] {
|
||||
return getSettings().game.armorRupeeDrain.getValue() !=
|
||||
@@ -1427,7 +1424,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
.on_pressed([i] {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().game.armorRupeeDrain.setValue(static_cast<MagicArmorMode>(i));
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
}
|
||||
pane.add_rml(
|
||||
@@ -1480,13 +1477,13 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().game.enableAchievementToasts.setValue(true);
|
||||
getSettings().game.enableControllerToasts.setValue(true);
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
pane.add_button("Select None").on_pressed([] {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().game.enableAchievementToasts.setValue(false);
|
||||
getSettings().game.enableControllerToasts.setValue(false);
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
|
||||
pane.add_section("Types");
|
||||
@@ -1502,7 +1499,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
auto& v = getSettings().game.enableAchievementToasts;
|
||||
v.setValue(!v.getValue());
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
pane.add_button(
|
||||
{
|
||||
@@ -1514,7 +1511,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
auto& v = getSettings().game.enableControllerToasts;
|
||||
v.setValue(!v.getValue());
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
pane.add_rml("<br/>Choose which notifications can be displayed.");
|
||||
});
|
||||
@@ -1580,7 +1577,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
}
|
||||
}
|
||||
},
|
||||
.isDisabled = [] { return getSettings().game.speedrunMode; },
|
||||
.isDisabled = [] { return getSettings().game.speedrunMode.getValue(); },
|
||||
});
|
||||
config_bool_select(leftPane, rightPane, getSettings().game.showInputViewer,
|
||||
{
|
||||
@@ -1617,15 +1614,13 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
[i] {
|
||||
return getSettings().game.menuScalingMode.getValue() ==
|
||||
static_cast<MenuScaling>(i);
|
||||
;
|
||||
},
|
||||
})
|
||||
.on_pressed([i] {
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
getSettings().game.menuScalingMode.setValue(
|
||||
static_cast<MenuScaling>(i));
|
||||
;
|
||||
config::Save();
|
||||
config::save();
|
||||
});
|
||||
}
|
||||
pane.add_rml("<br/>Changes how the Collection and File Select menus scale to your "
|
||||
@@ -1651,7 +1646,7 @@ void SettingsWindow::update() {
|
||||
}
|
||||
|
||||
void SettingsWindow::hide(bool close) {
|
||||
config::Save();
|
||||
config::save();
|
||||
Window::hide(close);
|
||||
}
|
||||
|
||||
|
||||
@@ -585,7 +585,7 @@ bool TouchControlsEditor::handle_nav_command(Rml::Event& event, NavCommand cmd)
|
||||
void TouchControlsEditor::save_layout() {
|
||||
mWorkingLayout.version = ControlLayout::Version;
|
||||
getSettings().game.touchControlsLayout.setValue(mWorkingLayout);
|
||||
config::Save();
|
||||
config::save();
|
||||
mDoAud_seStartMenu(kSoundItemChange);
|
||||
pop();
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ static void mDoMemCdRWm_BuildHeader(mDoMemCdRWm_HeaderData* header) {
|
||||
#endif
|
||||
|
||||
OSCalendarTime time;
|
||||
OSTicksToCalendarTime(OSGetTime(), &time);
|
||||
OSTicksToCalendarTime(DUSK_IF_ELSE(OSGetSystemTime(), OSGetTime()), &time);
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::version::isRegionPal()) {
|
||||
|
||||
@@ -527,7 +527,7 @@ void myExceptionCallback(u16, OSContext*, u32, u32) {
|
||||
u32 btnHold;
|
||||
u32 btnTrig;
|
||||
|
||||
mDoMain::sHungUpTime = OSGetTime();
|
||||
mDoMain::sHungUpTime = DUSK_IF_ELSE(OSGetSystemTime(), OSGetTime());
|
||||
OSReportEnable();
|
||||
cAPICPad_recalibrate();
|
||||
// "Vibration stopping & resetting to default\n"
|
||||
|
||||
+15
-21
@@ -249,12 +249,12 @@ void main01(void) {
|
||||
goto eventsDone;
|
||||
case AURORA_PAUSED:
|
||||
dusk::audio::SetPaused(true);
|
||||
dusk::mouse::onFocusLost();
|
||||
dusk::mouse::on_focus_lost();
|
||||
break;
|
||||
case AURORA_UNPAUSED:
|
||||
dusk::audio::SetPaused(false);
|
||||
dusk::game_clock::reset_frame_timer();
|
||||
dusk::mouse::onFocusGained();
|
||||
dusk::mouse::on_focus_gained();
|
||||
break;
|
||||
case AURORA_SDL_EVENT:
|
||||
dusk::mouse::handle_event(event->sdl);
|
||||
@@ -265,7 +265,7 @@ void main01(void) {
|
||||
if (dusk::getSettings().video.rememberWindowSize && !dusk::getSettings().video.enableFullscreen) {
|
||||
dusk::getSettings().video.lastWindowWidth.setValue(event->windowSize.width);
|
||||
dusk::getSettings().video.lastWindowHeight.setValue(event->windowSize.height);
|
||||
dusk::config::Save();
|
||||
dusk::config::save();
|
||||
}
|
||||
break;
|
||||
case AURORA_DISPLAY_SCALE_CHANGED:
|
||||
@@ -430,16 +430,7 @@ static void ApplyCVarOverrides(const cxxopts::OptionValue& option) {
|
||||
const auto name = std::string_view(cvarArg).substr(0, sep);
|
||||
const auto value = std::string_view(cvarArg).substr(sep + 1);
|
||||
|
||||
const auto cVar = dusk::config::GetConfigVar(name);
|
||||
if (!cVar) {
|
||||
DuskLog.fatal("Unknown --cvar name: '{}'", name);
|
||||
}
|
||||
|
||||
try {
|
||||
cVar->getImpl()->loadFromArg(*cVar, value);
|
||||
} catch (const std::exception& e) {
|
||||
DuskLog.fatal("Unable to parse: '{}': {}", value, e.what());
|
||||
}
|
||||
dusk::config::load_arg_override(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,7 +501,6 @@ int game_main(int argc, char* argv[]) {
|
||||
mainCalled = true;
|
||||
|
||||
dusk::registerSettings();
|
||||
dusk::config::FinishRegistration();
|
||||
|
||||
cxxopts::ParseResult parsed_arg_options;
|
||||
|
||||
@@ -551,10 +541,7 @@ int game_main(int argc, char* argv[]) {
|
||||
|
||||
log_build_info();
|
||||
|
||||
dusk::config::LoadFromUserPreferences();
|
||||
if (dusk::getSettings().game.speedrunMode) {
|
||||
dusk::resetForSpeedrunMode();
|
||||
}
|
||||
dusk::config::load_from_user_preferences();
|
||||
ApplyCVarOverrides(parsed_arg_options["cvar"]);
|
||||
dusk::android::update_surface_frame_rate();
|
||||
dusk::crash_reporting::initialize();
|
||||
@@ -618,6 +605,12 @@ int game_main(int argc, char* argv[]) {
|
||||
auroraInfo = aurora_initialize(argc, argv, &config);
|
||||
}
|
||||
|
||||
// Apply after aurora_initialize: speedrun mode mutates cvars whose change callbacks push
|
||||
// values into aurora.
|
||||
if (dusk::getSettings().game.speedrunMode) {
|
||||
dusk::resetForSpeedrunMode();
|
||||
}
|
||||
|
||||
#ifdef DUSK_DISCORD
|
||||
if (dusk::getSettings().game.enableDiscordPresence) {
|
||||
dusk::discord::initialize();
|
||||
@@ -700,7 +693,7 @@ int game_main(int argc, char* argv[]) {
|
||||
dusk::getSettings().backend.isoPath.setValue(dvd_path);
|
||||
dusk::getSettings().backend.isoVerification.setValue(
|
||||
dusk::DiscVerificationState::Unknown);
|
||||
dusk::config::Save();
|
||||
dusk::config::save();
|
||||
dusk::IsGameLaunched = true;
|
||||
}
|
||||
} else {
|
||||
@@ -723,7 +716,7 @@ int game_main(int argc, char* argv[]) {
|
||||
saveConfigBeforePrelaunch = true;
|
||||
}
|
||||
if (saveConfigBeforePrelaunch) {
|
||||
dusk::config::Save();
|
||||
dusk::config::save();
|
||||
}
|
||||
|
||||
if (!dusk::getSettings().backend.skipPreLaunchUI) {
|
||||
@@ -777,7 +770,7 @@ int game_main(int argc, char* argv[]) {
|
||||
|
||||
OSInit();
|
||||
|
||||
mDoMain::sPowerOnTime = OSGetTime();
|
||||
mDoMain::sPowerOnTime = DUSK_IF_ELSE(OSGetSystemTime(), OSGetTime());
|
||||
|
||||
// Reset Data
|
||||
static mDoRstData sResetData = {0};
|
||||
@@ -814,6 +807,7 @@ int game_main(int argc, char* argv[]) {
|
||||
#endif
|
||||
dusk::ui::shutdown();
|
||||
dusk::texture_replacements::shutdown();
|
||||
dusk::config::shutdown();
|
||||
aurora_shutdown();
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user