diff --git a/source-code/data/plugins/playerdata.ini b/source-code/data/plugins/playerdata.ini
index 41bb174..53a22b1 100644
--- a/source-code/data/plugins/playerdata.ini
+++ b/source-code/data/plugins/playerdata.ini
@@ -20,6 +20,9 @@ slide_se_equip = -1
# IDs defined in rom/gm_chainslide_se_tbl.farc/gm_chainslide_se_id.bin
chainslide_se_equip = -1
+# Enable button/slider sounds
+act_toggle = true
+
# Show clear borders on Progress Bar for:
# Great
border_great = true
diff --git a/source-code/source/PD-Loader/dllmain.cpp b/source-code/source/PD-Loader/dllmain.cpp
index e26843a..d6a4bba 100644
--- a/source-code/source/PD-Loader/dllmain.cpp
+++ b/source-code/source/PD-Loader/dllmain.cpp
@@ -158,7 +158,8 @@ void FindFiles(WIN32_FIND_DATAW* fd)
if (fd->cFileName[pos - 4] == '.' &&
(fd->cFileName[pos - 3] == 'd' || fd->cFileName[pos - 3] == 'D') &&
(fd->cFileName[pos - 2] == 'v' || fd->cFileName[pos - 2] == 'V') &&
- (fd->cFileName[pos - 1] == 'a' || fd->cFileName[pos - 1] == 'A'))
+ (fd->cFileName[pos - 1] == 'a' || fd->cFileName[pos - 1] == 'A') &&
+ GetPrivateProfileIntW(L"plugins", fd->cFileName, TRUE, iniPaths))
{
auto path = dir + L'\\' + fd->cFileName;
diff --git a/source-code/source/plugins/DivaSound/DivaSound.vcxproj b/source-code/source/plugins/DivaSound/DivaSound.vcxproj
index 1813284..d49c39a 100644
--- a/source-code/source/plugins/DivaSound/DivaSound.vcxproj
+++ b/source-code/source/plugins/DivaSound/DivaSound.vcxproj
@@ -82,6 +82,7 @@
+
diff --git a/source-code/source/plugins/DivaSound/DivaSound.vcxproj.filters b/source-code/source/plugins/DivaSound/DivaSound.vcxproj.filters
index 3d3bf67..99a4edb 100644
--- a/source-code/source/plugins/DivaSound/DivaSound.vcxproj.filters
+++ b/source-code/source/plugins/DivaSound/DivaSound.vcxproj.filters
@@ -23,5 +23,8 @@
Header Files
+
+ Header Files
+
\ No newline at end of file
diff --git a/source-code/source/plugins/DivaSound/src/PluginConfigApi.h b/source-code/source/plugins/DivaSound/src/PluginConfigApi.h
new file mode 100644
index 0000000..d0ffd94
--- /dev/null
+++ b/source-code/source/plugins/DivaSound/src/PluginConfigApi.h
@@ -0,0 +1,168 @@
+#pragma once
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#include
+#include
+
+// resolution class to store and sort the width and height easily
+class resolution
+{
+public:
+ unsigned int width;
+ unsigned int height;
+
+ resolution()
+ {
+ width = 0;
+ height = 0;
+ }
+
+ resolution(unsigned int width, unsigned int height)
+ {
+ resolution::width = width;
+ resolution::height = height;
+ }
+
+ bool operator ==(const resolution &res2)
+ {
+ return width == res2.width && height == res2.height;
+ }
+
+ // in comparisons width takes priority because it's usually displayed first
+ bool operator <(const resolution &res2)
+ {
+ if (width == res2.width)
+ return height < res2.height;
+ else
+ return width < res2.width;
+ }
+ bool operator >(const resolution &res2)
+ {
+ if (width == res2.width)
+ return height > res2.height;
+ else
+ return width > res2.width;
+ }
+};
+
+namespace PluginConfig
+{
+#pragma pack(push, 1)
+ enum ConfigType {
+ CONFIG_BOOLEAN,
+ CONFIG_NUMERIC,
+ CONFIG_STRING,
+ CONFIG_DROPDOWN_INDEX,
+ CONFIG_DROPDOWN_TEXT,
+ CONFIG_DROPDOWN_NUMBER,
+ CONFIG_RESOLUTION,
+ CONFIG_GROUP_START,
+ CONFIG_GROUP_END,
+ CONFIG_BUTTON,
+ CONFIG_SPACER
+ };
+
+ struct PluginConfigBooleanData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ bool defaultVal;
+ bool saveAsString;
+ };
+
+ struct PluginConfigNumericData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ int defaultVal;
+ int minVal;
+ int maxVal;
+ };
+
+ struct PluginConfigStringData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ LPCWSTR defaultVal;
+ bool useUtf8;
+ };
+
+ struct PluginConfigDropdownIndexData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ int defaultVal;
+ std::vector valueStrings;
+ };
+
+ struct PluginConfigDropdownTextData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ LPCWSTR defaultVal;
+ std::vector valueStrings;
+ bool editable;
+ bool useUtf8;
+ };
+
+ struct PluginConfigDropdownNumberData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ int defaultVal;
+ std::vector valueInts;
+ bool editable;
+ };
+
+ struct PluginConfigResolutionData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniVarName2;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ resolution defaultVal;
+ std::vector valueResolutions;
+ bool editable;
+ };
+
+ struct PluginConfigGroupData
+ {
+ LPCWSTR name;
+ int height;
+ };
+
+ struct PluginConfigButtonData {
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ void(*func)();
+ };
+
+ struct PluginConfigSpacerData {
+ int height;
+ };
+
+ struct PluginConfigOption
+ {
+ ConfigType cfgType;
+ void* data;
+ };
+
+ struct PluginConfigArray
+ {
+ int len;
+ PluginConfigOption* options;
+ };
+#pragma pack(pop)
+}
\ No newline at end of file
diff --git a/source-code/source/plugins/DivaSound/src/dllmain.cpp b/source-code/source/plugins/DivaSound/src/dllmain.cpp
index 350b118..a22837f 100644
--- a/source-code/source/plugins/DivaSound/src/dllmain.cpp
+++ b/source-code/source/plugins/DivaSound/src/dllmain.cpp
@@ -1,4 +1,5 @@
#include "framework.h"
+#include "PluginConfigApi.h"
#include
#pragma comment(lib, "detours.lib")
@@ -7,6 +8,7 @@
#include
#include
#include
+#include
void InjectCode(void* address, const std::vector data)
{
@@ -410,3 +412,37 @@ BOOL APIENTRY DllMain(HMODULE hModule,
return TRUE;
}
+
+using namespace PluginConfig;
+
+void OpenWiki()
+{
+ ShellExecuteW(NULL, L"open", L"https://github.com/somewhatlurker/DivaSound/wiki", NULL, NULL, SW_SHOW);
+}
+
+PluginConfigOption config[] = {
+ { CONFIG_DROPDOWN_TEXT, new PluginConfigDropdownTextData{L"backend", L"general", CONFIG_FILE, L"Backend:", L"Sets the audio output protocol.", L"WASAPI", std::vector({ L"WASAPI", L"WASAPI_Exclusive" }), true, false } },
+ { CONFIG_DROPDOWN_NUMBER, new PluginConfigDropdownNumberData{ L"channels", L"general", CONFIG_FILE, L"Channels:", L"Sets the number of channels.", 2, std::vector({ 2, 4 }), false } },
+ { CONFIG_DROPDOWN_NUMBER, new PluginConfigDropdownNumberData{ L"bit_depth", L"general", CONFIG_FILE, L"Bit Depth:", L"Sets the audio sample format.\n(32 uses floating point samples)", 16, std::vector({ 16, 24, 32 }), false } },
+ { CONFIG_NUMERIC, new PluginConfigNumericData{ L"buffer_size", L"buffer", CONFIG_FILE, L"Target Buffer Size:", L"Sets the target buffer size in ms.\nWASAPI will often ignore this and adapt to your hardware config automatically.", 10, 1, 100 } },
+ { CONFIG_NUMERIC, new PluginConfigNumericData{ L"periods", L"buffer", CONFIG_FILE, L"Buffer Periods:", L"Sets how often the buffer should be filled.\nFewer periods usually allows for lower latency, but lowering this may cause issues.", 2, 1, 8 } },
+ { CONFIG_BOOLEAN, new PluginConfigBooleanData{ L"alternate_init", L"general", CONFIG_FILE, L"Use new init", L"Use the full initialisation replacement.\nTry unchecking this if DivaSound seems to cause crashes.", true } },
+ { CONFIG_SPACER, new PluginConfigSpacerData{ 8 } },
+ { CONFIG_BUTTON, new PluginConfigButtonData{ L"Help", L"Get help on the DivaSound wiki.", OpenWiki } },
+ { CONFIG_SPACER, new PluginConfigSpacerData{ 8 } },
+};
+
+extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void)
+{
+ return L"DivaSound";
+}
+
+extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void)
+{
+ return L"DivaSound Plugin by somewhatlurker\n\nDivaSound replaces the game's original audio output,\nimproving device support and adding configurable options.";
+}
+
+extern "C" __declspec(dllexport) PluginConfigArray GetPluginOptions(void)
+{
+ return PluginConfigArray{ _countof(config), config };
+}
\ No newline at end of file
diff --git a/source-code/source/plugins/Launcher/ConfigOption.h b/source-code/source/plugins/Launcher/ConfigOption.h
index d1d0304..47888f2 100644
--- a/source-code/source/plugins/Launcher/ConfigOption.h
+++ b/source-code/source/plugins/Launcher/ConfigOption.h
@@ -9,6 +9,8 @@
#include
+#include "PluginConfigApi.h"
+
using namespace System;
using namespace System::Windows::Forms;
@@ -16,6 +18,7 @@ float BaseScaleSize = 96;
int Col1Width = 110;
int Col2Left = 114;
int Col2Width = 110;
+int ConfigBtnLeft = 160;
int ControlSpacing = 6;
// Custom function. Works like GetPrivateProfileIntW but returns bool. Can detect a numeric value or string.
@@ -39,46 +42,9 @@ bool GetPrivateProfileBoolW(LPCWSTR lpAppName, LPCWSTR lpKeyName, bool default,
return out;
}
-// resolution class to store and sort the width and height easily
-class resolution
-{
-public:
- unsigned int width;
- unsigned int height;
-
- resolution()
- {
- width = 0;
- height = 0;
- }
-
- resolution(unsigned int width, unsigned int height)
- {
- resolution::width = width;
- resolution::height = height;
- }
-
- bool operator ==(const resolution &res2)
- {
- return width == res2.width && height == res2.height;
- }
-
- // in comparisons width takes priority because it's usually displayed first
- bool operator <(const resolution &res2)
- {
- if (width == res2.width)
- return height < res2.height;
- else
- return width < res2.width;
- }
- bool operator >(const resolution &res2)
- {
- if (width == res2.width)
- return height > res2.height;
- else
- return width > res2.width;
- }
-};
+// declare this early (actual definitions below)
+class ConfigOptionBase;
+Panel^ MakePanel(int width, int height, std::vector &cfg, ToolTip^ tooltip, bool* hasChanged);
ref class ComboboxValidation
@@ -178,7 +144,78 @@ public:
};
-static ref class ChangeHandler
+ref class PluginConfigHandler
+{
+public:
+ Form^ form;
+
+ PluginConfigHandler(Panel^ optspanel, String^ title)
+ {
+ form = gcnew Form();
+
+ form->Text = title;
+
+ form->FormBorderStyle = FormBorderStyle::FixedDialog;
+ form->StartPosition = FormStartPosition::CenterScreen;
+ form->MaximizeBox = false;
+ form->MinimizeBox = false;
+ form->ShowInTaskbar = false;
+ form->ShowIcon = false;
+ //form->TopMost = true;
+
+ form->BackColor = Drawing::Color::FromArgb(64, 64, 64);
+ form->ForeColor = Drawing::Color::White;
+
+ optspanel->Left = 0;
+ optspanel->Top = 0;
+
+ Button^ OkBtn = gcnew Button();
+ OkBtn->Text = L"OK";
+ OkBtn->Left = 4;
+ OkBtn->Top = optspanel->Bottom + 4;
+ OkBtn->AutoSize = true;
+ OkBtn->FlatStyle = System::Windows::Forms::FlatStyle::Flat;
+
+ form->ClientSize = Drawing::Size(optspanel->Width, OkBtn->Bottom + 4);
+
+ form->Controls->Add(optspanel);
+ form->Controls->Add(OkBtn);
+ form->AcceptButton = OkBtn;
+
+ form->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &PluginConfigHandler::FormClosing);
+ OkBtn->Click += gcnew EventHandler(this, &PluginConfigHandler::OkClick);
+ }
+
+ System::Void OpenForm(System::Object^ sender, System::EventArgs^ e)
+ {
+ // ShowDialog seems to prevent disposal by copying the panel...
+ // which would be fine if I didn't rely on using the control handles
+ // MessageBox::Show(form->Controls[0]->Handle.ToString());
+
+ //Application::OpenForms[0]->Enabled = false;
+ form->Owner = Application::OpenForms[0];
+ if (form->Visible)
+ form->Hide();
+ form->Show();
+ }
+
+ System::Void FormClosing(System::Object^ sender, FormClosingEventArgs^ e)
+ {
+ if (e->CloseReason == CloseReason::UserClosing)
+ {
+ form->Hide();
+ //Application::OpenForms[0]->Enabled = true;
+ e->Cancel = true;
+ }
+ }
+
+ System::Void OkClick(System::Object^ sender, System::EventArgs^ e)
+ {
+ form->Close();
+ }
+};
+
+ref class ChangeHandler
{
public:
bool* changebool;
@@ -194,6 +231,22 @@ public:
}
};
+ref class CustomFuncHandler
+{
+public:
+ void(*_func)();
+
+ CustomFuncHandler(void(*func)())
+ {
+ _func = func;
+ }
+
+ System::Void RunFunc(System::Object^ sender, System::EventArgs^ e)
+ {
+ _func();
+ }
+};
+
class ConfigOptionBase
{
@@ -220,6 +273,42 @@ public:
};
+class OptionMetaGroupStart : public ConfigOptionBase
+{
+public:
+ int _height;
+
+ OptionMetaGroupStart(LPCWSTR friendlyName, int height)
+ {
+ _friendlyName = friendlyName;
+ _height = height;
+ }
+};
+class OptionMetaGroupEnd : public ConfigOptionBase
+{
+public:
+ OptionMetaGroupEnd()
+ {
+ }
+};
+
+class OptionMetaSpacer : public ConfigOptionBase
+{
+public:
+ int _height;
+
+ OptionMetaSpacer(int height)
+ {
+ _height = height;
+ }
+
+ virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip)
+ {
+ return _height;
+ }
+};
+
+
class BooleanOption : public ConfigOptionBase
{
public:
@@ -252,15 +341,20 @@ public:
cb->BackColor = System::Drawing::Color::FromArgb(0, 0, 0, 0);
Form^ RootForm = panel->FindForm();
- Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
- float ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
- float ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ float ScaleWidth = 1.0f;
+ float ScaleHeight = 1.0f;
+ if (RootForm)
+ {
+ Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
+ ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
+ ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ }
cb->Scale(ScaleWidth, ScaleHeight);
tooltip->SetToolTip(cb, gcnew String(_description));
if (hasChanged == nullptr)
- hasChanged = new bool;
+ hasChanged = new bool(false);
ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged);
cb->CheckedChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
@@ -325,9 +419,14 @@ public:
numberbox->AutoSize = true;
Form^ RootForm = panel->FindForm();
- Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
- float ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
- float ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ float ScaleWidth = 1.0f;
+ float ScaleHeight = 1.0f;
+ if (RootForm)
+ {
+ Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
+ ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
+ ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ }
label->Scale(ScaleWidth, ScaleHeight);
numberbox->Scale(ScaleWidth, ScaleHeight);
@@ -335,7 +434,7 @@ public:
tooltip->SetToolTip(numberbox, gcnew String(_description));
if (hasChanged == nullptr)
- hasChanged = new bool;
+ hasChanged = new bool(false);
ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged);
numberbox->ValueChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
@@ -404,9 +503,14 @@ public:
textbox->AutoSize = true;
Form^ RootForm = panel->FindForm();
- Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
- float ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
- float ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ float ScaleWidth = 1.0f;
+ float ScaleHeight = 1.0f;
+ if (RootForm)
+ {
+ Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
+ ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
+ ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ }
label->Scale(ScaleWidth, ScaleHeight);
textbox->Scale(ScaleWidth, ScaleHeight);
@@ -419,7 +523,7 @@ public:
tooltip->SetToolTip(textbox, gcnew String(_description));
if (hasChanged == nullptr)
- hasChanged = new bool;
+ hasChanged = new bool(false);
ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged);
textbox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
@@ -498,9 +602,14 @@ public:
combobox->DropDownStyle = ComboBoxStyle::DropDownList;
Form^ RootForm = panel->FindForm();
- Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
- float ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
- float ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ float ScaleWidth = 1.0f;
+ float ScaleHeight = 1.0f;
+ if (RootForm)
+ {
+ Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
+ ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
+ ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ }
label->Scale(ScaleWidth, ScaleHeight);
combobox->Scale(ScaleWidth, ScaleHeight);
@@ -508,7 +617,7 @@ public:
tooltip->SetToolTip(combobox, gcnew String(_description));
if (hasChanged == nullptr)
- hasChanged = new bool;
+ hasChanged = new bool(false);
ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged);
combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
@@ -532,14 +641,15 @@ public:
};
-class EditableDropdownOption : public ConfigOptionBase
+class DropdownTextOption : public ConfigOptionBase
{
public:
LPCWSTR _defaultVal;
std::vector _valueStrings;
+ bool _editable;
bool _useUtf8;
- EditableDropdownOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, LPCWSTR defaultVal, std::vector valueStrings, bool useUtf8)
+ DropdownTextOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, LPCWSTR defaultVal, std::vector valueStrings, bool editable, bool useUtf8)
{
_iniVarName = iniVarName;
_iniSectionName = iniSectionName;
@@ -548,6 +658,7 @@ public:
_description = description;
_defaultVal = defaultVal;
_valueStrings = valueStrings;
+ _editable = editable;
_useUtf8 = useUtf8;
}
@@ -582,12 +693,21 @@ public:
combobox->Width = Col2Width;
combobox->AutoSize = true;
combobox->FlatStyle = System::Windows::Forms::FlatStyle::Flat;
- combobox->DropDownStyle = ComboBoxStyle::DropDown;
+
+ if (_editable)
+ combobox->DropDownStyle = ComboBoxStyle::DropDown;
+ else
+ combobox->DropDownStyle = ComboBoxStyle::DropDownList;
Form^ RootForm = panel->FindForm();
- Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
- float ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
- float ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ float ScaleWidth = 1.0f;
+ float ScaleHeight = 1.0f;
+ if (RootForm)
+ {
+ Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
+ ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
+ ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ }
label->Scale(ScaleWidth, ScaleHeight);
combobox->Scale(ScaleWidth, ScaleHeight);
@@ -601,9 +721,12 @@ public:
tooltip->SetToolTip(combobox, gcnew String(_description));
if (hasChanged == nullptr)
- hasChanged = new bool;
+ hasChanged = new bool(false);
ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged);
- combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
+ if (_editable)
+ combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
+ else
+ combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
panel->Controls->Add(label);
panel->Controls->Add(combobox);
@@ -639,13 +762,14 @@ public:
};
-class EditableDropdownNumberOption : public ConfigOptionBase
+class DropdownNumberOption : public ConfigOptionBase
{
public:
int _defaultVal;
std::vector _valueInts;
+ bool _editable;
- EditableDropdownNumberOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, int defaultVal, std::vector valueInts)
+ DropdownNumberOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, int defaultVal, std::vector valueInts, bool editable)
{
_iniVarName = iniVarName;
_iniSectionName = iniSectionName;
@@ -654,6 +778,7 @@ public:
_description = description;
_defaultVal = defaultVal;
_valueInts = valueInts;
+ _editable = editable;
}
virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip)
@@ -682,12 +807,21 @@ public:
combobox->Width = Col2Width;
combobox->AutoSize = true;
combobox->FlatStyle = System::Windows::Forms::FlatStyle::Flat;
- combobox->DropDownStyle = ComboBoxStyle::DropDown;
+
+ if (_editable)
+ combobox->DropDownStyle = ComboBoxStyle::DropDown;
+ else
+ combobox->DropDownStyle = ComboBoxStyle::DropDownList;
Form^ RootForm = panel->FindForm();
- Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
- float ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
- float ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ float ScaleWidth = 1.0f;
+ float ScaleHeight = 1.0f;
+ if (RootForm)
+ {
+ Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
+ ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
+ ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ }
label->Scale(ScaleWidth, ScaleHeight);
combobox->Scale(ScaleWidth, ScaleHeight);
@@ -698,9 +832,12 @@ public:
combobox->Leave += gcnew System::EventHandler(validation, &ComboboxValidation::CheckNumberLeave);
if (hasChanged == nullptr)
- hasChanged = new bool;
+ hasChanged = new bool(false);
ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged);
- combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
+ if (_editable)
+ combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
+ else
+ combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
panel->Controls->Add(label);
panel->Controls->Add(combobox);
@@ -729,8 +866,9 @@ public:
LPCWSTR _iniVarName2;
resolution _defaultVal;
std::vector _valueResolutions;
+ bool _editable;
- ResolutionOption(LPCWSTR iniVarName, LPCWSTR iniVarName2, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, resolution defaultVal, std::vector valueResolutions)
+ ResolutionOption(LPCWSTR iniVarName, LPCWSTR iniVarName2, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, resolution defaultVal, std::vector valueResolutions, bool editable)
{
_iniVarName = iniVarName;
_iniVarName2 = iniVarName2;
@@ -740,6 +878,7 @@ public:
_description = description;
_defaultVal = defaultVal;
_valueResolutions = valueResolutions;
+ _editable = editable;
}
virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip)
@@ -777,12 +916,21 @@ public:
combobox->Width = Col2Width;
combobox->AutoSize = true;
combobox->FlatStyle = System::Windows::Forms::FlatStyle::Flat;
- combobox->DropDownStyle = ComboBoxStyle::DropDown;
+
+ if (_editable)
+ combobox->DropDownStyle = ComboBoxStyle::DropDown;
+ else
+ combobox->DropDownStyle = ComboBoxStyle::DropDownList;
Form^ RootForm = panel->FindForm();
- Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
- float ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
- float ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ float ScaleWidth = 1.0f;
+ float ScaleHeight = 1.0f;
+ if (RootForm)
+ {
+ Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
+ ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
+ ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ }
label->Scale(ScaleWidth, ScaleHeight);
combobox->Scale(ScaleWidth, ScaleHeight);
@@ -790,9 +938,12 @@ public:
tooltip->SetToolTip(combobox, gcnew String(_description));
if (hasChanged == nullptr)
- hasChanged = new bool;
+ hasChanged = new bool(false);
ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged);
- combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
+ if (_editable)
+ combobox->TextChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
+ else
+ combobox->SelectedIndexChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
ComboboxValidation^ validation = gcnew ComboboxValidation(combobox);
combobox->Leave += gcnew System::EventHandler(validation, &ComboboxValidation::CheckResolutionLeave);
@@ -823,4 +974,209 @@ public:
WritePrivateProfileStringW(_iniSectionName, _iniVarName2, tempWStr.c_str(), _iniFilePath);
}
-};
\ No newline at end of file
+};
+
+
+class ButtonOption : public ConfigOptionBase
+{
+public:
+ void(*_func)();
+
+ ButtonOption(LPCWSTR friendlyName, LPCWSTR description, void(*func)())
+ {
+ _friendlyName = friendlyName;
+ _description = description;
+ _func = func;
+ }
+
+ virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip)
+ {
+ Button^ button = gcnew Button();
+
+ button->Text = gcnew String(_friendlyName);
+ button->Left = left;
+ button->Top = top;
+ button->AutoSize = true;
+ button->FlatStyle = System::Windows::Forms::FlatStyle::Flat;
+
+ Form^ RootForm = panel->FindForm();
+ float ScaleWidth = 1.0f;
+ float ScaleHeight = 1.0f;
+ if (RootForm)
+ {
+ Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
+ ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
+ ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ }
+ button->Scale(ScaleWidth, ScaleHeight);
+
+ tooltip->SetToolTip(button, gcnew String(_description));
+
+ CustomFuncHandler^ funchandler = gcnew CustomFuncHandler(_func);
+ button->Click += gcnew System::EventHandler(funchandler, &CustomFuncHandler::RunFunc);
+
+ panel->Controls->Add(button);
+
+ int ControlHeight = button->Height / ScaleHeight;
+ return ControlHeight + ControlSpacing;
+ }
+};
+
+
+class PluginOption : public ConfigOptionBase
+{
+public:
+ bool _defaultVal;
+ std::vector _configopts;
+
+ PluginOption(LPCWSTR iniVarName, LPCWSTR iniSectionName, LPCWSTR iniFilePath, LPCWSTR friendlyName, LPCWSTR description, bool defaultVal, std::vector configopts)
+ {
+ _iniVarName = iniVarName;
+ _iniSectionName = iniSectionName;
+ _iniFilePath = iniFilePath;
+ _friendlyName = friendlyName;
+ _description = description;
+ _defaultVal = defaultVal;
+ _configopts = configopts;
+ }
+
+ virtual int AddToPanel(Panel^ panel, unsigned int left, unsigned int top, ToolTip^ tooltip)
+ {
+ CheckBox^ cb = gcnew CheckBox();
+ Button^ button = gcnew Button();
+
+ cb->Text = gcnew String(_friendlyName);
+ cb->Checked = GetPrivateProfileBoolW(_iniSectionName, _iniVarName, _defaultVal, _iniFilePath);
+ cb->Left = left + 2;
+ cb->Top = top + 3;
+ cb->AutoSize = true;
+ cb->FlatStyle = System::Windows::Forms::FlatStyle::Flat;
+
+ // hack to ensure high contrast
+ cb->BackColor = System::Drawing::Color::FromArgb(0, 0, 0, 0);
+
+ button->Text = L"Config";
+ button->Left = left + ConfigBtnLeft;
+ button->Top = top;
+ button->AutoSize = true;
+ button->FlatStyle = System::Windows::Forms::FlatStyle::Flat;
+
+ Form^ RootForm = panel->FindForm();
+ float ScaleWidth = 1.0f;
+ float ScaleHeight = 1.0f;
+ if (RootForm)
+ {
+ Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
+ ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
+ ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ }
+ cb->Scale(ScaleWidth, ScaleHeight);
+ button->Scale(ScaleWidth, ScaleHeight);
+
+ tooltip->SetToolTip(cb, gcnew String(_description));
+
+ if (hasChanged == nullptr)
+ hasChanged = new bool(false);
+ ChangeHandler^ changehandler = gcnew ChangeHandler(hasChanged);
+ cb->CheckedChanged += gcnew System::EventHandler(changehandler, &ChangeHandler::SetChanged);
+
+ panel->Controls->Add(cb);
+ mainControlHandle = cb->Handle;
+
+ if (_configopts.size() > 0)
+ {
+ ToolTip^ paneltooltip = gcnew ToolTip();
+ Panel^ configPanel = MakePanel((Col2Left + Col2Width + 64), 250, _configopts, paneltooltip, hasChanged);
+ configPanel->Scale(ScaleWidth, ScaleHeight);
+ PluginConfigHandler^ confighandler = gcnew PluginConfigHandler(configPanel, gcnew String(_friendlyName) + " Options");
+ button->Click += gcnew System::EventHandler(confighandler, &PluginConfigHandler::OpenForm);
+
+ panel->Controls->Add(button);
+ }
+
+ int ControlHeight = button->Height / ScaleHeight;
+ return ControlHeight + ControlSpacing;
+ }
+
+ virtual void SaveOption()
+ {
+ bool boolEnabled = ((CheckBox^)CheckBox::FromHandle(mainControlHandle))->Checked;
+
+ WritePrivateProfileStringW(_iniSectionName, _iniVarName, boolEnabled ? L"1" : L"0", _iniFilePath);
+
+ for (ConfigOptionBase* opt : _configopts)
+ {
+ opt->SaveOption();
+ }
+ }
+};
+
+
+Panel^ MakePanel(int width, int height, std::vector &cfg, ToolTip^ tooltip, bool* hasChanged)
+{
+ Panel^ outpanel = gcnew Panel();
+ outpanel->Width = width;
+ outpanel->Height = height;
+ outpanel->AutoScroll = true;
+
+ Form^ RootForm = outpanel->FindForm();
+ float ScaleWidth = 1.0f;
+ float ScaleHeight = 1.0f;
+ if (RootForm)
+ {
+ Drawing::SizeF CurrentScaleSize = RootForm->CurrentAutoScaleDimensions;
+ ScaleWidth = CurrentScaleSize.Width / BaseScaleSize;
+ ScaleHeight = CurrentScaleSize.Height / BaseScaleSize;
+ }
+
+ int curX = 12;
+ int curY = 3;
+
+ for (int i = 0; i < cfg.size(); i++)
+ {
+ if (typeid(*cfg[i]).hash_code() == typeid(OptionMetaGroupEnd).hash_code())
+ continue;
+
+ if (typeid(*cfg[i]).hash_code() == typeid(OptionMetaGroupStart).hash_code())
+ {
+ OptionMetaGroupStart* groupData = (OptionMetaGroupStart*)(cfg[i]);
+ GroupBox^ groupbox = gcnew GroupBox();
+ groupbox->Width = width - (ScaleWidth * 8);
+ groupbox->Height = ScaleHeight * groupData->_height;
+ groupbox->Left = ScaleWidth * 4;
+ groupbox->Top = ScaleHeight * curY;
+ groupbox->Text = gcnew String(groupData->_friendlyName);
+
+ // find the end of this group by simple iteration keeping track of indent level
+ int level = 1;
+ int endidx;
+ for (endidx = i + 1; endidx < cfg.size(); endidx++)
+ {
+ if (typeid(*cfg[endidx]).hash_code() == typeid(OptionMetaGroupStart).hash_code())
+ level++;
+ if (typeid(*cfg[endidx]).hash_code() == typeid(OptionMetaGroupEnd).hash_code())
+ level--;
+
+ if (level == 0)
+ break;
+ }
+
+ Panel^ groupPanel = MakePanel(groupbox->Width - (ScaleWidth * 8), groupbox->Height - (ScaleHeight * 10), std::vector(&(cfg[i + 1]), &(cfg[endidx])), tooltip, hasChanged);
+ groupPanel->Left = ScaleWidth * 12;
+ groupPanel->Top = ScaleHeight * (curY + 8);
+
+ groupbox->Controls->Add(groupPanel);
+ outpanel->Controls->Add(groupbox);
+
+ i = endidx;
+ curY += groupData->_height;
+ }
+ else
+ {
+ cfg[i]->hasChanged = hasChanged;
+ curY += cfg[i]->AddToPanel(outpanel, curX, curY, tooltip);
+ }
+ }
+
+ return outpanel;
+}
\ No newline at end of file
diff --git a/source-code/source/plugins/Launcher/Launcher.vcxproj b/source-code/source/plugins/Launcher/Launcher.vcxproj
index d4e6170..f8c2f87 100644
--- a/source-code/source/plugins/Launcher/Launcher.vcxproj
+++ b/source-code/source/plugins/Launcher/Launcher.vcxproj
@@ -167,6 +167,8 @@
+
+
diff --git a/source-code/source/plugins/Launcher/PluginConfig.h b/source-code/source/plugins/Launcher/PluginConfig.h
new file mode 100644
index 0000000..b2d3e35
--- /dev/null
+++ b/source-code/source/plugins/Launcher/PluginConfig.h
@@ -0,0 +1,71 @@
+#pragma once
+#include "ConfigOption.h"
+#include "PluginConfigApi.h"
+
+namespace PluginConfig
+{
+ ConfigOptionBase* GetConfigOption(PluginConfigOption cfg)
+ {
+ PluginConfigBooleanData* boolData = (PluginConfigBooleanData*)(cfg.data);
+ PluginConfigNumericData* numericData = (PluginConfigNumericData*)(cfg.data);
+ PluginConfigStringData* stringData = (PluginConfigStringData*)(cfg.data);
+ PluginConfigDropdownIndexData* ddIdxData = (PluginConfigDropdownIndexData*)(cfg.data);
+ PluginConfigDropdownTextData* ddTextData = (PluginConfigDropdownTextData*)(cfg.data);
+ PluginConfigDropdownNumberData* ddNumberData = (PluginConfigDropdownNumberData*)(cfg.data);
+ PluginConfigResolutionData* resData = (PluginConfigResolutionData*)(cfg.data);
+ PluginConfigGroupData* groupData = (PluginConfigGroupData*)(cfg.data);
+ PluginConfigButtonData* btnData = (PluginConfigButtonData*)(cfg.data);
+ PluginConfigSpacerData* spacerData = (PluginConfigSpacerData*)(cfg.data);
+
+ switch (cfg.cfgType)
+ {
+ case CONFIG_BOOLEAN:
+ return new BooleanOption(boolData->iniVarName, boolData->iniSectionName, boolData->iniFilePath, boolData->friendlyName, boolData->description, boolData->defaultVal, boolData->saveAsString);
+ case CONFIG_NUMERIC:
+ return new NumericOption(numericData->iniVarName, numericData->iniSectionName, numericData->iniFilePath, numericData->friendlyName, numericData->description, numericData->defaultVal, numericData->minVal, numericData->maxVal);
+ case CONFIG_STRING:
+ return new StringOption(stringData->iniVarName, stringData->iniSectionName, stringData->iniFilePath, stringData->friendlyName, stringData->description, stringData->defaultVal, stringData->useUtf8);
+ case CONFIG_DROPDOWN_INDEX:
+ return new DropdownOption(ddIdxData->iniVarName, ddIdxData->iniSectionName, ddIdxData->iniFilePath, ddIdxData->friendlyName, ddIdxData->description, ddIdxData->defaultVal, ddIdxData->valueStrings);
+ case CONFIG_DROPDOWN_TEXT:
+ return new DropdownTextOption(ddTextData->iniVarName, ddTextData->iniSectionName, ddTextData->iniFilePath, ddTextData->friendlyName, ddTextData->description, ddTextData->defaultVal, ddTextData->valueStrings, ddTextData->editable, ddTextData->useUtf8);
+ case CONFIG_DROPDOWN_NUMBER:
+ return new DropdownNumberOption(ddNumberData->iniVarName, ddNumberData->iniSectionName, ddNumberData->iniFilePath, ddNumberData->friendlyName, ddNumberData->description, ddNumberData->defaultVal, ddNumberData->valueInts, ddNumberData->editable);
+ case CONFIG_RESOLUTION:
+ return new ResolutionOption(resData->iniVarName, resData->iniVarName2, resData->iniSectionName, resData->iniFilePath, resData->friendlyName, resData->description, resData->defaultVal, resData->valueResolutions, resData->editable);
+ case CONFIG_GROUP_START:
+ return new OptionMetaGroupStart(groupData->name, groupData->height);
+ case CONFIG_GROUP_END:
+ return new OptionMetaGroupEnd();
+ case CONFIG_BUTTON:
+ return new ButtonOption(btnData->friendlyName, btnData->description, btnData->func);
+ case CONFIG_SPACER:
+ return new OptionMetaSpacer(spacerData->height);
+ default:
+ return new ConfigOptionBase();
+ }
+ }
+
+ std::vector GetConfigOptionVec(PluginConfigArray &in)
+ {
+ std::vector outvec;
+ for (int i = 0; i < in.len; i++)
+ {
+ // basic check for validity
+ if (in.options[i].data == nullptr)
+ break;
+
+ outvec.push_back(GetConfigOption(in.options[i]));
+ }
+ return outvec;
+ }
+
+ /*std::vector testcfg =
+ {
+ PluginConfigOption{ CONFIG_GROUP_START, new PluginConfigGroupData{L"Screen Resolution", 400 } },
+ PluginConfigOption{ CONFIG_DROPDOWN_INDEX, new PluginConfigDropdownIndexData{ L"display", RESOLUTION_SECTION, CONFIG_FILE, L"Display:", L"Sets the window/screen mode.", 0, std::vector({ L"Windowed", L"Borderless", L"Fullscreen" }) } },
+ PluginConfigOption{ CONFIG_RESOLUTION, new PluginConfigResolutionData{ L"width", L"height", RESOLUTION_SECTION, CONFIG_FILE, L"Resolution:", L"Sets the display resolution.", resolution(1280, 720), getScreenResolutionsVec(screenModes) } }
+ };*/
+
+ //std::vector testcfgconfigopts = GetConfigOptionVec(testcfg);
+};
\ No newline at end of file
diff --git a/source-code/source/plugins/Launcher/PluginConfigApi.h b/source-code/source/plugins/Launcher/PluginConfigApi.h
new file mode 100644
index 0000000..d0ffd94
--- /dev/null
+++ b/source-code/source/plugins/Launcher/PluginConfigApi.h
@@ -0,0 +1,168 @@
+#pragma once
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#include
+#include
+
+// resolution class to store and sort the width and height easily
+class resolution
+{
+public:
+ unsigned int width;
+ unsigned int height;
+
+ resolution()
+ {
+ width = 0;
+ height = 0;
+ }
+
+ resolution(unsigned int width, unsigned int height)
+ {
+ resolution::width = width;
+ resolution::height = height;
+ }
+
+ bool operator ==(const resolution &res2)
+ {
+ return width == res2.width && height == res2.height;
+ }
+
+ // in comparisons width takes priority because it's usually displayed first
+ bool operator <(const resolution &res2)
+ {
+ if (width == res2.width)
+ return height < res2.height;
+ else
+ return width < res2.width;
+ }
+ bool operator >(const resolution &res2)
+ {
+ if (width == res2.width)
+ return height > res2.height;
+ else
+ return width > res2.width;
+ }
+};
+
+namespace PluginConfig
+{
+#pragma pack(push, 1)
+ enum ConfigType {
+ CONFIG_BOOLEAN,
+ CONFIG_NUMERIC,
+ CONFIG_STRING,
+ CONFIG_DROPDOWN_INDEX,
+ CONFIG_DROPDOWN_TEXT,
+ CONFIG_DROPDOWN_NUMBER,
+ CONFIG_RESOLUTION,
+ CONFIG_GROUP_START,
+ CONFIG_GROUP_END,
+ CONFIG_BUTTON,
+ CONFIG_SPACER
+ };
+
+ struct PluginConfigBooleanData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ bool defaultVal;
+ bool saveAsString;
+ };
+
+ struct PluginConfigNumericData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ int defaultVal;
+ int minVal;
+ int maxVal;
+ };
+
+ struct PluginConfigStringData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ LPCWSTR defaultVal;
+ bool useUtf8;
+ };
+
+ struct PluginConfigDropdownIndexData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ int defaultVal;
+ std::vector valueStrings;
+ };
+
+ struct PluginConfigDropdownTextData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ LPCWSTR defaultVal;
+ std::vector valueStrings;
+ bool editable;
+ bool useUtf8;
+ };
+
+ struct PluginConfigDropdownNumberData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ int defaultVal;
+ std::vector valueInts;
+ bool editable;
+ };
+
+ struct PluginConfigResolutionData {
+ LPCWSTR iniVarName;
+ LPCWSTR iniVarName2;
+ LPCWSTR iniSectionName;
+ LPCWSTR iniFilePath;
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ resolution defaultVal;
+ std::vector valueResolutions;
+ bool editable;
+ };
+
+ struct PluginConfigGroupData
+ {
+ LPCWSTR name;
+ int height;
+ };
+
+ struct PluginConfigButtonData {
+ LPCWSTR friendlyName;
+ LPCWSTR description;
+ void(*func)();
+ };
+
+ struct PluginConfigSpacerData {
+ int height;
+ };
+
+ struct PluginConfigOption
+ {
+ ConfigType cfgType;
+ void* data;
+ };
+
+ struct PluginConfigArray
+ {
+ int len;
+ PluginConfigOption* options;
+ };
+#pragma pack(pop)
+}
\ No newline at end of file
diff --git a/source-code/source/plugins/Launcher/framework.h b/source-code/source/plugins/Launcher/framework.h
index 4d575e3..1579fc2 100644
--- a/source-code/source/plugins/Launcher/framework.h
+++ b/source-code/source/plugins/Launcher/framework.h
@@ -9,6 +9,7 @@
#include
#include "ConfigOption.h"
+#include "PluginConfig.h"
int (__cdecl* divaMain)(int argc, const char** argv, const char** envp) = (int(__cdecl*)(int argc, const char** argv, const char** envp))0x140194D90;
@@ -34,13 +35,15 @@ LPCWSTR DIVA_EXECUTABLE = DIVA_EXECUTABLE_STRING.c_str();
wstring DIVA_EXECUTABLE_LAUNCH_STRING = DIVA_EXECUTABLE_STRING + L" --launch";
LPWSTR DIVA_EXECUTABLE_LAUNCH = const_cast(DIVA_EXECUTABLE_LAUNCH_STRING.c_str());
-wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\config.ini";
+wstring PLUGINS_DIR = DirPath() + L"\\plugins";
+
+wstring CONFIG_FILE_STRING = PLUGINS_DIR + L"\\config.ini";
LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str();
-wstring COMPONENTS_FILE_STRING = DirPath() + L"\\plugins\\components.ini";
+wstring COMPONENTS_FILE_STRING = PLUGINS_DIR + L"\\components.ini";
LPCWSTR COMPONENTS_FILE = COMPONENTS_FILE_STRING.c_str();
-wstring PLAYERDATA_FILE_STRING = DirPath() + L"\\plugins\\playerdata.ini";
+wstring PLAYERDATA_FILE_STRING = PLUGINS_DIR + L"\\playerdata.ini";
LPCWSTR PLAYERDATA_FILE = PLAYERDATA_FILE_STRING.c_str();
LPCWSTR PATCHES_SECTION = L"patches";
@@ -124,17 +127,17 @@ std::vector screenModes = getScreenModes();
DropdownOption* DisplayModeDropdown = new DropdownOption(L"display", RESOLUTION_SECTION, CONFIG_FILE, L"Display:", L"Sets the window/screen mode.", 0, std::vector({ L"Windowed", L"Borderless", L"Fullscreen" }));
-ResolutionOption* DisplayResolutionOption = new ResolutionOption(L"width", L"height", RESOLUTION_SECTION, CONFIG_FILE, L"Resolution:", L"Sets the display resolution.", resolution(1280, 720), getScreenResolutionsVec(screenModes));
+ResolutionOption* DisplayResolutionOption = new ResolutionOption(L"width", L"height", RESOLUTION_SECTION, CONFIG_FILE, L"Resolution:", L"Sets the display resolution.", resolution(1280, 720), getScreenResolutionsVec(screenModes), true);
ConfigOptionBase* screenResolutionArray[] = {
DisplayModeDropdown,
DisplayResolutionOption,
- //new EditableDropdownNumberOption(L"bitdepth", RESOLUTION_SECTION, CONFIG_FILE, L"Bit Depth:", L"Sets the display bit depth.", 32, getScreenDepthsVec(screenModes)),
- new EditableDropdownNumberOption(L"refreshrate", RESOLUTION_SECTION, CONFIG_FILE, L"Refresh Rate:", L"Sets the display refresh rate.", 60, getScreenRatesVec(screenModes)),
+ //new DropdownNumberOption(L"bitdepth", RESOLUTION_SECTION, CONFIG_FILE, L"Bit Depth:", L"Sets the display bit depth.", 32, getScreenDepthsVec(screenModes), true),
+ new DropdownNumberOption(L"refreshrate", RESOLUTION_SECTION, CONFIG_FILE, L"Refresh Rate:", L"Sets the display refresh rate.", 60, getScreenRatesVec(screenModes), true),
};
BooleanOption* InternalResolutionCheckbox = new BooleanOption(L"r.enable", RESOLUTION_SECTION, CONFIG_FILE, L"Enable", L"Enable or disable custom internal resolution.", false, false);
-ResolutionOption* InternalResolutionOption = new ResolutionOption(L"r.width", L"r.height", RESOLUTION_SECTION, CONFIG_FILE, L"Resolution:", L"Sets the internal resolution.", resolution(1280, 720), std::vector({ resolution(640,480), resolution(800,600), resolution(960,720), resolution(1280,720), resolution(1600,900), resolution(1920,1080), resolution(2560,1440), resolution(3200,1800), resolution(3840,2160), resolution(5120,2880), resolution(6400,3600), resolution(7680,4320) }));
+ResolutionOption* InternalResolutionOption = new ResolutionOption(L"r.width", L"r.height", RESOLUTION_SECTION, CONFIG_FILE, L"Resolution:", L"Sets the internal resolution.", resolution(1280, 720), std::vector({ resolution(640,480), resolution(800,600), resolution(960,720), resolution(1280,720), resolution(1600,900), resolution(1920,1080), resolution(2560,1440), resolution(3200,1800), resolution(3840,2160), resolution(5120,2880), resolution(6400,3600), resolution(7680,4320) }), true);
ConfigOptionBase* internalResolutionArray[] = {
InternalResolutionCheckbox,
@@ -181,6 +184,7 @@ ConfigOptionBase* playerdataArray[] = {
new NumericOption(L"btn_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Button Sound:", L"Sets the sound effect for buttons.\n-1 = song default", -1, -1, INT_MAX),
new NumericOption(L"slide_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Slide Sound:", L"Sets the sound effect for slides.\n-1 = song default", -1, -1, INT_MAX),
new NumericOption(L"chainslide_se_equip", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Chainslide Sound:", L"Sets the sound effect for chain slides.\n-1 = song default", -1, -1, INT_MAX),
+ new BooleanOption(L"act_toggle", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Button SE", L"Enables button/slider sounds.", true, true),
new BooleanOption(L"border_great", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Clear Border (Great)", L"Shows the clear border for a great rating on the progress bar.", true, true),
new BooleanOption(L"border_excellent", PLAYERDATA_SECTION, PLAYERDATA_FILE, L"Clear Border (Excellent)", L"Shows the clear border for an excellent rating on the progress bar.", true, true),
@@ -265,6 +269,87 @@ void PrependFile(LPCSTR newStr, LPCWSTR fileName)
}
+struct PluginInfo {
+ HMODULE handle;
+ std::wstring filename;
+ std::wstring name;
+ std::wstring description;
+ std::vector configopts;
+};
+std::vector LoadPlugins()
+{
+ std::vector outvec;
+
+ HANDLE hFind;
+ WIN32_FIND_DATAW ffd;
+
+ hFind = FindFirstFileW((PLUGINS_DIR + L"\\*.dva").c_str(), &ffd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ auto pos = wcslen(ffd.cFileName);
+
+ if (ffd.cFileName[pos - 4] == '.' &&
+ (ffd.cFileName[pos - 3] == 'd' || ffd.cFileName[pos - 3] == 'D') &&
+ (ffd.cFileName[pos - 2] == 'v' || ffd.cFileName[pos - 2] == 'V') &&
+ (ffd.cFileName[pos - 1] == 'a' || ffd.cFileName[pos - 1] == 'A'))
+ {
+ PluginInfo thisplugin;
+ thisplugin.handle = LoadLibraryW((PLUGINS_DIR + L"\\" + ffd.cFileName).c_str());
+ thisplugin.filename = ffd.cFileName;
+
+ if (thisplugin.handle == NULL)
+ continue;
+
+ auto nameFunc = (LPCWSTR(*)())GetProcAddress(thisplugin.handle, "GetPluginName");
+ auto descFunc = (LPCWSTR(*)())GetProcAddress(thisplugin.handle, "GetPluginDescription");
+ auto optsFunc = (PluginConfig::PluginConfigArray(*)())GetProcAddress(thisplugin.handle, "GetPluginOptions");
+
+ if (nameFunc != NULL)
+ thisplugin.name = nameFunc();
+ else
+ thisplugin.name = thisplugin.filename;
+
+ if (descFunc != NULL)
+ thisplugin.description = descFunc();
+ else
+ thisplugin.description = (thisplugin.filename + L" Plugin").c_str();
+
+ if (optsFunc != NULL)
+ thisplugin.configopts = PluginConfig::GetConfigOptionVec(optsFunc());
+
+ // sometimes this might screw with custom button config, so let's just not free stuff
+ // FreeLibrary(thisplugin.handle);
+
+ outvec.push_back(thisplugin);
+ }
+ }
+ } while (FindNextFileW(hFind, &ffd));
+ FindClose(hFind);
+ }
+
+ return outvec;
+}
+// don't load until actually needed to avoid loading disabled plugins
+std::vector AllPlugins; // = LoadPlugins();
+
+std::vector GetPluginOptions(std::vector* plugins)
+{
+ std::vector outvec;
+
+ for (PluginInfo &pi : *plugins)
+ {
+ PluginOption* opt = new PluginOption(pi.filename.c_str(), L"plugins", CONFIG_FILE, pi.name.c_str(), pi.description.c_str(), true, pi.configopts);
+ outvec.push_back(opt);
+ }
+
+ return outvec;
+}
+// don't load until actually needed to avoid loading disabled plugins
+std::vector AllPluginOpts; // = GetPluginOptions(&AllPlugins);
+
+
// used to trick Optimus into switching to the NVIDIA GPU
HMODULE nvcudaModule = LoadLibraryW(L"nvcuda.dll");
// cuInit actually returns a CUresult, but we don't really care about it
diff --git a/source-code/source/plugins/Launcher/ui.h b/source-code/source/plugins/Launcher/ui.h
index 42b2d81..d49e2da 100644
--- a/source-code/source/plugins/Launcher/ui.h
+++ b/source-code/source/plugins/Launcher/ui.h
@@ -6,6 +6,7 @@
#include
#include
#include "SkinnedMessageBox.h"
+#include "PluginConfig.h"
namespace Launcher {
@@ -90,6 +91,7 @@ namespace Launcher {
this->panel_Patches->PerformLayout();
+
this->panel_Playerdata->SuspendLayout();
// populate playerdata options from array in framework
@@ -118,6 +120,20 @@ namespace Launcher {
this->panel_Components->PerformLayout();
+ AllPlugins = LoadPlugins();
+ AllPluginOpts = GetPluginOptions(&AllPlugins);
+
+ this->panel_Plugins->SuspendLayout();
+
+ int pluginsY = 3;
+ for (ConfigOptionBase* option : AllPluginOpts)
+ {
+ option->hasChanged = ConfigHasChanged;
+ pluginsY += option->AddToPanel(panel_Plugins, 12, pluginsY, toolTip1);
+ }
+ this->panel_Plugins->ResumeLayout(false);
+ this->panel_Plugins->PerformLayout();
+
// trick Optimus into switching to the NVIDIA GPU
if (cuInit != NULL) cuInit(0);
@@ -176,6 +192,8 @@ namespace Launcher {
private: System::Windows::Forms::Panel^ panel_Components;
private: System::Windows::Forms::TabPage^ tabPage_Patches;
private: System::Windows::Forms::Panel^ panel_Patches;
+ private: System::Windows::Forms::TabPage^ tabPage_Plugins;
+ private: System::Windows::Forms::Panel^ panel_Plugins;
private: System::Windows::Forms::Button^ button_Discord;
private: System::Windows::Forms::Button^ button_github;
private: System::Windows::Forms::TabPage^ tabPage_Playerdata;
@@ -231,6 +249,8 @@ namespace Launcher {
this->panel_Playerdata = (gcnew System::Windows::Forms::Panel());
this->tabPage_Components = (gcnew System::Windows::Forms::TabPage());
this->panel_Components = (gcnew System::Windows::Forms::Panel());
+ this->tabPage_Plugins = (gcnew System::Windows::Forms::TabPage());
+ this->panel_Plugins = (gcnew System::Windows::Forms::Panel());
this->button_Discord = (gcnew System::Windows::Forms::Button());
this->button_github = (gcnew System::Windows::Forms::Button());
this->toolTip1 = (gcnew System::Windows::Forms::ToolTip(this->components));
@@ -242,6 +262,7 @@ namespace Launcher {
this->tabPage_Patches->SuspendLayout();
this->tabPage_Playerdata->SuspendLayout();
this->tabPage_Components->SuspendLayout();
+ this->tabPage_Plugins->SuspendLayout();
this->SuspendLayout();
//
// button_Launch
@@ -299,6 +320,7 @@ namespace Launcher {
this->tabControl->Controls->Add(this->tabPage_Patches);
this->tabControl->Controls->Add(this->tabPage_Playerdata);
this->tabControl->Controls->Add(this->tabPage_Components);
+ this->tabControl->Controls->Add(this->tabPage_Plugins);
this->tabControl->Location = System::Drawing::Point(0, 0);
this->tabControl->Margin = System::Windows::Forms::Padding(4);
this->tabControl->Name = L"tabControl";
@@ -420,6 +442,28 @@ namespace Launcher {
this->panel_Components->Size = System::Drawing::Size(429, 425);
this->panel_Components->TabIndex = 0;
//
+ // tabPage_Plugins
+ //
+ this->tabPage_Plugins->BackColor = System::Drawing::Color::FromArgb(static_cast(static_cast(64)),
+ static_cast(static_cast(64)), static_cast(static_cast(64)));
+ this->tabPage_Plugins->Controls->Add(this->panel_Plugins);
+ this->tabPage_Plugins->Location = System::Drawing::Point(4, 32);
+ this->tabPage_Plugins->Margin = System::Windows::Forms::Padding(4);
+ this->tabPage_Plugins->Name = L"tabPage_Plugins";
+ this->tabPage_Plugins->Padding = System::Windows::Forms::Padding(4);
+ this->tabPage_Plugins->Size = System::Drawing::Size(433, 429);
+ this->tabPage_Plugins->TabIndex = 3;
+ this->tabPage_Plugins->Text = L"Plugins";
+ //
+ // panel_Plugins
+ //
+ this->panel_Plugins->AutoScroll = true;
+ this->panel_Plugins->Location = System::Drawing::Point(0, 0);
+ this->panel_Plugins->Margin = System::Windows::Forms::Padding(4);
+ this->panel_Plugins->Name = L"panel_Plugins";
+ this->panel_Plugins->Size = System::Drawing::Size(429, 425);
+ this->panel_Plugins->TabIndex = 0;
+ //
// button_Discord
//
this->button_Discord->BackColor = System::Drawing::Color::Transparent;
@@ -504,6 +548,7 @@ namespace Launcher {
this->tabPage_Patches->ResumeLayout(false);
this->tabPage_Playerdata->ResumeLayout(false);
this->tabPage_Components->ResumeLayout(false);
+ this->tabPage_Plugins->ResumeLayout(false);
this->ResumeLayout(false);
}
@@ -533,6 +578,11 @@ private: System::Void SaveSettings() {
{
component->SaveOption();
}
+
+ for (ConfigOptionBase* option : AllPluginOpts)
+ {
+ option->SaveOption();
+ }
}
private: System::Void Ui_Load(System::Object^ sender, System::EventArgs^ e){
}
diff --git a/source-code/source/plugins/TLAC/Components/CustomPlayerData.h b/source-code/source/plugins/TLAC/Components/CustomPlayerData.h
index c8a156e..cd5efbf 100644
--- a/source-code/source/plugins/TLAC/Components/CustomPlayerData.h
+++ b/source-code/source/plugins/TLAC/Components/CustomPlayerData.h
@@ -16,5 +16,6 @@ namespace TLAC::Components
bool ShowExcellentClearBorder;
bool UseCard;
bool GameModifierOptions;
+ bool ActionSE;
};
}
diff --git a/source-code/source/plugins/TLAC/Components/PlayerDataManager.cpp b/source-code/source/plugins/TLAC/Components/PlayerDataManager.cpp
index 5154382..0ed96e8 100644
--- a/source-code/source/plugins/TLAC/Components/PlayerDataManager.cpp
+++ b/source-code/source/plugins/TLAC/Components/PlayerDataManager.cpp
@@ -237,6 +237,7 @@ namespace TLAC::Components
customPlayerData->ShowGreatClearBorder = config.GetBooleanValue("border_great");
customPlayerData->UseCard = config.GetBooleanValue("use_card");
customPlayerData->GameModifierOptions = config.GetBooleanValue("gamemode_options");
+ customPlayerData->ActionSE = config.GetBooleanValue("act_toggle");
moduleCardWorkaround = config.GetBooleanValue("module_card_workaround");
if (moduleCardWorkaround) {
@@ -313,15 +314,14 @@ namespace TLAC::Components
setIfNotEqual(&playerData->btn_se_equip, customPlayerData->BtnSeEquip, -1);
setIfNotEqual(&playerData->slide_se_equip, customPlayerData->SlideSeEquip, -1);
setIfNotEqual(&playerData->chainslide_se_equip, customPlayerData->ChainslideSeEquip, -1);
+ setIfNotEqual(&playerData->act_toggle, customPlayerData->ActionSE, 1);
// Display clear borders on the progress bar
*(byte*)(PLAYER_DATA_ADDRESS + 0xD94) = (customPlayerData->ShowExcellentClearBorder << 1) | (customPlayerData->ShowGreatClearBorder);
- if (customPlayerData->UseCard)
- playerData->use_card = 1; // required to allow for module selection
+ playerData->use_card = customPlayerData->UseCard; // required to allow for module selection
- if (customPlayerData->GameModifierOptions)
- playerData->game_opts = 1; // hi-speed, etc..
+ playerData->game_opts = customPlayerData->GameModifierOptions; // hi-speed, etc..
memset((void*)MODULE_TABLE_START, 0xFF, 128);
memset((void*)ITEM_TABLE_START, 0xFF, 128);