summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKiritoDev <36680385+KiritoDv@users.noreply.github.com>2022-07-13 22:12:11 -0500
committerGitHub <noreply@github.com>2022-07-13 23:12:11 -0400
commit219804cbe4e9d494f0152f40155115bb308002d4 (patch)
treebdf53087d58f947bdcd305c1d69a0d68ab6d60f9
parentcb6876792e99f8420ca0626ac55a9b57c638bc13 (diff)
Controller Configuration UI and JSON Config (#760)
* Initial controller hud ui * Reverted fbdemo changes * Moved config to json and implemented controller config * fix build on linux, gitignore new config file * fix build * Fix compilation and file directory paths * Call save on cvar save * Fixed cvar loading and added deck slots to the config * Changed control deck port 0 to use a physical device by default * Added gyro and rumble & fixed loading errors * Save config on toggle menubar * fix linux build * Fixed drift calculation * Controller config now saves when pressing F1 * Removed ExitGame hook from ImGuiImpl * Moved mappings to a map * Added GetKeyName * untranslate scancodes * Fixed hud layout on keyboard device * Fixed keyboard read on hud * Fixed crash when reloading controllers * Removed ConfigFile and changed file extension * Changed Dummy to Disconnected and fixed filters * Removed function leftover * Changed ControllerHud to InputEditor Co-authored-by: briaguya <briaguya@alice> Co-authored-by: David Chavez <david@dcvz.io>
-rw-r--r--.gitignore1
-rw-r--r--libultraship/Makefile2
-rw-r--r--libultraship/libultraship/ConfigFile.cpp164
-rw-r--r--libultraship/libultraship/ConfigFile.h42
-rw-r--r--libultraship/libultraship/ControlDeck.cpp155
-rw-r--r--libultraship/libultraship/ControlDeck.h20
-rw-r--r--libultraship/libultraship/Controller.cpp108
-rw-r--r--libultraship/libultraship/Controller.h70
-rw-r--r--libultraship/libultraship/ControllerHud.cpp277
-rw-r--r--libultraship/libultraship/Cvar.cpp3
-rw-r--r--libultraship/libultraship/DisconnectedController.h31
-rw-r--r--libultraship/libultraship/GameSettings.cpp14
-rw-r--r--libultraship/libultraship/GlobalCtx2.cpp28
-rw-r--r--libultraship/libultraship/GlobalCtx2.h11
-rw-r--r--libultraship/libultraship/Hooks.h6
-rw-r--r--libultraship/libultraship/ImGuiImpl.cpp208
-rw-r--r--libultraship/libultraship/ImGuiImpl.h8
-rw-r--r--libultraship/libultraship/InputEditor.cpp277
-rw-r--r--libultraship/libultraship/InputEditor.h20
-rw-r--r--libultraship/libultraship/KeyboardController.cpp89
-rw-r--r--libultraship/libultraship/KeyboardController.h34
-rw-r--r--libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp9
-rw-r--r--libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp20
-rw-r--r--libultraship/libultraship/Lib/Fast3D/gfx_window_manager_api.h1
-rw-r--r--libultraship/libultraship/Lib/Mercury/Mercury.cpp134
-rw-r--r--libultraship/libultraship/Lib/Mercury/Mercury.h47
-rw-r--r--libultraship/libultraship/Lib/nlohmann/LICENSE.MIT (renamed from soh/soh/Lib/nlohmann/LICENSE.MIT)0
-rw-r--r--libultraship/libultraship/Lib/nlohmann/json.hpp (renamed from soh/soh/Lib/nlohmann/json.hpp)0
-rw-r--r--libultraship/libultraship/SDLController.cpp504
-rw-r--r--libultraship/libultraship/SDLController.h41
-rw-r--r--libultraship/libultraship/UltraController.h4
-rw-r--r--libultraship/libultraship/Window.cpp171
-rw-r--r--libultraship/libultraship/Window.h12
-rw-r--r--libultraship/libultraship/libultraship.vcxproj22
-rw-r--r--libultraship/libultraship/libultraship.vcxproj.filters42
-rw-r--r--soh/include/functions.h1
-rw-r--r--soh/soh.vcxproj3
-rw-r--r--soh/soh.vcxproj.filters9
-rw-r--r--soh/soh/Enhancements/bootcommands.c3
-rw-r--r--soh/soh/Enhancements/debugconsole.cpp63
-rw-r--r--soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp2
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer.cpp2
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer.h5
-rw-r--r--soh/soh/OTRGlobals.cpp61
-rw-r--r--soh/soh/OTRGlobals.h4
-rw-r--r--soh/src/code/padmgr.c2
-rw-r--r--soh/src/code/z_camera.c2
-rw-r--r--soh/src/code/z_fbdemo_wipe1.c1
-rw-r--r--soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c4
49 files changed, 1841 insertions, 896 deletions
diff --git a/.gitignore b/.gitignore
index 5a201405d..4b6eb3968 100644
--- a/.gitignore
+++ b/.gitignore
@@ -405,3 +405,4 @@ tags
oot.otr
*.sav
shipofharkinian.ini
+shipofharkinian.json \ No newline at end of file
diff --git a/libultraship/Makefile b/libultraship/Makefile
index 819acce9f..18dfca271 100644
--- a/libultraship/Makefile
+++ b/libultraship/Makefile
@@ -82,6 +82,7 @@ CXX_FILES := \
$(shell find libultraship/Lib/Fast3D -name "*.cpp") \
$(shell find libultraship -maxdepth 1 -name "*.cpp") \
$(shell find libultraship/Lib/ImGui -maxdepth 1 -name "*.cpp") \
+ $(shell find libultraship/Lib/Mercury -maxdepth 1 -name "*.cpp") \
libultraship/Lib/ImGui/backends/imgui_impl_opengl3.cpp \
libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp \
libultraship/Lib/StrHash64.cpp \
@@ -114,6 +115,7 @@ INC_DIRS := $(addprefix -I, \
libultraship/Lib/spdlog \
libultraship/Lib/spdlog/include \
libultraship/Lib/ImGui \
+ libultraship/Lib/Mercury \
libultraship \
../StormLib/src \
)
diff --git a/libultraship/libultraship/ConfigFile.cpp b/libultraship/libultraship/ConfigFile.cpp
deleted file mode 100644
index e8a52d881..000000000
--- a/libultraship/libultraship/ConfigFile.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-#include "ConfigFile.h"
-#include "spdlog/spdlog.h"
-#include "GlobalCtx2.h"
-#include "Window.h"
-#include "GameSettings.h"
-
-namespace Ship {
- ConfigFile::ConfigFile(std::shared_ptr<GlobalCtx2> Context, const std::string& Path) : Context(Context), Path(Path), File(Path.c_str()) {
- if (Path.empty()) {
- SPDLOG_ERROR("ConfigFile received an empty file name");
- exit(EXIT_FAILURE);
- }
-
- if (!File.read(Val)) {
- if (!CreateDefaultConfig()) {
- SPDLOG_ERROR("Failed to create default configs");
- exit(EXIT_FAILURE);
- }
- }
- }
-
- ConfigFile::~ConfigFile() {
- if (!Save()) {
- SPDLOG_ERROR("Failed to save configs!!!");
- }
-
- SPDLOG_INFO("destruct configfile");
- }
-
- mINI::INIMap<std::string>& ConfigFile::operator[](const std::string& Section) {
- return Val[Section];
- }
-
- mINI::INIMap<std::string> ConfigFile::get(const std::string& Section) {
- return Val.get(Section);
- }
-
- bool ConfigFile::has(const std::string& Section) {
- return Val.has(Section);
- }
-
- bool ConfigFile::remove(const std::string& Section) {
- return Val.remove(Section);
- }
-
- void ConfigFile::clear() {
- Val.clear();
- }
-
- std::size_t ConfigFile::size() const {
- return Val.size();
- }
-
- bool ConfigFile::Save() {
- return File.write(Val);
- }
-
- bool ConfigFile::CreateDefaultConfig() {
- (*this)["ARCHIVE"]["Main Archive"] = "";
- (*this)["ARCHIVE"]["Patches Directory"] = "";
-
- (*this)["SAVE"]["Save Filename"] = "";
-
- (*this)["CONTROLLERS"]["CONTROLLER 1"] = "Auto";
- (*this)["CONTROLLERS"]["CONTROLLER 2"] = "Unplugged";
- (*this)["CONTROLLERS"]["CONTROLLER 3"] = "Unplugged";
- (*this)["CONTROLLERS"]["CONTROLLER 4"] = "Unplugged";
-
- (*this)["KEYBOARD SHORTCUTS"]["KEY_FULLSCREEN"] = std::to_string(0x044);
- (*this)["KEYBOARD SHORTCUTS"]["KEY_CONSOLE"] = std::to_string(0x029);
-
- (*this)["WINDOW"]["WINDOW WIDTH"] = std::to_string(640);
- (*this)["WINDOW"]["WINDOW HEIGHT"] = std::to_string(480);
- (*this)["WINDOW"]["FULLSCREEN WIDTH"] = std::to_string(1920);
- (*this)["WINDOW"]["FULLSCREEN HEIGHT"] = std::to_string(1080);
- (*this)["WINDOW"]["FULLSCREEN"] = std::to_string(false);
- (*this)["WINDOW"]["GFX BACKEND"] = "";
-
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CRIGHT)] = std::to_string(0x14D);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CLEFT)] = std::to_string(0x14B);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CDOWN)] = std::to_string(0x150);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CUP)] = std::to_string(0x148);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_R)] = std::to_string(0x013);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_L)] = std::to_string(0x012);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_DRIGHT)] = std::to_string(0x023);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_DLEFT)] = std::to_string(0x021);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_DDOWN)] = std::to_string(0x022);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_DUP)] = std::to_string(0x014);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_START)] = std::to_string(0x039);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_Z)] = std::to_string(0x02C);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_B)] = std::to_string(0x02E);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_A)] = std::to_string(0x02D);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_STICKRIGHT)] = std::to_string(0x020);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_STICKLEFT)] = std::to_string(0x01E);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_STICKDOWN)] = std::to_string(0x01F);
- (*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_STICKUP)] = std::to_string(0x011);
-
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_CRIGHT)] = std::to_string(0x14D);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_CLEFT)] = std::to_string(0x14B);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_CDOWN)] = std::to_string(0x150);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_CUP)] = std::to_string(0x148);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_R)] = std::to_string(0x013);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_L)] = std::to_string(0x012);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_DRIGHT)] = std::to_string(0x023);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_DLEFT)] = std::to_string(0x021);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_DDOWN)] = std::to_string(0x022);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_DUP)] = std::to_string(0x014);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_START)] = std::to_string(0x039);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_Z)] = std::to_string(0x02C);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_B)] = std::to_string(0x02E);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_A)] = std::to_string(0x02D);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_STICKRIGHT)] = std::to_string(0x020);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_STICKLEFT)] = std::to_string(0x01E);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_STICKDOWN)] = std::to_string(0x01F);
- (*this)["KEYBOARD CONTROLLER BINDING 2"][STR(BTN_STICKUP)] = std::to_string(0x011);
-
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_CRIGHT)] = std::to_string(0x14D);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_CLEFT)] = std::to_string(0x14B);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_CDOWN)] = std::to_string(0x150);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_CUP)] = std::to_string(0x148);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_R)] = std::to_string(0x013);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_L)] = std::to_string(0x012);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_DRIGHT)] = std::to_string(0x023);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_DLEFT)] = std::to_string(0x021);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_DDOWN)] = std::to_string(0x022);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_DUP)] = std::to_string(0x014);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_START)] = std::to_string(0x039);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_Z)] = std::to_string(0x02C);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_B)] = std::to_string(0x02E);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_A)] = std::to_string(0x02D);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_STICKRIGHT)] = std::to_string(0x020);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_STICKLEFT)] = std::to_string(0x01E);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_STICKDOWN)] = std::to_string(0x01F);
- (*this)["KEYBOARD CONTROLLER BINDING 3"][STR(BTN_STICKUP)] = std::to_string(0x011);
-
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_CRIGHT)] = std::to_string(0x14D);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_CLEFT)] = std::to_string(0x14B);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_CDOWN)] = std::to_string(0x150);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_CUP)] = std::to_string(0x148);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_R)] = std::to_string(0x013);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_L)] = std::to_string(0x012);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_DRIGHT)] = std::to_string(0x023);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_DLEFT)] = std::to_string(0x021);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_DDOWN)] = std::to_string(0x022);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_DUP)] = std::to_string(0x014);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_START)] = std::to_string(0x039);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_Z)] = std::to_string(0x02C);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_B)] = std::to_string(0x02E);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_A)] = std::to_string(0x02D);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_STICKRIGHT)] = std::to_string(0x020);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_STICKLEFT)] = std::to_string(0x01E);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_STICKDOWN)] = std::to_string(0x01F);
- (*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_STICKUP)] = std::to_string(0x011);
-
- (*this)["ENHANCEMENT SETTINGS"]["TEXT_SPEED"] = "1";
-
- (*this)["SDL CONTROLLER 1"]["GUID"] = "";
- (*this)["SDL CONTROLLER 2"]["GUID"] = "";
- (*this)["SDL CONTROLLER 3"]["GUID"] = "";
- (*this)["SDL CONTROLLER 4"]["GUID"] = "";
-
- return File.generate(Val);
- }
-}
diff --git a/libultraship/libultraship/ConfigFile.h b/libultraship/libultraship/ConfigFile.h
deleted file mode 100644
index b94e22f88..000000000
--- a/libultraship/libultraship/ConfigFile.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef CONFIG_FILE_H
-#define CONFIG_FILE_H
-
-#pragma once
-
-#include <string>
-#include <memory>
-#include "Lib/mINI/src/mini/ini.h"
-#include "UltraController.h"
-#include "LUSMacros.h"
-
-namespace Ship {
- class GlobalCtx2;
-
- class ConfigFile {
- public:
- ConfigFile(std::shared_ptr<GlobalCtx2> Context, const std::string& Path);
- ~ConfigFile();
-
- bool Save();
-
- // Expose the ini values.
- mINI::INIMap<std::string>& operator[](const std::string& Section);
- mINI::INIMap<std::string> get(const std::string& Section);
- bool has(const std::string& Section);
- bool remove(const std::string& Section);
- void clear();
- std::size_t size() const;
- std::shared_ptr<GlobalCtx2> GetContext() { return Context.lock(); }
-
- protected:
- bool CreateDefaultConfig();
-
- private:
- mINI::INIStructure Val;
- std::weak_ptr<GlobalCtx2> Context;
- std::string Path;
- mINI::INIFile File;
- };
-}
-
-#endif
diff --git a/libultraship/libultraship/ControlDeck.cpp b/libultraship/libultraship/ControlDeck.cpp
new file mode 100644
index 000000000..2fbf3d225
--- /dev/null
+++ b/libultraship/libultraship/ControlDeck.cpp
@@ -0,0 +1,155 @@
+#include "ControlDeck.h"
+
+#include "Window.h"
+#include "Controller.h"
+#include "DisconnectedController.h"
+#include "KeyboardController.h"
+#include "SDLController.h"
+#include <Utils/StringHelper.h>
+
+uint8_t* controllerBits;
+
+void Ship::ControlDeck::Init(uint8_t* bits) {
+ ScanPhysicalDevices();
+ controllerBits = bits;
+}
+
+void Ship::ControlDeck::ScanPhysicalDevices() {
+
+ virtualDevices.clear();
+ physicalDevices.clear();
+
+ for (int i = 0; i < SDL_NumJoysticks(); i++) {
+ if (SDL_IsGameController(i)) {
+ auto sdl = std::make_shared<SDLController>(i);
+ sdl->Open();
+ physicalDevices.push_back(sdl);
+ }
+ }
+
+ physicalDevices.push_back(std::make_shared<KeyboardController>());
+ physicalDevices.push_back(std::make_shared<DisconnectedController>());
+
+ for (const auto& device : physicalDevices) {
+ for (int i = 0; i < MAXCONTROLLERS; i++) {
+ device->CreateDefaultBinding(i);
+ }
+ }
+
+ for (int i = 0; i < MAXCONTROLLERS; i++) {
+ virtualDevices.push_back(i == 0 ? 0 : static_cast<int>(physicalDevices.size()) - 1);
+ }
+
+ LoadControllerSettings();
+}
+
+void Ship::ControlDeck::SetPhysicalDevice(int slot, int deviceSlot) {
+ const std::shared_ptr<Controller> backend = physicalDevices[deviceSlot];
+ virtualDevices[slot] = deviceSlot;
+ *controllerBits |= (backend->Connected()) << slot;
+}
+
+void Ship::ControlDeck::WriteToPad(OSContPad* pad) const {
+ for (size_t i = 0; i < virtualDevices.size(); i++) {
+ physicalDevices[virtualDevices[i]]->Read(&pad[i], i);
+ }
+}
+
+#define NESTED(key, ...) StringHelper::Sprintf("Controllers.%s.Slot_%d." key, device->GetGuid().c_str(), slot, __VA_ARGS__)
+
+void Ship::ControlDeck::LoadControllerSettings() {
+ std::shared_ptr<Mercury> Config = GlobalCtx2::GetInstance()->GetConfig();
+
+ for (auto const& val : Config->rjson["Controllers"]["Deck"].items()) {
+ int slot = std::stoi(val.key().substr(5));
+
+ for (size_t dev = 0; dev < physicalDevices.size(); dev++) {
+ std::string guid = physicalDevices[dev]->GetGuid();
+ if(guid != val.value()) continue;
+
+ virtualDevices[slot] = dev;
+ }
+ }
+
+ for (size_t i = 0; i < virtualDevices.size(); i++) {
+ std::shared_ptr<Controller> backend = physicalDevices[virtualDevices[i]];
+ Config->setString(StringHelper::Sprintf("Controllers.Deck.Slot_%d", (int)i), backend->GetGuid());
+ }
+
+ for (const auto& device : physicalDevices) {
+
+ std::string guid = device->GetGuid();
+
+ for (int slot = 0; slot < MAXCONTROLLERS; slot++) {
+
+ if (!(Config->rjson["Controllers"].contains(guid) && Config->rjson["Controllers"][guid].contains(StringHelper::Sprintf("Slot_%d", slot)))) continue;
+
+ auto& profile = device->profiles[slot];
+ auto rawProfile = Config->rjson["Controllers"][guid][StringHelper::Sprintf("Slot_%d", slot)];
+
+ profile.Mappings.clear();
+ profile.Thresholds.clear();
+ profile.GyroThresholds.clear();
+ profile.UseRumble = Config->getBool(NESTED("Rumble.Enabled", ""));
+ profile.RumbleStrength = Config->getBool(NESTED("Rumble.Strength", ""));
+ profile.UseGyro = Config->getBool(NESTED("Gyro.Enabled", ""));
+
+ for (auto const& val : rawProfile["Gyro"]["Thresholds"].items()) {
+ profile.GyroThresholds[std::stoi(val.key())] = val.value();
+ }
+
+ for (auto const& val : rawProfile["Thresholds"].items()) {
+ profile.Thresholds[static_cast<ControllerThresholds>(std::stoi(val.key()))] = val.value();
+ }
+
+ for (auto const& val : rawProfile["Mappings"].items()) {
+ device->SetButtonMapping(slot, std::stoi(val.key().substr(4)), val.value());
+ }
+ }
+ }
+}
+
+void Ship::ControlDeck::SaveControllerSettings() {
+ std::shared_ptr<Mercury> Config = GlobalCtx2::GetInstance()->GetConfig();
+
+ for (size_t i = 0; i < virtualDevices.size(); i++) {
+ std::shared_ptr<Controller> backend = physicalDevices[virtualDevices[i]];
+ Config->setString(StringHelper::Sprintf("Controllers.Deck.Slot_%d", (int)i), backend->GetGuid());
+ }
+
+ for (const auto& device : physicalDevices) {
+
+ int slot = 0;
+ std::string guid = device->GetGuid();
+
+ for (const auto& profile : device->profiles) {
+
+ if (!device->Connected()) continue;
+
+ auto rawProfile = Config->rjson["Controllers"][guid][StringHelper::Sprintf("Slot_%d", slot)];
+ Config->setBool(NESTED("Rumble.Enabled", ""), profile.UseRumble);
+ Config->setFloat(NESTED("Rumble.Strength", ""), profile.RumbleStrength);
+ Config->setBool(NESTED("Gyro.Enabled", ""), profile.UseGyro);
+
+ for (auto const& val : rawProfile["Mappings"].items()) {
+ Config->setInt(NESTED("Mappings.%s", val.key().c_str()), -1);
+ }
+
+ for (auto const& [key, val] : profile.GyroThresholds) {
+ Config->setInt(NESTED("Gyro.Thresholds.%d", key), val);
+ }
+
+ for (auto const& [key, val] : profile.Thresholds) {
+ Config->setInt(NESTED("Thresholds.%d", key), val);
+ }
+
+ for (auto const& [key, val] : profile.Mappings) {
+ Config->setInt(NESTED("Mappings.BTN_%d", val), key);
+ }
+
+ slot++;
+ }
+ }
+
+ Config->save();
+} \ No newline at end of file
diff --git a/libultraship/libultraship/ControlDeck.h b/libultraship/libultraship/ControlDeck.h
new file mode 100644
index 000000000..fbbaca7ab
--- /dev/null
+++ b/libultraship/libultraship/ControlDeck.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "Controller.h"
+#include <vector>
+#include <string>
+
+namespace Ship {
+
+ class ControlDeck {
+ public:
+ std::vector<int> virtualDevices;
+ std::vector<std::shared_ptr<Controller>> physicalDevices = {};
+ void Init(uint8_t* controllerBits);
+ void ScanPhysicalDevices();
+ void WriteToPad(OSContPad* pad) const;
+ void LoadControllerSettings();
+ void SaveControllerSettings();
+ void SetPhysicalDevice(int slot, int deviceSlot);
+ };
+}
diff --git a/libultraship/libultraship/Controller.cpp b/libultraship/libultraship/Controller.cpp
index 7cad7f178..8c0994a85 100644
--- a/libultraship/libultraship/Controller.cpp
+++ b/libultraship/libultraship/Controller.cpp
@@ -1,8 +1,6 @@
#include "Controller.h"
-#include "GlobalCtx2.h"
-#include "stox.h"
#include <memory>
-#include <string>
+#include <algorithm>
#if __APPLE__
#include <SDL_events.h>
#else
@@ -10,29 +8,29 @@
#endif
namespace Ship {
- Controller::Controller(int32_t dwControllerNumber) : dwControllerNumber(dwControllerNumber) {
- dwPressedButtons = 0;
- wStickX = 0;
- wStickY = 0;
- wGyroX = 0;
- wGyroY = 0;
+
+ Controller::Controller() : isRumbling(false), wStickX(0), wStickY(0), wGyroX(0), wGyroY(0), dwPressedButtons(0){
Attachment = nullptr;
+ profiles.resize(MAXCONTROLLERS);
+ for(int slot = 0; slot < MAXCONTROLLERS; slot++) {
+ dwPressedButtons.push_back(0);
+ }
}
- void Controller::Read(OSContPad* pad) {
- ReadFromSource();
+ void Controller::Read(OSContPad* pad, int32_t slot) {
+ ReadFromSource(slot);
SDL_PumpEvents();
// Button Inputs
- pad->button |= dwPressedButtons & 0xFFFF;
+ pad->button |= dwPressedButtons[slot] & 0xFFFF;
// Stick Inputs
if (pad->stick_x == 0) {
- if (dwPressedButtons & BTN_STICKLEFT) {
+ if (dwPressedButtons[slot] & BTN_STICKLEFT) {
pad->stick_x = -128;
}
- else if (dwPressedButtons & BTN_STICKRIGHT) {
+ else if (dwPressedButtons[slot] & BTN_STICKRIGHT) {
pad->stick_x = 127;
}
else {
@@ -41,10 +39,10 @@ namespace Ship {
}
if (pad->stick_y == 0) {
- if (dwPressedButtons & BTN_STICKDOWN) {
+ if (dwPressedButtons[slot] & BTN_STICKDOWN) {
pad->stick_y = -128;
}
- else if (dwPressedButtons & BTN_STICKUP) {
+ else if (dwPressedButtons[slot] & BTN_STICKUP) {
pad->stick_y = 127;
}
else {
@@ -52,60 +50,38 @@ namespace Ship {
}
}
+ // Stick Inputs
+ if (pad->cam_x == 0) {
+ if (dwPressedButtons[slot] & BTN_VSTICKLEFT) {
+ pad->cam_x = -128 * 10.0f;
+ }
+ else if (dwPressedButtons[slot] & BTN_VSTICKRIGHT) {
+ pad->cam_x = 127 * 10.0f;
+ }
+ else {
+ pad->cam_x = wCamX;
+ }
+ }
+ if (pad->cam_y == 0) {
+ if (dwPressedButtons[slot] & BTN_VSTICKDOWN) {
+ pad->cam_y = -128 * 10.0f;
+ }
+ else if (dwPressedButtons[slot] & BTN_VSTICKUP) {
+ pad->cam_y = 127 * 10.0f;
+ }
+ else {
+ pad->cam_y = wCamY;
+ }
+ }
+
// Gyro
pad->gyro_x = wGyroX;
pad->gyro_y = wGyroY;
-
- // Right Stick
- pad->cam_x = wCamX;
- pad->cam_y = wCamY;
- }
-
- void Controller::SetButtonMapping(const std::string& szButtonName, int32_t dwScancode) {
- // Update the config value.
- std::string ConfSection = GetBindingConfSection();
- std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
- ConfigFile& Conf = *pConf.get();
- Conf[ConfSection][szButtonName] = dwScancode;
-
- // Reload the button mapping from Config
- LoadBinding();
- }
-
- void Controller::LoadBinding() {
- std::string ConfSection = GetBindingConfSection();
- std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
- ConfigFile& Conf = *pConf.get();
-
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CRIGHT)])] = BTN_CRIGHT;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CLEFT)])] = BTN_CLEFT;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CDOWN)])] = BTN_CDOWN;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CUP)])] = BTN_CUP;
- //ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CRIGHT + "_2")])] = BTN_CRIGHT;
- //ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CLEFT + "_2")])] = BTN_CLEFT;
- //ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CDOWN + "_2")])] = BTN_CDOWN;
- //ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_CUP + "_2")])] = BTN_CUP;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_R)])] = BTN_R;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_L)])] = BTN_L;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_DRIGHT)])] = BTN_DRIGHT;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_DLEFT)])] = BTN_DLEFT;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_DDOWN)])] = BTN_DDOWN;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_DUP)])] = BTN_DUP;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_START)])] = BTN_START;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_Z)])] = BTN_Z;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_B)])] = BTN_B;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_A)])] = BTN_A;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_STICKRIGHT)])] = BTN_STICKRIGHT;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_STICKLEFT)])] = BTN_STICKLEFT;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_STICKDOWN)])] = BTN_STICKDOWN;
- ButtonMapping[Ship::stoi(Conf[ConfSection][STR(BTN_STICKUP)])] = BTN_STICKUP;
- }
-
- std::string Controller::GetConfSection() {
- return GetControllerType() + " CONTROLLER " + std::to_string(GetControllerNumber() + 1);
}
- std::string Controller::GetBindingConfSection() {
- return GetControllerType() + " CONTROLLER BINDING " + std::to_string(GetControllerNumber() + 1);
+ void Controller::SetButtonMapping(int slot, int32_t n64Button, int32_t dwScancode) {
+ std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings;
+ std::erase_if(Mappings, [n64Button](const std::pair<int32_t, int32_t>& bin) { return bin.second == n64Button; });
+ Mappings[dwScancode] = n64Button;
}
}
diff --git a/libultraship/libultraship/Controller.h b/libultraship/libultraship/Controller.h
index d03d70e8a..ffbeeaabf 100644
--- a/libultraship/libultraship/Controller.h
+++ b/libultraship/libultraship/Controller.h
@@ -1,52 +1,82 @@
#pragma once
-#include <memory>
#include <map>
+#include <memory>
#include <string>
-#include <optional>
#include "stdint.h"
#include "UltraController.h"
#include "ControllerAttachment.h"
+#include <vector>
+#include <unordered_map>
#define EXTENDED_SCANCODE_BIT (1 << 8)
#define AXIS_SCANCODE_BIT (1 << 9)
namespace Ship {
+
+ enum ControllerThresholds {
+ LEFT_STICK = 1,
+ RIGHT_STICK = 2,
+ LEFT_TRIGGER = 3,
+ RIGHT_TRIGGER = 4,
+ DRIFT_X = 5,
+ DRIFT_Y = 6,
+ SENSITIVITY = 7,
+ GYRO_SENSITIVITY = 8
+ };
+
+ struct DeviceProfile {
+ bool UseRumble = false;
+ bool UseGyro = false;
+ float RumbleStrength = 1.0f;
+ std::unordered_map<ControllerThresholds, int32_t> Thresholds;
+ std::unordered_map<int32_t, int32_t> GyroThresholds;
+ std::map<int32_t, int32_t> Mappings;
+ };
+
class Controller {
public:
- Controller(int32_t dwControllerNumber);
-
- void Read(OSContPad* pad);
- virtual void ReadFromSource() = 0;
- virtual void WriteToSource(ControllerCallback* controller) = 0;
+ virtual ~Controller() = default;
+ Controller();
+ void Read(OSContPad* pad, int32_t slot);
+ virtual void ReadFromSource(int32_t slot) = 0;
+ virtual void WriteToSource(int32_t slot, ControllerCallback* controller) = 0;
virtual bool Connected() const = 0;
virtual bool CanRumble() const = 0;
+ virtual bool CanGyro() const = 0;
+ virtual void CreateDefaultBinding(int32_t slot) = 0;
bool isRumbling;
+ std::vector<DeviceProfile> profiles;
- void SetButtonMapping(const std::string& szButtonName, int32_t dwScancode);
+ virtual void ClearRawPress() = 0;
+ virtual int32_t ReadRawPress() = 0;
+ void SetButtonMapping(int slot, int32_t n64Button, int32_t dwScancode);
std::shared_ptr<ControllerAttachment> GetAttachment() { return Attachment; }
- int32_t GetControllerNumber() { return dwControllerNumber; }
- virtual bool HasPadConf() const = 0;
- virtual std::optional<std::string> GetPadConfSection() = 0;
+ std::string GetGuid() { return GUID; }
+ virtual const char* GetButtonName(int slot, int n64Button) = 0;
+ virtual const char* GetControllerName() = 0;
- protected:
- int32_t dwPressedButtons;
- std::map<int32_t, int32_t> ButtonMapping;
int8_t wStickX;
int8_t wStickY;
float wGyroX;
float wGyroY;
- float wCamX;
- float wCamY;
+ float wCamX;
+ float wCamY;
+
+ protected:
+ std::vector<int32_t> dwPressedButtons;
+ std::string GUID;
- virtual std::string GetControllerType() = 0;
- virtual std::string GetConfSection() = 0;
- virtual std::string GetBindingConfSection() = 0;
void LoadBinding();
private:
std::shared_ptr<ControllerAttachment> Attachment;
- int32_t dwControllerNumber;
};
+
+ struct ControllerEntry {
+ uint8_t* controllerBits;
+ Controller* entryIO;
+ };
+
}
diff --git a/libultraship/libultraship/ControllerHud.cpp b/libultraship/libultraship/ControllerHud.cpp
new file mode 100644
index 000000000..e40990b0d
--- /dev/null
+++ b/libultraship/libultraship/ControllerHud.cpp
@@ -0,0 +1,277 @@
+#include "InputEditor.h"
+#include "Controller.h"
+#include "Window.h"
+#include "Lib/ImGui/imgui.h"
+#include "ImGuiImpl.h"
+#include "Utils/StringHelper.h"
+#include "Lib/ImGui/imgui_internal.h"
+
+namespace Ship {
+
+ extern "C" uint8_t __enableGameInput;
+ #define SEPARATION() ImGui::Dummy(ImVec2(0, 5))
+
+ void InputEditor::Init() {
+ BtnReading = -1;
+ }
+
+ std::shared_ptr<Controller> GetControllerPerSlot(int slot) {
+ const std::vector<int> vDevices = Window::ControllerApi->virtualDevices;
+ return Window::ControllerApi->physicalDevices[vDevices[slot]];
+ }
+
+ void InputEditor::DrawButton(const char* label, int n64Btn) {
+ const std::shared_ptr<Controller> backend = GetControllerPerSlot(CurrentPort);
+
+ float size = 40;
+ bool readingMode = BtnReading == n64Btn;
+ bool disabled = BtnReading != -1 && !readingMode || !backend->Connected();
+ ImVec2 len = ImGui::CalcTextSize(label);
+ ImVec2 pos = ImGui::GetCursorPos();
+ ImGui::SetCursorPosY(pos.y + len.y / 4);
+ ImGui::SetCursorPosX(pos.x + abs(len.x - size));
+ ImGui::Text("%s", label);
+ ImGui::SameLine();
+ ImGui::SetCursorPosY(pos.y);
+
+ if(disabled) {
+ ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
+ ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
+ }
+
+ if(readingMode) {
+ const int32_t btn = backend->ReadRawPress();
+
+ if(btn != -1) {
+ backend->SetButtonMapping(CurrentPort, n64Btn, btn);
+ BtnReading = -1;
+ }
+ }
+
+ const char* BtnName = backend->GetButtonName(CurrentPort, n64Btn);
+
+ if (ImGui::Button(StringHelper::Sprintf("%s##HBTNID_%d", readingMode ? "Press a Key..." : BtnName, n64Btn).c_str())) {
+ BtnReading = n64Btn;
+ backend->ClearRawPress();
+ }
+
+ if(disabled) {
+ ImGui::PopItemFlag();
+ ImGui::PopStyleVar();
+ }
+ }
+
+ void InputEditor::DrawVirtualStick(const char* label, ImVec2 stick) {
+ ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 5, ImGui::GetCursorPos().y));
+ ImGui::BeginChild(label, ImVec2(68, 75), false);
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ const ImVec2 p = ImGui::GetCursorScreenPos();
+
+ float sz = 45.0f;
+ float rad = sz * 0.5f;
+ ImVec2 pos = ImVec2(p.x + sz * 0.5f + 12, p.y + sz * 0.5f + 11);
+
+ float stickX = (stick.x / 83.0f) * (rad * 0.5f);
+ float stickY = -(stick.y / 83.0f) * (rad * 0.5f);
+
+ ImVec4 rect = ImVec4(p.x + 2, p.y + 2, 65, 65);
+ draw_list->AddRect(ImVec2(rect.x, rect.y), ImVec2(rect.x + rect.z, rect.y + rect.w), ImColor(100, 100, 100, 255), 0.0f, 0, 1.5f);
+ draw_list->AddCircleFilled(pos, rad, ImColor(130, 130, 130, 255), 8);
+ draw_list->AddCircleFilled(ImVec2(pos.x + stickX, pos.y + stickY), 5, ImColor(15, 15, 15, 255), 7);
+ ImGui::EndChild();
+ }
+
+ void InputEditor::DrawControllerSchema() {
+
+ const std::vector<int> vDevices = Window::ControllerApi->virtualDevices;
+ const std::vector<std::shared_ptr<Controller>> devices = Window::ControllerApi->physicalDevices;
+
+ std::shared_ptr<Controller> Backend = devices[vDevices[CurrentPort]];
+ DeviceProfile& profile =Backend->profiles[CurrentPort];
+ float sensitivity = profile.Thresholds[SENSITIVITY];
+ bool IsKeyboard = Backend->GetGuid() == "Keyboard" || !Backend->Connected();
+ const char* ControllerName = Backend->GetControllerName();
+
+ if (ControllerName != nullptr && ImGui::BeginCombo("##ControllerEntries", ControllerName)) {
+ for (uint8_t i = 0; i < devices.size(); i++) {
+ if (ImGui::Selectable(devices[i]->GetControllerName(), i == vDevices[CurrentPort])) {
+ Window::ControllerApi->SetPhysicalDevice(CurrentPort, i);
+ }
+ }
+ ImGui::EndCombo();
+ }
+
+ ImGui::SameLine();
+
+ if(ImGui::Button("Refresh")) {
+ Window::ControllerApi->ScanPhysicalDevices();
+ }
+
+ SohImGui::BeginGroupPanel("Buttons", ImVec2(150, 20));
+ DrawButton("A", BTN_A);
+ DrawButton("B", BTN_B);
+ DrawButton("L", BTN_L);
+ DrawButton("R", BTN_R);
+ DrawButton("Z", BTN_Z);
+ DrawButton("START", BTN_START);
+ SEPARATION();
+ SohImGui::EndGroupPanel(IsKeyboard ? 7.0f : 48.0f);
+ ImGui::SameLine();
+ SohImGui::BeginGroupPanel("Digital Pad", ImVec2(150, 20));
+ DrawButton("Up", BTN_DUP);
+ DrawButton("Down", BTN_DDOWN);
+ DrawButton("Left", BTN_DLEFT);
+ DrawButton("Right", BTN_DRIGHT);
+ SEPARATION();
+ SohImGui::EndGroupPanel(IsKeyboard ? 53.0f : 94.0f);
+ ImGui::SameLine();
+ SohImGui::BeginGroupPanel("Analog Stick", ImVec2(150, 20));
+ DrawButton("Up", BTN_STICKUP);
+ DrawButton("Down", BTN_STICKDOWN);
+ DrawButton("Left", BTN_STICKLEFT);
+ DrawButton("Right", BTN_STICKRIGHT);
+
+ if (!IsKeyboard) {
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
+ DrawVirtualStick("##MainVirtualStick", ImVec2(Backend->wStickX, Backend->wStickY));
+ ImGui::SameLine();
+
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
+
+ ImGui::BeginChild("##MSInput", ImVec2(90, 50), false);
+ ImGui::Text("Deadzone");
+ ImGui::PushItemWidth(80);
+ ImGui::InputInt("##MDZone", &profile.Thresholds[LEFT_STICK]);
+ ImGui::PopItemWidth();
+ ImGui::EndChild();
+ } else {
+ ImGui::Dummy(ImVec2(0, 6));
+ }
+ SohImGui::EndGroupPanel(IsKeyboard ? 52.0f : 24.0f);
+ ImGui::SameLine();
+
+ if (!IsKeyboard) {
+ ImGui::SameLine();
+ SohImGui::BeginGroupPanel("Camera Stick", ImVec2(150, 20));
+ DrawButton("Up", BTN_VSTICKUP);
+ DrawButton("Down", BTN_VSTICKDOWN);
+ DrawButton("Left", BTN_VSTICKLEFT);
+ DrawButton("Right", BTN_VSTICKRIGHT);
+
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
+ DrawVirtualStick("##CameraVirtualStick", ImVec2(Backend->wCamX / sensitivity, Backend->wCamY / sensitivity));
+
+ ImGui::SameLine();
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
+ ImGui::BeginChild("##CSInput", ImVec2(90, 85), false);
+ ImGui::Text("Deadzone");
+ ImGui::PushItemWidth(80);
+ ImGui::InputInt("##MDZone", &profile.Thresholds[RIGHT_STICK]);
+ ImGui::PopItemWidth();
+ ImGui::Text("Sensitivity");
+ ImGui::PushItemWidth(80);
+ ImGui::InputInt("##MSensitivity", &profile.Thresholds[SENSITIVITY]);
+ ImGui::PopItemWidth();
+ ImGui::EndChild();
+ SohImGui::EndGroupPanel(14.0f);
+ }
+
+ if(Backend->CanGyro()) {
+ ImGui::SameLine();
+
+ SohImGui::BeginGroupPanel("Gyro Options", ImVec2(175, 20));
+ float cursorX = ImGui::GetCursorPosX() + 5;
+ ImGui::SetCursorPosX(cursorX);
+ ImGui::Checkbox("Enable Gyro", &profile.UseGyro);
+ ImGui::SetCursorPosX(cursorX);
+ ImGui::Text("Gyro Sensitivity: %d%%", profile.Thresholds[GYRO_SENSITIVITY]);
+ ImGui::PushItemWidth(135.0f);
+ ImGui::SetCursorPosX(cursorX);
+ ImGui::SliderInt("##GSensitivity", &profile.Thresholds[GYRO_SENSITIVITY], 0, 100, "");
+ ImGui::PopItemWidth();
+ ImGui::Dummy(ImVec2(0, 1));
+ ImGui::SetCursorPosX(cursorX);
+ if (ImGui::Button("Recalibrate Gyro##RGyro")) {
+ profile.Thresholds[DRIFT_X] = 0;
+ profile.Thresholds[DRIFT_Y] = 0;
+ }
+ ImGui::SetCursorPosX(cursorX);
+ DrawVirtualStick("##GyroPreview", ImVec2(Backend->wGyroX, Backend->wGyroY));
+
+ ImGui::SameLine();
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
+ ImGui::BeginChild("##GyInput", ImVec2(90, 85), false);
+ ImGui::Text("Drift X");
+ ImGui::PushItemWidth(80);
+ ImGui::InputInt("##GDriftX", &profile.Thresholds[DRIFT_X]);
+ ImGui::PopItemWidth();
+ ImGui::Text("Drift Y");
+ ImGui::PushItemWidth(80);
+ ImGui::InputInt("##GDriftY", &profile.Thresholds[DRIFT_Y]);
+ ImGui::PopItemWidth();
+ ImGui::EndChild();
+ SohImGui::EndGroupPanel(14.0f);
+ }
+
+ ImGui::SameLine();
+
+ const ImVec2 cursor = ImGui::GetCursorPos();
+
+ SohImGui::BeginGroupPanel("C-Buttons", ImVec2(158, 20));
+ DrawButton("Up", BTN_CUP);
+ DrawButton("Down", BTN_CDOWN);
+ DrawButton("Left", BTN_CLEFT);
+ DrawButton("Right", BTN_CRIGHT);
+ ImGui::Dummy(ImVec2(0, 5));
+ SohImGui::EndGroupPanel();
+
+ ImGui::SetCursorPosX(cursor.x);
+ ImGui::SetCursorPosY(cursor.y + 120);
+ SohImGui::BeginGroupPanel("Options", ImVec2(158, 20));
+ float cursorX = ImGui::GetCursorPosX() + 5;
+ ImGui::SetCursorPosX(cursorX);
+ ImGui::Checkbox("Rumble Enabled", &profile.UseRumble);
+ if (Backend->CanRumble()) {
+ ImGui::SetCursorPosX(cursorX);
+ ImGui::Text("Rumble Force: %d%%", static_cast<int>(100 * profile.RumbleStrength));
+ ImGui::SetCursorPosX(cursorX);
+ ImGui::PushItemWidth(135.0f);
+ ImGui::SliderFloat("##RStrength", &profile.RumbleStrength, 0, 1.0f, "");
+ ImGui::PopItemWidth();
+ }
+ ImGui::Dummy(ImVec2(0, 5));
+ SohImGui::EndGroupPanel(IsKeyboard ? 0.0f : 2.0f);
+ }
+
+ void InputEditor::DrawHud() {
+
+ __enableGameInput = true;
+
+ if (!this->Opened) {
+ BtnReading = -1;
+ return;
+ }
+
+ ImGui::SetNextWindowSizeConstraints(ImVec2(641, 250), ImVec2(1200, 290));
+ //OTRTODO: Disable this stupid workaround ( ReadRawPress() only works when the window is on the main viewport )
+ ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID);
+ ImGui::Begin("Controller Configuration", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize);
+
+ ImGui::BeginTabBar("##Controllers");
+
+ for (int i = 0; i < 4; i++) {
+ if (ImGui::BeginTabItem(StringHelper::Sprintf("Port %d", i + 1).c_str())) {
+ CurrentPort = i;
+ ImGui::EndTabItem();
+ }
+ }
+
+ ImGui::EndTabBar();
+
+ // Draw current cfg
+
+ DrawControllerSchema();
+
+ ImGui::End();
+ }
+}
diff --git a/libultraship/libultraship/Cvar.cpp b/libultraship/libultraship/Cvar.cpp
index 55fc70793..231308fe7 100644
--- a/libultraship/libultraship/Cvar.cpp
+++ b/libultraship/libultraship/Cvar.cpp
@@ -5,6 +5,7 @@
#include <memory>
#include <utility>
#include <PR/ultra64/gbi.h>
+#include "imgui_internal.h"
std::map<std::string, std::unique_ptr<CVar>, std::less<>> cvars;
@@ -70,7 +71,7 @@ extern "C" void CVar_SetString(const char* name, const char* value) {
cvar = std::make_unique<CVar>();
}
cvar->type = CVAR_TYPE_STRING;
- cvar->value.valueStr = value;
+ cvar->value.valueStr = ImStrdup(value);
}
extern "C" void CVar_RegisterS32(const char* name, s32 defaultValue) {
diff --git a/libultraship/libultraship/DisconnectedController.h b/libultraship/libultraship/DisconnectedController.h
new file mode 100644
index 000000000..9cbc2b99c
--- /dev/null
+++ b/libultraship/libultraship/DisconnectedController.h
@@ -0,0 +1,31 @@
+#pragma once
+#include <vector>
+#include <optional>
+
+#include "Controller.h"
+
+class DisconnectedController final : public Ship::Controller {
+public:
+ DisconnectedController() {
+ GUID = "Disconnected";
+ }
+
+ std::map<std::vector<std::string>, int32_t> ReadButtonPress();
+ void ReadFromSource(int32_t slot) override {}
+ const char* GetControllerName() override { return "Disconnected"; }
+ const char* GetButtonName(int slot, int n64Button) override { return "None"; }
+ void WriteToSource(int32_t slot, ControllerCallback* controller) override { }
+ bool Connected() const override { return false; }
+ bool CanRumble() const override { return false; }
+ bool CanGyro() const override { return false; }
+
+ void ClearRawPress() override {}
+ int32_t ReadRawPress() override { return -1; }
+ bool HasPadConf() const { return true; }
+ std::optional<std::string> GetPadConfSection() { return "Unk"; }
+ void CreateDefaultBinding(int32_t slot) override {}
+protected:
+ std::string GetControllerType() { return "Unk"; }
+ std::string GetConfSection() { return "Unk"; }
+ std::string GetBindingConfSection() { return "Unk"; }
+};
diff --git a/libultraship/libultraship/GameSettings.cpp b/libultraship/libultraship/GameSettings.cpp
index 0cfbbd21a..e3f95ad76 100644
--- a/libultraship/libultraship/GameSettings.cpp
+++ b/libultraship/libultraship/GameSettings.cpp
@@ -7,7 +7,6 @@
#include <PR/ultra64/pi.h>
#include <PR/ultra64/message.h>
-#include "ConfigFile.h"
#include "Cvar.h"
#include "GlobalCtx2.h"
#include "ImGuiImpl.h"
@@ -33,18 +32,6 @@ namespace Game {
Audio_SetGameVolume(SEQ_SFX, CVar_GetFloat("gFanfareVolume", 1));
}
- void LoadPadSettings() {
- const std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
- ConfigFile& Conf = *pConf;
-
- for (const auto& [i, controllers] : Ship::Window::Controllers) {
- for (const auto& controller : controllers) {
- if (auto padConfSection = controller->GetPadConfSection()) {
- }
- }
- }
- }
-
void LoadSettings() {
DebugConsole_LoadCVars();
}
@@ -58,6 +45,7 @@ namespace Game {
ModInternal::RegisterHook<ModInternal::GfxInit>([] {
gfx_get_current_rendering_api()->set_texture_filter((FilteringMode) CVar_GetS32("gTextureFilter", FILTER_THREE_POINT));
SohImGui::console->opened = CVar_GetS32("gConsoleEnabled", 0);
+ SohImGui::controller->Opened = CVar_GetS32("gControllerConfigurationEnabled", 0);
UpdateAudio();
});
}
diff --git a/libultraship/libultraship/GlobalCtx2.cpp b/libultraship/libultraship/GlobalCtx2.cpp
index 54e64e0ce..329644192 100644
--- a/libultraship/libultraship/GlobalCtx2.cpp
+++ b/libultraship/libultraship/GlobalCtx2.cpp
@@ -15,7 +15,6 @@
namespace Ship {
std::weak_ptr<GlobalCtx2> GlobalCtx2::Context;
ModManager* INSTANCE;
-
std::shared_ptr<GlobalCtx2> GlobalCtx2::GetInstance() {
return Context.lock();
}
@@ -49,7 +48,7 @@ namespace Ship {
return GlobalCtx2::GetAppDirectoryPath() + "/" + path;
}
- GlobalCtx2::GlobalCtx2(const std::string& Name) : Name(Name), MainPath(""), PatchesPath("") {
+ GlobalCtx2::GlobalCtx2(std::string Name) : Name(std::move(Name)) {
}
@@ -60,22 +59,19 @@ namespace Ship {
void GlobalCtx2::InitWindow() {
InitLogging();
- Config = std::make_shared<ConfigFile>(GlobalCtx2::GetInstance(), GetPathRelativeToAppDirectory("shipofharkinian.ini"));
- MainPath = (*Config)["ARCHIVE"]["Main Archive"];
- if (MainPath.empty()) {
- MainPath = GetPathRelativeToAppDirectory("oot.otr");
- }
- PatchesPath = (*Config)["ARCHIVE"]["Patches Directory"];
- if (PatchesPath.empty()) {
- PatchesPath = GetAppDirectoryPath() + "/";
- }
- ResMan = std::make_shared<ResourceMgr>(GlobalCtx2::GetInstance(), MainPath, PatchesPath);
- Win = std::make_shared<Window>(GlobalCtx2::GetInstance());
+ Config = std::make_shared<Mercury>(GetPathRelativeToAppDirectory("shipofharkinian.json"));
+ Config->reload();
+
+ MainPath = Config->getString("Game.Main Archive", GetPathRelativeToAppDirectory("oot.otr"));
+ PatchesPath = Config->getString("Game.Patches Archive", GetAppDirectoryPath() + "/mods");
+
+ ResMan = std::make_shared<ResourceMgr>(GetInstance(), MainPath, PatchesPath);
+ Win = std::make_shared<Window>(GetInstance());
if (!ResMan->DidLoadSuccessfully())
{
#ifdef _WIN32
- MessageBox(NULL, L"Main OTR file not found!", L"Uh oh", MB_OK);
+ MessageBox(nullptr, L"Main OTR file not found!", L"Uh oh", MB_OK);
#else
SPDLOG_ERROR("Main OTR file not found!");
#endif
@@ -109,7 +105,7 @@ namespace Ship {
}
}
- void GlobalCtx2::WriteSaveFile(std::filesystem::path savePath, uintptr_t addr, void* dramAddr, size_t size) {
+ void GlobalCtx2::WriteSaveFile(const std::filesystem::path& savePath, const uintptr_t addr, void* dramAddr, const size_t size) {
std::ofstream saveFile = std::ofstream(savePath, std::fstream::in | std::fstream::out | std::fstream::binary);
saveFile.seekp(addr);
saveFile.write((char*)dramAddr, size);
@@ -129,4 +125,4 @@ namespace Ship {
saveFile.close();
}
-} \ No newline at end of file
+}
diff --git a/libultraship/libultraship/GlobalCtx2.h b/libultraship/libultraship/GlobalCtx2.h
index 5736e2b66..21402070d 100644
--- a/libultraship/libultraship/GlobalCtx2.h
+++ b/libultraship/libultraship/GlobalCtx2.h
@@ -6,8 +6,9 @@
#ifdef __cplusplus
#include <filesystem>
#include <memory>
+#include <fstream>
#include "spdlog/spdlog.h"
-#include "ConfigFile.h"
+#include "Lib/Mercury/Mercury.h"
namespace Ship {
class ResourceMgr;
@@ -22,15 +23,15 @@ namespace Ship {
std::shared_ptr<Window> GetWindow() { return Win; }
std::shared_ptr<ResourceMgr> GetResourceManager() { return ResMan; }
std::shared_ptr<spdlog::logger> GetLogger() { return Logger; }
- std::shared_ptr<ConfigFile> GetConfig() { return Config; }
+ std::shared_ptr<Mercury> GetConfig() { return Config; }
static std::string GetAppDirectoryPath();
static std::string GetPathRelativeToAppDirectory(const char* path);
- void WriteSaveFile(std::filesystem::path savePath, uintptr_t addr, void* dramAddr, size_t size);
+ void WriteSaveFile(const std::filesystem::path& savePath, uintptr_t addr, void* dramAddr, size_t size);
void ReadSaveFile(std::filesystem::path savePath, uintptr_t addr, void* dramAddr, size_t size);
- GlobalCtx2(const std::string& Name);
+ GlobalCtx2(std::string Name);
~GlobalCtx2();
protected:
@@ -41,7 +42,7 @@ namespace Ship {
static std::weak_ptr <GlobalCtx2> Context;
std::shared_ptr<spdlog::logger> Logger;
std::shared_ptr<Window> Win;
- std::shared_ptr<ConfigFile> Config; // Config needs to be after the Window because we call the Window during it's destructor.
+ std::shared_ptr<Mercury> Config; // Config needs to be after the Window because we call the Window during it's destructor.
std::shared_ptr<ResourceMgr> ResMan;
std::string Name;
std::string MainPath;
diff --git a/libultraship/libultraship/Hooks.h b/libultraship/libultraship/Hooks.h
index b5dec8159..411cffe42 100644
--- a/libultraship/libultraship/Hooks.h
+++ b/libultraship/libultraship/Hooks.h
@@ -5,6 +5,7 @@
#include <functional>
#include "UltraController.h"
+#include "Controller.h"
#define DEFINE_HOOK(name, type) struct name { typedef std::function<type> fn; }
@@ -28,12 +29,11 @@ namespace ModInternal {
}
DEFINE_HOOK(ControllerRead, void(OSContPad* cont_pad));
-
+ DEFINE_HOOK(ControllerRawInput, void(Ship::Controller* backend, uint32_t raw));
DEFINE_HOOK(AudioInit, void());
-
DEFINE_HOOK(LoadTexture, void(const char* path, uint8_t** texture));
-
DEFINE_HOOK(GfxInit, void());
+ DEFINE_HOOK(ExitGame, void());
}
diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp
index 69d05a74d..dd172118d 100644
--- a/libultraship/libultraship/ImGuiImpl.cpp
+++ b/libultraship/libultraship/ImGuiImpl.cpp
@@ -12,6 +12,7 @@
#include "GameSettings.h"
#include "Console.h"
#include "Hooks.h"
+#define IMGUI_DEFINE_MATH_OPERATORS
#include "Lib/ImGui/imgui_internal.h"
#include "GlobalCtx2.h"
#include "ResourceMgr.h"
@@ -63,6 +64,8 @@ namespace SohImGui {
ImGuiIO* io;
Console* console = new Console;
GameOverlay* overlay = new GameOverlay;
+ InputEditor* controller = new InputEditor;
+ static ImVector<ImRect> s_GroupPanelLabelStack;
bool p_open = false;
bool needs_save = false;
@@ -326,6 +329,7 @@ namespace SohImGui {
}
console->Init();
overlay->Init();
+ controller->Init();
ImGuiWMInit();
ImGuiBackendInit();
@@ -346,23 +350,17 @@ namespace SohImGui {
LoadTexture("C-Down", "assets/ship_of_harkinian/buttons/CDown.png");
});
- for (const auto& [i, controllers] : Ship::Window::Controllers)
- {
- CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftX", i).c_str(), 0);
- CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftY", i).c_str(), 0);
- needs_save = true;
- }
-
ModInternal::RegisterHook<ModInternal::ControllerRead>([](OSContPad* cont_pad) {
pads = cont_pad;
});
+
Game::InitSettings();
CVar_SetS32("gRandoGenerating", 0);
CVar_SetS32("gNewSeedGenerated", 0);
CVar_SetS32("gNewFileDropped", 0);
- CVar_SetString("gDroppedFile", "");
- Game::SaveSettings();
+ CVar_SetString("gDroppedFile", "None");
+ // Game::SaveSettings();
}
void Update(EventImpl event) {
@@ -511,7 +509,7 @@ namespace SohImGui {
}
void EnhancementCombo(const std::string& name, const char* cvarName, const std::vector<std::string>& items, int defaultValue) {
-
+
if (ImGui::BeginCombo(name.c_str(), items[static_cast<int>(CVar_GetS32(cvarName, defaultValue))].c_str())) {
for (int settingIndex = 0; settingIndex < (int) items.size(); settingIndex++) {
if (ImGui::Selectable(items[settingIndex].c_str())) {
@@ -691,36 +689,32 @@ namespace SohImGui {
needs_save = true;
GlobalCtx2::GetInstance()->GetWindow()->dwMenubar = menu_bar;
ShowCursor(menu_bar, Dialogues::dMenubar);
-
+ GlobalCtx2::GetInstance()->GetWindow()->GetControlDeck()->SaveControllerSettings();
if (CVar_GetS32("gControlNav", 0)) {
if (CVar_GetS32("gOpenMenuBar", 0)) {
io->ConfigFlags |=ImGuiConfigFlags_NavEnableGamepad | ImGuiConfigFlags_NavEnableKeyboard;
+ } else {
+ io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
}
- else
- {
- io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
- }
- }
- else
- {
- io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
+ } else {
+ io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
}
}
#if __APPLE__
if ((ImGui::IsKeyDown(ImGuiKey_LeftSuper) ||
- ImGui::IsKeyDown(ImGuiKey_RightSuper)) &&
+ ImGui::IsKeyDown(ImGuiKey_RightSuper)) &&
ImGui::IsKeyPressed(ImGuiKey_R, false)) {
console->Commands["reset"].handler(emptyArgs);
}
#else
if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) ||
- ImGui::IsKeyDown(ImGuiKey_RightCtrl)) &&
+ ImGui::IsKeyDown(ImGuiKey_RightCtrl)) &&
ImGui::IsKeyPressed(ImGuiKey_R, false)) {
console->Commands["reset"].handler(emptyArgs);
}
#endif
-
+
if (ImGui::BeginMenuBar()) {
if (DefaultAssets.contains("Game_Icon")) {
ImGui::SetCursorPos(ImVec2(5, 2.5f));
@@ -740,7 +734,7 @@ namespace SohImGui {
console->Commands["reset"].handler(emptyArgs);
}
ImGui::EndMenu();
- }
+ }
if (ImGui::BeginMenu("Audio")) {
EnhancementSliderFloat("Master Volume: %d %%", "##Master_Vol", "gGameMasterVolume", 0.0f, 1.0f, "", 1.0f, true);
@@ -758,6 +752,9 @@ namespace SohImGui {
EnhancementCheckbox("Use Controller Navigation", "gControlNav");
Tooltip("Allows controller navigation of the menu bar\nD-pad to move between items, A to select, and X to grab focus on the menu bar");
+ EnhancementCheckbox("Controller Configuration", "gControllerConfigurationEnabled");
+ controller->Opened = CVar_GetS32("gControllerConfigurationEnabled", 0);
+
ImGui::Separator();
// TODO mutual exclusions -- There should be some system to prevent conclifting enhancements from being selected
@@ -771,41 +768,9 @@ namespace SohImGui {
EnhancementCheckbox("Show Inputs", "gInputEnabled");
Tooltip("Shows currently pressed inputs on the bottom right of the screen");
- EnhancementCheckbox("Rumble Enabled", "gRumbleEnabled");
EnhancementSliderFloat("Input Scale: %.1f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, false);
- Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting");
-
- ImGui::Separator();
-
- for (const auto& [i, controllers] : Ship::Window::Controllers)
- {
- bool hasPad = std::find_if(controllers.begin(), controllers.end(), [](const auto& c) {
- return c->HasPadConf() && c->Connected();
- }) != controllers.end();
-
- if (!hasPad) continue;
-
- auto menuLabel = "Controller " + std::to_string(i + 1);
- if (ImGui::BeginMenu(menuLabel.c_str()))
- {
- EnhancementSliderFloat("Gyro Sensitivity: %d %%", "##GYROSCOPE", StringHelper::Sprintf("gCont%i_GyroSensitivity", i).c_str(), 0.0f, 1.0f, "", 1.0f, true);
-
- if (ImGui::Button("Recalibrate Gyro"))
- {
- CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftX", i).c_str(), 0);
- CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftY", i).c_str(), 0);
- needs_save = true;
- }
-
- ImGui::Separator();
-
- EnhancementSliderFloat("Rumble Strength: %d %%", "##RUMBLE", StringHelper::Sprintf("gCont%i_RumbleStrength", i).c_str(), 0.0f, 1.0f, "", 1.0f, true);
-
- ImGui::EndMenu();
- }
- ImGui::Separator();
- }
+ Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting");
ImGui::EndMenu();
}
@@ -933,7 +898,7 @@ namespace SohImGui {
Tooltip("Disables random drops, except from the Goron Pot, Dampe, and bosses");
EnhancementCheckbox("No Heart Drops", "gNoHeartDrops");
Tooltip("Disables heart drops, but not heart placements, like from a Deku Scrub running off\nThis simulates Hero Mode from other games in the series");
-
+
if (ImGui::BeginMenu("Potion Values"))
{
EnhancementCheckbox("Change Red Potion Effect", "gRedPotionEffect");
@@ -942,7 +907,7 @@ namespace SohImGui {
Tooltip("Changes the amount of health restored by Red Potions");
EnhancementCheckbox("Red Potion Percent Restore", "gRedPercentRestore");
Tooltip("Toggles from Red Potions restoring a fixed amount of health to a percent of the player's current max health");
-
+
EnhancementCheckbox("Change Green Potion Effect", "gGreenPotionEffect");
Tooltip("Enable the following changes to the amount of mana restored by Green Potions");
EnhancementSliderInt("Green Potion Mana: %d", "##GREENPOTIONMANA", "gGreenPotionMana", 1, 100, "");
@@ -956,7 +921,7 @@ namespace SohImGui {
Tooltip("Changes the amount of health restored by Blue Potions");
EnhancementCheckbox("Blue Potion Health Percent Restore", "gBlueHealthPercentRestore");
Tooltip("Toggles from Blue Potions restoring a fixed amount of health to a percent of the player's current max health");
-
+
EnhancementSliderInt("Blue Potion Mana: %d", "##BLUEPOTIONMANA", "gBluePotionMana", 1, 100, "");
Tooltip("Changes the amount of mana restored by Blue Potions, base max mana is 48, max upgraded mana is 96");
EnhancementCheckbox("Blue Potion Mana Percent Restore", "gBlueManaPercentRestore");
@@ -1019,7 +984,7 @@ namespace SohImGui {
ImGui::EndMenu();
}
-
+
EnhancementCheckbox("Visual Stone of Agony", "gVisualAgony");
Tooltip("Displays an icon and plays a sound when Stone of Agony\nshould be activated, for those without rumble");
EnhancementCheckbox("Assignable Tunics and Boots", "gAssignableTunicsAndBoots");
@@ -1268,7 +1233,7 @@ namespace SohImGui {
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::SetNextWindowSize(ImVec2 (0,0));
ImGuiWindowFlags HiddenWndFlags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoSavedSettings |
- ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNavInputs |
+ ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNavInputs |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoDecoration;
ImGui::Begin(category.first.c_str(), nullptr, HiddenWndFlags);
ImGui::End();
@@ -1292,6 +1257,7 @@ namespace SohImGui {
}
console->Draw();
+ controller->DrawHud();
for (auto& windowIter : customWindows) {
CustomWindow& window = windowIter.second;
@@ -1457,4 +1423,124 @@ namespace SohImGui {
#endif
return reinterpret_cast<ImTextureID>(id);
}
+
+ void BeginGroupPanel(const char* name, const ImVec2& size)
+ {
+ ImGui::BeginGroup();
+
+ // auto cursorPos = ImGui::GetCursorScreenPos();
+ auto itemSpacing = ImGui::GetStyle().ItemSpacing;
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
+
+ auto frameHeight = ImGui::GetFrameHeight();
+ ImGui::BeginGroup();
+
+ ImVec2 effectiveSize = size;
+ if (size.x < 0.0f)
+ effectiveSize.x = ImGui::GetContentRegionAvail().x;
+ else
+ effectiveSize.x = size.x;
+ ImGui::Dummy(ImVec2(effectiveSize.x, 0.0f));
+
+ ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
+ ImGui::SameLine(0.0f, 0.0f);
+ ImGui::BeginGroup();
+ ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
+ ImGui::SameLine(0.0f, 0.0f);
+ ImGui::TextUnformatted(name);
+ auto labelMin = ImGui::GetItemRectMin();
+ auto labelMax = ImGui::GetItemRectMax();
+ ImGui::SameLine(0.0f, 0.0f);
+ ImGui::Dummy(ImVec2(0.0, frameHeight + itemSpacing.y));
+ ImGui::BeginGroup();
+
+ //ImGui::GetWindowDrawList()->AddRect(labelMin, labelMax, IM_COL32(255, 0, 255, 255));
+
+ ImGui::PopStyleVar(2);
+
+#if IMGUI_VERSION_NUM >= 17301
+ ImGui::GetCurrentWindow()->ContentRegionRect.Max.x -= frameHeight * 0.5f;
+ ImGui::GetCurrentWindow()->WorkRect.Max.x -= frameHeight * 0.5f;
+ ImGui::GetCurrentWindow()->InnerRect.Max.x -= frameHeight * 0.5f;
+#else
+ ImGui::GetCurrentWindow()->ContentsRegionRect.Max.x -= frameHeight * 0.5f;
+#endif
+ ImGui::GetCurrentWindow()->Size.x -= frameHeight;
+
+ auto itemWidth = ImGui::CalcItemWidth();
+ ImGui::PushItemWidth(ImMax(0.0f, itemWidth - frameHeight));
+ s_GroupPanelLabelStack.push_back(ImRect(labelMin, labelMax));
+ }
+
+ void EndGroupPanel(float minHeight) {
+ ImGui::PopItemWidth();
+
+ auto itemSpacing = ImGui::GetStyle().ItemSpacing;
+
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
+
+ auto frameHeight = ImGui::GetFrameHeight();
+
+ ImGui::EndGroup();
+
+ //ImGui::GetWindowDrawList()->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(0, 255, 0, 64), 4.0f);
+
+ ImGui::EndGroup();
+
+ ImGui::SameLine(0.0f, 0.0f);
+ ImGui::Dummy(ImVec2(frameHeight * 0.5f, 0.0f));
+ ImGui::Dummy(ImVec2(0.0, std::max(frameHeight - frameHeight * 0.5f - itemSpacing.y, minHeight)));
+
+ ImGui::EndGroup();
+
+ auto itemMin = ImGui::GetItemRectMin();
+ auto itemMax = ImGui::GetItemRectMax();
+ //ImGui::GetWindowDrawList()->AddRectFilled(itemMin, itemMax, IM_COL32(255, 0, 0, 64), 4.0f);
+
+ auto labelRect = s_GroupPanelLabelStack.back();
+ s_GroupPanelLabelStack.pop_back();
+
+ ImVec2 halfFrame = ImVec2(frameHeight * 0.25f, frameHeight) * 0.5f;
+ ImRect frameRect = ImRect(itemMin + halfFrame, itemMax - ImVec2(halfFrame.x, 0.0f));
+ labelRect.Min.x -= itemSpacing.x;
+ labelRect.Max.x += itemSpacing.x;
+ for (int i = 0; i < 4; ++i)
+ {
+ switch (i)
+ {
+ // left half-plane
+ case 0: ImGui::PushClipRect(ImVec2(-FLT_MAX, -FLT_MAX), ImVec2(labelRect.Min.x, FLT_MAX), true); break;
+ // right half-plane
+ case 1: ImGui::PushClipRect(ImVec2(labelRect.Max.x, -FLT_MAX), ImVec2(FLT_MAX, FLT_MAX), true); break;
+ // top
+ case 2: ImGui::PushClipRect(ImVec2(labelRect.Min.x, -FLT_MAX), ImVec2(labelRect.Max.x, labelRect.Min.y), true); break;
+ // bottom
+ case 3: ImGui::PushClipRect(ImVec2(labelRect.Min.x, labelRect.Max.y), ImVec2(labelRect.Max.x, FLT_MAX), true); break;
+ }
+
+ ImGui::GetWindowDrawList()->AddRect(
+ frameRect.Min, frameRect.Max,
+ ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Border)),
+ halfFrame.x);
+
+ ImGui::PopClipRect();
+ }
+
+ ImGui::PopStyleVar(2);
+
+#if IMGUI_VERSION_NUM >= 17301
+ ImGui::GetCurrentWindow()->ContentRegionRect.Max.x += frameHeight * 0.5f;
+ ImGui::GetCurrentWindow()->WorkRect.Max.x += frameHeight * 0.5f;
+ ImGui::GetCurrentWindow()->InnerRect.Max.x += frameHeight * 0.5f;
+#else
+ ImGui::GetCurrentWindow()->ContentsRegionRect.Max.x += frameHeight * 0.5f;
+#endif
+ ImGui::GetCurrentWindow()->Size.x += frameHeight;
+
+ ImGui::Dummy(ImVec2(0.0f, 0.0f));
+
+ ImGui::EndGroup();
+ }
}
diff --git a/libultraship/libultraship/ImGuiImpl.h b/libultraship/libultraship/ImGuiImpl.h
index 34bc368a6..1b2ba06c1 100644
--- a/libultraship/libultraship/ImGuiImpl.h
+++ b/libultraship/libultraship/ImGuiImpl.h
@@ -3,6 +3,7 @@
#include "GameOverlay.h"
#include "Lib/ImGui/imgui.h"
#include "Console.h"
+#include "InputEditor.h"
struct GameAsset {
uint32_t textureId;
@@ -59,12 +60,13 @@ namespace SohImGui {
} CustomWindow;
extern Console* console;
+ extern Ship::InputEditor* controller;
extern Ship::GameOverlay* overlay;
extern bool needs_save;
void Init(WindowImpl window_impl);
void Update(EventImpl event);
void Tooltip(const char* text);
-
+
void EnhancementRadioButton(const char* text, const char* cvarName, int id);
void EnhancementCheckbox(const char* text, const char* cvarName);
void EnhancementButton(const char* text, const char* cvarName);
@@ -75,7 +77,7 @@ namespace SohImGui {
void EnhancementCombo(const std::string& name, const char* cvarName, const std::vector<std::string>& items, int defaultValue = 0);
void DrawMainMenuAndCalculateGameSize(void);
-
+
void DrawFramebufferAndGameInput(void);
void Render(void);
void CancelFrame(void);
@@ -90,4 +92,6 @@ namespace SohImGui {
void ResetColor(const char* cvarName, ImVec4* colors, ImVec4 defaultcolors, bool has_alpha);
ImTextureID GetTextureByID(int id);
ImTextureID GetTextureByName(const std::string& name);
+ void BeginGroupPanel(const char* name, const ImVec2 & size = ImVec2(0.0f, 0.0f));
+ void EndGroupPanel(float minHeight = 0.0f);
}
diff --git a/libultraship/libultraship/InputEditor.cpp b/libultraship/libultraship/InputEditor.cpp
new file mode 100644
index 000000000..e40990b0d
--- /dev/null
+++ b/libultraship/libultraship/InputEditor.cpp
@@ -0,0 +1,277 @@
+#include "InputEditor.h"
+#include "Controller.h"
+#include "Window.h"
+#include "Lib/ImGui/imgui.h"
+#include "ImGuiImpl.h"
+#include "Utils/StringHelper.h"
+#include "Lib/ImGui/imgui_internal.h"
+
+namespace Ship {
+
+ extern "C" uint8_t __enableGameInput;
+ #define SEPARATION() ImGui::Dummy(ImVec2(0, 5))
+
+ void InputEditor::Init() {
+ BtnReading = -1;
+ }
+
+ std::shared_ptr<Controller> GetControllerPerSlot(int slot) {
+ const std::vector<int> vDevices = Window::ControllerApi->virtualDevices;
+ return Window::ControllerApi->physicalDevices[vDevices[slot]];
+ }
+
+ void InputEditor::DrawButton(const char* label, int n64Btn) {
+ const std::shared_ptr<Controller> backend = GetControllerPerSlot(CurrentPort);
+
+ float size = 40;
+ bool readingMode = BtnReading == n64Btn;
+ bool disabled = BtnReading != -1 && !readingMode || !backend->Connected();
+ ImVec2 len = ImGui::CalcTextSize(label);
+ ImVec2 pos = ImGui::GetCursorPos();
+ ImGui::SetCursorPosY(pos.y + len.y / 4);
+ ImGui::SetCursorPosX(pos.x + abs(len.x - size));
+ ImGui::Text("%s", label);
+ ImGui::SameLine();
+ ImGui::SetCursorPosY(pos.y);
+
+ if(disabled) {
+ ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
+ ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
+ }
+
+ if(readingMode) {
+ const int32_t btn = backend->ReadRawPress();
+
+ if(btn != -1) {
+ backend->SetButtonMapping(CurrentPort, n64Btn, btn);
+ BtnReading = -1;
+ }
+ }
+
+ const char* BtnName = backend->GetButtonName(CurrentPort, n64Btn);
+
+ if (ImGui::Button(StringHelper::Sprintf("%s##HBTNID_%d", readingMode ? "Press a Key..." : BtnName, n64Btn).c_str())) {
+ BtnReading = n64Btn;
+ backend->ClearRawPress();
+ }
+
+ if(disabled) {
+ ImGui::PopItemFlag();
+ ImGui::PopStyleVar();
+ }
+ }
+
+ void InputEditor::DrawVirtualStick(const char* label, ImVec2 stick) {
+ ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 5, ImGui::GetCursorPos().y));
+ ImGui::BeginChild(label, ImVec2(68, 75), false);
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ const ImVec2 p = ImGui::GetCursorScreenPos();
+
+ float sz = 45.0f;
+ float rad = sz * 0.5f;
+ ImVec2 pos = ImVec2(p.x + sz * 0.5f + 12, p.y + sz * 0.5f + 11);
+
+ float stickX = (stick.x / 83.0f) * (rad * 0.5f);
+ float stickY = -(stick.y / 83.0f) * (rad * 0.5f);
+
+ ImVec4 rect = ImVec4(p.x + 2, p.y + 2, 65, 65);
+ draw_list->AddRect(ImVec2(rect.x, rect.y), ImVec2(rect.x + rect.z, rect.y + rect.w), ImColor(100, 100, 100, 255), 0.0f, 0, 1.5f);
+ draw_list->AddCircleFilled(pos, rad, ImColor(130, 130, 130, 255), 8);
+ draw_list->AddCircleFilled(ImVec2(pos.x + stickX, pos.y + stickY), 5, ImColor(15, 15, 15, 255), 7);
+ ImGui::EndChild();
+ }
+
+ void InputEditor::DrawControllerSchema() {
+
+ const std::vector<int> vDevices = Window::ControllerApi->virtualDevices;
+ const std::vector<std::shared_ptr<Controller>> devices = Window::ControllerApi->physicalDevices;
+
+ std::shared_ptr<Controller> Backend = devices[vDevices[CurrentPort]];
+ DeviceProfile& profile =Backend->profiles[CurrentPort];
+ float sensitivity = profile.Thresholds[SENSITIVITY];
+ bool IsKeyboard = Backend->GetGuid() == "Keyboard" || !Backend->Connected();
+ const char* ControllerName = Backend->GetControllerName();
+
+ if (ControllerName != nullptr && ImGui::BeginCombo("##ControllerEntries", ControllerName)) {
+ for (uint8_t i = 0; i < devices.size(); i++) {
+ if (ImGui::Selectable(devices[i]->GetControllerName(), i == vDevices[CurrentPort])) {
+ Window::ControllerApi->SetPhysicalDevice(CurrentPort, i);
+ }
+ }
+ ImGui::EndCombo();
+ }
+
+ ImGui::SameLine();
+
+ if(ImGui::Button("Refresh")) {
+ Window::ControllerApi->ScanPhysicalDevices();
+ }
+
+ SohImGui::BeginGroupPanel("Buttons", ImVec2(150, 20));
+ DrawButton("A", BTN_A);
+ DrawButton("B", BTN_B);
+ DrawButton("L", BTN_L);
+ DrawButton("R", BTN_R);
+ DrawButton("Z", BTN_Z);
+ DrawButton("START", BTN_START);
+ SEPARATION();
+ SohImGui::EndGroupPanel(IsKeyboard ? 7.0f : 48.0f);
+ ImGui::SameLine();
+ SohImGui::BeginGroupPanel("Digital Pad", ImVec2(150, 20));
+ DrawButton("Up", BTN_DUP);
+ DrawButton("Down", BTN_DDOWN);
+ DrawButton("Left", BTN_DLEFT);
+ DrawButton("Right", BTN_DRIGHT);
+ SEPARATION();
+ SohImGui::EndGroupPanel(IsKeyboard ? 53.0f : 94.0f);
+ ImGui::SameLine();
+ SohImGui::BeginGroupPanel("Analog Stick", ImVec2(150, 20));
+ DrawButton("Up", BTN_STICKUP);
+ DrawButton("Down", BTN_STICKDOWN);
+ DrawButton("Left", BTN_STICKLEFT);
+ DrawButton("Right", BTN_STICKRIGHT);
+
+ if (!IsKeyboard) {
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
+ DrawVirtualStick("##MainVirtualStick", ImVec2(Backend->wStickX, Backend->wStickY));
+ ImGui::SameLine();
+
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
+
+ ImGui::BeginChild("##MSInput", ImVec2(90, 50), false);
+ ImGui::Text("Deadzone");
+ ImGui::PushItemWidth(80);
+ ImGui::InputInt("##MDZone", &profile.Thresholds[LEFT_STICK]);
+ ImGui::PopItemWidth();
+ ImGui::EndChild();
+ } else {
+ ImGui::Dummy(ImVec2(0, 6));
+ }
+ SohImGui::EndGroupPanel(IsKeyboard ? 52.0f : 24.0f);
+ ImGui::SameLine();
+
+ if (!IsKeyboard) {
+ ImGui::SameLine();
+ SohImGui::BeginGroupPanel("Camera Stick", ImVec2(150, 20));
+ DrawButton("Up", BTN_VSTICKUP);
+ DrawButton("Down", BTN_VSTICKDOWN);
+ DrawButton("Left", BTN_VSTICKLEFT);
+ DrawButton("Right", BTN_VSTICKRIGHT);
+
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
+ DrawVirtualStick("##CameraVirtualStick", ImVec2(Backend->wCamX / sensitivity, Backend->wCamY / sensitivity));
+
+ ImGui::SameLine();
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
+ ImGui::BeginChild("##CSInput", ImVec2(90, 85), false);
+ ImGui::Text("Deadzone");
+ ImGui::PushItemWidth(80);
+ ImGui::InputInt("##MDZone", &profile.Thresholds[RIGHT_STICK]);
+ ImGui::PopItemWidth();
+ ImGui::Text("Sensitivity");
+ ImGui::PushItemWidth(80);
+ ImGui::InputInt("##MSensitivity", &profile.Thresholds[SENSITIVITY]);
+ ImGui::PopItemWidth();
+ ImGui::EndChild();
+ SohImGui::EndGroupPanel(14.0f);
+ }
+
+ if(Backend->CanGyro()) {
+ ImGui::SameLine();
+
+ SohImGui::BeginGroupPanel("Gyro Options", ImVec2(175, 20));
+ float cursorX = ImGui::GetCursorPosX() + 5;
+ ImGui::SetCursorPosX(cursorX);
+ ImGui::Checkbox("Enable Gyro", &profile.UseGyro);
+ ImGui::SetCursorPosX(cursorX);
+ ImGui::Text("Gyro Sensitivity: %d%%", profile.Thresholds[GYRO_SENSITIVITY]);
+ ImGui::PushItemWidth(135.0f);
+ ImGui::SetCursorPosX(cursorX);
+ ImGui::SliderInt("##GSensitivity", &profile.Thresholds[GYRO_SENSITIVITY], 0, 100, "");
+ ImGui::PopItemWidth();
+ ImGui::Dummy(ImVec2(0, 1));
+ ImGui::SetCursorPosX(cursorX);
+ if (ImGui::Button("Recalibrate Gyro##RGyro")) {
+ profile.Thresholds[DRIFT_X] = 0;
+ profile.Thresholds[DRIFT_Y] = 0;
+ }
+ ImGui::SetCursorPosX(cursorX);
+ DrawVirtualStick("##GyroPreview", ImVec2(Backend->wGyroX, Backend->wGyroY));
+
+ ImGui::SameLine();
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
+ ImGui::BeginChild("##GyInput", ImVec2(90, 85), false);
+ ImGui::Text("Drift X");
+ ImGui::PushItemWidth(80);
+ ImGui::InputInt("##GDriftX", &profile.Thresholds[DRIFT_X]);
+ ImGui::PopItemWidth();
+ ImGui::Text("Drift Y");
+ ImGui::PushItemWidth(80);
+ ImGui::InputInt("##GDriftY", &profile.Thresholds[DRIFT_Y]);
+ ImGui::PopItemWidth();
+ ImGui::EndChild();
+ SohImGui::EndGroupPanel(14.0f);
+ }
+
+ ImGui::SameLine();
+
+ const ImVec2 cursor = ImGui::GetCursorPos();
+
+ SohImGui::BeginGroupPanel("C-Buttons", ImVec2(158, 20));
+ DrawButton("Up", BTN_CUP);
+ DrawButton("Down", BTN_CDOWN);
+ DrawButton("Left", BTN_CLEFT);
+ DrawButton("Right", BTN_CRIGHT);
+ ImGui::Dummy(ImVec2(0, 5));
+ SohImGui::EndGroupPanel();
+
+ ImGui::SetCursorPosX(cursor.x);
+ ImGui::SetCursorPosY(cursor.y + 120);
+ SohImGui::BeginGroupPanel("Options", ImVec2(158, 20));
+ float cursorX = ImGui::GetCursorPosX() + 5;
+ ImGui::SetCursorPosX(cursorX);
+ ImGui::Checkbox("Rumble Enabled", &profile.UseRumble);
+ if (Backend->CanRumble()) {
+ ImGui::SetCursorPosX(cursorX);
+ ImGui::Text("Rumble Force: %d%%", static_cast<int>(100 * profile.RumbleStrength));
+ ImGui::SetCursorPosX(cursorX);
+ ImGui::PushItemWidth(135.0f);
+ ImGui::SliderFloat("##RStrength", &profile.RumbleStrength, 0, 1.0f, "");
+ ImGui::PopItemWidth();
+ }
+ ImGui::Dummy(ImVec2(0, 5));
+ SohImGui::EndGroupPanel(IsKeyboard ? 0.0f : 2.0f);
+ }
+
+ void InputEditor::DrawHud() {
+
+ __enableGameInput = true;
+
+ if (!this->Opened) {
+ BtnReading = -1;
+ return;
+ }
+
+ ImGui::SetNextWindowSizeConstraints(ImVec2(641, 250), ImVec2(1200, 290));
+ //OTRTODO: Disable this stupid workaround ( ReadRawPress() only works when the window is on the main viewport )
+ ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID);
+ ImGui::Begin("Controller Configuration", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize);
+
+ ImGui::BeginTabBar("##Controllers");
+
+ for (int i = 0; i < 4; i++) {
+ if (ImGui::BeginTabItem(StringHelper::Sprintf("Port %d", i + 1).c_str())) {
+ CurrentPort = i;
+ ImGui::EndTabItem();
+ }
+ }
+
+ ImGui::EndTabBar();
+
+ // Draw current cfg
+
+ DrawControllerSchema();
+
+ ImGui::End();
+ }
+}
diff --git a/libultraship/libultraship/InputEditor.h b/libultraship/libultraship/InputEditor.h
new file mode 100644
index 000000000..39bddd51d
--- /dev/null
+++ b/libultraship/libultraship/InputEditor.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <string>
+
+#include "Lib/ImGui/imgui.h"
+
+namespace Ship {
+
+ class InputEditor {
+ int CurrentPort = 0;
+ int BtnReading = -1;
+ public:
+ bool Opened = false;
+ void Init();
+ void DrawButton(const char* label, int n64Btn);
+ void DrawVirtualStick(const char* label, ImVec2 stick);
+ void DrawControllerSchema();
+ void DrawHud();
+ };
+}
diff --git a/libultraship/libultraship/KeyboardController.cpp b/libultraship/libultraship/KeyboardController.cpp
index 13014c6a7..0ba08f415 100644
--- a/libultraship/libultraship/KeyboardController.cpp
+++ b/libultraship/libultraship/KeyboardController.cpp
@@ -1,56 +1,105 @@
#include "KeyboardController.h"
+
+#if __APPLE__
+#include <SDL_keyboard.h>
+#else
+#include <SDL2/SDL_keyboard.h>
+#endif
+
+#include "Hooks.h"
#include "GlobalCtx2.h"
+#include "Window.h"
namespace Ship {
- KeyboardController::KeyboardController(int32_t dwControllerNumber) : Controller(dwControllerNumber) {
- LoadBinding();
- }
- KeyboardController::~KeyboardController() {
-
+ KeyboardController::KeyboardController() : Controller(), lastScancode(-1) {
+ GUID = "Keyboard";
}
bool KeyboardController::PressButton(int32_t dwScancode) {
- if (ButtonMapping.contains(dwScancode)) {
- dwPressedButtons |= ButtonMapping[dwScancode];
- return true;
+
+ lastKey = dwScancode;
+
+ for (int slot = 0; slot < MAXCONTROLLERS; slot++) {
+
+ if (profiles[slot].Mappings.contains(dwScancode)) {
+ dwPressedButtons[slot] |= profiles[slot].Mappings[dwScancode];
+ return true;
+ }
}
return false;
}
bool KeyboardController::ReleaseButton(int32_t dwScancode) {
- if (ButtonMapping.contains(dwScancode)) {
- dwPressedButtons &= ~ButtonMapping[dwScancode];
- return true;
+ for (int slot = 0; slot < MAXCONTROLLERS; slot++) {
+ if (profiles[slot].Mappings.contains(dwScancode)) {
+ dwPressedButtons[slot] &= ~profiles[slot].Mappings[dwScancode];
+ return true;
+ }
}
return false;
}
void KeyboardController::ReleaseAllButtons() {
- dwPressedButtons = 0;
+ for(int slot = 0; slot < MAXCONTROLLERS; slot++) {
+ dwPressedButtons[slot] = 0;
+ }
}
- void KeyboardController::ReadFromSource() {
+ void KeyboardController::ReadFromSource(int32_t slot) {
wStickX = 0;
wStickY = 0;
+ wCamX = 0;
+ wCamY = 0;
+ }
+
+ int32_t KeyboardController::ReadRawPress() {
+ return lastKey;
}
- void KeyboardController::WriteToSource(ControllerCallback* controller)
+
+ void KeyboardController::WriteToSource(int32_t slot, ControllerCallback* controller)
{
}
- std::string KeyboardController::GetControllerType() {
- return "KEYBOARD";
+ const char* KeyboardController::GetButtonName(int slot, int n64Button) {
+ std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings;
+ const auto find = std::find_if(Mappings.begin(), Mappings.end(), [n64Button](const std::pair<int32_t, int32_t>& pair) {
+ return pair.second == n64Button;
+ });
+
+ if (find == Mappings.end()) return "Unknown";
+ const char* name = GlobalCtx2::GetInstance()->GetWindow()->GetKeyName(find->first);
+ return strlen(name) == 0 ? "Unknown" : name;
}
- std::string KeyboardController::GetConfSection() {
- return GetControllerType() + " CONTROLLER " + std::to_string(GetControllerNumber() + 1);
+
+ void KeyboardController::CreateDefaultBinding(int32_t slot) {
+ DeviceProfile& profile = profiles[slot];
+ profile.Mappings[0x14D] = BTN_CRIGHT;
+ profile.Mappings[0x14B] = BTN_CLEFT;
+ profile.Mappings[0x150] = BTN_CDOWN;
+ profile.Mappings[0x148] = BTN_CUP;
+ profile.Mappings[0x13] = BTN_R;
+ profile.Mappings[0x12] = BTN_L;
+ profile.Mappings[0x023] = BTN_DRIGHT;
+ profile.Mappings[0x021] = BTN_DLEFT;
+ profile.Mappings[0x022] = BTN_DDOWN;
+ profile.Mappings[0x014] = BTN_DUP;
+ profile.Mappings[0x039] = BTN_START;
+ profile.Mappings[0x02C] = BTN_Z;
+ profile.Mappings[0x02E] = BTN_B;
+ profile.Mappings[0x02D] = BTN_A;
+ profile.Mappings[0x020] = BTN_STICKRIGHT;
+ profile.Mappings[0x01E] = BTN_STICKLEFT;
+ profile.Mappings[0x01F] = BTN_STICKDOWN;
+ profile.Mappings[0x011] = BTN_STICKUP;
}
- std::string KeyboardController::GetBindingConfSection() {
- return GetControllerType() + " CONTROLLER BINDING " + std::to_string(GetControllerNumber() + 1);
+ const char* KeyboardController::GetControllerName() {
+ return "Keyboard";
}
}
diff --git a/libultraship/libultraship/KeyboardController.h b/libultraship/libultraship/KeyboardController.h
index f6c109ca7..cc0aca04e 100644
--- a/libultraship/libultraship/KeyboardController.h
+++ b/libultraship/libultraship/KeyboardController.h
@@ -5,24 +5,34 @@
namespace Ship {
class KeyboardController : public Controller {
public:
- KeyboardController(int32_t dwControllerNumber);
- ~KeyboardController();
-
- void ReadFromSource();
- void WriteToSource(ControllerCallback* controller);
- bool Connected() const { return true; }
- bool CanRumble() const { return false; }
+ KeyboardController();
+ void ReadFromSource(int32_t slot) override;
+ void WriteToSource(int32_t slot, ControllerCallback* controller) override;
+ bool Connected() const override { return true; }
+ bool CanRumble() const override { return false; }
+ bool CanGyro() const override { return false; }
+ const char* GetControllerName() override;
+ const char* GetButtonName(int slot, int n64Button) override;
bool PressButton(int32_t dwScancode);
bool ReleaseButton(int32_t dwScancode);
+
+ void ClearRawPress() override {
+ lastKey = -1;
+ }
+
+ int32_t ReadRawPress() override;
void ReleaseAllButtons();
- bool HasPadConf() const { return false; }
- std::optional<std::string> GetPadConfSection() { return {}; }
+ void SetLastScancode(int32_t key) {
+ lastScancode = key;
+ }
+
+ int32_t GetLastScancode() { return lastScancode; }
+ void CreateDefaultBinding(int32_t slot) override;
protected:
- std::string GetControllerType();
- std::string GetConfSection();
- std::string GetBindingConfSection();
+ int32_t lastScancode;
+ int32_t lastKey = -1;
};
}
diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp
index 06ff5f60a..620fb5271 100644
--- a/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp
+++ b/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp
@@ -28,6 +28,7 @@
#include "gfx_pc.h"
#include "../../ImGuiImpl.h"
#include "../../Cvar.h"
+#include "../../Hooks.h"
#define DECLARE_GFX_DXGI_FUNCTIONS
#include "gfx_dxgi.h"
@@ -240,6 +241,7 @@ static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_par
dxgi.current_height = (uint32_t)(l_param >> 16);
break;
case WM_DESTROY:
+ ModInternal::ExecuteHooks<ModInternal::ExitGame>();
exit(0);
case WM_PAINT:
if (dxgi.in_paint) {
@@ -718,6 +720,12 @@ void ThrowIfFailed(HRESULT res, HWND h_wnd, const char *message) {
}
}
+const char* gfx_dxgi_get_key_name(int scancode) {
+ TCHAR* Text = new TCHAR[64];
+ GetKeyNameText(scancode << 16, Text, 64);
+ return (char*) Text;
+}
+
extern "C" struct GfxWindowManagerAPI gfx_dxgi_api = {
gfx_dxgi_init,
gfx_dxgi_set_keyboard_callbacks,
@@ -734,6 +742,7 @@ extern "C" struct GfxWindowManagerAPI gfx_dxgi_api = {
gfx_dxgi_set_target_fps,
gfx_dxgi_set_maximum_frame_latency,
gfx_dxgi_get_detected_hz,
+ gfx_dxgi_get_key_name
};
#endif
diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp
index 44ad9ec37..cb0d7a7f0 100644
--- a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp
+++ b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp
@@ -23,6 +23,7 @@
#include "../../ImGuiImpl.h"
#include "../../Cvar.h"
+#include "../../Hooks.h"
#include "gfx_window_manager_api.h"
#include "gfx_screen_config.h"
@@ -108,7 +109,7 @@ static void set_fullscreen(bool on, bool call_callback) {
SDL_GetDesktopDisplayMode(0, &mode);
window_width = mode.w;
window_height = mode.h;
- //SDL_ShowCursor(false);
+ SDL_ShowCursor(false);
} else {
window_width = DESIRED_SCREEN_WIDTH;
window_height = DESIRED_SCREEN_HEIGHT;
@@ -229,6 +230,15 @@ static int translate_scancode(int scancode) {
}
}
+static int untranslate_scancode(int translatedScancode) {
+ for (int i = 0; i < 512; i++) {
+ if (inverted_scancode_table[i] == translatedScancode) {
+ return i;
+ }
+ }
+ return 0;
+}
+
static void gfx_sdl_onkeydown(int scancode) {
int key = translate_scancode(scancode);
if (on_key_down_callback != NULL) {
@@ -270,6 +280,7 @@ static void gfx_sdl_handle_events(void) {
Game::SaveSettings();
break;
case SDL_QUIT:
+ ModInternal::ExecuteHooks<ModInternal::ExitGame>();
SDL_Quit(); // bandaid fix for linux window closing issue
exit(0);
}
@@ -339,6 +350,10 @@ static float gfx_sdl_get_detected_hz(void) {
return 0;
}
+static const char* gfx_sdl_get_key_name(int scancode) {
+ return SDL_GetScancodeName((SDL_Scancode) untranslate_scancode(scancode));
+}
+
struct GfxWindowManagerAPI gfx_sdl = {
gfx_sdl_init,
gfx_sdl_set_keyboard_callbacks,
@@ -354,7 +369,8 @@ struct GfxWindowManagerAPI gfx_sdl = {
gfx_sdl_get_time,
gfx_sdl_set_target_fps,
gfx_sdl_set_maximum_frame_latency,
- gfx_sdl_get_detected_hz
+ gfx_sdl_get_detected_hz,
+ gfx_sdl_get_key_name
};
#endif
diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_window_manager_api.h b/libultraship/libultraship/Lib/Fast3D/gfx_window_manager_api.h
index 50618f661..99344940e 100644
--- a/libultraship/libultraship/Lib/Fast3D/gfx_window_manager_api.h
+++ b/libultraship/libultraship/Lib/Fast3D/gfx_window_manager_api.h
@@ -20,6 +20,7 @@ struct GfxWindowManagerAPI {
void (*set_target_fps)(int fps);
void (*set_maximum_frame_latency)(int latency);
float (*get_detected_hz)(void);
+ const char* (*get_key_name)(int scancode);
};
#endif
diff --git a/libultraship/libultraship/Lib/Mercury/Mercury.cpp b/libultraship/libultraship/Lib/Mercury/Mercury.cpp
new file mode 100644
index 000000000..d6bf734ea
--- /dev/null
+++ b/libultraship/libultraship/Lib/Mercury/Mercury.cpp
@@ -0,0 +1,134 @@
+#include "Mercury.h"
+
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <filesystem>
+#include <unordered_map>
+#include <any>
+
+namespace fs = std::filesystem;
+using json = nlohmann::json;
+
+std::unordered_map<std::string, std::any> ramMap;
+
+Mercury::Mercury(std::string path) : path_(std::move(path)) {
+ this->reload();
+}
+
+std::vector<std::string> split(const std::string& s, const char delimiter) {
+ std::vector<std::string> result;
+ std::stringstream ss(s);
+ std::string item;
+ while (getline(ss, item, delimiter)) {
+ result.push_back(item);
+ }
+ return result;
+}
+
+std::string Mercury::formatNestedKey(const std::string& key) {
+ const std::vector<std::string> dots = split(key, '.');
+ std::string tmp;
+ if (dots.size() > 1)
+ for (const auto& dot : dots) {
+ tmp += "/" + dot;
+ }
+ else
+ tmp = "/" + dots[0];
+
+ return tmp;
+}
+
+json Mercury::nested(const std::string& key) {
+ std::vector<std::string> dots = split(key, '.');
+ if (!this->vjson.is_object())
+ return this->vjson;
+ json gjson = this->vjson.unflatten();
+
+ if (dots.size() > 1) {
+ for (auto& key : dots) {
+ if (key == "*" || gjson.contains(key))
+ gjson = gjson[key];
+ }
+ return gjson;
+ }
+
+ return gjson[key];
+}
+
+std::string Mercury::getString(const std::string& key, const std::string& def) {
+ json n = this->nested(key);
+ if (n.is_string() && !n.get<std::string>().empty())
+ return n;
+ return def;
+}
+
+float Mercury::getFloat(const std::string& key, float def) {
+ json n = this->nested(key);
+ if (n.is_number_float())
+ return n;
+ return def;
+}
+
+bool Mercury::getBool(const std::string& key, bool def) {
+ json n = this->nested(key);
+ if (n.is_boolean())
+ return n;
+ return def;
+}
+
+int Mercury::getInt(const std::string& key, int def) {
+ json n = this->nested(key);
+ if (n.is_number_integer())
+ return n;
+ return def;
+}
+
+bool Mercury::contains(const std::string& key) {
+ return !this->nested(key).is_null();
+}
+
+void Mercury::setString(const std::string& key, const std::string& value) {
+ this->vjson[formatNestedKey(key)] = value;
+}
+
+void Mercury::setFloat(const std::string& key, float value) {
+ this->vjson[formatNestedKey(key)] = value;
+}
+
+void Mercury::setBool(const std::string& key, bool value) {
+ this->vjson[formatNestedKey(key)] = value;
+}
+
+void Mercury::setInt(const std::string& key, int value) {
+ this->vjson[formatNestedKey(key)] = value;
+}
+
+void Mercury::setUInt(const std::string& key, uint32_t value) {
+ this->vjson[formatNestedKey(key)] = value;
+}
+
+void Mercury::erase(const std::string& key) {
+ this->vjson.erase(formatNestedKey(key));
+}
+
+void Mercury::reload() {
+ if (this->path_ == "None" || !fs::exists(this->path_) || !fs::is_regular_file(this->path_)) {
+ this->isNewInstance = true;
+ this->vjson = json::object();
+ return;
+ }
+ std::ifstream ifs(this->path_);
+ try {
+ this->rjson = json::parse(ifs);
+ this->vjson = this->rjson.flatten();
+ }
+ catch (...) {
+ this->vjson = json::object();
+ }
+}
+
+void Mercury::save() const {
+ std::ofstream file(this->path_);
+ file << this->vjson.unflatten().dump(4);
+}
diff --git a/libultraship/libultraship/Lib/Mercury/Mercury.h b/libultraship/libultraship/Lib/Mercury/Mercury.h
new file mode 100644
index 000000000..5c2646d36
--- /dev/null
+++ b/libultraship/libultraship/Lib/Mercury/Mercury.h
@@ -0,0 +1,47 @@
+#pragma once
+#include <any>
+#include <vector>
+#include <string>
+#include "../nlohmann/json.hpp"
+
+class Mercury {
+protected:
+ std::string path_;
+public:
+ explicit Mercury(std::string path);
+
+ nlohmann::json vjson;
+ nlohmann::json rjson;
+ nlohmann::json nested(const std::string& key);
+ static std::string formatNestedKey(const std::string& key);
+ std::string getString(const std::string& key, const std::string& def = "");
+ float getFloat(const std::string& key, float defValue = 0.0f);
+ bool getBool(const std::string& key, bool defValue = false);
+ int getInt(const std::string& key, int defValue = 0);
+ bool contains(const std::string& key);
+ template< typename T > std::vector<T> getArray(const std::string& key);
+ void setString(const std::string& key, const std::string& value);
+ void setFloat(const std::string& key, float value);
+ void setBool(const std::string& key, bool value);
+ void setInt(const std::string& key, int value);
+ void setUInt(const std::string& key, uint32_t value);
+ void erase(const std::string& key);
+ void set(const std::string& key, std::any value);
+ template< typename T > void setArray(const std::string& key, std::vector<T> array);
+
+ void reload();
+ void save() const;
+ bool isNewInstance = false;
+};
+
+template< typename T >
+std::vector<T> Mercury::getArray(const std::string& key) {
+ if (nlohmann::json tmp = this->nested(key); tmp.is_array())
+ return tmp.get<std::vector<T>>();
+ return std::vector<T>();
+};
+
+template <typename T>
+void Mercury::setArray(const std::string& key, std::vector<T> array) {
+ this->vjson[formatNestedKey(key)] = nlohmann::json(array);
+}
diff --git a/soh/soh/Lib/nlohmann/LICENSE.MIT b/libultraship/libultraship/Lib/nlohmann/LICENSE.MIT
index 1c1f7a690..1c1f7a690 100644
--- a/soh/soh/Lib/nlohmann/LICENSE.MIT
+++ b/libultraship/libultraship/Lib/nlohmann/LICENSE.MIT
diff --git a/soh/soh/Lib/nlohmann/json.hpp b/libultraship/libultraship/Lib/nlohmann/json.hpp
index cb27e0581..cb27e0581 100644
--- a/soh/soh/Lib/nlohmann/json.hpp
+++ b/libultraship/libultraship/Lib/nlohmann/json.hpp
diff --git a/libultraship/libultraship/SDLController.cpp b/libultraship/libultraship/SDLController.cpp
index d0550e730..fc813dd66 100644
--- a/libultraship/libultraship/SDLController.cpp
+++ b/libultraship/libultraship/SDLController.cpp
@@ -1,103 +1,36 @@
#include "SDLController.h"
-
-#include "GameSettings.h"
#include "GlobalCtx2.h"
#include "spdlog/spdlog.h"
-#include "stox.h"
#include "Window.h"
-#include "Cvar.h"
#include <Utils/StringHelper.h>
extern "C" uint8_t __osMaxControllers;
namespace Ship {
- SDLController::SDLController(int32_t dwControllerNumber) : Controller(dwControllerNumber), Cont(nullptr), guid(INVALID_SDL_CONTROLLER_GUID) {
-
- }
-
- SDLController::~SDLController() {
- Close();
- }
-
- bool SDLController::IsGuidInUse(const std::string& guid) {
- // Check if the GUID is loaded in any other controller;
- for (size_t i = 0; i < __osMaxControllers; i++) {
- for (size_t j = 0; j < Window::Controllers[i].size(); j++) {
- SDLController* OtherCont = dynamic_cast<SDLController*>(Window::Controllers[i][j].get());
-
- if (OtherCont != nullptr && OtherCont->GetGuid().compare(guid) == 0) {
- return true;
- }
- }
- }
-
- return false;
- }
bool SDLController::Open() {
- std::string ConfSection = GetConfSection();
- std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
- ConfigFile& Conf = *pConf.get();
-
- for (int i = 0; i < SDL_NumJoysticks(); i++) {
- if (SDL_IsGameController(i)) {
- // Get the GUID from SDL
- char GuidBuf[33];
- SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i), GuidBuf, sizeof(GuidBuf));
- auto NewGuid = std::string(GuidBuf);
-
- // Invalid GUID read. Go to next.
- if (NewGuid.compare(INVALID_SDL_CONTROLLER_GUID) == 0) {
- SPDLOG_ERROR("SDL Controller returned invalid guid");
- continue;
- }
-
- // The GUID is in use, we want to use a different physical controller. Go to next.
- if (IsGuidInUse(NewGuid)) {
- continue;
- }
-
- // If the GUID is blank from the config, OR if the config GUID matches, load the controller.
- if (Conf[ConfSection]["GUID"].compare("") == 0 || Conf[ConfSection]["GUID"].compare(INVALID_SDL_CONTROLLER_GUID) == 0 || Conf[ConfSection]["GUID"].compare(NewGuid) == 0) {
- auto NewCont = SDL_GameControllerOpen(i);
- // We failed to load the controller. Go to next.
- if (NewCont == nullptr) {
- SPDLOG_ERROR("SDL Controller failed to open: ({})", SDL_GetError());
- continue;
- }
-
- if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO))
- {
- SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE);
- }
-
- guid = NewGuid;
- Cont = NewCont;
-
- std::string BindingConfSection = GetBindingConfSection();
- std::string PadConfSection = *GetPadConfSection();
- std::shared_ptr<ConfigFile> config = GlobalCtx2::GetInstance()->GetConfig();
-
- if (!config->has(BindingConfSection)) {
- CreateDefaultBinding();
- }
-
- if (!config->has(PadConfSection)) {
- CreateDefaultPadConf();
- }
+ const auto NewCont = SDL_GameControllerOpen(physicalSlot);
- LoadBinding();
- LoadAxisThresholds();
- // Update per-controller settings in ImGui menu after opening controller.
- Game::LoadPadSettings();
+ // We failed to load the controller. Go to next.
+ if (NewCont == nullptr) {
+ SPDLOG_ERROR("SDL Controller failed to open: ({})", SDL_GetError());
+ return false;
+ }
- break;
- }
- }
+ if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO)) {
+ SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE);
+ supportsGyro = true;
}
- return Cont != nullptr;
+ char GuidBuf[33];
+ SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(physicalSlot), GuidBuf, sizeof(GuidBuf));
+ GUID = std::string(GuidBuf);
+ Cont = NewCont;
+ wCamX = 0;
+ wCamY = 0;
+
+ return true;
}
bool SDLController::Close() {
@@ -108,31 +41,14 @@ namespace Ship {
SDL_GameControllerClose(Cont);
}
Cont = nullptr;
- guid = "";
- ButtonMapping.clear();
- ThresholdMapping.clear();
- dwPressedButtons = 0;
wStickX = 0;
wStickY = 0;
return true;
}
- void SDLController::LoadAxisThresholds() {
- std::string ConfSection = GetBindingConfSection();
- std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
- ConfigFile& Conf = *pConf.get();
-
- ThresholdMapping[SDL_CONTROLLER_AXIS_LEFTX] = Ship::stoi(Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTX) + "_threshold"]);
- ThresholdMapping[SDL_CONTROLLER_AXIS_LEFTY] = Ship::stoi(Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTY) + "_threshold"]);
- ThresholdMapping[SDL_CONTROLLER_AXIS_RIGHTX] = Ship::stoi(Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTX) + "_threshold"]);
- ThresholdMapping[SDL_CONTROLLER_AXIS_RIGHTY] = Ship::stoi(Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTY) + "_threshold"]);
- ThresholdMapping[SDL_CONTROLLER_AXIS_TRIGGERLEFT] = Ship::stoi(Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERLEFT) + "_threshold"]);
- ThresholdMapping[SDL_CONTROLLER_AXIS_TRIGGERRIGHT] = Ship::stoi(Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + "_threshold"]);
- }
-
- void SDLController::NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold, bool isRightStick) {
+ void SDLController::NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold, bool isRightStick, float sensitivity) {
//scale {-32768 ... +32767} to {-84 ... +84}
auto ax = wAxisValueX * 85.0 / 32767.0;
auto ay = wAxisValueY * 85.0 / 32767.0;
@@ -166,18 +82,56 @@ namespace Ship {
if (!isRightStick) {
wStickX = +ax;
wStickY = -ay;
+ } else {
+ wCamX = +ax * sensitivity;
+ wCamY = -ay * sensitivity;
}
- else {
- //SOHTODO KIRITO: Camera Sensitivity
- wCamX = +ax * 15.0f;
- wCamY = -ay * 15.0f;
+ }
+
+
+ int32_t SDLController::ReadRawPress() {
+ SDL_GameControllerUpdate();
+
+ for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
+ if (SDL_GameControllerGetButton(Cont, static_cast<SDL_GameControllerButton>(i))) {
+ return i;
+ }
+ }
+
+ for (int32_t i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) {
+ const auto Axis = static_cast<SDL_GameControllerAxis>(i);
+ const auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis) / 32767;
+
+ if(AxisValue < 0) {
+ return -(Axis + AXIS_SCANCODE_BIT);
+ }
+
+ if (AxisValue > 0) {
+ return (Axis + AXIS_SCANCODE_BIT);
+ }
+ }
+
+ return -1;
+ }
+
+ ControllerThresholds SDLAxisToThreshold( uint32_t axis ){
+ switch(axis){
+ case SDL_CONTROLLER_AXIS_LEFTX:
+ case SDL_CONTROLLER_AXIS_LEFTY:
+ return LEFT_STICK;
+ case SDL_CONTROLLER_AXIS_RIGHTX:
+ case SDL_CONTROLLER_AXIS_RIGHTY:
+ return RIGHT_STICK;
+ case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
+ return LEFT_TRIGGER;
+ case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
+ return RIGHT_TRIGGER;
+ default: return DRIFT_X;
}
}
- void SDLController::ReadFromSource() {
- std::string ConfSection = GetBindingConfSection();
- std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
- ConfigFile& Conf = *pConf.get();
+ void SDLController::ReadFromSource(int32_t slot) {
+ DeviceProfile& profile = profiles[slot];
SDL_GameControllerUpdate();
@@ -194,21 +148,14 @@ namespace Ship {
}
}
- auto cameraX = SDL_GameControllerGetAxis(Cont, SDL_CONTROLLER_AXIS_RIGHTX);
- auto cameraY = SDL_GameControllerGetAxis(Cont, SDL_CONTROLLER_AXIS_RIGHTY);
- NormalizeStickAxis(cameraX, cameraY, ThresholdMapping[SDL_CONTROLLER_AXIS_LEFTX], true);
-
- if (SDL_GameControllerHasSensor(Cont, SDL_SENSOR_GYRO))
- {
- size_t contNumber = GetControllerNumber();
+ if (supportsGyro && profile.UseGyro) {
float gyroData[3];
SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3);
- const char* contName = SDL_GameControllerName(Cont);
- float gyro_drift_x = CVar_GetFloat(StringHelper::Sprintf("gCont%i_GyroDriftX", contNumber).c_str(), 0.0f);
- float gyro_drift_y = CVar_GetFloat(StringHelper::Sprintf("gCont%i_GyroDriftY", contNumber).c_str(), 0.0f);
- const float gyro_sensitivity = CVar_GetFloat(StringHelper::Sprintf("gCont%i_GyroSensitivity", contNumber).c_str(), 1.0f);
+ float gyro_drift_x = profile.GyroThresholds[DRIFT_X] / 100.0f;
+ float gyro_drift_y = profile.GyroThresholds[DRIFT_Y] / 100.0f;
+ const float gyro_sensitivity = profile.GyroThresholds[SENSITIVITY] / 100.0f;
if (gyro_drift_x == 0) {
gyro_drift_x = gyroData[0];
@@ -218,8 +165,8 @@ namespace Ship {
gyro_drift_y = gyroData[1];
}
- CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftX", contNumber).c_str(), gyro_drift_x);
- CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftY", contNumber).c_str(), gyro_drift_y);
+ profile.GyroThresholds[DRIFT_X] = (int) gyro_drift_x * 100;
+ profile.GyroThresholds[DRIFT_Y] = (int) gyro_drift_y * 100;
wGyroX = gyroData[0] - gyro_drift_x;
wGyroY = gyroData[1] - gyro_drift_y;
@@ -229,28 +176,32 @@ namespace Ship {
}
for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
- if (ButtonMapping.contains(i)) {
- if (SDL_GameControllerGetButton(Cont, (SDL_GameControllerButton)i)) {
- dwPressedButtons |= ButtonMapping[i];
+ if (profile.Mappings.contains(i)) {
+ if (SDL_GameControllerGetButton(Cont, static_cast<SDL_GameControllerButton>(i))) {
+ dwPressedButtons[slot] |= profile.Mappings[i];
}
else {
- dwPressedButtons &= ~ButtonMapping[i];
+ dwPressedButtons[slot] &= ~profile.Mappings[i];
}
}
}
- SDL_GameControllerAxis StickAxisX = SDL_CONTROLLER_AXIS_INVALID;
- SDL_GameControllerAxis StickAxisY = SDL_CONTROLLER_AXIS_INVALID;
- int32_t StickDeadzone = 0;
+ SDL_GameControllerAxis LStickAxisX = SDL_CONTROLLER_AXIS_INVALID;
+ SDL_GameControllerAxis LStickAxisY = SDL_CONTROLLER_AXIS_INVALID;
+ int32_t LStickDeadzone = 0;
+
+ SDL_GameControllerAxis RStickAxisX = SDL_CONTROLLER_AXIS_INVALID;
+ SDL_GameControllerAxis RStickAxisY = SDL_CONTROLLER_AXIS_INVALID;
+ int32_t RStickDeadzone = 0;
for (int32_t i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) {
- auto Axis = (SDL_GameControllerAxis)i;
- auto PosScancode = i + AXIS_SCANCODE_BIT;
- auto NegScancode = -PosScancode;
- auto AxisThreshold = ThresholdMapping[i];
- auto PosButton = ButtonMapping[PosScancode];
- auto NegButton = ButtonMapping[NegScancode];
- auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis);
+ const auto Axis = static_cast<SDL_GameControllerAxis>(i);
+ const auto PosScancode = i + AXIS_SCANCODE_BIT;
+ const auto NegScancode = -PosScancode;
+ const auto AxisThreshold = profile.Thresholds[SDLAxisToThreshold(i)];
+ const auto PosButton = profile.Mappings[PosScancode];
+ const auto NegButton = profile.Mappings[NegScancode];
+ const auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis);
#ifdef TARGET_WEB
// Firefox has a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1606562
@@ -263,94 +214,176 @@ namespace Ship {
}
#endif
- // If the axis is NOT mapped to the control stick.
if (!(
PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT ||
PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN ||
NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT ||
NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN)) {
- if (AxisValue > AxisThreshold) {
- dwPressedButtons |= PosButton;
- dwPressedButtons &= ~NegButton;
+
+ if (AxisValue > 0x1E00) {
+ dwPressedButtons[slot] |= PosButton;
+ dwPressedButtons[slot] &= ~NegButton;
}
- else if (AxisValue < -AxisThreshold) {
- dwPressedButtons &= ~PosButton;
- dwPressedButtons |= NegButton;
+ else if (AxisValue < -0x1E00) {
+ dwPressedButtons[slot] &= ~PosButton;
+ dwPressedButtons[slot] |= NegButton;
}
else {
- dwPressedButtons &= ~PosButton;
- dwPressedButtons &= ~NegButton;
+ dwPressedButtons[slot] &= ~PosButton;
+ dwPressedButtons[slot] &= ~NegButton;
}
}
else {
if (PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT) {
- if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisX != Axis) {
- SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", StickAxisX, Axis);
+ if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisX != Axis) {
+ SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", LStickAxisX, Axis);
}
- if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
- SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", StickDeadzone, AxisThreshold);
+ if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
+ SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", LStickDeadzone, AxisThreshold);
}
- StickDeadzone = AxisThreshold;
- StickAxisX = Axis;
+ LStickDeadzone = AxisThreshold;
+ LStickAxisX = Axis;
}
if (PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN) {
- if (StickAxisY != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != Axis) {
- SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", StickAxisY, Axis);
+ if (LStickAxisY != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != Axis) {
+ SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", LStickAxisY, Axis);
}
- if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
- SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
+ if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
+ SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold);
}
- StickDeadzone = AxisThreshold;
- StickAxisY = Axis;
+ LStickDeadzone = AxisThreshold;
+ LStickAxisY = Axis;
}
if (NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT) {
- if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisX != Axis) {
- SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", StickAxisX, Axis);
+ if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisX != Axis) {
+ SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", LStickAxisX, Axis);
}
- if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
- SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
+ if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
+ SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold);
}
- StickDeadzone = AxisThreshold;
- StickAxisX = Axis;
+ LStickDeadzone = AxisThreshold;
+ LStickAxisX = Axis;
}
if (NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN) {
- if (StickAxisY != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != Axis) {
- SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", StickAxisY, Axis);
+ if (LStickAxisY != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != Axis) {
+ SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", LStickAxisY, Axis);
}
- if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
- SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
+ if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
+ SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold);
}
- StickDeadzone = AxisThreshold;
- StickAxisY = Axis;
+ LStickDeadzone = AxisThreshold;
+ LStickAxisY = Axis;
}
}
- if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
- auto AxisValueX = SDL_GameControllerGetAxis(Cont, StickAxisX);
- auto AxisValueY = SDL_GameControllerGetAxis(Cont, StickAxisY);
- NormalizeStickAxis(AxisValueX, AxisValueY, StickDeadzone, false);
+ if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
+ const auto AxisValueX = SDL_GameControllerGetAxis(Cont, LStickAxisX);
+ const auto AxisValueY = SDL_GameControllerGetAxis(Cont, LStickAxisY);
+ NormalizeStickAxis(AxisValueX, AxisValueY, LStickDeadzone, false, profile.Thresholds[SENSITIVITY]);
+ }
+
+ // Right Stick
+ // If the axis is NOT mapped to the control stick.
+ if (!(
+ PosButton == BTN_VSTICKLEFT || PosButton == BTN_VSTICKRIGHT ||
+ PosButton == BTN_VSTICKUP || PosButton == BTN_VSTICKDOWN ||
+ NegButton == BTN_VSTICKLEFT || NegButton == BTN_VSTICKRIGHT ||
+ NegButton == BTN_VSTICKUP || NegButton == BTN_VSTICKDOWN)) {
+
+ if (AxisValue > 0x1E00) {
+ dwPressedButtons[slot] |= PosButton;
+ dwPressedButtons[slot] &= ~NegButton;
+ }
+ else if (AxisValue < -0x1E00) {
+ dwPressedButtons[slot] &= ~PosButton;
+ dwPressedButtons[slot] |= NegButton;
+ }
+ else {
+ dwPressedButtons[slot] &= ~PosButton;
+ dwPressedButtons[slot] &= ~NegButton;
+ }
+
+ } else {
+ if (PosButton == BTN_VSTICKLEFT || PosButton == BTN_VSTICKRIGHT) {
+ if (RStickAxisX != SDL_CONTROLLER_AXIS_INVALID && RStickAxisX != Axis) {
+ SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", RStickAxisX, Axis);
+ }
+
+ if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) {
+ SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", RStickDeadzone, AxisThreshold);
+ }
+
+ RStickDeadzone = AxisThreshold;
+ RStickAxisX = Axis;
+ }
+
+ if (PosButton == BTN_VSTICKUP || PosButton == BTN_VSTICKDOWN) {
+ if (RStickAxisY != SDL_CONTROLLER_AXIS_INVALID && RStickAxisY != Axis) {
+ SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", RStickAxisY, Axis);
+ }
+
+ if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) {
+ SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisThreshold);
+ }
+
+ RStickDeadzone = AxisThreshold;
+ RStickAxisY = Axis;
+ }
+
+ if (NegButton == BTN_VSTICKLEFT || NegButton == BTN_VSTICKRIGHT) {
+ if (RStickAxisX != SDL_CONTROLLER_AXIS_INVALID && RStickAxisX != Axis) {
+ SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", RStickAxisX, Axis);
+ }
+
+ if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) {
+ SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisThreshold);
+ }
+
+ RStickDeadzone = AxisThreshold;
+ RStickAxisX = Axis;
+ }
+
+ if (NegButton == BTN_VSTICKUP || NegButton == BTN_VSTICKDOWN) {
+ if (RStickAxisY != SDL_CONTROLLER_AXIS_INVALID && RStickAxisY != Axis) {
+ SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", RStickAxisY, Axis);
+ }
+
+ if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) {
+ SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisThreshold);
+ }
+
+ RStickDeadzone = AxisThreshold;
+ RStickAxisY = Axis;
+ }
+ }
+
+ if (RStickAxisX != SDL_CONTROLLER_AXIS_INVALID && RStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
+ const auto AxisValueX = SDL_GameControllerGetAxis(Cont, RStickAxisX);
+ const auto AxisValueY = SDL_GameControllerGetAxis(Cont, RStickAxisY);
+ NormalizeStickAxis(AxisValueX, AxisValueY, RStickDeadzone, true, profile.Thresholds[SENSITIVITY]);
}
}
}
- void SDLController::WriteToSource(ControllerCallback* controller)
+ void SDLController::WriteToSource(int32_t slot, ControllerCallback* controller)
{
- if (CanRumble()) {
+ if (CanRumble() && profiles[slot].UseRumble) {
if (controller->rumble > 0) {
- float rumble_strength = CVar_GetFloat(StringHelper::Sprintf("gCont%i_RumbleStrength", GetControllerNumber()).c_str(), 1.0f);
+ float rumble_strength = profiles[slot].RumbleStrength;
SDL_GameControllerRumble(Cont, 0xFFFF * rumble_strength, 0xFFFF * rumble_strength, 0);
- } else {
+ }
+ else {
SDL_GameControllerRumble(Cont, 0, 0, 0);
}
}
@@ -373,74 +406,71 @@ namespace Ship {
}
}
- void SDLController::CreateDefaultBinding() {
- std::string ConfSection = GetBindingConfSection();
- std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
-
- ConfigFile& Conf = *pConf.get();
-
- Conf[ConfSection][STR(BTN_CRIGHT)] = std::to_string(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
- Conf[ConfSection][STR(BTN_CLEFT)] = std::to_string(SDL_CONTROLLER_BUTTON_Y);
- Conf[ConfSection][STR(BTN_CDOWN)] = std::to_string(SDL_CONTROLLER_BUTTON_X);
- Conf[ConfSection][STR(BTN_CUP)] = std::to_string(SDL_CONTROLLER_BUTTON_RIGHTSTICK);
- //Conf[ConfSection][STR(BTN_CRIGHT + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_X);
- //Conf[ConfSection][STR(BTN_CLEFT + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_Y);
- //Conf[ConfSection][STR(BTN_CDOWN + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
- //Conf[ConfSection][STR(BTN_CUP + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_RIGHTSTICK);
- Conf[ConfSection][STR(BTN_R)] = std::to_string((SDL_CONTROLLER_AXIS_TRIGGERRIGHT + AXIS_SCANCODE_BIT));
- Conf[ConfSection][STR(BTN_L)] = std::to_string(SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
- Conf[ConfSection][STR(BTN_DRIGHT)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
- Conf[ConfSection][STR(BTN_DLEFT)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_LEFT);
- Conf[ConfSection][STR(BTN_DDOWN)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_DOWN);
- Conf[ConfSection][STR(BTN_DUP)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_UP);
- Conf[ConfSection][STR(BTN_START)] = std::to_string(SDL_CONTROLLER_BUTTON_START);
- Conf[ConfSection][STR(BTN_Z)] = std::to_string((SDL_CONTROLLER_AXIS_TRIGGERLEFT + AXIS_SCANCODE_BIT));
- Conf[ConfSection][STR(BTN_B)] = std::to_string(SDL_CONTROLLER_BUTTON_B);
- Conf[ConfSection][STR(BTN_A)] = std::to_string(SDL_CONTROLLER_BUTTON_A);
- Conf[ConfSection][STR(BTN_STICKRIGHT)] = std::to_string((SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT));
- Conf[ConfSection][STR(BTN_STICKLEFT)] = std::to_string(-(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT));
- Conf[ConfSection][STR(BTN_STICKDOWN)] = std::to_string((SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT));
- Conf[ConfSection][STR(BTN_STICKUP)] = std::to_string(-(SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT));
-
- Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTX) + "_threshold"] = std::to_string(16.0);
- Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTY) + "_threshold"] = std::to_string(16.0);
- Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTX) + "_threshold"] = std::to_string(0x4000);
- Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTY) + "_threshold"] = std::to_string(0x4000);
- Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERLEFT) + "_threshold"] = std::to_string(0x1E00);
- Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + "_threshold"] = std::to_string(0x1E00);
-
- Conf.Save();
- }
+ const char* AxisNames[] = {
+ "Left Stick X",
+ "Left Stick Y",
+ "Right Stick X",
+ "Right Stick Y",
+ "Left Trigger",
+ "Right Trigger",
+ "Start Button"
+ };
- void SDLController::CreateDefaultPadConf() {
- std::string ConfSection = *GetPadConfSection();
- std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
- ConfigFile& Conf = *pConf.get();
+ char buffer[50];
+ const char* SDLController::GetButtonName(int slot, int n64Button) {
+ std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings;
+ const auto find = std::find_if(Mappings.begin(), Mappings.end(), [n64Button](const std::pair<int32_t, int32_t>& pair) {
+ return pair.second == n64Button;
+ });
- Conf.Save();
- }
+ if (find == Mappings.end()) return "Unknown";
- void SDLController::SetButtonMapping(const std::string& szButtonName, int32_t dwScancode) {
- if (guid.compare(INVALID_SDL_CONTROLLER_GUID)) {
- return;
- }
+ int btn = abs(find->first);
- Controller::SetButtonMapping(szButtonName, dwScancode);
- }
+ if(btn >= AXIS_SCANCODE_BIT) {
+ btn -= AXIS_SCANCODE_BIT;
- std::string SDLController::GetControllerType() {
- return "SDL";
- }
+ snprintf(buffer, sizeof(buffer), "%s%s", AxisNames[btn], find->first > 0 ? "+" : "-");
+ return buffer;
+ }
- std::string SDLController::GetConfSection() {
- return GetControllerType() + " CONTROLLER " + std::to_string(GetControllerNumber() + 1);
+ snprintf(buffer, sizeof(buffer), "Button %d", btn);
+ return buffer;
}
- std::string SDLController::GetBindingConfSection() {
- return GetControllerType() + " CONTROLLER BINDING " + guid;
+ const char* SDLController::GetControllerName() {
+ return SDL_GameControllerNameForIndex(physicalSlot);
}
- std::optional<std::string> SDLController::GetPadConfSection() {
- return GetControllerType() + " CONTROLLER PAD " + guid;
+ void SDLController::CreateDefaultBinding(int32_t slot) {
+ DeviceProfile& profile = profiles[slot];
+ profile.Mappings.clear();
+
+ profile.UseRumble = true;
+ profile.RumbleStrength = 1.0f;
+ profile.UseGyro = false;
+ profile.Mappings[ SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT] = BTN_CRIGHT;
+ profile.Mappings[-(SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT)] = BTN_CLEFT;
+ profile.Mappings[ SDL_CONTROLLER_AXIS_RIGHTY | AXIS_SCANCODE_BIT] = BTN_CDOWN;
+ profile.Mappings[-(SDL_CONTROLLER_AXIS_RIGHTY | AXIS_SCANCODE_BIT)] = BTN_CUP;
+ profile.Mappings[SDL_CONTROLLER_AXIS_TRIGGERRIGHT + AXIS_SCANCODE_BIT] = BTN_R;
+ profile.Mappings[SDL_CONTROLLER_BUTTON_LEFTSHOULDER] = BTN_L;
+ profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_RIGHT] = BTN_DRIGHT;
+ profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_LEFT] = BTN_DLEFT;
+ profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_DOWN] = BTN_DDOWN;
+ profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_UP] = BTN_DUP;
+ profile.Mappings[SDL_CONTROLLER_BUTTON_START] = BTN_START;
+ profile.Mappings[SDL_CONTROLLER_AXIS_TRIGGERLEFT + AXIS_SCANCODE_BIT] = BTN_Z;
+ profile.Mappings[SDL_CONTROLLER_BUTTON_B] = BTN_B;
+ profile.Mappings[SDL_CONTROLLER_BUTTON_A] = BTN_A;
+ profile.Mappings[(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT)] = BTN_STICKRIGHT;
+ profile.Mappings[-(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT)] = BTN_STICKLEFT;
+ profile.Mappings[SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT] = BTN_STICKDOWN;
+ profile.Mappings[-(SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT)] = BTN_STICKUP;
+ profile.Thresholds[LEFT_STICK] = 16.0;
+ profile.Thresholds[RIGHT_STICK] = 16.0;
+ profile.Thresholds[LEFT_TRIGGER] = 0x1E00;
+ profile.Thresholds[RIGHT_TRIGGER] = 0x1E00;
+ profile.Thresholds[SENSITIVITY] = 16.0;
}
}
diff --git a/libultraship/libultraship/SDLController.h b/libultraship/libultraship/SDLController.h
index d1d671bb9..ae239a2f1 100644
--- a/libultraship/libultraship/SDLController.h
+++ b/libultraship/libultraship/SDLController.h
@@ -6,46 +6,35 @@
#include <SDL2/SDL.h>
#endif
-#define INVALID_SDL_CONTROLLER_GUID (std::string("00000000000000000000000000000000"))
-
namespace Ship {
class SDLController : public Controller {
public:
- SDLController(int32_t dwControllerNumber);
- ~SDLController();
-
- void ReadFromSource();
- void WriteToSource(ControllerCallback* controller);
- bool Connected() const { return Cont != nullptr; }
- bool CanRumble() const {
+ SDLController(int slot) : Controller(), Cont(nullptr), physicalSlot(slot) { }
+ void ReadFromSource(int32_t slot) override;
+ const char* GetControllerName() override;
+ const char* GetButtonName(int slot, int n64Button) override;
+ void WriteToSource(int32_t slot, ControllerCallback* controller) override;
+ bool Connected() const override { return Cont != nullptr; }
+ bool CanGyro() const override { return supportsGyro; }
+ bool CanRumble() const override {
#if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18)
return SDL_GameControllerHasRumble(Cont);
#endif
return true;
}
- std::string GetGuid() { return guid; };
-
- bool HasPadConf() const { return true; }
- std::optional<std::string> GetPadConfSection();
+ bool Open();
+ void ClearRawPress() override {}
+ int32_t ReadRawPress() override;
protected:
- std::string GetControllerType();
- void SetButtonMapping(const std::string& szButtonName, int32_t dwScancode);
- std::string GetConfSection();
- std::string GetBindingConfSection();
- void CreateDefaultBinding();
- void CreateDefaultPadConf();
- static bool IsGuidInUse(const std::string& guid);
+ void CreateDefaultBinding(int32_t slot) override;
private:
SDL_GameController* Cont;
- std::string guid;
- std::map<int32_t, int16_t> ThresholdMapping;
-
- void LoadAxisThresholds();
- void NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold, bool isRightStick);
- bool Open();
+ int physicalSlot;
+ bool supportsGyro;
+ void NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold, bool isRightStick, float sensitivity);
bool Close();
};
}
diff --git a/libultraship/libultraship/UltraController.h b/libultraship/libultraship/UltraController.h
index e08212b97..41ea7f082 100644
--- a/libultraship/libultraship/UltraController.h
+++ b/libultraship/libultraship/UltraController.h
@@ -101,6 +101,10 @@
#define BTN_STICKRIGHT 0x20000
#define BTN_STICKDOWN 0x40000
#define BTN_STICKUP 0x80000
+#define BTN_VSTICKUP 0x100000
+#define BTN_VSTICKDOWN 0x200000
+#define BTN_VSTICKLEFT 0x400000
+#define BTN_VSTICKRIGHT 0x800000
typedef struct {
/* 0x00 */ int32_t ram[15];
diff --git a/libultraship/libultraship/Window.cpp b/libultraship/libultraship/Window.cpp
index 91878b890..b8f8957c4 100644
--- a/libultraship/libultraship/Window.cpp
+++ b/libultraship/libultraship/Window.cpp
@@ -38,8 +38,7 @@ extern "C" {
uint8_t __enableGameInput = 1;
int32_t osContInit(OSMesgQueue* mq, uint8_t* controllerBits, OSContStatus* status) {
- std::shared_ptr<Ship::ConfigFile> pConf = Ship::GlobalCtx2::GetInstance()->GetConfig();
- Ship::ConfigFile& Conf = *pConf.get();
+ *controllerBits = 0;
if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0) {
SPDLOG_ERROR("Failed to initialize SDL game controllers ({})", SDL_GetError());
@@ -54,43 +53,7 @@ extern "C" {
SPDLOG_ERROR("Failed add SDL game controller mappings from \"{}\" ({})", controllerDb, SDL_GetError());
}
- // TODO: This for loop is debug. Burn it with fire.
- for (int i = 0; i < SDL_NumJoysticks(); i++) {
- if (SDL_IsGameController(i)) {
- // Get the GUID from SDL
- char buf[33];
- SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i), buf, sizeof(buf));
- auto guid = std::string(buf);
- auto name = std::string(SDL_GameControllerNameForIndex(i));
-
- SPDLOG_INFO("Found Controller \"{}\" with ID \"{}\"", name, guid);
- }
- }
-
- for (int32_t i = 0; i < __osMaxControllers; i++) {
- std::string ControllerType = Conf["CONTROLLERS"]["CONTROLLER " + std::to_string(i+1)];
- mINI::INIStringUtil::toLower(ControllerType);
-
- if (ControllerType == "auto") {
- Ship::Window::Controllers[i].push_back(std::make_shared<Ship::KeyboardController>(i));
- Ship::Window::Controllers[i].push_back(std::make_shared<Ship::SDLController>(i));
- } else if (ControllerType == "keyboard") {
- Ship::Window::Controllers[i].push_back(std::make_shared<Ship::KeyboardController>(i));
- } else if (ControllerType == "usb") {
- Ship::Window::Controllers[i].push_back(std::make_shared<Ship::SDLController>(i));
- } else if (ControllerType == "unplugged") {
- // Do nothing for unplugged controllers
- } else {
- SPDLOG_ERROR("Invalid Controller Type: {}", ControllerType);
- }
- }
-
- *controllerBits = 0;
- for (size_t i = 0; i < __osMaxControllers; i++) {
- if (Ship::Window::Controllers[i].size() > 0) {
- *controllerBits |= 1 << i;
- }
- }
+ Ship::Window::ControllerApi->Init(controllerBits);
return 0;
}
@@ -103,17 +66,14 @@ extern "C" {
pad->button = 0;
pad->stick_x = 0;
pad->stick_y = 0;
+ pad->cam_x = 0;
+ pad->cam_y = 0;
pad->err_no = 0;
pad->gyro_x = 0;
pad->gyro_y = 0;
- if (__enableGameInput)
- {
- for (size_t i = 0; i < __osMaxControllers; i++) {
- for (size_t j = 0; j < Ship::Window::Controllers[i].size(); j++) {
- Ship::Window::Controllers[i][j]->Read(&pad[i]);
- }
- }
+ if (__enableGameInput) {
+ Ship::Window::ControllerApi->WriteToPad(pad);
}
ModInternal::ExecuteHooks<ModInternal::ControllerRead>(pad);
@@ -129,15 +89,10 @@ extern "C" {
if (hashStr != nullptr) {
auto res = std::static_pointer_cast<Ship::Array>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str()));
-
- //if (res != nullptr)
- return (Vtx*)res->vertices.data();
- //else
- //return (Vtx*)Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadFile(hashStr)->buffer.get();
- }
- else {
- return nullptr;
+ return (Vtx*)res->vertices.data();
}
+
+ return nullptr;
}
int32_t* ResourceMgr_LoadMtxByCRC(uint64_t crc) {
@@ -146,9 +101,9 @@ extern "C" {
if (hashStr != nullptr) {
auto res = std::static_pointer_cast<Ship::Matrix>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(hashStr->c_str()));
return (int32_t*)res->mtx.data();
- } else {
- return nullptr;
}
+
+ return nullptr;
}
Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc) {
@@ -233,7 +188,7 @@ extern GfxWindowManagerAPI gfx_sdl;
void SetWindowManager(GfxWindowManagerAPI** WmApi, GfxRenderingAPI** RenderingApi, const std::string& gfx_backend);
namespace Ship {
- std::map<size_t, std::vector<std::shared_ptr<Controller>>> Window::Controllers;
+
int32_t Window::lastScancode;
Window::Window(std::shared_ptr<GlobalCtx2> Context) : Context(Context), APlayer(nullptr) {
@@ -248,26 +203,49 @@ namespace Ship {
SPDLOG_INFO("destruct window");
}
+ void Window::CreateDefaults() {
+ const std::shared_ptr<Mercury> pConf = GlobalCtx2::GetInstance()->GetConfig();
+ if (pConf->isNewInstance) {
+ pConf->setInt("Window.Width", 640);
+ pConf->setInt("Window.Height", 480);
+ pConf->setBool("Window.Options", false);
+ pConf->setString("Window.GfxBackend", "");
+
+ pConf->setBool("Window.Fullscreen.Enabled", false);
+ pConf->setInt("Window.Fullscreen.Width", 640);
+ pConf->setInt("Window.Fullscreen.Height", 480);
+
+ pConf->setString("Game.SaveName", "");
+ pConf->setString("Game.Main Archive", "");
+ pConf->setString("Game.Patches Archive", "");
+
+ pConf->setInt("Shortcuts.Fullscreen", 0x044);
+ pConf->setInt("Shortcuts.Console", 0x029);
+ pConf->save();
+ }
+ }
+
void Window::Init() {
- std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
- ConfigFile& Conf = *pConf.get();
+ std::shared_ptr<Mercury> pConf = GlobalCtx2::GetInstance()->GetConfig();
+
+ CreateDefaults();
SetAudioPlayer();
- bIsFullscreen = Ship::stob(Conf["WINDOW"]["FULLSCREEN"]);
- if (bIsFullscreen) {
- dwWidth = Ship::stoi(Conf["WINDOW"]["FULLSCREEN WIDTH"], 1920);
- dwHeight = Ship::stoi(Conf["WINDOW"]["FULLSCREEN HEIGHT"], 1080);
- } else {
- dwWidth = Ship::stoi(Conf["WINDOW"]["WINDOW WIDTH"], 640);
- dwHeight = Ship::stoi(Conf["WINDOW"]["WINDOW HEIGHT"], 480);
- }
- dwMenubar = Ship::stoi(Conf["WINDOW"]["menubar"], 0);
- const std::string& gfx_backend = Conf["WINDOW"]["GFX BACKEND"];
+ bIsFullscreen = pConf->getBool("Window.Fullscreen.Enabled", false);
+
+ dwWidth = pConf->getInt("Window.Fullscreen.Width", bIsFullscreen ? 1920 : 640);
+ dwHeight = pConf->getInt("Window.Fullscreen.Height", bIsFullscreen ? 1080 : 480);
+ dwMenubar = pConf->getBool("Window.Options", false);
+ const std::string& gfx_backend = pConf->getString("Window.GfxBackend");
SetWindowManager(&WmApi, &RenderingApi, gfx_backend);
gfx_init(WmApi, RenderingApi, GetContext()->GetName().c_str(), bIsFullscreen, dwWidth, dwHeight);
- WmApi->set_fullscreen_changed_callback(Window::OnFullscreenChanged);
- WmApi->set_keyboard_callbacks(Window::KeyDown, Window::KeyUp, Window::AllKeysUp);
+ WmApi->set_fullscreen_changed_callback(OnFullscreenChanged);
+ WmApi->set_keyboard_callbacks(KeyDown, KeyUp, AllKeysUp);
+
+ ModInternal::RegisterHook<ModInternal::ExitGame>([]() {
+ ControllerApi->SaveControllerSettings();
+ });
}
void Window::StartFrame() {
@@ -318,30 +296,26 @@ namespace Ship {
void Window::MainLoop(void (*MainFunction)(void)) {
WmApi->main_loop(MainFunction);
}
+
bool Window::KeyUp(int32_t dwScancode) {
- std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
- ConfigFile& Conf = *pConf.get();
+ std::shared_ptr<Mercury> pConf = GlobalCtx2::GetInstance()->GetConfig();
- if (dwScancode == Ship::stoi(Conf["KEYBOARD SHORTCUTS"]["KEY_FULLSCREEN"])) {
+ if (dwScancode == pConf->getInt("Shortcuts.Fullscreen", 0x044)) {
GlobalCtx2::GetInstance()->GetWindow()->ToggleFullscreen();
}
-
-
// OTRTODO: Rig with Kirito's console?
//if (dwScancode == Ship::stoi(Conf["KEYBOARD SHORTCUTS"]["KEY_CONSOLE"])) {
// ToggleConsole();
//}
+
+ lastScancode = -1;
bool bIsProcessed = false;
- for (size_t i = 0; i < __osMaxControllers; i++) {
- for (size_t j = 0; j < Controllers[i].size(); j++) {
- KeyboardController* pad = dynamic_cast<KeyboardController*>(Ship::Window::Controllers[i][j].get());
- if (pad != nullptr) {
- if (pad->ReleaseButton(dwScancode)) {
- bIsProcessed = true;
- }
- }
+ const auto pad = dynamic_cast<KeyboardController*>(ControllerApi->physicalDevices[ControllerApi->physicalDevices.size() - 2].get());
+ if (pad != nullptr) {
+ if (pad->ReleaseButton(dwScancode)) {
+ bIsProcessed = true;
}
}
@@ -350,14 +324,11 @@ namespace Ship {
bool Window::KeyDown(int32_t dwScancode) {
bool bIsProcessed = false;
- for (size_t i = 0; i < __osMaxControllers; i++) {
- for (size_t j = 0; j < Controllers[i].size(); j++) {
- KeyboardController* pad = dynamic_cast<KeyboardController*>(Ship::Window::Controllers[i][j].get());
- if (pad != nullptr) {
- if (pad->PressButton(dwScancode)) {
- bIsProcessed = true;
- }
- }
+
+ const auto pad = dynamic_cast<KeyboardController*>(ControllerApi->physicalDevices[ControllerApi->physicalDevices.size() - 2].get());
+ if (pad != nullptr) {
+ if (pad->PressButton(dwScancode)) {
+ bIsProcessed = true;
}
}
@@ -368,21 +339,17 @@ namespace Ship {
void Window::AllKeysUp(void) {
- for (size_t i = 0; i < __osMaxControllers; i++) {
- for (size_t j = 0; j < Controllers[i].size(); j++) {
- KeyboardController* pad = dynamic_cast<KeyboardController*>(Ship::Window::Controllers[i][j].get());
- if (pad != nullptr) {
- pad->ReleaseAllButtons();
- }
- }
+ const auto pad = dynamic_cast<KeyboardController*>(ControllerApi->physicalDevices[ControllerApi->physicalDevices.size() - 2].get());
+ if (pad != nullptr) {
+ pad->ReleaseAllButtons();
}
}
void Window::OnFullscreenChanged(bool bIsFullscreen) {
- std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
- ConfigFile& Conf = *pConf.get();
+ std::shared_ptr<Mercury> pConf = GlobalCtx2::GetInstance()->GetConfig();
+
GlobalCtx2::GetInstance()->GetWindow()->bIsFullscreen = bIsFullscreen;
- Conf["WINDOW"]["FULLSCREEN"] = std::to_string(bIsFullscreen);
+ pConf->setBool("Window.Fullscreen.Enabled", bIsFullscreen);
GlobalCtx2::GetInstance()->GetWindow()->ShowCursor(!bIsFullscreen);
}
diff --git a/libultraship/libultraship/Window.h b/libultraship/libultraship/Window.h
index a3087bf0c..1fa43abeb 100644
--- a/libultraship/libultraship/Window.h
+++ b/libultraship/libultraship/Window.h
@@ -5,17 +5,22 @@
#include "UltraController.h"
#include "Controller.h"
#include "GlobalCtx2.h"
+#include "ControlDeck.h"
+#include <string>
+
+#include "Lib/Fast3D/gfx_window_manager_api.h"
namespace Ship {
class AudioPlayer;
class Window {
public:
- static std::map<size_t, std::vector<std::shared_ptr<Controller>>> Controllers;
static int32_t lastScancode;
+ inline static ControlDeck* ControllerApi = new ControlDeck;
Window(std::shared_ptr<GlobalCtx2> Context);
~Window();
+ void CreateDefaults();
void MainLoop(void (*MainFunction)(void));
void Init();
void StartFrame();
@@ -31,9 +36,11 @@ namespace Ship {
bool IsFullscreen() { return bIsFullscreen; }
uint32_t GetCurrentWidth();
uint32_t GetCurrentHeight();
+ ControlDeck* GetControlDeck() { return ControllerApi; };
uint32_t dwMenubar;
std::shared_ptr<GlobalCtx2> GetContext() { return Context.lock(); }
std::shared_ptr<AudioPlayer> GetAudioPlayer() { return APlayer; }
+ const char* GetKeyName(int scancode) { return WmApi->get_key_name(scancode); }
protected:
private:
@@ -46,11 +53,10 @@ namespace Ship {
std::weak_ptr<GlobalCtx2> Context;
std::shared_ptr<AudioPlayer> APlayer;
- GfxWindowManagerAPI* WmApi;
GfxRenderingAPI* RenderingApi;
+ GfxWindowManagerAPI* WmApi;
bool bIsFullscreen;
uint32_t dwWidth;
uint32_t dwHeight;
};
}
-
diff --git a/libultraship/libultraship/libultraship.vcxproj b/libultraship/libultraship/libultraship.vcxproj
index d37915482..964f51f51 100644
--- a/libultraship/libultraship/libultraship.vcxproj
+++ b/libultraship/libultraship/libultraship.vcxproj
@@ -38,38 +38,38 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v142</PlatformToolset>
+ <PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Testing|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v142</PlatformToolset>
+ <PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v142</PlatformToolset>
+ <PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v142</PlatformToolset>
+ <PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Testing|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v142</PlatformToolset>
+ <PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v142</PlatformToolset>
+ <PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
@@ -256,13 +256,16 @@
<ItemGroup>
<ClCompile Include="Audio.cpp" />
<ClCompile Include="Blob.cpp" />
+ <ClCompile Include="ControlDeck.cpp" />
<ClCompile Include="Cvar.cpp" />
<ClCompile Include="Environment.cpp" />
<ClCompile Include="Factories\AudioFactory.cpp" />
+ <ClCompile Include="InputEditor.cpp" />
<ClCompile Include="GameOverlay.cpp" />
<ClCompile Include="GameSettings.cpp" />
<ClCompile Include="Lib\ImGui\backends\imgui_impl_dx11.cpp" />
<ClCompile Include="Lib\ImGui\backends\imgui_impl_win32.cpp" />
+ <ClCompile Include="Lib\Mercury\Mercury.cpp" />
<ClCompile Include="luslog.cpp" />
<ClCompile Include="mixer.c" />
<ClCompile Include="ModManager.cpp" />
@@ -279,7 +282,6 @@
<ClCompile Include="Factories\TextureFactory.cpp" />
<ClCompile Include="Factories\VtxFactory.cpp" />
<ClCompile Include="Array.cpp" />
- <ClCompile Include="ConfigFile.cpp" />
<ClCompile Include="Controller.cpp" />
<ClCompile Include="Hooks.cpp" />
<ClCompile Include="ImGuiImpl.cpp" />
@@ -342,13 +344,18 @@
<ClCompile Include="SDLController.cpp" />
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="Lib\Mercury\Mercury.h" />
+ <ClInclude Include="Lib\nlohmann\json.hpp" />
<ClInclude Include="abi.h" />
<ClInclude Include="Audio.h" />
<ClInclude Include="AudioPlayer.h" />
<ClInclude Include="Blob.h" />
+ <ClInclude Include="ControlDeck.h" />
<ClInclude Include="Cvar.h" />
+ <ClInclude Include="DisconnectedController.h" />
<ClInclude Include="Environment.h" />
<ClInclude Include="Factories\AudioFactory.h" />
+ <ClInclude Include="InputEditor.h" />
<ClInclude Include="GameOverlay.h" />
<ClInclude Include="GameSettings.h" />
<ClInclude Include="GameVersions.h" />
@@ -404,7 +411,6 @@
<ClInclude Include="Vertex.h" />
<ClInclude Include="stox.h" />
<ClInclude Include="Lib\mINI\src\mini\ini.h" />
- <ClInclude Include="ConfigFile.h" />
<ClInclude Include="Controller.h" />
<ClInclude Include="KeyboardController.h" />
<ClInclude Include="Factories\CollisionHeaderFactory.h" />
diff --git a/libultraship/libultraship/libultraship.vcxproj.filters b/libultraship/libultraship/libultraship.vcxproj.filters
index d1682c86f..ec1c6f870 100644
--- a/libultraship/libultraship/libultraship.vcxproj.filters
+++ b/libultraship/libultraship/libultraship.vcxproj.filters
@@ -31,9 +31,6 @@
<Filter Include="Source Files\Globals">
<UniqueIdentifier>{c0f07350-c627-444e-9f66-23e19407ad9a}</UniqueIdentifier>
</Filter>
- <Filter Include="Source Files\Config">
- <UniqueIdentifier>{9cf4833f-e90c-4a9d-8747-d47cde657beb}</UniqueIdentifier>
- </Filter>
<Filter Include="Source Files\Resources\Files">
<UniqueIdentifier>{2aa34c3b-6148-480f-a4fc-19c4e0f8c822}</UniqueIdentifier>
</Filter>
@@ -94,6 +91,15 @@
<Filter Include="Source Files\Lib\dr_libs">
<UniqueIdentifier>{db6e02cc-fc4c-4138-8219-1d281ad93ec2}</UniqueIdentifier>
</Filter>
+ <Filter Include="Source Files\Lib\nlohmann">
+ <UniqueIdentifier>{2be7c90f-ba21-455d-8a11-6f99452be15c}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\Lib\Mercury">
+ <UniqueIdentifier>{7e415dd2-403b-4d4d-b4f2-3e311f91db19}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\Controller\InputEditor">
+ <UniqueIdentifier>{010dc29b-d1f6-4793-a4e7-4156aa4fcdd6}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Factories\MaterialFactory.cpp">
@@ -165,9 +171,6 @@
<ClCompile Include="MemoryPack.cpp">
<Filter>Source Files\Controller\Attachment</Filter>
</ClCompile>
- <ClCompile Include="ConfigFile.cpp">
- <Filter>Source Files\Config</Filter>
- </ClCompile>
<ClCompile Include="CollisionHeader.cpp">
<Filter>Source Files\Resources\Files</Filter>
</ClCompile>
@@ -354,6 +357,15 @@
<ClCompile Include="Factories\AudioFactory.cpp">
<Filter>Source Files\Resources\Factories</Filter>
</ClCompile>
+ <ClCompile Include="InputEditor.cpp">
+ <Filter>Source Files\Controller\InputEditor</Filter>
+ </ClCompile>
+ <ClCompile Include="ControlDeck.cpp">
+ <Filter>Source Files\Controller</Filter>
+ </ClCompile>
+ <ClCompile Include="Lib\Mercury\Mercury.cpp">
+ <Filter>Source Files\Lib\Mercury</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Lib\tinyxml2\tinyxml2.h">
@@ -386,9 +398,6 @@
<ClInclude Include="MemoryPack.h">
<Filter>Source Files\Controller\Attachment</Filter>
</ClInclude>
- <ClInclude Include="ConfigFile.h">
- <Filter>Source Files\Config</Filter>
- </ClInclude>
<ClInclude Include="ResourceMgr.h">
<Filter>Source Files\Resources</Filter>
</ClInclude>
@@ -659,5 +668,20 @@
<ClInclude Include="Lib\dr_libs\wav.h">
<Filter>Source Files\Lib\dr_libs</Filter>
</ClInclude>
+ <ClInclude Include="InputEditor.h">
+ <Filter>Source Files\Controller\InputEditor</Filter>
+ </ClInclude>
+ <ClInclude Include="ControlDeck.h">
+ <Filter>Source Files\Controller</Filter>
+ </ClInclude>
+ <ClInclude Include="DisconnectedController.h">
+ <Filter>Source Files\Controller</Filter>
+ </ClInclude>
+ <ClInclude Include="Lib\nlohmann\json.hpp">
+ <Filter>Source Files\Lib\nlohmann</Filter>
+ </ClInclude>
+ <ClInclude Include="Lib\Mercury\Mercury.h">
+ <Filter>Source Files\Lib\Mercury</Filter>
+ </ClInclude>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/soh/include/functions.h b/soh/include/functions.h
index 73f366bb5..72fd6e98c 100644
--- a/soh/include/functions.h
+++ b/soh/include/functions.h
@@ -559,6 +559,7 @@ void ActorOverlayTable_Cleanup(void);
u16 DynaSSNodeList_GetNextNodeIdx(DynaSSNodeList*);
void func_80038A28(CollisionPoly* poly, f32 tx, f32 ty, f32 tz, MtxF* dest);
f32 CollisionPoly_GetPointDistanceFromPlane(CollisionPoly* poly, Vec3f* point);
+CollisionHeader* BgCheck_GetCollisionHeader(CollisionContext* colCtx, s32 bgId);
void CollisionPoly_GetVerticesByBgId(CollisionPoly* poly, s32 bgId, CollisionContext* colCtx, Vec3f* dest);
s32 BgCheck_CheckStaticCeiling(StaticLookup* lookup, u16 xpFlags, CollisionContext* colCtx, f32* outY, Vec3f* pos,
f32 checkHeight, CollisionPoly** outPoly);
diff --git a/soh/soh.vcxproj b/soh/soh.vcxproj
index 5f7ea818f..c305b03b1 100644
--- a/soh/soh.vcxproj
+++ b/soh/soh.vcxproj
@@ -143,7 +143,7 @@
<ClCompile>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<SDLCheck>false</SDLCheck>
- <PreprocessorDefinitions>INCLUDE_GAME_PRINTF;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;ENABLE_DX11;%(PreprocessorDefinitions)GLEW_STATIC </PreprocessorDefinitions>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;ENABLE_DX11;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@@ -1038,7 +1038,6 @@
<ClInclude Include="soh\Enhancements\debugger\debugSaveEditor.h" />
<ClInclude Include="soh\Enhancements\debugger\ImGuiHelpers.h" />
<ClInclude Include="soh\gameconsole.h" />
- <ClInclude Include="soh\Lib\nlohmann\json.hpp" />
<ClInclude Include="soh\OTRAudio.h" />
<ClInclude Include="soh\OTRGlobals.h" />
<ClInclude Include="soh\SaveManager.h" />
diff --git a/soh/soh.vcxproj.filters b/soh/soh.vcxproj.filters
index bbe6578f2..457e23ed1 100644
--- a/soh/soh.vcxproj.filters
+++ b/soh/soh.vcxproj.filters
@@ -82,12 +82,6 @@
<Filter Include="Source Files\soh\Enhancements\debugger">
<UniqueIdentifier>{04fc1c52-49ff-48e2-ae23-2c00867374f8}</UniqueIdentifier>
</Filter>
- <Filter Include="Source Files\soh\Lib">
- <UniqueIdentifier>{dbcf07c4-80b1-4c88-ac54-2bbdd8f53ee4}</UniqueIdentifier>
- </Filter>
- <Filter Include="Source Files\soh\Lib\nlohmann">
- <UniqueIdentifier>{9c880c8e-492b-48f6-b230-1fd269ea74b1}</UniqueIdentifier>
- </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\boot\assert.c">
@@ -3947,9 +3941,6 @@
<ClInclude Include="soh\OTRAudio.h">
<Filter>Source Files\soh</Filter>
</ClInclude>
- <ClInclude Include="soh\Lib\nlohmann\json.hpp">
- <Filter>Source Files\soh\Lib\nlohmann</Filter>
- </ClInclude>
<ClInclude Include="soh\SaveManager.h">
<Filter>Source Files\soh</Filter>
</ClInclude>
diff --git a/soh/soh/Enhancements/bootcommands.c b/soh/soh/Enhancements/bootcommands.c
index 0b789b445..4f20155d4 100644
--- a/soh/soh/Enhancements/bootcommands.c
+++ b/soh/soh/Enhancements/bootcommands.c
@@ -20,7 +20,7 @@ extern BootCommandFunc BootCommands_Command_LoadFileSelect(char** argv, s32 argc
static BootCommand sCommands[] = { { "--skiplogo", BootCommands_Command_SkipLogo },
{ "--loadfileselect", BootCommands_Command_LoadFileSelect } };
-void BootCommands_Init()
+void BootCommands_Init()
{
CVar_RegisterS32("gDisableLOD", 0);
CVar_RegisterS32("gDebugEnabled", 0);
@@ -30,7 +30,6 @@ void BootCommands_Init()
CVar_RegisterS32("gHoverFishing", 0);
CVar_RegisterS32("gN64WeirdFrames", 0);
CVar_RegisterS32("gBombchusOOB", 0);
- CVar_RegisterS32("gRumbleEnabled", 0);
CVar_RegisterS32("gUniformLR", 0);
CVar_RegisterS32("gTwoHandedIdle", 0);
CVar_RegisterS32("gDekuNutUpgradeFix", 0);
diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp
index b2981d361..4bb4efd19 100644
--- a/soh/soh/Enhancements/debugconsole.cpp
+++ b/soh/soh/Enhancements/debugconsole.cpp
@@ -16,6 +16,7 @@
#include <Utils/StringHelper.h>
#include <Utils/File.h>
+#include "Window.h"
#include "Lib/ImGui/imgui_internal.h"
#undef PATH_HACK
#undef Path
@@ -315,7 +316,7 @@ static bool SaveStateHandler(const std::vector<std::string>& args) {
unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE });
- switch (rtn) {
+ switch (rtn) {
case SaveStateReturn::SUCCESS:
INFO("[SOH] Saved state to slot %u", slot);
return CMD_SUCCESS;
@@ -329,7 +330,7 @@ static bool SaveStateHandler(const std::vector<std::string>& args) {
static bool LoadStateHandler(const std::vector<std::string>& args) {
unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD });
-
+
switch (rtn) {
case SaveStateReturn::SUCCESS:
INFO("[SOH] Loaded state from slot %u", slot);
@@ -342,7 +343,7 @@ static bool LoadStateHandler(const std::vector<std::string>& args) {
return CMD_FAILED;
case SaveStateReturn::FAIL_WRONG_GAMESTATE:
ERROR("[SOH] Can not load a state outside of \"GamePlay\"");
- return CMD_FAILED;
+ return CMD_FAILED;
}
}
@@ -360,7 +361,7 @@ static bool StateSlotSelectHandler(const std::vector<std::string>& args) {
ERROR("[SOH] SaveState slot value must be a number.");
return CMD_FAILED;
}
-
+
if (slot < 0) {
ERROR("[SOH] Invalid slot passed. Slot must be between 0 and 2");
return CMD_FAILED;
@@ -498,8 +499,7 @@ template <typename Numeric> bool is_number(const std::string& s) {
return ((std::istringstream(s) >> n >> std::ws).eof());
}
-void DebugConsole_LoadCVars()
-{
+void DebugConsole_LoadLegacyCVars() {
auto cvarsConfig = Ship::GlobalCtx2::GetPathRelativeToAppDirectory("cvars.cfg");
if (File::Exists(cvarsConfig)) {
const auto lines = File::ReadAllLines(cvarsConfig);
@@ -520,23 +520,58 @@ void DebugConsole_LoadCVars()
CVar_SetS32(cfg[0].c_str(), std::stoi(cfg[1]));
}
}
+
+ fs::remove("cvars.cfg");
}
}
+void DebugConsole_LoadCVars() {
+
+ std::shared_ptr<Mercury> pConf = Ship::GlobalCtx2::GetInstance()->GetConfig();
+ pConf->reload();
+
+ for (const auto& item : pConf->rjson["CVars"].items()) {
+ auto value = item.value();
+ switch (value.type()) {
+ case nlohmann::detail::value_t::array:
+ break;
+ case nlohmann::detail::value_t::string:
+ CVar_SetString(item.key().c_str(), value.get<std::string>().c_str());
+ break;
+ case nlohmann::detail::value_t::boolean:
+ CVar_SetS32(item.key().c_str(), value.get<bool>());
+ break;
+ case nlohmann::detail::value_t::number_unsigned:
+ case nlohmann::detail::value_t::number_integer:
+ CVar_SetS32(item.key().c_str(), value.get<int>());
+ break;
+ case nlohmann::detail::value_t::number_float:
+ CVar_SetFloat(item.key().c_str(), value.get<float>());
+ break;
+ default: ;
+ }
+ if (item.key() == "gOpenMenuBar") {
+ int bp = 0;
+ }
+ }
+
+ DebugConsole_LoadLegacyCVars();
+}
+
void DebugConsole_SaveCVars()
{
- std::string output;
+ std::shared_ptr<Mercury> pConf = Ship::GlobalCtx2::GetInstance()->GetConfig();
for (const auto &cvar : cvars) {
- if (cvar.second->type == CVAR_TYPE_STRING)
- output += StringHelper::Sprintf("%s = \"%s\"\n", cvar.first.c_str(), cvar.second->value.valueStr);
+ const std::string key = StringHelper::Sprintf("CVars.%s", cvar.first.c_str());
+
+ if (cvar.second->type == CVAR_TYPE_STRING && cvar.second->value.valueStr != nullptr)
+ pConf->setString(key, std::string(cvar.second->value.valueStr));
else if (cvar.second->type == CVAR_TYPE_S32)
- output += StringHelper::Sprintf("%s = %i\n", cvar.first.c_str(), cvar.second->value.valueS32);
+ pConf->setInt(key, cvar.second->value.valueS32);
else if (cvar.second->type == CVAR_TYPE_FLOAT)
- output += StringHelper::Sprintf("%s = %f\n", cvar.first.c_str(), cvar.second->value.valueFloat);
+ pConf->setFloat(key, cvar.second->value.valueFloat);
}
-
- auto cvarsConfig = Ship::GlobalCtx2::GetPathRelativeToAppDirectory("cvars.cfg");
- File::WriteAllText(cvarsConfig, output);
+ pConf->save();
}
diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp
index 3ed486a44..24662f1d7 100644
--- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp
@@ -11,7 +11,7 @@
#include "utils.hpp"
#include "shops.hpp"
#include "hints.hpp"
-#include "soh/Lib/nlohmann/json.hpp"
+#include "Lib/nlohmann/json.hpp"
#include <cstdio>
#include <cstdlib>
diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp
index 43e278ab5..09704e867 100644
--- a/soh/soh/Enhancements/randomizer/randomizer.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer.cpp
@@ -1,5 +1,5 @@
#include "randomizer.h"
-#include "soh/Lib/nlohmann/json.hpp"
+#include "Lib/nlohmann/json.hpp"
#include <fstream>
#include <variables.h>
#include <macros.h>
diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h
index 5fe2e0ae4..7f4d16031 100644
--- a/soh/soh/Enhancements/randomizer/randomizer.h
+++ b/soh/soh/Enhancements/randomizer/randomizer.h
@@ -1,5 +1,4 @@
-#ifndef RANDOMIZER_H
-#define RANDOMIZER_H
+#pragma once
#include <unordered_map>
#include <string>
@@ -54,5 +53,3 @@ void Rando_Init(void);
}
#endif
-
-#endif
diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp
index 3a862d58a..514edc563 100644
--- a/soh/soh/OTRGlobals.cpp
+++ b/soh/soh/OTRGlobals.cpp
@@ -1153,34 +1153,27 @@ extern "C" s32* ResourceMgr_LoadCSByName(const char* path)
return (s32*)res->commands.data();
}
-std::filesystem::path GetSaveFile(Ship::ConfigFile& Conf) {
- std::string fileName = Conf.get("SAVE").get("Save Filename");
-
- if (fileName.empty()) {
- Conf["SAVE"]["Save Filename"] = Ship::GlobalCtx2::GetPathRelativeToAppDirectory("oot_save.sav");
- Conf.Save();
- }
+std::filesystem::path GetSaveFile(std::shared_ptr<Mercury> Conf) {
+ const std::string fileName = Conf->getString("Game.SaveName", Ship::GlobalCtx2::GetPathRelativeToAppDirectory("oot_save.sav"));
std::filesystem::path saveFile = std::filesystem::absolute(fileName);
- if (!std::filesystem::exists(saveFile.parent_path())) {
- std::filesystem::create_directories(saveFile.parent_path());
+ if (!exists(saveFile.parent_path())) {
+ create_directories(saveFile.parent_path());
}
return saveFile;
}
std::filesystem::path GetSaveFile() {
- std::shared_ptr<Ship::ConfigFile> pConf = OTRGlobals::Instance->context->GetConfig();
- Ship::ConfigFile& Conf = *pConf.get();
+ const std::shared_ptr<Mercury> pConf = OTRGlobals::Instance->context->GetConfig();
- return GetSaveFile(Conf);
+ return GetSaveFile(pConf);
}
-void OTRGlobals::CheckSaveFile(size_t sramSize) {
- std::shared_ptr<Ship::ConfigFile> pConf = context->GetConfig();
- Ship::ConfigFile& Conf = *pConf.get();
+void OTRGlobals::CheckSaveFile(size_t sramSize) const {
+ const std::shared_ptr<Mercury> pConf = Instance->context->GetConfig();
- std::filesystem::path savePath = GetSaveFile(Conf);
+ std::filesystem::path savePath = GetSaveFile(pConf);
std::fstream saveFile(savePath, std::fstream::in | std::fstream::out | std::fstream::binary);
if (saveFile.fail()) {
saveFile.open(savePath, std::fstream::in | std::fstream::out | std::fstream::binary | std::fstream::app);
@@ -1199,25 +1192,6 @@ extern "C" void Ctx_WriteSaveFile(uintptr_t addr, void* dramAddr, size_t size) {
OTRGlobals::Instance->context->WriteSaveFile(GetSaveFile(), addr, dramAddr, size);
}
-/* Remember to free after use of value */
-extern "C" char* Config_getValue(char* category, char* key) {
- std::shared_ptr<Ship::ConfigFile> pConf = OTRGlobals::Instance->context->GetConfig();
- Ship::ConfigFile& Conf = *pConf.get();
-
- std::string data = Conf.get(std::string(category)).get(std::string(key));
- char* retval = (char*)malloc(data.length()+1);
- strcpy(retval, data.c_str());
-
- return retval;
-}
-
-extern "C" bool Config_setValue(char* category, char* key, char* value) {
- std::shared_ptr<Ship::ConfigFile> pConf = OTRGlobals::Instance->context->GetConfig();
- Ship::ConfigFile& Conf = *pConf.get();
- Conf[std::string(category)][std::string(key)] = std::string(value);
- return Conf.Save();
-}
-
std::wstring StringToU16(const std::string& s) {
std::vector<unsigned long> result;
size_t i = 0;
@@ -1319,11 +1293,10 @@ extern "C" uint32_t OTRGetCurrentHeight() {
}
extern "C" void OTRControllerCallback(ControllerCallback* controller) {
- auto controllers = OTRGlobals::Instance->context->GetWindow()->Controllers;
- for (size_t i = 0; i < controllers.size(); i++) {
- for (int j = 0; j < controllers[i].size(); j++) {
- OTRGlobals::Instance->context->GetWindow()->Controllers[i][j]->WriteToSource(controller);
- }
+ const auto controllers = Ship::Window::ControllerApi->virtualDevices;
+
+ for (int i = 0; i < controllers.size(); ++i) {
+ Ship::Window::ControllerApi->physicalDevices[controllers[i]]->WriteToSource(i, controller);
}
}
@@ -1377,11 +1350,11 @@ extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len) {
}
extern "C" int Controller_ShouldRumble(size_t i) {
- for (const auto& controller : Ship::Window::Controllers.at(i))
- {
- float rumble_strength = CVar_GetFloat(StringHelper::Sprintf("gCont%i_RumbleStrength", i).c_str(), 1.0f);
- if (controller->CanRumble() && rumble_strength > 0.001f) {
+ const auto controllers = Ship::Window::ControllerApi->virtualDevices;
+
+ for (const auto virtual_entry : controllers) {
+ if (Ship::Window::ControllerApi->physicalDevices[virtual_entry]->CanRumble()) {
return 1;
}
}
diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h
index 7c56e54c1..7c42da370 100644
--- a/soh/soh/OTRGlobals.h
+++ b/soh/soh/OTRGlobals.h
@@ -23,7 +23,7 @@ public:
~OTRGlobals();
private:
- void CheckSaveFile(size_t sramSize);
+ void CheckSaveFile(size_t sramSize) const;
};
#endif
@@ -61,8 +61,6 @@ SoundFontSample* ResourceMgr_LoadAudioSample(const char* path);
CollisionHeader* ResourceMgr_LoadColByName(const char* path);
void Ctx_ReadSaveFile(uintptr_t addr, void* dramAddr, size_t size);
void Ctx_WriteSaveFile(uintptr_t addr, void* dramAddr, size_t size);
-char* Config_getValue(char* category, char* key);
-bool Config_setValue(char* category, char* key, char* value);
uint64_t GetPerfCounter();
struct SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path);
diff --git a/soh/src/code/padmgr.c b/soh/src/code/padmgr.c
index d89207e6f..9bd9d53e7 100644
--- a/soh/src/code/padmgr.c
+++ b/soh/src/code/padmgr.c
@@ -269,7 +269,7 @@ void PadMgr_ProcessInputs(PadMgr* padMgr) {
input->press.stick_y += (s8)(input->cur.stick_y - input->prev.stick_y);
}
- controllerCallback.rumble = CVar_GetS32("gRumbleEnabled", 0) && (padMgr->rumbleEnable[0] > 0);
+ controllerCallback.rumble = (padMgr->rumbleEnable[0] > 0);
if (HealthMeter_IsCritical()) {
controllerCallback.ledColor = 0;
diff --git a/soh/src/code/z_camera.c b/soh/src/code/z_camera.c
index 704062b1b..287edeb60 100644
--- a/soh/src/code/z_camera.c
+++ b/soh/src/code/z_camera.c
@@ -1481,7 +1481,7 @@ s32 Camera_Free(Camera* camera) {
camBgChk.pos = camera->eye;
- float maxRadius = 160.0f;
+ float maxRadius = 150.0f;
if (Camera_BGCheckInfo(camera, &at, &camBgChk)) {
VecSph collSphere;
OLib_Vec3fDiffToVecSphGeo(&collSphere, &at, &camBgChk.pos);
diff --git a/soh/src/code/z_fbdemo_wipe1.c b/soh/src/code/z_fbdemo_wipe1.c
index 1dfb0a501..d4502f8e7 100644
--- a/soh/src/code/z_fbdemo_wipe1.c
+++ b/soh/src/code/z_fbdemo_wipe1.c
@@ -89,6 +89,7 @@ void TransitionWipe_Draw(void* thisx, Gfx** gfxP) {
TransitionWipe* this = (TransitionWipe*)thisx;
s32 pad[4];
Gfx* tex;
+ Gfx* wipeDl = sWipeDList;
modelView = this->modelView[this->frame];
diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c
index d07222768..576f550c7 100644
--- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c
+++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c
@@ -419,7 +419,7 @@ void FileChoose_UpdateMainMenu(GameState* thisx) {
(!fileSelectSpoilerFileLoaded &&
SpoilerFileExists(CVar_GetString("gSpoilerLog", "")))) {
if (CVar_GetS32("gNewFileDropped", 0) != 0) {
- CVar_SetString("gSpoilerLog", CVar_GetString("gDroppedFile", ""));
+ CVar_SetString("gSpoilerLog", CVar_GetString("gDroppedFile", "None"));
}
bool silent = true;
if ((CVar_GetS32("gNewFileDropped", 0) != 0) ||
@@ -1894,7 +1894,7 @@ void FileChoose_Main(GameState* thisx) {
};
FileChooseContext* this = (FileChooseContext*)thisx;
Input* input = &this->state.input[0];
-
+
if (CVar_GetS32("gTimeFlowFileSelect", 0) != 0) {
gSaveContext.skyboxTime += 0x10;
}