mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-20 05:16:24 -04:00
Mod SDK: Gamemode Service, Change Speedrun mode to a gamemode, Allow prelaunch to be restarted
This commit is contained in:
@@ -470,6 +470,53 @@ if (svc_camera->get_camera(mod_ctx, game_view, &camera) == MOD_OK) {
|
||||
first in-game frame. Projection matrices match the renderer's WebGPU clip convention and renderer depth convention
|
||||
(reversed-Z by default).
|
||||
|
||||
### GamemodeService (`mods/svc/gamemode.h`)
|
||||
|
||||
Allows a mod to register a gamemode that allows the game to designate one form of gameplay (named a gamemode). This
|
||||
is intended to allow large mods that change large amounts of game logic (such as a randomizer) to have explicit control
|
||||
over how the game will function at certain points. When a gamemode is registered via the service, it will add an entry
|
||||
to the pre-launch menu. When selected, the game will use a unique set of savefiles (designated by the `saveName` field)
|
||||
to store save data while the gamemode is active. Any function pointers registered with the gamemode will be called by
|
||||
dusklight when their condition is met.
|
||||
|
||||
Note: for any gamemode wishing to use the vanilla set of savefiles, use `gczelda2` as the save file name.
|
||||
|
||||
```cpp
|
||||
IMPORT_SERVICE(GamemodeService, svc_gamemode);
|
||||
|
||||
void onSaveLoaded() {
|
||||
// This function will be invoked by the game as a save is loaded
|
||||
}
|
||||
|
||||
#define ONLY_GAMEMODE(ctx, id) \
|
||||
{ \
|
||||
bool isGamemodeActive; \
|
||||
svc_gamemode->is_active(ctx, id, &isGamemodeActive); \
|
||||
if (!isGamemodeActive) { \
|
||||
return; \
|
||||
} \
|
||||
}
|
||||
|
||||
static HookAction myFunctionHook(ModContext *ctx, void *args, void *, void *) {
|
||||
// Note: normal function hooks will need to check if the gamemode is active
|
||||
ONLY_GAMEMODE(ctx,"id"); // A macro like this can make it easy
|
||||
}
|
||||
|
||||
const GamemodeDesc gamemodeDesc = {
|
||||
.gamemodeId = "my-unique-gamemode-id",
|
||||
.fullName = "Gamemode Name",
|
||||
.saveName = "my-unique-save-name",
|
||||
.onActivatedFunction = nullptr,
|
||||
.onDeactivatedFunction = nullptr,
|
||||
.onPlayFunction = nullptr,
|
||||
.onSaveLoadedFunction = onSaveLoaded,
|
||||
.onNewSaveFunction = nullptr,
|
||||
.onGameResetFunction = nullptr,
|
||||
.onTickFunction = nullptr,
|
||||
};
|
||||
svc_gamemode->register_gamemode(mod_ctx, &gamemodeDesc);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Hooking Game Functions
|
||||
|
||||
@@ -1441,6 +1441,7 @@ set(DUSK_FILES
|
||||
src/dusk/file_select.hpp
|
||||
src/dusk/frame_interpolation.cpp
|
||||
src/dusk/game_clock.cpp
|
||||
src/dusk/gamemode.cpp
|
||||
src/dusk/gamepad_color.cpp
|
||||
src/dusk/globals.cpp
|
||||
src/dusk/gyro.cpp
|
||||
@@ -1498,6 +1499,7 @@ set(DUSK_FILES
|
||||
src/dusk/mods/svc/texture.cpp
|
||||
src/dusk/mods/svc/ui.cpp
|
||||
src/dusk/mods/svc/ui.hpp
|
||||
src/dusk/mods/svc/gamemode.cpp
|
||||
src/dusk/mouse.cpp
|
||||
src/dusk/scope_guard.hpp
|
||||
src/dusk/settings.cpp
|
||||
|
||||
@@ -112,6 +112,11 @@ public:
|
||||
mSerialNo = serial_no;
|
||||
}
|
||||
|
||||
#ifdef TARGET_PC
|
||||
void setFileName(const std::string& fileName);
|
||||
const char* getFileName();
|
||||
#endif
|
||||
|
||||
/* 0x0000 */ u8 mData[SAVEFILE_SIZE];
|
||||
/* 0x1FBC */ u8 mChannel;
|
||||
/* 0x1FBD */ u8 mCopyToPos;
|
||||
@@ -124,6 +129,11 @@ public:
|
||||
/* 0x1FEC */ s32 mNandState;
|
||||
/* 0x1FF0 */ u64 mSerialNo;
|
||||
/* 0x1FF8 */ u32 mDataVersion;
|
||||
#ifdef TARGET_PC
|
||||
bool mInitialized;
|
||||
std::string mFileName;
|
||||
#endif
|
||||
|
||||
}; // Size: 0x2000
|
||||
|
||||
STATIC_ASSERT(sizeof(mDoMemCd_Ctrl_c) == 8192);
|
||||
@@ -230,4 +240,14 @@ inline s32 mDoMemCd_checkNANDFile() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_PC
|
||||
inline void mDoMemCd_SetFileName(const std::string& fileName) {
|
||||
g_mDoMemCd_control.setFileName(fileName);
|
||||
}
|
||||
|
||||
inline const char* mDoMemCd_GetFileName() {
|
||||
return g_mDoMemCd_control.getFileName();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* M_DO_M_DO_MEMCARD_H */
|
||||
|
||||
@@ -519,3 +519,13 @@ progress.verification-progress-bar {
|
||||
flex: 0 0 auto;
|
||||
padding-top: 4dp;
|
||||
}
|
||||
|
||||
.modal-actions-vertical {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.modal-actions-vertical button.modal-btn {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <mods/api.h>
|
||||
#include <mods/svc/config.h>
|
||||
|
||||
#define GAMEMODE_SERVICE_ID "dev.twilitrealm.dusklight.gamemode"
|
||||
#define GAMEMODE_SERVICE_MAJOR 1u
|
||||
#define GAMEMODE_SERVICE_MINOR 0u
|
||||
|
||||
typedef struct {
|
||||
const char* gamemodeId;
|
||||
const char* fullName;
|
||||
const char* saveName;
|
||||
void (*onActivatedFunction)();
|
||||
void (*onDeactivatedFunction)();
|
||||
void (*onPlayFunction)();
|
||||
void (*onSaveLoadedFunction)();
|
||||
void (*onNewSaveFunction)();
|
||||
void (*onGameResetFunction)();
|
||||
void (*onTickFunction)();
|
||||
} GamemodeDesc;
|
||||
|
||||
typedef struct GamemodeService {
|
||||
ServiceHeader header;
|
||||
ModResult (*register_gamemode)(ModContext* ctx, const GamemodeDesc* desc);
|
||||
ModResult (*unregister_gamemode)(ModContext* ctx, const char* id);
|
||||
ModResult (*is_active)(ModContext* ctx, const char* gamemodeId, bool* out_active);
|
||||
} GamemodeService;
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "mods/service.hpp"
|
||||
|
||||
template <>
|
||||
struct mods::ServiceTraits<GamemodeService> {
|
||||
static constexpr const char* id = GAMEMODE_SERVICE_ID;
|
||||
static constexpr uint16_t major_version = GAMEMODE_SERVICE_MAJOR;
|
||||
static constexpr uint16_t minor_version = GAMEMODE_SERVICE_MINOR;
|
||||
};
|
||||
#endif
|
||||
@@ -23,9 +23,12 @@
|
||||
#include "d/actor/d_a_npc_tkc.h"
|
||||
#include <cstring>
|
||||
|
||||
#ifdef TARGET_PC
|
||||
#include "dusk/imgui/ImGuiConsole.hpp"
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/speedrun.h"
|
||||
#include "dusk/gamemode.hpp"
|
||||
#endif
|
||||
|
||||
BOOL daAlink_c::checkEventRun() const {
|
||||
return dComIfGp_event_runCheck() || checkPlayerDemoMode();
|
||||
@@ -4009,9 +4012,9 @@ int daAlink_c::procGanonFinishInit() {
|
||||
onEndResetFlg1(ERFLG1_SHIELD_BACKBONE);
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.speedrunMode) {
|
||||
if (dusk::m_speedrunInfo.m_isRunStarted) {
|
||||
dusk::m_speedrunInfo.stopRun();
|
||||
if (dusk::speedrun::isActive()) {
|
||||
if (dusk::speedrun::g_speedrunInfo.m_isRunStarted) {
|
||||
dusk::speedrun::g_speedrunInfo.stopRun();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -9,11 +9,15 @@
|
||||
#include "JSystem/J2DGraph/J2DScreen.h"
|
||||
#include "JSystem/J2DGraph/J2DTextBox.h"
|
||||
#include "d/d_msg_string.h"
|
||||
#include "m_Do/m_Do_controller_pad.h"
|
||||
|
||||
#ifdef TARGET_PC
|
||||
#include <dusk/autosave.h>
|
||||
#include "dusk/livesplit.h"
|
||||
#include "dusk/imgui/ImGuiConsole.hpp"
|
||||
#include "dusk/speedrun.h"
|
||||
#include "m_Do/m_Do_controller_pad.h"
|
||||
#include <dusk/autosave.h>
|
||||
#include "dusk/gamemode.hpp"
|
||||
#endif
|
||||
|
||||
dBrightCheck_c::dBrightCheck_c(JKRArchive* i_archive) {
|
||||
mArchive = i_archive;
|
||||
@@ -143,12 +147,10 @@ void dBrightCheck_c::modeMove() {
|
||||
if (mDoCPd_c::getTrigA(PAD_1) || mDoCPd_c::getTrigStart(PAD_1)) {
|
||||
mDoAud_seStart(Z2SE_ENTER_GAME, NULL, 0, 0);
|
||||
#ifdef TARGET_PC
|
||||
if (dusk::getSettings().game.speedrunMode && !dusk::getSettings().game.hideTvSettingsScreen) {
|
||||
// start a new run if a run isn't already in progress
|
||||
if (!dusk::m_speedrunInfo.m_isRunStarted) {
|
||||
dusk::resetForSpeedrunMode();
|
||||
dusk::m_speedrunInfo.startRun();
|
||||
dusk::speedrun::start();
|
||||
if (!dusk::getSettings().game.hideTvSettingsScreen) {
|
||||
const dusk::gamemode::Gamemode* gamemode = dusk::gamemode::getGamemodeManager().getCurrentGamemode();
|
||||
if (gamemode) {
|
||||
gamemode->mOnSaveLoadedFunction();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-12
@@ -9,11 +9,6 @@
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/d_meter2_info.h"
|
||||
#include "d/d_s_name.h"
|
||||
#include "dusk/imgui/ImGuiConsole.hpp"
|
||||
#include "dusk/livesplit.h"
|
||||
#include "dusk/memory.h"
|
||||
#include "dusk/speedrun.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "f_op/f_op_overlap_mng.h"
|
||||
#include "f_op/f_op_scene_mng.h"
|
||||
#include "m_Do/m_Do_Reset.h"
|
||||
@@ -21,7 +16,16 @@
|
||||
#include "m_Do/m_Do_machine.h"
|
||||
#include "m_Do/m_Do_main.h"
|
||||
#include "m_Do/m_Do_mtx.h"
|
||||
#include <dusk/autosave.h>
|
||||
|
||||
#ifdef TARGET_PC
|
||||
#include "dusk/imgui/ImGuiConsole.hpp"
|
||||
#include "dusk/livesplit.h"
|
||||
#include "dusk/memory.h"
|
||||
#include "dusk/speedrun.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/autosave.h"
|
||||
#include "dusk/gamemode.hpp"
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
#define SHOW_TV_SETTINGS_SCREEN (this->mShowTvSettingsScreen)
|
||||
@@ -418,12 +422,10 @@ void dScnName_c::changeGameScene() {
|
||||
dComIfGs_setRestartRoomParam(0);
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.speedrunMode && dusk::getSettings().game.hideTvSettingsScreen) {
|
||||
// start a new run on file load if a run isn't already in progress
|
||||
if (!dusk::m_speedrunInfo.m_isRunStarted) {
|
||||
dusk::resetForSpeedrunMode();
|
||||
dusk::m_speedrunInfo.startRun();
|
||||
dusk::speedrun::start();
|
||||
if (dusk::getSettings().game.hideTvSettingsScreen) {
|
||||
const dusk::gamemode::Gamemode* gamemode = dusk::gamemode::getGamemodeManager().getCurrentGamemode();
|
||||
if (gamemode) {
|
||||
gamemode->mOnSaveLoadedFunction();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/gamemode.hpp"
|
||||
#include <f_ap/f_ap_game.h>
|
||||
|
||||
#include "helpers/string.hpp"
|
||||
@@ -1531,6 +1532,13 @@ void dSv_save_c::init() {
|
||||
|
||||
mEvent.init();
|
||||
mMiniGame.init();
|
||||
|
||||
#ifdef TARGET_PC
|
||||
const dusk::gamemode::Gamemode* gamemode = dusk::gamemode::getGamemodeManager().getCurrentGamemode();
|
||||
if (gamemode) {
|
||||
gamemode->mOnNewSaveFunction();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
dSv_memory2_c* dSv_save_c::getSave2(int i_stage2No) {
|
||||
|
||||
@@ -509,6 +509,12 @@ BOOL OSJoinThread(OSThread* thread, void** val) {
|
||||
*(s32*)val = (s32)(intptr_t)thread->val;
|
||||
}
|
||||
thread->state = 0;
|
||||
|
||||
{
|
||||
std::lock_guard mapLock(GetThreadDataMutex());
|
||||
GetThreadDataMap().erase(thread);
|
||||
}
|
||||
sActiveThreadCount--;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
#include "dusk/gamemode.hpp"
|
||||
#include "dusk/config.hpp"
|
||||
#include "JSystem/JUtility/JUTGamePad.h"
|
||||
#include "aurora/lib/logging.hpp"
|
||||
#include "m_Do/m_Do_MemCard.h"
|
||||
#include "dusk/ui/prelaunch.hpp"
|
||||
|
||||
namespace dusk::gamemode {
|
||||
|
||||
GamemodeManager g_GamemodeManager;
|
||||
|
||||
aurora::Module DuskGamemodeLog("dusk::gamemode");
|
||||
|
||||
GamemodeManager::GamemodeManager() {
|
||||
registerGamemode(Gamemode("vanilla","Vanilla","gczelda2"));
|
||||
|
||||
mCurrentGamemodeId = "vanilla";
|
||||
}
|
||||
|
||||
void GamemodeManager::setGamemodeToPrevious() {
|
||||
// Gets the value from the settings of the last played gamemode id and sets that to the current gamemode (if registered)
|
||||
GamemodeId id = dusk::getSettings().game.lastSelectedGamemodeId;
|
||||
if (mRegisteredGamemodes.find(id) == mRegisteredGamemodes.end()) {
|
||||
setCurrentGamemode("vanilla");
|
||||
return;
|
||||
}
|
||||
setCurrentGamemode(id);
|
||||
}
|
||||
|
||||
void GamemodeManager::registerGamemode(const Gamemode& gamemode) {
|
||||
if (gamemode.getId().empty()) {
|
||||
DuskGamemodeLog.fatal("No gamemode id specified in GamemodeManager::registerGamemode!");
|
||||
}
|
||||
if (gamemode.getSaveName().empty()) {
|
||||
DuskGamemodeLog.fatal("No save name provided for gamemode {}", gamemode.getId());
|
||||
}
|
||||
if (gamemode.getFullName().empty()) {
|
||||
DuskGamemodeLog.fatal("No Name Specified for gamemode {}", gamemode.getId());
|
||||
}
|
||||
|
||||
if (mRegisteredGamemodes.find(gamemode.getId()) != mRegisteredGamemodes.end()) {
|
||||
DuskGamemodeLog.warn("Attempting to register gamemode {} when it is already registered!", gamemode.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
mRegisteredGamemodes.emplace(gamemode.getId(),gamemode);
|
||||
dusk::ui::Prelaunch::rebuild_menu_buttons();
|
||||
}
|
||||
|
||||
void GamemodeManager::unregisterGamemode(const GamemodeId& gamemodeId) {
|
||||
const auto& it = mRegisteredGamemodes.find(gamemodeId);
|
||||
if (it == mRegisteredGamemodes.end()) {
|
||||
DuskGamemodeLog.warn(
|
||||
"Attempting to unregister gamemode of id {} that isn't registered!", gamemodeId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrentGamemodeId == gamemodeId) {
|
||||
// We need to be careful if we are unregistering a running gamemode, the easiest way is just
|
||||
// to reset the game back to title as vanilla;
|
||||
ui::prelaunch_state().showPrelaunchOnReset = true;
|
||||
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
|
||||
setCurrentGamemode("vanilla");
|
||||
}
|
||||
mRegisteredGamemodes.erase(it);
|
||||
dusk::ui::Prelaunch::rebuild_menu_buttons();
|
||||
}
|
||||
|
||||
void GamemodeManager::setCurrentGamemode(const GamemodeId& id) {
|
||||
if (mCurrentGamemodeId == id) {
|
||||
return;
|
||||
}
|
||||
const Gamemode* currentGamemode = getCurrentGamemode();
|
||||
if (currentGamemode) {
|
||||
currentGamemode->mOnDeactivatedFunction();
|
||||
}
|
||||
if (mRegisteredGamemodes.find(id) == mRegisteredGamemodes.end()) {
|
||||
DuskGamemodeLog.warn("Attempting to set current game mode to {} when it hasn't been registered!", id);
|
||||
}
|
||||
|
||||
mCurrentGamemodeId = id;
|
||||
dusk::getSettings().game.lastSelectedGamemodeId.setValue(id);
|
||||
dusk::config::save();
|
||||
|
||||
currentGamemode = getCurrentGamemode();
|
||||
if (currentGamemode) {
|
||||
// Set the loaded save file to our gamemode's save name
|
||||
mDoMemCd_SetFileName(currentGamemode->mSaveName);
|
||||
currentGamemode->mOnActivatedFunction();
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace dusk::gamemode
|
||||
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
namespace dusk::gamemode {
|
||||
using GamemodeId = std::string;
|
||||
|
||||
// This class holds the definition for the gamemode and various function pointers to call
|
||||
class Gamemode {
|
||||
public:
|
||||
Gamemode(const GamemodeId& id, const std::string& fullName, const std::string& saveName) {
|
||||
mId = id;
|
||||
mFullName = fullName;
|
||||
mSaveName = saveName;
|
||||
}
|
||||
const GamemodeId& getId() const { return mId; }
|
||||
const std::string& getFullName() const { return mFullName; }
|
||||
const std::string& getSaveName() const { return mSaveName; }
|
||||
|
||||
GamemodeId mId;
|
||||
std::string mFullName;
|
||||
std::string mSaveName;
|
||||
|
||||
std::function<void()> mOnActivatedFunction = gamemodeStub;
|
||||
std::function<void()> mOnDeactivatedFunction = gamemodeStub;
|
||||
std::function<void()> mOnPlayFunction = gamemodeStub;
|
||||
std::function<void()> mOnSaveLoadedFunction = gamemodeStub;
|
||||
std::function<void()> mOnNewSaveFunction = gamemodeStub;
|
||||
std::function<void()> mOnGameResetFunction = gamemodeStub;
|
||||
std::function<void()> mOnTickFunction = gamemodeStub;
|
||||
|
||||
private:
|
||||
static void gamemodeStub() {}
|
||||
};
|
||||
|
||||
class GamemodeManager {
|
||||
public:
|
||||
GamemodeManager();
|
||||
void registerGamemode(const Gamemode& gamemode);
|
||||
void unregisterGamemode(const GamemodeId& gamemodeId);
|
||||
|
||||
const Gamemode* getCurrentGamemode() const {
|
||||
const auto& it = mRegisteredGamemodes.find(mCurrentGamemodeId);
|
||||
return it != mRegisteredGamemodes.end() ? &it->second : &mRegisteredGamemodes.at("vanilla");
|
||||
}
|
||||
bool isCurrentGamemode(const GamemodeId& id) const {
|
||||
const Gamemode* gamemode = getCurrentGamemode();
|
||||
if (gamemode && gamemode->getId() == id) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void setCurrentGamemode(const GamemodeId& id);
|
||||
void setGamemodeToPrevious();
|
||||
|
||||
std::map<GamemodeId, Gamemode>& getRegisteredGamemodes() { return mRegisteredGamemodes; }
|
||||
|
||||
private:
|
||||
GamemodeId mCurrentGamemodeId;
|
||||
std::map<GamemodeId, Gamemode> mRegisteredGamemodes;
|
||||
};
|
||||
|
||||
extern GamemodeManager g_GamemodeManager;
|
||||
|
||||
inline GamemodeManager& getGamemodeManager() {
|
||||
return g_GamemodeManager;
|
||||
}
|
||||
|
||||
}; // namespace dusk::gamemode
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "dusk/main.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/ui/ui.hpp"
|
||||
#include "dusk/gamemode.hpp"
|
||||
#include "f_pc/f_pc_manager.h"
|
||||
#include "f_pc/f_pc_name.h"
|
||||
#include "m_Do/m_Do_controller_pad.h"
|
||||
@@ -285,7 +286,7 @@ namespace dusk {
|
||||
|
||||
if (dusk::IsGameLaunched && !m_isLaunchInitialized) {
|
||||
m_isLaunchInitialized = true;
|
||||
if (getSettings().game.speedrunMode && getSettings().game.liveSplitEnabled) {
|
||||
if (dusk::speedrun::isActive() && getSettings().game.liveSplitEnabled) {
|
||||
dusk::speedrun::connectLiveSplit();
|
||||
}
|
||||
}
|
||||
@@ -357,7 +358,7 @@ namespace dusk {
|
||||
|
||||
m_menuTools.ShowInputViewer();
|
||||
|
||||
if (dusk::IsGameLaunched && !dusk::getSettings().game.speedrunMode) {
|
||||
if (dusk::IsGameLaunched && !dusk::speedrun::isActive()) {
|
||||
m_menuTools.ShowDebugOverlay();
|
||||
m_menuTools.ShowCameraOverlay();
|
||||
m_menuTools.ShowProcessManager();
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "dusk/data.hpp"
|
||||
#include "dusk/dusk.h"
|
||||
#include "dusk/speedrun.h"
|
||||
#include "dusk/main.h"
|
||||
#include "dusk/os.h"
|
||||
#include "m_Do/m_Do_main.h"
|
||||
@@ -38,7 +39,7 @@ namespace dusk {
|
||||
ImGui::BeginDisabled();
|
||||
}
|
||||
|
||||
ImGui::BeginDisabled(getSettings().game.speedrunMode);
|
||||
ImGui::BeginDisabled(dusk::speedrun::isActive());
|
||||
|
||||
ImGui::MenuItem("Save Editor", hotkeys::SHOW_SAVE_EDITOR, &m_showSaveEditor);
|
||||
ImGui::MenuItem("State Share", hotkeys::SHOW_STATE_SHARE, &m_showStateShare);
|
||||
@@ -60,7 +61,7 @@ namespace dusk {
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Debug")) {
|
||||
ImGui::BeginDisabled(getSettings().game.speedrunMode);
|
||||
ImGui::BeginDisabled(dusk::speedrun::isActive());
|
||||
|
||||
bool developmentMode = mDoMain::developmentMode == 1;
|
||||
if (ImGui::Checkbox("Development Mode", &developmentMode)) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define DUSK_ISO_VALIDATE_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include "dusk/settings.h"
|
||||
|
||||
namespace dusk::iso {
|
||||
struct KnownDisc;
|
||||
|
||||
+73
-63
@@ -1,46 +1,48 @@
|
||||
#if _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
using socket_t = SOCKET;
|
||||
static void closeSocket(socket_t s) {
|
||||
LINGER li{1, 0};
|
||||
setsockopt(s, SOL_SOCKET, SO_LINGER, reinterpret_cast<const char*>(&li), sizeof(li));
|
||||
closesocket(s);
|
||||
}
|
||||
static int socketError(socket_t s) {
|
||||
int err = 0; int len = sizeof(err);
|
||||
getsockopt(s, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&err), &len);
|
||||
return err;
|
||||
}
|
||||
static constexpr int kSendFlags = 0;
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
using socket_t = SOCKET;
|
||||
static void closeSocket(socket_t s) {
|
||||
LINGER li{1, 0};
|
||||
setsockopt(s, SOL_SOCKET, SO_LINGER, reinterpret_cast<const char*>(&li), sizeof(li));
|
||||
closesocket(s);
|
||||
}
|
||||
static int socketError(socket_t s) {
|
||||
int err = 0;
|
||||
int len = sizeof(err);
|
||||
getsockopt(s, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&err), &len);
|
||||
return err;
|
||||
}
|
||||
static constexpr int kSendFlags = 0;
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
using socket_t = int;
|
||||
static void closeSocket(socket_t s) {
|
||||
struct linger li{1, 0};
|
||||
setsockopt(s, SOL_SOCKET, SO_LINGER, &li, sizeof(li));
|
||||
close(s);
|
||||
}
|
||||
static int socketError(socket_t s) {
|
||||
int err = 0; socklen_t len = sizeof(err);
|
||||
getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len);
|
||||
return err;
|
||||
}
|
||||
#ifndef INVALID_SOCKET
|
||||
#define INVALID_SOCKET -1
|
||||
#endif
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
using socket_t = int;
|
||||
static void closeSocket(socket_t s) {
|
||||
struct linger li{1, 0};
|
||||
setsockopt(s, SOL_SOCKET, SO_LINGER, &li, sizeof(li));
|
||||
close(s);
|
||||
}
|
||||
static int socketError(socket_t s) {
|
||||
int err = 0;
|
||||
socklen_t len = sizeof(err);
|
||||
getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len);
|
||||
return err;
|
||||
}
|
||||
#ifndef INVALID_SOCKET
|
||||
#define INVALID_SOCKET -1
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
static constexpr int kSendFlags = 0;
|
||||
#else
|
||||
static constexpr int kSendFlags = MSG_NOSIGNAL;
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
static constexpr int kSendFlags = 0;
|
||||
#else
|
||||
static constexpr int kSendFlags = MSG_NOSIGNAL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
@@ -49,18 +51,18 @@
|
||||
|
||||
namespace dusk::speedrun {
|
||||
|
||||
static bool running = false;
|
||||
static bool startPending = false;
|
||||
static uint64_t frameCount = 0;
|
||||
static socket_t sock = INVALID_SOCKET;
|
||||
static bool wasLoading = false;
|
||||
static bool connected = false;
|
||||
static bool connectPending = false;
|
||||
static bool disconnectPending = false;
|
||||
static uint32_t idleProbeCounter = 0;
|
||||
static uint32_t reconnectCounter = 0;
|
||||
static char storedHost[64] = "127.0.0.1";
|
||||
static int storedPort = 16834;
|
||||
static bool running = false;
|
||||
static bool startPending = false;
|
||||
static uint64_t frameCount = 0;
|
||||
static socket_t sock = INVALID_SOCKET;
|
||||
static bool wasLoading = false;
|
||||
static bool connected = false;
|
||||
static bool connectPending = false;
|
||||
static bool disconnectPending = false;
|
||||
static uint32_t idleProbeCounter = 0;
|
||||
static uint32_t reconnectCounter = 0;
|
||||
static char storedHost[64] = "127.0.0.1";
|
||||
static int storedPort = 16834;
|
||||
|
||||
static void sendCmd(const char* cmd) {
|
||||
if (sock == INVALID_SOCKET) {
|
||||
@@ -122,9 +124,11 @@ void onGameFrame() {
|
||||
}
|
||||
|
||||
void start() {
|
||||
if (running) {
|
||||
if (g_speedrunInfo.m_isRunStarted || running) {
|
||||
return;
|
||||
}
|
||||
resetForSpeedrunMode();
|
||||
g_speedrunInfo.startRun();
|
||||
|
||||
running = true;
|
||||
startPending = true;
|
||||
@@ -214,8 +218,16 @@ void disconnectLiveSplit() {
|
||||
connected = connectPending = disconnectPending = false;
|
||||
}
|
||||
|
||||
bool consumeConnectedEvent() { bool v = connectPending; connectPending = false; return v; }
|
||||
bool consumeDisconnectedEvent() { bool v = disconnectPending; disconnectPending = false; return v; }
|
||||
bool consumeConnectedEvent() {
|
||||
bool v = connectPending;
|
||||
connectPending = false;
|
||||
return v;
|
||||
}
|
||||
bool consumeDisconnectedEvent() {
|
||||
bool v = disconnectPending;
|
||||
disconnectPending = false;
|
||||
return v;
|
||||
}
|
||||
|
||||
void updateLiveSplit() {
|
||||
if (sock == INVALID_SOCKET) {
|
||||
@@ -267,7 +279,8 @@ void updateLiveSplit() {
|
||||
#else
|
||||
|| (r < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
#endif
|
||||
) {
|
||||
)
|
||||
{
|
||||
if (connected) {
|
||||
disconnectPending = true;
|
||||
}
|
||||
@@ -280,15 +293,12 @@ void updateLiveSplit() {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint64_t totalMs = frameCount * 1000 / 30;
|
||||
const uint64_t totalMs = frameCount * 1000 / 30;
|
||||
const uint64_t totalSec = totalMs / 1000;
|
||||
char cmd[32];
|
||||
snprintf(cmd, sizeof(cmd), "setgametime %u:%02u:%02u.%03u",
|
||||
static_cast<uint32_t>(totalSec / 3600),
|
||||
static_cast<uint32_t>((totalSec / 60) % 60),
|
||||
static_cast<uint32_t>(totalSec % 60),
|
||||
static_cast<uint32_t>(totalMs % 1000)
|
||||
);
|
||||
static_cast<uint32_t>(totalSec / 3600), static_cast<uint32_t>((totalSec / 60) % 60),
|
||||
static_cast<uint32_t>(totalSec % 60), static_cast<uint32_t>(totalMs % 1000));
|
||||
sendCmd(cmd);
|
||||
}
|
||||
|
||||
@@ -299,4 +309,4 @@ void shutdown() {
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace dusk::speedrun
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "dusk/gamemode.hpp"
|
||||
#include "dusk/speedrun.h"
|
||||
|
||||
namespace dusk::speedrun {
|
||||
void onGameFrame();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace dusk {
|
||||
|
||||
extern bool IsRunning;
|
||||
@@ -21,8 +20,6 @@ struct StageRequest {
|
||||
};
|
||||
extern StageRequest StageRequested;
|
||||
|
||||
|
||||
|
||||
#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS) || \
|
||||
(defined(TARGET_OS_TV) && TARGET_OS_TV)
|
||||
inline constexpr bool SupportsProcessRestart = false;
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
#include "mods/svc/gamemode.h"
|
||||
#include "dusk/gamemode.hpp"
|
||||
|
||||
#include "config.hpp"
|
||||
#include "registry.hpp"
|
||||
#include "slot_map.hpp"
|
||||
|
||||
#include "aurora/lib/logging.hpp"
|
||||
#include "dusk/mod_loader.hpp"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
|
||||
namespace dusk::mods::svc::gamemode_impl {
|
||||
namespace {
|
||||
|
||||
aurora::Module Log("dusk::mods::gamemode");
|
||||
|
||||
// These track which gamemodes are registered by which mods, allowing us to automatically unregister them
|
||||
std::unordered_map<std::string, std::vector<std::string>> s_gamemodesRegisteredToMods;
|
||||
|
||||
std::string get_mod_gamemode_id(ModContext* ctx, const std::string& id) {
|
||||
return id + "_" + ctx->mod->metadata.id;
|
||||
}
|
||||
|
||||
void gamemode_remove_mod(LoadedMod& mod) {
|
||||
const auto it = s_gamemodesRegisteredToMods.find(mod.metadata.id);
|
||||
if (it != s_gamemodesRegisteredToMods.end()) {
|
||||
for (const auto& id : it->second) {
|
||||
dusk::gamemode::getGamemodeManager().unregisterGamemode(id);
|
||||
}
|
||||
s_gamemodesRegisteredToMods.erase(it);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
ModResult register_gamemode(ModContext* ctx, const GamemodeDesc* desc) {
|
||||
std::string id;
|
||||
if (!desc->gamemodeId) {
|
||||
Log.error("Attempted to register a gamemode with a null id!");
|
||||
return MOD_ERROR;
|
||||
}
|
||||
id = desc->gamemodeId;
|
||||
if (id.empty()) {
|
||||
Log.error("Attempted to register a gamemode with an empty id!");
|
||||
return MOD_ERROR;
|
||||
}
|
||||
id = get_mod_gamemode_id(ctx, id); // Append the mod id to the end of the gamemode id to ensure they are unique
|
||||
|
||||
std::string fullName;
|
||||
if (!desc->fullName) {
|
||||
Log.warn("Attempted to register gamemode {} with a null full name! Defaulting to: ({})",id,id);
|
||||
fullName = id;
|
||||
}else{
|
||||
fullName = desc->fullName;
|
||||
if (fullName.empty()) {
|
||||
Log.warn("Attempted to register gamemode {} with an empty full name! Defaulting to: ({})",id,id);
|
||||
fullName = id;
|
||||
}
|
||||
}
|
||||
|
||||
std::string saveName;
|
||||
if (!desc->saveName) {
|
||||
Log.warn("Attempted to register gamemode {} with a null save name! Defaulting to: (gczelda2)",id);
|
||||
saveName = "gczelda2";
|
||||
}else{
|
||||
saveName = desc->saveName;
|
||||
if (saveName.empty()) {
|
||||
Log.warn("Attempted to register gamemode {} with an empty save name! Defaulting to: (gczelda2)",id);
|
||||
saveName = "gczelda2";
|
||||
}
|
||||
}
|
||||
|
||||
dusk::gamemode::Gamemode gamemode(id, fullName, saveName);
|
||||
|
||||
if (desc->onActivatedFunction) {
|
||||
gamemode.mOnActivatedFunction = desc->onActivatedFunction;
|
||||
}
|
||||
if (desc->onDeactivatedFunction) {
|
||||
gamemode.mOnDeactivatedFunction = desc->onDeactivatedFunction;
|
||||
}
|
||||
if (desc->onPlayFunction) {
|
||||
gamemode.mOnPlayFunction = desc->onPlayFunction;
|
||||
}
|
||||
if (desc->onSaveLoadedFunction) {
|
||||
gamemode.mOnSaveLoadedFunction = desc->onSaveLoadedFunction;
|
||||
}
|
||||
if (desc->onNewSaveFunction) {
|
||||
gamemode.mOnNewSaveFunction = desc->onNewSaveFunction;
|
||||
}
|
||||
if (desc->onGameResetFunction) {
|
||||
gamemode.mOnGameResetFunction = desc->onGameResetFunction;
|
||||
}
|
||||
if (desc->onTickFunction) {
|
||||
gamemode.mOnTickFunction = desc->onTickFunction;
|
||||
}
|
||||
|
||||
dusk::gamemode::getGamemodeManager().registerGamemode(gamemode);
|
||||
|
||||
const auto it = s_gamemodesRegisteredToMods.find(ctx->mod->metadata.id);
|
||||
if (it == s_gamemodesRegisteredToMods.end()) {
|
||||
std::vector<std::string> registeredGamemodes = {id};
|
||||
s_gamemodesRegisteredToMods.emplace(ctx->mod->metadata.id, registeredGamemodes);
|
||||
}else {
|
||||
it->second.push_back(id);
|
||||
}
|
||||
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult unregister_gamemode(ModContext* ctx, const char* id) {
|
||||
dusk::gamemode::getGamemodeManager().unregisterGamemode(get_mod_gamemode_id(ctx,id));
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult is_active(ModContext* ctx, const char* gamemodeId, bool* out_active) {
|
||||
*out_active = dusk::gamemode::getGamemodeManager().isCurrentGamemode(get_mod_gamemode_id(ctx,gamemodeId));
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace dusk::mods::svc {
|
||||
namespace {
|
||||
|
||||
constexpr GamemodeService s_gamemodeService{
|
||||
.header = SERVICE_HEADER(GamemodeService, GAMEMODE_SERVICE_MAJOR, GAMEMODE_SERVICE_MINOR),
|
||||
.register_gamemode = gamemode_impl::register_gamemode,
|
||||
.unregister_gamemode = gamemode_impl::unregister_gamemode,
|
||||
.is_active = gamemode_impl::is_active
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
constinit const ServiceModule g_gamemodeModule{
|
||||
.id = GAMEMODE_SERVICE_ID,
|
||||
.majorVersion = GAMEMODE_SERVICE_MAJOR,
|
||||
.minorVersion = GAMEMODE_SERVICE_MINOR,
|
||||
.service = &s_gamemodeService,
|
||||
.modDetached = gamemode_impl::gamemode_remove_mod,
|
||||
};
|
||||
|
||||
} // namespace dusk::mods::svc
|
||||
@@ -210,6 +210,7 @@ void ModLoader::init_services() {
|
||||
&svc::g_gameModule,
|
||||
&svc::g_cameraModule,
|
||||
&svc::g_gfxModule,
|
||||
&svc::g_gamemodeModule,
|
||||
})
|
||||
{
|
||||
svc::register_module(*module);
|
||||
|
||||
@@ -72,5 +72,6 @@ extern const ServiceModule g_uiModule;
|
||||
extern const ServiceModule g_gameModule;
|
||||
extern const ServiceModule g_cameraModule;
|
||||
extern const ServiceModule g_gfxModule;
|
||||
extern const ServiceModule g_gamemodeModule;
|
||||
|
||||
} // namespace dusk::mods::svc
|
||||
|
||||
@@ -154,7 +154,8 @@ UserSettings g_userSettings = {
|
||||
.recordingMode {"game.recordingMode", false},
|
||||
.removeQuestMapMarkers {"game.removeQuestMapMarkers", false},
|
||||
.showInputViewer {"game.showInputViewer", false},
|
||||
.showInputViewerGyro {"game.showInputViewerGyro", false}
|
||||
.showInputViewerGyro {"game.showInputViewerGyro", false},
|
||||
.lastSelectedGamemodeId {"game.lastSelectedGamemodeId", "vanilla"}
|
||||
},
|
||||
|
||||
.backend = {
|
||||
@@ -302,6 +303,7 @@ void registerSettings() {
|
||||
Register(g_userSettings.game.removeQuestMapMarkers);
|
||||
Register(g_userSettings.game.showInputViewer);
|
||||
Register(g_userSettings.game.showInputViewerGyro);
|
||||
Register(g_userSettings.game.lastSelectedGamemodeId);
|
||||
Register(g_userSettings.game.fastSpinner);
|
||||
Register(g_userSettings.game.infiniteHearts);
|
||||
Register(g_userSettings.game.infiniteArrows);
|
||||
|
||||
@@ -282,6 +282,8 @@ struct UserSettings {
|
||||
ConfigVar<bool> removeQuestMapMarkers;
|
||||
ConfigVar<bool> showInputViewer;
|
||||
ConfigVar<bool> showInputViewerGyro;
|
||||
|
||||
ConfigVar<std::string> lastSelectedGamemodeId;
|
||||
} game;
|
||||
|
||||
struct {
|
||||
|
||||
+29
-2
@@ -3,10 +3,37 @@
|
||||
#include "dusk/config.hpp"
|
||||
#include "m_Do/m_Do_main.h"
|
||||
#include <aurora/aurora.h>
|
||||
#include "dusk/gamemode.hpp"
|
||||
#include "dusk/livesplit.h"
|
||||
|
||||
namespace dusk {
|
||||
namespace dusk::speedrun {
|
||||
|
||||
SpeedrunInfo m_speedrunInfo;
|
||||
SpeedrunInfo g_speedrunInfo;
|
||||
|
||||
static void onSpeedrunModeActive() {
|
||||
resetForSpeedrunMode();
|
||||
}
|
||||
|
||||
static void onSpeedrunModeDeactive() {
|
||||
restoreFromSpeedrunMode();
|
||||
if (getSettings().game.liveSplitEnabled) {
|
||||
speedrun::disconnectLiveSplit();
|
||||
}
|
||||
}
|
||||
|
||||
void registerSpeedrunGamemode() {
|
||||
dusk::gamemode::Gamemode speedrunGamemode(DUSK_SPEEDRUN_GAMEMODE_ID,"Speedrun","gczelda2-speedrun");
|
||||
speedrunGamemode.mOnSaveLoadedFunction = dusk::speedrun::start;
|
||||
speedrunGamemode.mOnActivatedFunction = onSpeedrunModeActive;
|
||||
speedrunGamemode.mOnDeactivatedFunction = onSpeedrunModeDeactive;
|
||||
speedrunGamemode.mOnTickFunction = dusk::speedrun::onGameFrame;
|
||||
|
||||
dusk::gamemode::getGamemodeManager().registerGamemode(speedrunGamemode);
|
||||
}
|
||||
|
||||
void unregisterSpeedrunGamemode() {
|
||||
dusk::gamemode::getGamemodeManager().unregisterGamemode(DUSK_SPEEDRUN_GAMEMODE_ID);
|
||||
}
|
||||
|
||||
void resetForSpeedrunMode() {
|
||||
mDoMain::developmentMode = -1;
|
||||
|
||||
+11
-2
@@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
#include <aurora/aurora.h>
|
||||
#include "dusk/gamemode.hpp"
|
||||
|
||||
namespace dusk {
|
||||
#define DUSK_SPEEDRUN_GAMEMODE_ID "vanilla_speedrun"
|
||||
|
||||
namespace dusk::speedrun {
|
||||
|
||||
struct SpeedrunInfo {
|
||||
void startRun() {
|
||||
@@ -34,9 +37,15 @@ struct SpeedrunInfo {
|
||||
OSTime m_igtTimer = 0;
|
||||
};
|
||||
|
||||
extern SpeedrunInfo m_speedrunInfo;
|
||||
extern SpeedrunInfo g_speedrunInfo;
|
||||
|
||||
void registerSpeedrunGamemode();
|
||||
void unregisterSpeedrunGamemode();
|
||||
void resetForSpeedrunMode();
|
||||
void restoreFromSpeedrunMode();
|
||||
|
||||
inline bool isActive() {
|
||||
return dusk::gamemode::getGamemodeManager().isCurrentGamemode(DUSK_SPEEDRUN_GAMEMODE_ID);
|
||||
}
|
||||
|
||||
} // namespace dusk
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "achievements.hpp"
|
||||
#include "aurora/rmlui.hpp"
|
||||
#include "dusk/livesplit.h"
|
||||
#include "dusk/gamemode.hpp"
|
||||
#include "dusk/main.h"
|
||||
#include "dusk/mods/svc/ui.hpp"
|
||||
#include "dusk/settings.h"
|
||||
@@ -20,6 +21,7 @@
|
||||
#include "mods_window.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "dusk/ui/prelaunch.hpp"
|
||||
#include "warp.hpp"
|
||||
#include "window.hpp"
|
||||
|
||||
@@ -93,9 +95,10 @@ MenuBar::MenuBar()
|
||||
dismiss(modal);
|
||||
return;
|
||||
}
|
||||
prelaunch_state().showPrelaunchOnReset = true;
|
||||
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
|
||||
dismiss(modal);
|
||||
hide(false);
|
||||
Document::hide(true);
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -134,11 +137,11 @@ MenuBar::MenuBar()
|
||||
}));
|
||||
});
|
||||
|
||||
if (getSettings().game.speedrunMode) {
|
||||
if (dusk::speedrun::isActive()) {
|
||||
mTabBar->add_tab("Reset Timer", [this] {
|
||||
mTabBar->set_active_tab(-1);
|
||||
mDoAud_seStartMenu(kSoundClick);
|
||||
m_speedrunInfo.reset();
|
||||
dusk::speedrun::g_speedrunInfo.reset();
|
||||
if (getSettings().game.liveSplitEnabled) {
|
||||
dusk::speedrun::reset();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ Modal::Modal(Props props) : WindowSmall("modal", "modal-dialog"), mProps(std::mo
|
||||
|
||||
auto* actions = append(mDialog, "div");
|
||||
actions->SetClass("modal-actions", true);
|
||||
if (props.isVertical) {
|
||||
actions->SetClass("modal-actions-vertical", true);
|
||||
}else{
|
||||
}
|
||||
|
||||
for (auto& action : mProps.actions) {
|
||||
add_action(std::move(action));
|
||||
@@ -87,9 +91,11 @@ bool Modal::handle_nav_command(Rml::Event& event, NavCommand cmd) {
|
||||
}
|
||||
|
||||
int direction = 0;
|
||||
if (cmd == NavCommand::Left) {
|
||||
NavCommand prevCommand = mProps.isVertical ? NavCommand::Up : NavCommand::Left;
|
||||
NavCommand nextCommand = mProps.isVertical ? NavCommand::Down : NavCommand::Right;
|
||||
if (cmd == prevCommand) {
|
||||
direction = -1;
|
||||
} else if (cmd == NavCommand::Right) {
|
||||
} else if (cmd == nextCommand) {
|
||||
direction = 1;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
std::function<void(Modal&)> onDismiss;
|
||||
Rml::String variant;
|
||||
Rml::String icon = "";
|
||||
bool isVertical;
|
||||
};
|
||||
|
||||
explicit Modal(Props props);
|
||||
|
||||
+13
-13
@@ -289,7 +289,7 @@ void Overlay::update() {
|
||||
update_pipeline_progress();
|
||||
|
||||
#if !(defined(__ANDROID__) || (defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST))
|
||||
if (getSettings().game.speedrunMode && getSettings().game.liveSplitEnabled) {
|
||||
if (dusk::speedrun::isActive() && getSettings().game.liveSplitEnabled) {
|
||||
dusk::speedrun::updateLiveSplit();
|
||||
if (dusk::speedrun::consumeConnectedEvent()) {
|
||||
push_toast({.title = "LiveSplit connected", .duration = std::chrono::seconds(3)});
|
||||
@@ -301,33 +301,33 @@ void Overlay::update() {
|
||||
#endif
|
||||
|
||||
if (mSpeedrunTimer != nullptr && mSpeedrunRta != nullptr && mSpeedrunIgt != nullptr) {
|
||||
if (getSettings().game.speedrunMode) {
|
||||
if (dusk::speedrun::isActive()) {
|
||||
// L+R+A+Start to reset timer
|
||||
if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) &&
|
||||
mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigZ(PAD_1))
|
||||
{
|
||||
m_speedrunInfo.reset();
|
||||
dusk::speedrun::g_speedrunInfo.reset();
|
||||
}
|
||||
|
||||
// L+R+A+Y to manually stop timer
|
||||
if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) &&
|
||||
mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigY(PAD_1))
|
||||
{
|
||||
if (m_speedrunInfo.m_isRunStarted) {
|
||||
m_speedrunInfo.m_endTimestamp = OSGetTime() - m_speedrunInfo.m_startTimestamp;
|
||||
m_speedrunInfo.m_isRunStarted = false;
|
||||
if (dusk::speedrun::g_speedrunInfo.m_isRunStarted) {
|
||||
dusk::speedrun::g_speedrunInfo.m_endTimestamp = OSGetTime() - dusk::speedrun::g_speedrunInfo.m_startTimestamp;
|
||||
dusk::speedrun::g_speedrunInfo.m_isRunStarted = false;
|
||||
}
|
||||
}
|
||||
|
||||
OSTime elapsedTime = 0;
|
||||
if (m_speedrunInfo.m_isRunStarted) {
|
||||
elapsedTime = OSGetTime() - m_speedrunInfo.m_startTimestamp;
|
||||
} else if (m_speedrunInfo.m_endTimestamp != 0) {
|
||||
elapsedTime = m_speedrunInfo.m_endTimestamp;
|
||||
if (dusk::speedrun::g_speedrunInfo.m_isRunStarted) {
|
||||
elapsedTime = OSGetTime() - dusk::speedrun::g_speedrunInfo.m_startTimestamp;
|
||||
} else if (dusk::speedrun::g_speedrunInfo.m_endTimestamp != 0) {
|
||||
elapsedTime = dusk::speedrun::g_speedrunInfo.m_endTimestamp;
|
||||
}
|
||||
|
||||
if (!m_speedrunInfo.m_isPauseIGT) {
|
||||
m_speedrunInfo.m_igtTimer = elapsedTime - m_speedrunInfo.m_totalLoadTime;
|
||||
if (!dusk::speedrun::g_speedrunInfo.m_isPauseIGT) {
|
||||
dusk::speedrun::g_speedrunInfo.m_igtTimer = elapsedTime - dusk::speedrun::g_speedrunInfo.m_totalLoadTime;
|
||||
}
|
||||
|
||||
mSpeedrunTimer->SetAttribute("open", "");
|
||||
@@ -340,7 +340,7 @@ void Overlay::update() {
|
||||
}
|
||||
|
||||
mSpeedrunIgt->SetInnerRML(
|
||||
escape(fmt::format("IGT {}", FormatTime(m_speedrunInfo.m_igtTimer))));
|
||||
escape(fmt::format("IGT {}", FormatTime(dusk::speedrun::g_speedrunInfo.m_igtTimer))));
|
||||
} else {
|
||||
mSpeedrunTimer->RemoveAttribute("open");
|
||||
}
|
||||
|
||||
+155
-53
@@ -3,9 +3,11 @@
|
||||
#include "dusk/config.hpp"
|
||||
#include "dusk/data.hpp"
|
||||
#include "dusk/file_select.hpp"
|
||||
#include "dusk/gamemode.hpp"
|
||||
#include "dusk/iso_validate.hpp"
|
||||
#include "dusk/main.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/ui/menu_bar.hpp"
|
||||
#include "dusk/update_check.hpp"
|
||||
#include "modal.hpp"
|
||||
#include "mods_window.hpp"
|
||||
@@ -685,61 +687,42 @@ void try_apply_mirrored_layout(Rml::Element* body) {
|
||||
body->SetClass("mirrored", getSettings().game.enableMirrorMode.getValue());
|
||||
}
|
||||
|
||||
Prelaunch::Prelaunch()
|
||||
: Document(kDocumentSource, false, DocumentScope::Prelaunch),
|
||||
mRoot(mDocument->GetElementById("root")) {
|
||||
void Prelaunch::rebuild_menu_buttons() {
|
||||
for (auto& doc : get_document_stack()) {
|
||||
if (auto* prelaunch = dynamic_cast<Prelaunch*>(doc.get())) {
|
||||
auto* menuList = prelaunch->mDocument->GetElementById("menu-list");
|
||||
while (menuList->GetNumChildren() > 0) {
|
||||
menuList->RemoveChild(menuList->GetChild(0));
|
||||
}
|
||||
prelaunch->mMenuButtons.clear();
|
||||
prelaunch->build_menu_buttons();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getPlayButtonText() {
|
||||
auto& state = prelaunch_state();
|
||||
const bool activeDiscLoaded = !state.activeDiscPath.empty();
|
||||
if (activeDiscLoaded == false) {
|
||||
return "Select Disc Image";
|
||||
}
|
||||
std::string playText;
|
||||
const dusk::gamemode::Gamemode* currentGameMode =
|
||||
dusk::gamemode::getGamemodeManager().getCurrentGamemode();
|
||||
if (currentGameMode != nullptr) {
|
||||
return currentGameMode->getId() == "vanilla" ? "Play" :
|
||||
"Play " + currentGameMode->getFullName();
|
||||
}
|
||||
return "Play";
|
||||
}
|
||||
|
||||
Prelaunch::Prelaunch() : Document(kDocumentSource, false, DocumentScope::Prelaunch) {
|
||||
mRoot = mDocument->GetElementById("root");
|
||||
ensure_initialized();
|
||||
begin_update_check();
|
||||
|
||||
if (auto* menuList = mDocument->GetElementById("menu-list")) {
|
||||
auto& state = prelaunch_state();
|
||||
const bool activeDiscLoaded = !state.activeDiscPath.empty();
|
||||
mMenuButtons.push_back(
|
||||
std::make_unique<Button>(menuList, activeDiscLoaded ? "Play" : "Select Disc Image"));
|
||||
mMenuButtons.back()->on_pressed([this] {
|
||||
if (prelaunch_state().activeDiscPath.empty()) {
|
||||
open_iso_picker();
|
||||
return;
|
||||
}
|
||||
|
||||
mDoAud_seStartMenu(kSoundPlay);
|
||||
show_menu_notification();
|
||||
|
||||
if (getSettings().audio.menuSounds) {
|
||||
JAISoundHandle* handle = g_mEnvSeMgr.field_0x144.getHandle();
|
||||
if (*handle) {
|
||||
(*handle)->stop(60);
|
||||
(*handle)->releaseHandle();
|
||||
}
|
||||
}
|
||||
|
||||
if (g_mDoMemCd_control.mCardCommand == mDoMemCd_Ctrl_c::Command_e::COMM_NONE_e) {
|
||||
mDoMemCd_ThdInit();
|
||||
}
|
||||
|
||||
IsGameLaunched = true;
|
||||
pop();
|
||||
});
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-1");
|
||||
|
||||
mMenuButtons.push_back(std::make_unique<Button>(menuList, "Settings"));
|
||||
mMenuButtons.back()->on_pressed([this] {
|
||||
mRestartSuppressed = false;
|
||||
push(std::make_unique<SettingsWindow>(true));
|
||||
});
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-2");
|
||||
|
||||
mMenuButtons.push_back(std::make_unique<Button>(menuList, "Mods"));
|
||||
mMenuButtons.back()->on_pressed([this] {
|
||||
mRestartSuppressed = false;
|
||||
push(std::make_unique<ModsWindow>());
|
||||
});
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-3");
|
||||
|
||||
mMenuButtons.push_back(std::make_unique<Button>(menuList, "Quit"));
|
||||
mMenuButtons.back()->on_pressed([] { IsRunning = false; });
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-4");
|
||||
}
|
||||
build_menu_buttons();
|
||||
|
||||
mDiscStatus = mDocument->GetElementById("disc-status");
|
||||
mDiscDetail = mDocument->GetElementById("disc-version");
|
||||
@@ -777,6 +760,125 @@ Prelaunch::Prelaunch()
|
||||
});
|
||||
}
|
||||
|
||||
void Prelaunch::build_menu_buttons() {
|
||||
if (auto* menuList = mDocument->GetElementById("menu-list")) {
|
||||
// Set the gamemode to the last used before showing the play button
|
||||
dusk::gamemode::getGamemodeManager().setGamemodeToPrevious();
|
||||
|
||||
mMenuButtons.push_back(std::make_unique<Button>(menuList, getPlayButtonText()));
|
||||
mMenuButtons.back()->on_pressed([this] {
|
||||
if (prelaunch_state().activeDiscPath.empty()) {
|
||||
open_iso_picker();
|
||||
return;
|
||||
}
|
||||
|
||||
mDoAud_seStartMenu(kSoundPlay);
|
||||
show_menu_notification();
|
||||
|
||||
if (getSettings().audio.menuSounds) {
|
||||
JAISoundHandle* handle = g_mEnvSeMgr.field_0x144.getHandle();
|
||||
if (*handle) {
|
||||
(*handle)->stop(60);
|
||||
(*handle)->releaseHandle();
|
||||
}
|
||||
}
|
||||
|
||||
if (g_mDoMemCd_control.mCardCommand == mDoMemCd_Ctrl_c::Command_e::COMM_NONE_e) {
|
||||
mDoMemCd_ThdInit();
|
||||
}
|
||||
|
||||
prelaunch_state().firstLaunch = false;
|
||||
const dusk::gamemode::Gamemode* gamemode =
|
||||
dusk::gamemode::getGamemodeManager().getCurrentGamemode();
|
||||
if (gamemode) {
|
||||
gamemode->mOnPlayFunction();
|
||||
}
|
||||
|
||||
IsGameLaunched = true;
|
||||
pop();
|
||||
|
||||
// If we deleted the menubar on a previous reset, create it again here
|
||||
bool menuBarExists = false;
|
||||
for (auto& doc : dusk::ui::get_document_stack()) {
|
||||
if (auto* menubar = dynamic_cast<dusk::ui::MenuBar*>(doc.get())) {
|
||||
menuBarExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (menuBarExists) {
|
||||
MenuBar::rebuild();
|
||||
}else{
|
||||
dusk::ui::push_document(std::make_unique<dusk::ui::MenuBar>(), false);
|
||||
}
|
||||
});
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-1");
|
||||
|
||||
// If we have more gamemodes registered than the default vanilla, show the gamemode
|
||||
// selection
|
||||
if (dusk::gamemode::getGamemodeManager().getRegisteredGamemodes().size() > 1) {
|
||||
mMenuButtons.push_back(std::make_unique<Button>(menuList, "Select Gamemode"));
|
||||
mMenuButtons.back()->on_pressed([this] {
|
||||
std::vector<ModalAction> gamemodeActions;
|
||||
gamemodeActions.push_back(dusk::ui::ModalAction{
|
||||
.label = "Vanilla", .onPressed = [this](dusk::ui::Modal& modal) {
|
||||
mDoAud_seStartMenu(kSoundClick);
|
||||
dusk::gamemode::getGamemodeManager().setCurrentGamemode("vanilla");
|
||||
modal.pop();
|
||||
update();
|
||||
}});
|
||||
for (const auto& [id, gamemode] :
|
||||
dusk::gamemode::getGamemodeManager().getRegisteredGamemodes())
|
||||
{
|
||||
if (id == "vanilla") {
|
||||
// Force vanilla to the top
|
||||
continue;
|
||||
}
|
||||
gamemodeActions.push_back(dusk::ui::ModalAction{.label = gamemode.getFullName(),
|
||||
.onPressed = [this, id](dusk::ui::Modal& modal) {
|
||||
mDoAud_seStartMenu(kSoundClick);
|
||||
dusk::gamemode::getGamemodeManager().setCurrentGamemode(id);
|
||||
modal.pop();
|
||||
update();
|
||||
}});
|
||||
}
|
||||
mRestartSuppressed = false;
|
||||
push(std::make_unique<dusk::ui::Modal>(dusk::ui::Modal::Props{
|
||||
.title = "Play Type",
|
||||
.bodyRml = "What mode would you like to play?",
|
||||
.actions = gamemodeActions,
|
||||
.onDismiss =
|
||||
[this](dusk::ui::Modal& modal) {
|
||||
mDoAud_seStartMenu(kSoundWindowClose);
|
||||
modal.pop();
|
||||
},
|
||||
.icon = "question-mark",
|
||||
.isVertical = true,
|
||||
}));
|
||||
});
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-1");
|
||||
}
|
||||
|
||||
mMenuButtons.push_back(std::make_unique<Button>(menuList, "Settings"));
|
||||
mMenuButtons.back()->on_pressed([this] {
|
||||
mRestartSuppressed = false;
|
||||
bool showPrelaunchSettings = prelaunch_state().firstLaunch;
|
||||
push(std::make_unique<SettingsWindow>(showPrelaunchSettings));
|
||||
});
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-2");
|
||||
|
||||
mMenuButtons.push_back(std::make_unique<Button>(menuList, "Mods"));
|
||||
mMenuButtons.back()->on_pressed([this] {
|
||||
mRestartSuppressed = false;
|
||||
push(std::make_unique<ModsWindow>());
|
||||
});
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-3");
|
||||
|
||||
mMenuButtons.push_back(std::make_unique<Button>(menuList, "Quit"));
|
||||
mMenuButtons.back()->on_pressed([] { IsRunning = false; });
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-4");
|
||||
}
|
||||
}
|
||||
|
||||
void Prelaunch::show() {
|
||||
Document::show();
|
||||
mDocument->SetAttribute("open", "");
|
||||
@@ -856,7 +958,7 @@ void Prelaunch::update() {
|
||||
}
|
||||
|
||||
if (!mMenuButtons.empty()) {
|
||||
mMenuButtons[0]->set_text(activeDiscLoaded ? "Play" : "Select Disc Image");
|
||||
mMenuButtons[0]->set_text(getPlayButtonText());
|
||||
}
|
||||
|
||||
const auto discStatusLabel = mDiscStatus->GetElementById("disc-status-label");
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "button.hpp"
|
||||
#include "document.hpp"
|
||||
#include "dusk/iso_validate.hpp"
|
||||
#include "dusk/settings.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -13,6 +14,7 @@ namespace dusk::ui {
|
||||
class Prelaunch : public Document {
|
||||
public:
|
||||
Prelaunch();
|
||||
void build_menu_buttons();
|
||||
|
||||
void show() override;
|
||||
void hide(bool close) override;
|
||||
@@ -21,13 +23,15 @@ public:
|
||||
bool visible() const override;
|
||||
bool obscures_game() const override { return true; }
|
||||
|
||||
static void rebuild_menu_buttons();
|
||||
|
||||
protected:
|
||||
bool handle_nav_command(Rml::Event& event, NavCommand cmd) override;
|
||||
|
||||
private:
|
||||
bool mEntranceAnimationStarted = false;
|
||||
bool mRestartSuppressed = false;
|
||||
std::vector<std::unique_ptr<Button> > mMenuButtons;
|
||||
std::vector<std::unique_ptr<Button>> mMenuButtons;
|
||||
Rml::Element* mRoot = nullptr;
|
||||
Rml::Element* mDiscStatus = nullptr;
|
||||
Rml::Element* mDiscDetail = nullptr;
|
||||
@@ -42,6 +46,7 @@ class PrelaunchOptions;
|
||||
|
||||
struct PrelaunchState {
|
||||
bool initialized = false;
|
||||
bool firstLaunch = true;
|
||||
std::string configuredDiscPath;
|
||||
bool configuredDiscCanLaunch = false;
|
||||
iso::DiscInfo configuredDiscInfo{};
|
||||
@@ -55,6 +60,7 @@ struct PrelaunchState {
|
||||
std::string pendingDiscPath;
|
||||
iso::DiscInfo pendingDiscInfo{};
|
||||
iso::ValidationError pendingDiscValidation = iso::ValidationError::Unknown;
|
||||
bool showPrelaunchOnReset = false;
|
||||
};
|
||||
|
||||
PrelaunchState& prelaunch_state() noexcept;
|
||||
|
||||
+13
-13
@@ -375,7 +375,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.getValue(); },
|
||||
.isDisabled = [] { return dusk::speedrun::isActive(); },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -692,7 +692,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
{
|
||||
.key = "Pause on Focus Lost",
|
||||
.helpText = "Pause the game when window focus is lost.",
|
||||
.isDisabled = [] { return IsMobile || getSettings().game.speedrunMode; },
|
||||
.isDisabled = [] { return IsMobile || dusk::speedrun::isActive(); },
|
||||
});
|
||||
leftPane.register_control(
|
||||
leftPane.add_select_button({
|
||||
@@ -1053,7 +1053,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.getValue(); });
|
||||
[] { return dusk::speedrun::isActive(); });
|
||||
addOption("Reset Key (" + Rml::String{hotkeys::DO_RESET} + ")",
|
||||
getSettings().game.enableResetKeybind,
|
||||
"Press " + Rml::String{hotkeys::DO_RESET} + " to reset the game.");
|
||||
@@ -1166,7 +1166,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
getSettings().game.damageMultiplier.setValue(value);
|
||||
config::save();
|
||||
},
|
||||
.isDisabled = [] { return getSettings().game.speedrunMode.getValue(); },
|
||||
.isDisabled = [] { return dusk::speedrun::isActive(); },
|
||||
.isModified =
|
||||
[] {
|
||||
return getSettings().game.damageMultiplier.getValue() !=
|
||||
@@ -1225,14 +1225,14 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
.helpText =
|
||||
"Enables speedrunning options while restricting certain gameplay modifiers.",
|
||||
.onChange =
|
||||
[](bool enabled) {
|
||||
[this](bool enabled) {
|
||||
if (enabled) {
|
||||
resetForSpeedrunMode();
|
||||
dusk::speedrun::registerSpeedrunGamemode();
|
||||
} else {
|
||||
restoreFromSpeedrunMode();
|
||||
if (getSettings().game.liveSplitEnabled) {
|
||||
speedrun::disconnectLiveSplit();
|
||||
if (dusk::speedrun::isActive()) {
|
||||
pop();
|
||||
}
|
||||
dusk::speedrun::unregisterSpeedrunGamemode();
|
||||
}
|
||||
MenuBar::rebuild();
|
||||
},
|
||||
@@ -1250,13 +1250,13 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
speedrun::disconnectLiveSplit();
|
||||
}
|
||||
},
|
||||
.isDisabled = [] { return IsMobile || !getSettings().game.speedrunMode; },
|
||||
.isDisabled = [] { return IsMobile || !dusk::speedrun::isActive(); },
|
||||
});
|
||||
config_bool_select(leftPane, rightPane, getSettings().game.showSpeedrunRTATimer,
|
||||
{
|
||||
.key = "Show RTA",
|
||||
.helpText = "Display the RTA timer. IGT is always visible.",
|
||||
.isDisabled = [] { return !getSettings().game.speedrunMode; },
|
||||
.isDisabled = [] { return !dusk::speedrun::isActive(); },
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1305,7 +1305,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
[] {
|
||||
return kMagicArmorModes[static_cast<u8>(getSettings().game.armorRupeeDrain.getValue())];
|
||||
},
|
||||
.isDisabled = [] { return getSettings().game.speedrunMode.getValue(); },
|
||||
.isDisabled = [] { return dusk::speedrun::isActive(); },
|
||||
.isModified =
|
||||
[] {
|
||||
return getSettings().game.armorRupeeDrain.getValue() !=
|
||||
@@ -1469,7 +1469,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
"Shift+F1.<br/><br/><icon class=\"warning\"/> WARNING: Debugging tools "
|
||||
"can easily break your game. Do not use on a regular save!",
|
||||
.onChange = [](bool) { MenuBar::rebuild(); },
|
||||
.isDisabled = [] { return getSettings().game.speedrunMode.getValue(); },
|
||||
.isDisabled = [] { return dusk::speedrun::isActive(); },
|
||||
});
|
||||
config_bool_select(leftPane, rightPane, getSettings().game.showInputViewer,
|
||||
{
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#include "nav_types.hpp"
|
||||
|
||||
#include "Z2AudioLib/Z2SeMgr.h"
|
||||
|
||||
namespace dusk::ui {
|
||||
class Document;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <dusk/gamepad_color.h>
|
||||
#include <dusk/autosave.h>
|
||||
#include "dusk/menu_pointer.h"
|
||||
#include "dusk/gamemode.hpp"
|
||||
#endif
|
||||
|
||||
fapGm_HIO_c::fapGm_HIO_c() {
|
||||
@@ -845,7 +846,10 @@ void fapGm_Execute() {
|
||||
|
||||
cCt_Counter(0);
|
||||
#ifdef TARGET_PC
|
||||
dusk::speedrun::onGameFrame();
|
||||
const dusk::gamemode::Gamemode* gamemode = dusk::gamemode::getGamemodeManager().getCurrentGamemode();
|
||||
if (gamemode) {
|
||||
gamemode->mOnTickFunction();
|
||||
}
|
||||
dusk::AchievementSystem::get().tick();
|
||||
dusk::menu_pointer::end_game_frame();
|
||||
#endif
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
#include "f_op/f_op_overlap_req.h"
|
||||
#include "f_pc/f_pc_manager.h"
|
||||
|
||||
#ifdef TARGET_PC
|
||||
#include "dusk/speedrun.h"
|
||||
#include "dusk/gamemode.hpp"
|
||||
#endif
|
||||
|
||||
void fopOvlpReq_SetPeektime(overlap_request_class*, u16);
|
||||
|
||||
@@ -20,11 +23,11 @@ static int fopOvlpReq_phase_Done(overlap_request_class* i_overlapReq) {
|
||||
i_overlapReq->field_0xc = 0;
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.speedrunMode) {
|
||||
if (dusk::m_speedrunInfo.m_isRunStarted) {
|
||||
dusk::m_speedrunInfo.m_isPauseIGT = false;
|
||||
dusk::m_speedrunInfo.m_totalLoadTime += OSGetTime() - dusk::m_speedrunInfo.m_loadStartTimestamp;
|
||||
dusk::m_speedrunInfo.m_loadStartTimestamp = OSGetTime();
|
||||
if (dusk::speedrun::isActive()) {
|
||||
if (dusk::speedrun::g_speedrunInfo.m_isRunStarted) {
|
||||
dusk::speedrun::g_speedrunInfo.m_isPauseIGT = false;
|
||||
dusk::speedrun::g_speedrunInfo.m_totalLoadTime += OSGetTime() - dusk::speedrun::g_speedrunInfo.m_loadStartTimestamp;
|
||||
dusk::speedrun::g_speedrunInfo.m_loadStartTimestamp = OSGetTime();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -95,9 +98,9 @@ static int fopOvlpReq_phase_Create(overlap_request_class* i_overlapReq) {
|
||||
fpcM_Create(i_overlapReq->procname, NULL, NULL);
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::m_speedrunInfo.m_isRunStarted) {
|
||||
dusk::m_speedrunInfo.m_isPauseIGT = true;
|
||||
dusk::m_speedrunInfo.m_loadStartTimestamp = OSGetTime();
|
||||
if (dusk::speedrun::isActive() && dusk::speedrun::g_speedrunInfo.m_isRunStarted) {
|
||||
dusk::speedrun::g_speedrunInfo.m_isPauseIGT = true;
|
||||
dusk::speedrun::g_speedrunInfo.m_loadStartTimestamp = OSGetTime();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+104
-48
@@ -3,35 +3,35 @@
|
||||
* Memory Card Control
|
||||
*/
|
||||
|
||||
#include <card.h>
|
||||
#include "m_Do/m_Do_MemCard.h"
|
||||
#include <card.h>
|
||||
#include "JSystem/JKernel/JKRAssertHeap.h"
|
||||
#include "m_Do/m_Do_ext.h"
|
||||
#include "dusk/main.h"
|
||||
#include "dusk/os.h"
|
||||
#include "dusk/version.hpp"
|
||||
#include "m_Do/m_Do_MemCardRWmng.h"
|
||||
#include "m_Do/m_Do_Reset.h"
|
||||
#include "m_Do/m_Do_ext.h"
|
||||
#include "os_report.h"
|
||||
#include "dusk/os.h"
|
||||
#include "dusk/main.h"
|
||||
#include "dusk/version.hpp"
|
||||
|
||||
#if PLATFORM_WII || PLATFORM_SHIELD
|
||||
#include <cstring>
|
||||
#include <revolution/nand.h>
|
||||
#include <revolution/sc.h>
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
#define SLOT_A 0
|
||||
|
||||
#define CHECKSPACE_RESULT_READY 0
|
||||
#define CHECKSPACE_RESULT_READY 0
|
||||
#define CHECKSPACE_RESULT_INSSPACE 1
|
||||
#define CHECKSPACE_RESULT_NOENT 2
|
||||
#define CHECKSPACE_RESULT_ERROR 3
|
||||
#define CHECKSPACE_RESULT_NOENT 2
|
||||
#define CHECKSPACE_RESULT_ERROR 3
|
||||
|
||||
#if PLATFORM_WII
|
||||
s32 my_CARDOpen(s32 chan, const char* fileName, CARDFileInfo* fileInfo) {
|
||||
CARDStat stat;
|
||||
DVDDiskID* diskID = DVDGetCurrentDiskID();
|
||||
|
||||
|
||||
for (int i = 0; i < CARD_MAX_FILE; i++) {
|
||||
s32 ret = CARDGetStatus(chan, i, &stat);
|
||||
if (ret == CARD_RESULT_READY) {
|
||||
@@ -57,10 +57,10 @@ s32 my_CARDOpen(s32 chan, const char* fileName, CARDFileInfo* fileInfo) {
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WII
|
||||
#define NAND_OPEN NANDSafeOpen
|
||||
#define NAND_OPEN NANDSafeOpen
|
||||
#define NAND_CLOSE NANDSafeClose
|
||||
#elif PLATFORM_SHIELD
|
||||
#define NAND_OPEN NANDSimpleSafeOpen
|
||||
#define NAND_OPEN NANDSimpleSafeOpen
|
||||
#define NAND_CLOSE NANDSimpleSafeClose
|
||||
#endif
|
||||
|
||||
@@ -77,15 +77,20 @@ static u8 MemCardStack[STACK_SIZE];
|
||||
static OSThread MemCardThread;
|
||||
|
||||
void mDoMemCd_Ctrl_c::ThdInit() {
|
||||
#if !PLATFORM_SHIELD
|
||||
#ifdef TARGET_PC
|
||||
if (mInitialized) {
|
||||
return;
|
||||
}
|
||||
CARDSetLoadType((CARDFileType)dusk::getSettings().backend.cardFileType.getValue());
|
||||
#endif
|
||||
|
||||
#if !PLATFORM_SHIELD
|
||||
char version[5] = {};
|
||||
char maker[3] = {};
|
||||
std::memcpy(version, dusk::version::getDiskID().gameName, 4);
|
||||
std::memcpy(maker, dusk::version::getDiskID().company, 2);
|
||||
CARDInit(version, maker);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mCopyToPos = 0;
|
||||
mProbeStat = 2;
|
||||
@@ -93,6 +98,7 @@ void mDoMemCd_Ctrl_c::ThdInit() {
|
||||
|
||||
#if TARGET_PC
|
||||
mCardCommand = COMM_ATTACH_e;
|
||||
mInitialized = true;
|
||||
#else
|
||||
mCardCommand = COMM_NONE_e;
|
||||
#endif
|
||||
@@ -101,8 +107,9 @@ void mDoMemCd_Ctrl_c::ThdInit() {
|
||||
|
||||
OSInitMutex(&mMutex);
|
||||
OSInitCond(&mCond);
|
||||
OSCreateThread(&MemCardThread, (void*(*)(void*))mDoMemCd_main, NULL, MemCardStack + sizeof(MemCardStack),
|
||||
sizeof(MemCardStack), OSGetThreadPriority(OSGetCurrentThread()) + 1, 1);
|
||||
OSCreateThread(&MemCardThread, (void* (*)(void*))mDoMemCd_main, NULL,
|
||||
MemCardStack + sizeof(MemCardStack), sizeof(MemCardStack),
|
||||
OSGetThreadPriority(OSGetCurrentThread()) + 1, 1);
|
||||
OSResumeThread(&MemCardThread);
|
||||
|
||||
// "Memory Card Thread Init\n"
|
||||
@@ -112,23 +119,26 @@ void mDoMemCd_Ctrl_c::ThdInit() {
|
||||
void mDoMemCd_Ctrl_c::main() {
|
||||
do {
|
||||
OSLockMutex(&mMutex);
|
||||
while (mCardCommand == COMM_NONE_e
|
||||
#ifdef TARGET_PC
|
||||
&& !dusk::IsShuttingDown
|
||||
#endif
|
||||
) {
|
||||
bool shutdownThread = dusk::IsShuttingDown;
|
||||
while (mCardCommand == COMM_NONE_e && !shutdownThread) {
|
||||
OSWaitCond(&mCond, &mMutex);
|
||||
shutdownThread = dusk::IsShuttingDown;
|
||||
}
|
||||
OSUnlockMutex(&mMutex);
|
||||
|
||||
#ifdef TARGET_PC
|
||||
if (dusk::IsShuttingDown) {
|
||||
if (shutdownThread) {
|
||||
break;
|
||||
}
|
||||
#else
|
||||
while (mCardCommand == COMM_NONE_e) {
|
||||
OSWaitCond(&mCond, &mMutex);
|
||||
}
|
||||
OSUnlockMutex(&mMutex);
|
||||
#endif
|
||||
|
||||
switch (mCardCommand) {
|
||||
#if PLATFORM_GCN || PLATFORM_WII
|
||||
#if PLATFORM_GCN || PLATFORM_WII
|
||||
case COMM_RESTORE_e:
|
||||
restore();
|
||||
break;
|
||||
@@ -144,16 +154,16 @@ void mDoMemCd_Ctrl_c::main() {
|
||||
case COMM_DETACH_e:
|
||||
detach();
|
||||
break;
|
||||
#elif PLATFORM_SHIELD
|
||||
#elif PLATFORM_SHIELD
|
||||
case COMM_RESTORE_e:
|
||||
case COMM_STORE_e:
|
||||
case COMM_FORMAT_e:
|
||||
case COMM_ATTACH_e:
|
||||
case COMM_DETACH_e:
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WII || PLATFORM_SHIELD
|
||||
#if PLATFORM_WII || PLATFORM_SHIELD
|
||||
case COMM_RESTORE_NAND_e:
|
||||
restoreNAND();
|
||||
break;
|
||||
@@ -163,7 +173,7 @@ void mDoMemCd_Ctrl_c::main() {
|
||||
case COMM_STORE_SETUP_NAND_e:
|
||||
storeSetUpNAND();
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
OSLockMutex(&mMutex);
|
||||
@@ -180,7 +190,7 @@ void mDoMemCd_Ctrl_c::update() {
|
||||
OSUnlockMutex(&mMutex);
|
||||
OSSignalCond(&mCond);
|
||||
} else if (getStatus(0) != 14) {
|
||||
#if PLATFORM_GCN || PLATFORM_WII
|
||||
#if PLATFORM_GCN || PLATFORM_WII
|
||||
if (CARDProbe(SLOT_A) && getStatus(0) == 0) {
|
||||
OSLockMutex(&mMutex);
|
||||
mProbeStat = 0;
|
||||
@@ -196,7 +206,7 @@ void mDoMemCd_Ctrl_c::update() {
|
||||
OSUnlockMutex(&mMutex);
|
||||
OSSignalCond(&mCond);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +224,12 @@ void mDoMemCd_Ctrl_c::restore() {
|
||||
CARDFileInfo file;
|
||||
field_0x1fc8 = 0;
|
||||
|
||||
s32 ret = CARD_OPEN(mChannel, "gczelda2", &file);
|
||||
#ifdef TARGET_PC
|
||||
const char* fileName = getFileName();
|
||||
#else
|
||||
const char* fileName = "gczelda2";
|
||||
#endif
|
||||
s32 ret = CARD_OPEN(mChannel, fileName, &file);
|
||||
OS_REPORT("\x1b[43;30mCret=%d\n\x1b[m", ret);
|
||||
if (ret == CARD_RESULT_READY) {
|
||||
s32 ret2 = mDoMemCdRWm_Restore(&file, this, sizeof(mData));
|
||||
@@ -271,12 +286,18 @@ void mDoMemCd_Ctrl_c::store() {
|
||||
s32 ret;
|
||||
field_0x1fc8 = 0;
|
||||
|
||||
#ifdef TARGET_PC
|
||||
const char* fileName = getFileName();
|
||||
#else
|
||||
const char* fileName = "gczelda2";
|
||||
#endif
|
||||
|
||||
if (mCardState == CARD_STATE_NO_FILE_e) {
|
||||
#if PLATFORM_GCN
|
||||
ret = CARDCreate(mChannel, "gczelda2", CARD_FILE_SIZE, &file);
|
||||
#else
|
||||
#if PLATFORM_GCN
|
||||
ret = CARDCreate(mChannel, fileName, CARD_FILE_SIZE, &file);
|
||||
#else
|
||||
ret = CARDCreate(mChannel, "zeldaTp.dat", CARD_FILE_SIZE, &file);
|
||||
#endif
|
||||
#endif
|
||||
if (ret == CARD_RESULT_READY || ret == CARD_RESULT_EXIST) {
|
||||
mCardState = CARD_STATE_READY_e;
|
||||
} else {
|
||||
@@ -285,7 +306,7 @@ void mDoMemCd_Ctrl_c::store() {
|
||||
}
|
||||
|
||||
if (mCardState == CARD_STATE_READY_e) {
|
||||
ret = CARD_OPEN(mChannel, "gczelda2", &file);
|
||||
ret = CARD_OPEN(mChannel, fileName, &file);
|
||||
if (ret == CARD_RESULT_READY) {
|
||||
ret = mDoMemCdRWm_Store(&file, this, sizeof(mData));
|
||||
if (ret != CARD_RESULT_READY) {
|
||||
@@ -527,7 +548,13 @@ s32 mDoMemCd_Ctrl_c::mount() {
|
||||
s32 mDoMemCd_Ctrl_c::loadfile() {
|
||||
CARDFileInfo file;
|
||||
|
||||
s32 ret = CARD_OPEN(mChannel, "gczelda2", &file);
|
||||
#ifdef TARGET_PC
|
||||
const char* fileName = getFileName();
|
||||
#else
|
||||
const char* fileName = "gczelda2";
|
||||
#endif
|
||||
|
||||
s32 ret = CARD_OPEN(mChannel, fileName, &file);
|
||||
if (ret == CARD_RESULT_READY) {
|
||||
CARDClose(&file);
|
||||
return TRUE;
|
||||
@@ -543,7 +570,7 @@ s32 mDoMemCd_Ctrl_c::checkspace() {
|
||||
|
||||
if (result != CARD_RESULT_READY) {
|
||||
setCardState(result);
|
||||
return CHECKSPACE_RESULT_ERROR;
|
||||
return CHECKSPACE_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (bytesNotUsed < CARD_FILE_SIZE) {
|
||||
@@ -553,7 +580,7 @@ s32 mDoMemCd_Ctrl_c::checkspace() {
|
||||
if (filesNotUsed < 1) {
|
||||
return CHECKSPACE_RESULT_NOENT;
|
||||
}
|
||||
|
||||
|
||||
return CHECKSPACE_RESULT_READY;
|
||||
}
|
||||
|
||||
@@ -596,7 +623,7 @@ void mDoMemCd_Ctrl_c::restoreNAND() {
|
||||
NANDFileInfo file;
|
||||
s32 ret, ret2;
|
||||
|
||||
field_0x1fc8 = 0;
|
||||
field_0x1fc8 = 0;
|
||||
|
||||
ret = NANDOpen("zeldaTp.dat", &file, NAND_ACCESS_RW);
|
||||
OS_REPORT("\x1b[43;30mCret=%d\n\x1b[m", ret);
|
||||
@@ -668,7 +695,8 @@ void mDoMemCd_Ctrl_c::storeNAND() {
|
||||
ret = NANDCreate("banner.bin", NAND_PERM_RUSR | NAND_PERM_WUSR | NAND_PERM_RGRP, 0);
|
||||
printf("NAND bannerFile Create ret:%d\n", ret);
|
||||
if (ret == NAND_RESULT_OK || ret == NAND_RESULT_EXISTS) {
|
||||
ret = NAND_OPEN("banner.bin", &file, NAND_ACCESS_RW, l_safeCopyBuf, sizeof(l_safeCopyBuf));
|
||||
ret = NAND_OPEN(
|
||||
"banner.bin", &file, NAND_ACCESS_RW, l_safeCopyBuf, sizeof(l_safeCopyBuf));
|
||||
if (ret == NAND_RESULT_OK) {
|
||||
ret = mDoMemCdRWm_StoreBannerNAND(&file);
|
||||
if (ret == NAND_RESULT_OK) {
|
||||
@@ -686,7 +714,8 @@ void mDoMemCd_Ctrl_c::storeNAND() {
|
||||
}
|
||||
|
||||
if (ret == NAND_RESULT_OK) {
|
||||
ret = NAND_OPEN("zeldaTp.dat", &file, NAND_ACCESS_RW, l_safeCopyBuf, sizeof(l_safeCopyBuf));
|
||||
ret = NAND_OPEN(
|
||||
"zeldaTp.dat", &file, NAND_ACCESS_RW, l_safeCopyBuf, sizeof(l_safeCopyBuf));
|
||||
if (ret == NAND_RESULT_OK) {
|
||||
ret = mDoMemCdRWm_StoreNAND(&file, this, sizeof(mData));
|
||||
if (ret == NAND_RESULT_OK) {
|
||||
@@ -732,10 +761,11 @@ s32 mDoMemCd_Ctrl_c::SaveSyncNAND() {
|
||||
|
||||
void mDoMemCd_Ctrl_c::storeSetUpNAND() {
|
||||
field_0x1fc8 = 0;
|
||||
|
||||
while ((int)SCCheckStatus() != 0) {}
|
||||
|
||||
#if PLATFORM_WII
|
||||
while ((int)SCCheckStatus() != 0) {
|
||||
}
|
||||
|
||||
#if PLATFORM_WII
|
||||
if (!SCFlush()) {
|
||||
mNandState = NAND_STATE_WRITE_e;
|
||||
printf("== 本体設定Write OK ==\n");
|
||||
@@ -743,9 +773,9 @@ void mDoMemCd_Ctrl_c::storeSetUpNAND() {
|
||||
mNandState = NAND_STATE_FATAL_ERROR_e;
|
||||
printf("== 本体設定Write ERR ==\n");
|
||||
}
|
||||
#else
|
||||
#else
|
||||
mNandState = NAND_STATE_WRITE_e;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
field_0x1fc8 = 1;
|
||||
}
|
||||
@@ -866,7 +896,7 @@ s32 mDoMemCd_Ctrl_c::checkspaceNAND() {
|
||||
s32 result = NANDCheck(3, 2, &answer);
|
||||
if (result != NAND_RESULT_OK) {
|
||||
setNandState(result);
|
||||
return CHECKSPACE_RESULT_ERROR;
|
||||
return CHECKSPACE_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (answer == 0) {
|
||||
@@ -876,11 +906,37 @@ s32 mDoMemCd_Ctrl_c::checkspaceNAND() {
|
||||
} else if (answer & 10) {
|
||||
ret = 2;
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_PC
|
||||
void mDoMemCd_Ctrl_c::setFileName(const std::string& fileName) {
|
||||
if (mInitialized == false) {
|
||||
mFileName = fileName;
|
||||
} else {
|
||||
OSLockMutex(&mMutex);
|
||||
mFileName = fileName;
|
||||
OSUnlockMutex(&mMutex);
|
||||
}
|
||||
}
|
||||
|
||||
const char* mDoMemCd_Ctrl_c::getFileName() {
|
||||
const char* fileName = "gczelda2";
|
||||
if (mInitialized) {
|
||||
OSLockMutex(&mMutex);
|
||||
}
|
||||
if (!mFileName.empty()) {
|
||||
fileName = mFileName.c_str();
|
||||
}
|
||||
if (mInitialized) {
|
||||
OSUnlockMutex(&mMutex);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
#endif
|
||||
|
||||
DUSK_GAME_DATA mDoMemCd_Ctrl_c g_mDoMemCd_control;
|
||||
|
||||
static int mDoMemCd_main(void*) {
|
||||
|
||||
+41
-4
@@ -4,21 +4,27 @@
|
||||
*/
|
||||
|
||||
#include "m_Do/m_Do_Reset.h"
|
||||
#include <gx.h>
|
||||
#include "JSystem/JAudio2/JASDvdThread.h"
|
||||
#include "JSystem/JUtility/JUTGamePad.h"
|
||||
#include "JSystem/JUtility/JUTXfb.h"
|
||||
#include "SSystem/SComponent/c_API_controller_pad.h"
|
||||
#include <gx.h>
|
||||
#include "m_Do/m_Do_audio.h"
|
||||
#include "m_Do/m_Do_DVDError.h"
|
||||
#include "m_Do/m_Do_ext.h"
|
||||
#include "m_Do/m_Do_MemCard.h"
|
||||
#include "m_Do/m_Do_audio.h"
|
||||
#include "m_Do/m_Do_ext.h"
|
||||
|
||||
#if !PLATFORM_GCN
|
||||
#include <revolution/os.h>
|
||||
#endif
|
||||
#include "os_report.h"
|
||||
|
||||
#ifdef TARGET_PC
|
||||
#include "dusk/ui/prelaunch.hpp"
|
||||
#include "dusk/ui/menu_bar.hpp"
|
||||
#include "dusk/gamemode.hpp"
|
||||
#endif
|
||||
|
||||
static void my_OSCancelAlarmAll() {}
|
||||
|
||||
static void destroyVideo() {
|
||||
@@ -104,6 +110,13 @@ void checkDiskCallback(s32 result, DVDCommandBlock* block) {
|
||||
}
|
||||
|
||||
void mDoRst_resetCallBack(int port, void*) {
|
||||
#ifdef TARGET_PC
|
||||
const dusk::gamemode::Gamemode* gamemode = dusk::gamemode::getGamemodeManager().getCurrentGamemode();
|
||||
if (gamemode) {
|
||||
gamemode->mOnGameResetFunction();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mDoRst::isReset()) {
|
||||
return;
|
||||
}
|
||||
@@ -129,7 +142,8 @@ void mDoRst_resetCallBack(int port, void*) {
|
||||
#else
|
||||
DVDCommandBlock block;
|
||||
block.userData = (void*)-1;
|
||||
while (DVDCheckDiskAsync(&block, checkDiskCallback));
|
||||
while (DVDCheckDiskAsync(&block, checkDiskCallback))
|
||||
;
|
||||
do {
|
||||
check = (int)block.userData;
|
||||
} while (check == -1);
|
||||
@@ -141,6 +155,29 @@ void mDoRst_resetCallBack(int port, void*) {
|
||||
}
|
||||
}
|
||||
mDoRst::onReset();
|
||||
#ifdef TARGET_PC
|
||||
// Show pre-launch only if we have a registered gamemode and are resetting from the menubar
|
||||
if (dusk::ui::prelaunch_state().showPrelaunchOnReset == false || dusk::gamemode::getGamemodeManager().getRegisteredGamemodes().size() == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool prelaunchExists = false;
|
||||
for (auto& doc : dusk::ui::get_document_stack()) {
|
||||
if (auto* menubar = dynamic_cast<dusk::ui::MenuBar*>(doc.get())) {
|
||||
// Hide the menu bar
|
||||
menubar->Document::hide(true);
|
||||
}
|
||||
if (auto* prelaunch = dynamic_cast<dusk::ui::Prelaunch*>(doc.get())) {
|
||||
prelaunchExists = true;
|
||||
prelaunch->focus();
|
||||
}
|
||||
}
|
||||
if (prelaunchExists == false) {
|
||||
dusk::ui::Prelaunch& prelaunch = static_cast<dusk::ui::Prelaunch&>(dusk::ui::push_document(std::make_unique<dusk::ui::Prelaunch>(), true));
|
||||
prelaunch.focus();
|
||||
}
|
||||
dusk::ui::prelaunch_state().showPrelaunchOnReset = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mDoRst_shutdownCallBack() {
|
||||
|
||||
+11
-6
@@ -642,12 +642,6 @@ 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();
|
||||
@@ -889,6 +883,17 @@ int game_main(int argc, char* argv[]) {
|
||||
DuskLog.info("Initializing mods...");
|
||||
dusk::mods::ModLoader::instance().init();
|
||||
|
||||
// Apply after aurora_initialize: speedrun mode mutates cvars whose change callbacks push
|
||||
// values into aurora.
|
||||
if (dusk::getSettings().game.speedrunMode) {
|
||||
dusk::speedrun::registerSpeedrunGamemode();
|
||||
}
|
||||
|
||||
if (skipPreLaunchUI == true && dusk::gamemode::getGamemodeManager().getRegisteredGamemodes().size() > 1 && dusk::getSettings().backend.skipPreLaunchUI.getValue()) {
|
||||
// Force pre-launch if we have registered gamemodes that we need to choose from
|
||||
dusk::ui::push_document(std::make_unique<dusk::ui::Prelaunch>(), true);
|
||||
}
|
||||
|
||||
OSReport("Starting main01 (Game Loop)...\n");
|
||||
|
||||
main01();
|
||||
|
||||
Reference in New Issue
Block a user