Initial refactoring (WARNING: largely untested)

This commit is contained in:
nastys
2021-09-18 19:45:08 +02:00
parent e37d2833b4
commit def9581d75
24 changed files with 1096 additions and 689 deletions
@@ -204,7 +204,7 @@ extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void)
extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void)
{
return L"DivaMovie Plugin by Skyth\n\nDivaMovie enables movies on systems that does not support DXVA hardware decoding.";
return L"DivaMovie Plugin by Skyth\n\nDivaMovie enables movies on systems that do not support DXVA hardware decoding.";
}
extern "C" __declspec(dllexport) PluginConfig::PluginConfigArray GetPluginOptions(void)
@@ -19,6 +19,7 @@
<ProjectGuid>{2394C586-F73B-4EF2-BA3E-2A0FC3034B1A}</ProjectGuid>
<RootNamespace>DivaWig</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>CustoMixer</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+171 -20
View File
@@ -1,5 +1,5 @@
#include "framework.h"
#include "PluginConfigApi.h"
#include "framework.h"
#include <detours.h>
#include <string>
#include <iostream>
@@ -52,20 +52,163 @@ unsigned int last_unload_a2 = 0, last_reload_a2 = 0;
__int64 last_unload_a3 = 0, last_reload_a3 = 0;*/
bool dobeep = true, allowReloading = true, debug = false;
int nNoHandScaling, nDefaultHandSize, nSingMissed, nForceMouth, nForceExpressions, nForceLook;
void loadConfig()
{
dobeep = GetPrivateProfileIntW(L"general", L"beep", 1, CONFIG_FILE) > 0 ? true : false;
allowReloading = GetPrivateProfileIntW(L"general", L"reloading", 0, CONFIG_FILE) > 0 ? true : false;
{
dobeep = GetPrivateProfileIntW(L"wig", L"beep", 1, CONFIG_FILE) > 0 ? true : false;
allowReloading = GetPrivateProfileIntW(L"wig", L"reloading", 0, CONFIG_FILE) > 0 ? true : false;
debug = GetPrivateProfileIntW(L"general", L"debug", 0, CONFIG_FILE) > 0 ? true : false;
nSingMissed = GetPrivateProfileIntW(L"patches", L"sing_missed", FALSE, CONFIG_FILE) > 0 ? true : false;
nNoHandScaling = GetPrivateProfileIntW(L"patches", L"no_hand_scaling", FALSE, CONFIG_FILE) > 0 ? true : false;
nDefaultHandSize = GetPrivateProfileIntW(L"patches", L"default_hand_size", -1, CONFIG_FILE);
nForceMouth = GetPrivateProfileIntW(L"patches", L"force_mouth", 0, CONFIG_FILE);
nForceExpressions = GetPrivateProfileIntW(L"patches", L"force_expressions", 0, CONFIG_FILE);
nForceLook = GetPrivateProfileIntW(L"patches", L"force_look", 0, CONFIG_FILE);
return;
}
void pvPatches()
{
cout << "[CustoMixer] Applying PV patches..." << endl;
// Sing missed notes
if (nSingMissed)
{
InjectCode((void*)0x140109044, { 0xEB });
// Breaks border:
// InjectCode((void*)0x140109096, { 0xEB });
}
// Force mouth animations
{
if (nForceMouth == 1) // PDA
{
printf("[Patches] Forcing PDA mouth...\n");
int* mouth_table = (int*)(0x1409A1DC0);
DWORD oldProtect;
VirtualProtect(mouth_table, 44, PAGE_EXECUTE_READWRITE, &oldProtect);
for (int i = 0; i < 11; i++)
{
mouth_table[i]++;
}
VirtualProtect(mouth_table, 44, oldProtect, nullptr);
printf("[Patches] PDA mouth forced\n");
}
else if (nForceMouth == 2) // FT
{
printf("[Patches] Forcing FT mouth...\n");
int* mouth_table_oldid = (int*)(0x1409A1E1C);
DWORD oldProtect;
VirtualProtect(mouth_table_oldid, 44, PAGE_EXECUTE_READWRITE, &oldProtect);
for (int i = 0; i < 11; i++)
{
mouth_table_oldid[i]--;
}
VirtualProtect(mouth_table_oldid, 44, oldProtect, nullptr);
printf("[Patches] FT mouth forced\n");
}
}
// Force expressions
{
if (nForceExpressions == 1) // PDA
{
printf("[Patches] Forcing PDA expressions...\n");
int* exp_table = (int*)(0x140A21900);
DWORD oldProtect;
VirtualProtect(exp_table, 104, PAGE_EXECUTE_READWRITE, &oldProtect);
for (int i = 0; i < 26; i++)
{
exp_table[i] += 2;
}
VirtualProtect(exp_table, 104, oldProtect, nullptr);
printf("[Patches] PDA expressions forced\n");
}
else if (nForceExpressions == 2) // FT
{
printf("[Patches] Forcing FT expressions...\n");
int* exp_table_oldid = (int*)(0x140A219D0);
DWORD oldProtect;
VirtualProtect(exp_table_oldid, 104, PAGE_EXECUTE_READWRITE, &oldProtect);
for (int i = 0; i < 26; i++)
{
exp_table_oldid[i] -= 2;
}
VirtualProtect(exp_table_oldid, 104, oldProtect, nullptr);
printf("[Patches] FT expressions forced\n");
}
}
// Force look animations
{
if (nForceLook == 1) // PDA
{
printf("[Patches] Forcing PDA look...\n");
int* look_table = (int*)(0x1409A1D70);
DWORD oldProtect;
VirtualProtect(look_table, 36, PAGE_EXECUTE_READWRITE, &oldProtect);
for (int i = 0; i < 9; i++)
{
look_table[i]++;
}
VirtualProtect(look_table, 36, oldProtect, nullptr);
printf("[Patches] PDA look forced\n");
}
else if (nForceLook == 2) // FT
{
printf("[Patches] Forcing FT look...\n");
int* look_table_oldid = (int*)(0x1409A1D9C);
DWORD oldProtect;
VirtualProtect(look_table_oldid, 36, PAGE_EXECUTE_READWRITE, &oldProtect);
for (int i = 0; i < 9; i++)
{
look_table_oldid[i]--;
}
VirtualProtect(look_table_oldid, 36, oldProtect, nullptr);
printf("[Patches] FT look forced\n");
}
}
// Disable hand scaling
if (nNoHandScaling)
{
InjectCode((void*)0x0000000140120709, { 0xE9, 0x82, 0x0A, 0x00 });
}
// Default hand size
if (nDefaultHandSize != -1 && nDefaultHandSize < 1)
{
MessageBoxW(nullptr, L"The default hand size is lower than 1 and higher than -1 (default). Hands may disappear.\n\nIf this is not intentional, set it back to -1.", L"CustoMixer", MB_ICONWARNING);
printf("[Patches] Changing default hand size...\n");
const float num = (float)nDefaultHandSize / 10000.0;
DWORD oldProtect;
float* addr1 = (float*)(0x140506B59);
float* addr2 = (float*)(0x140506B60);
/*float* addr3 = (float*)(0x140506B67);
float* addr4 = (float*)(0x140506B71);*/
VirtualProtect(addr1, 4, PAGE_EXECUTE_READWRITE, &oldProtect);
VirtualProtect(addr2, 4, PAGE_EXECUTE_READWRITE, &oldProtect);
/*VirtualProtect(addr3, 4, PAGE_EXECUTE_READWRITE, &oldProtect);
VirtualProtect(addr4, 4, PAGE_EXECUTE_READWRITE, &oldProtect);*/
*addr1 = *addr2 /*= *addr3 = *addr4*/ = num;
VirtualProtect(addr1, 4, oldProtect, nullptr);
VirtualProtect(addr2, 4, oldProtect, nullptr);
/*VirtualProtect(addr3, 4, oldProtect, nullptr);
VirtualProtect(addr4, 4, oldProtect, nullptr);*/
printf("[Patches] New default hand size: %f\n", num);
}
cout << "[CustoMixer] PV patches applied." << endl;
}
void setPartToUpdate(char part, string message, unsigned short beepfreq)
{
part_to_update = part;
cout << "[DivaWig] " << message << endl;
cout << "[CustoMixer] " << message << endl;
if (dobeep) Beep(beepfreq, 300);
this_thread::sleep_for(chrono::seconds(1));
@@ -76,7 +219,7 @@ void unloadAll()
unloadFunc((uint64_t*)0x1411B7060, 0, 5387286240);
unloadFunc((uint64_t*)0x1411B7060, 0, 5387319280);
unloadFunc((uint64_t*)0x1411B7060, 0, 5387352320);
cout << "[DivaWig] All unloaded!" << endl;
cout << "[CustoMixer] All unloaded!" << endl;
if (dobeep) Beep(500, 100);
this_thread::sleep_for(chrono::seconds(1));;
}
@@ -84,7 +227,7 @@ void unloadAll()
void unload(__int64 performer_address)
{
unloadFunc((uint64_t*)0x1411B7060, 0, performer_address);
cout << "[DivaWig] Performer " << performer_address/33040 + 1 << " unloaded!" << endl;
cout << "[CustoMixer] Performer " << performer_address/33040 + 1 << " unloaded!" << endl;
if (dobeep) Beep(500, 100);
this_thread::sleep_for(chrono::seconds(1));;
}
@@ -94,7 +237,7 @@ void loadAll()
loadFunc((uint64_t*)0x1411B7060, 0, 5387286240);
loadFunc((uint64_t*)0x1411B7060, 0, 5387319280);
loadFunc((uint64_t*)0x1411B7060, 0, 5387352320);
cout << "[DivaWig] All loaded!" << endl;
cout << "[CustoMixer] All loaded!" << endl;
if (dobeep) Beep(600, 100);
this_thread::sleep_for(chrono::seconds(1));;
}
@@ -102,14 +245,14 @@ void loadAll()
void load(__int64 performer_address)
{
loadFunc((uint64_t*)0x1411B7060, 0, performer_address);
cout << "[DivaWig] Performer " << performer_address / 33040 + 1 << " loaded!" << endl;
cout << "[CustoMixer] Performer " << performer_address / 33040 + 1 << " loaded!" << endl;
if (dobeep) Beep(600, 100);
this_thread::sleep_for(chrono::seconds(1));
}
/*void hookedUnload(uint64_t* a1, unsigned int a2, __int64 a3)
{
cout << "[DivaWig] hookedUnload a1: " << a1 << "; a2: " << a2 << "; a3: " << a3 << endl;
cout << "[CustoMixer] hookedUnload a1: " << a1 << "; a2: " << a2 << "; a3: " << a3 << endl;
last_unload_a1 = a1;
last_unload_a2 = a2;
last_unload_a3 = a3;
@@ -118,7 +261,7 @@ void load(__int64 performer_address)
void hookedLoad(uint64_t* a1, unsigned int a2, __int64 a3)
{
cout << "[DivaWig] hookedReload a1: " << a1 << "; a2: " << a2 << "; a3: " << a3 << endl;
cout << "[CustoMixer] hookedReload a1: " << a1 << "; a2: " << a2 << "; a3: " << a3 << endl;
last_reload_a1 = a1;
last_reload_a2 = a2;
last_reload_a3 = a3;
@@ -163,7 +306,7 @@ void inputLoop(__int64 a1)
__int64 hookedWig(__int64 classp, int module_part, int part_id)
{
if (debug) cout << "[DivaWig] Performer: " << (classp-5387286232)/33040+1 << "; Module part: " << module_part << " (" << Strings[module_part] << ")" << "; Default part: " << part_id << "." << endl;
if (debug) cout << "[CustoMixer] Performer: " << (classp-5387286232)/33040+1 << "; Module part: " << module_part << " (" << Strings[module_part] << ")" << "; Default part: " << part_id << "." << endl;
if (part_to_update == ALL || part_to_update == module_part)
*(int*)(classp + 4i64 * module_part + 8) = part_id;
@@ -185,19 +328,19 @@ void hookedThi(unsigned int* a1, unsigned int module_part)
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
loadConfig();
pvPatches();
DisableThreadLibraryCalls(hModule);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
cout << "[DivaWig] Hooking functions..." << endl;
cout << "[CustoMixer] Hooking functions..." << endl;
DetourAttach(&(PVOID&)originalWig, (PVOID)hookedWig);
DetourAttach(&(PVOID&)originalSec, (PVOID)hookedSec);
DetourAttach(&(PVOID&)originalThi, (PVOID)hookedThi);
DetourAttach(&(PVOID&)pvTimerUpdate, (PVOID)inputLoop);
cout << "[DivaWig] Functions hooked." << endl;
cout << "[CustoMixer] Functions hooked." << endl;
DetourTransactionCommit();
/*if (allowReloading)
@@ -221,20 +364,28 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
return TRUE;
}
const std::vector<LPCWSTR> typeList = { L"Default", L"PDA", L"PDAFT/PDFT/PDM39" };
PluginConfig::PluginConfigOption config[] = {
{ PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"beep", L"general", CONFIG_FILE, L"Beep", L"Beep when selecting the part that should be updated.", true } },
{ PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"reloading", L"general", CONFIG_FILE, L"Unloading and loading (experimental)", L"Allow unloading (CTRL+U or U+number) and loading (CTRL+L or L+number).", false } },
{ PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"debug", L"general", CONFIG_FILE, L"Debug", L"Print extra information.", false } },
{ PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"beep", L"wig", CONFIG_FILE, L"Beep", L"Beep when selecting the part that should be updated.", true } },
{ PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"reloading", L"wig", CONFIG_FILE, L"Unloading and loading (experimental)", L"Allow unloading (CTRL+U or U+number) and loading (CTRL+L or L+number).", false } },
{ PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"sing_missed", L"patches", CONFIG_FILE, L"Sing Missed Notes", L"Sing Missed Notes.", false } },
{ PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"no_hand_scaling", L"patches", CONFIG_FILE, L"No Hand Scaling", L"Disable scripted hand scaling.", false } },
{ PluginConfig::CONFIG_NUMERIC, new PluginConfig::PluginConfigNumericData{ L"default_hand_size", L"patches", CONFIG_FILE, L"Default Hand Size:", L"-1: default\n12200: PDA", -1, -1, INT_MAX } },
{ PluginConfig::CONFIG_DROPDOWN_INDEX, new PluginConfig::PluginConfigDropdownIndexData{ L"force_mouth", L"patches", CONFIG_FILE, L"Mouth Animations:", L"Change the mouth animations.", 0, typeList}},
{ PluginConfig::CONFIG_DROPDOWN_INDEX, new PluginConfig::PluginConfigDropdownIndexData{ L"force_expressions", L"patches", CONFIG_FILE, L"Expr. Animations:", L"Change the expressions.", 0, typeList}},
{ PluginConfig::CONFIG_DROPDOWN_INDEX, new PluginConfig::PluginConfigDropdownIndexData{ L"force_look", L"patches", CONFIG_FILE, L"Look Animations:", L"Change the look animations.", 0, typeList}},
{ PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"debug", L"general", CONFIG_FILE, L"Debug", L"Print extra information.", false } },
};
extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void)
{
return L"DivaWig";
return L"CustoMixer";
}
extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void)
{
return L"DivaWig Plugin by nas\n\nDivaWig lets you mix some module parts by pressing CTRL+0~9.";
return L"CustoMixer Plugin by nas\n\nCustoMixer lets you change some PV settings, and mix module parts by pressing CTRL+0~9.";
}
extern "C" __declspec(dllexport) PluginConfig::PluginConfigArray GetPluginOptions(void)
+11 -1
View File
@@ -1,6 +1,16 @@
#include <windows.h>
#include <string>
void InjectCode(void* address, const std::vector<uint8_t> data)
{
const size_t byteCount = data.size() * sizeof(uint8_t);
DWORD oldProtect;
VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(address, data.data(), byteCount);
VirtualProtect(address, byteCount, oldProtect, nullptr);
}
std::wstring ExePath() {
WCHAR buffer[MAX_PATH];
GetModuleFileNameW(NULL, buffer, MAX_PATH);
@@ -13,5 +23,5 @@ std::wstring DirPath() {
return exepath.substr(0, pos);
}
std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\DivaWig.ini";
std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\CustoMixer.ini";
LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str();
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h" />
<ClInclude Include="PluginConfigApi.h" />
</ItemGroup>
</Project>
@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Minimalist|x64">
<Configuration>Minimalist</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{3C8071F4-22C8-DA6E-A075-C5EC646DAB7E}</ProjectGuid>
<RootNamespace>EnhancedStageManager</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Minimalist|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Minimalist|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetExt>.dva</TargetExt>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetExt>.dva</TargetExt>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Minimalist|x64'">
<TargetExt>.dva</TargetExt>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>-d2FH4- /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>-d2:-FH4- %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<AdditionalOptions>-d2FH4- /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalOptions>-d2:-FH4- %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Minimalist|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<AdditionalOptions>-d2FH4- /utf-8 %(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions>MINIMALIST;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalOptions>-d2:-FH4- %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h" />
<ClInclude Include="PluginConfigApi.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,168 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <vector>
// 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<LPCWSTR> valueStrings;
};
struct PluginConfigDropdownTextData {
LPCWSTR iniVarName;
LPCWSTR iniSectionName;
LPCWSTR iniFilePath;
LPCWSTR friendlyName;
LPCWSTR description;
LPCWSTR defaultVal;
std::vector<LPCWSTR> valueStrings;
bool editable;
bool useUtf8;
};
struct PluginConfigDropdownNumberData {
LPCWSTR iniVarName;
LPCWSTR iniSectionName;
LPCWSTR iniFilePath;
LPCWSTR friendlyName;
LPCWSTR description;
int defaultVal;
std::vector<int> valueInts;
bool editable;
};
struct PluginConfigResolutionData {
LPCWSTR iniVarName;
LPCWSTR iniVarName2;
LPCWSTR iniSectionName;
LPCWSTR iniFilePath;
LPCWSTR friendlyName;
LPCWSTR description;
resolution defaultVal;
std::vector<resolution> 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)
}
@@ -0,0 +1,76 @@
#include "PluginConfigApi.h"
#include "framework.h"
int nEStageManager, nEStageManagerEncore;
void loadConfig()
{
nEStageManager = GetPrivateProfileIntW(L"patches", L"enhanced_stage_manager", 0, CONFIG_FILE);
nEStageManagerEncore = GetPrivateProfileIntW(L"patches", L"enhanced_stage_manager_encore", FALSE, CONFIG_FILE) > 0 ? true : false;
if (nEStageManager < 1) nEStageManager = INT_MAX;
return;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
loadConfig();
//// TODO: rewrite without injecting assembly
// Replace the function that provides the number of stages and compact some of it
InjectCode((void*)0x000000014038AEF0, { 0x48, 0x8B, 0x88, 0x40, 0x01, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x20, 0x48, 0x8B, 0xD0, 0x48, 0x8B, 0x88, 0x48, 0x01, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x28, 0x8B, 0x88, 0x50, 0x01, 0x00, 0x00, 0x89, 0x4C, 0x24, 0x30, 0x8B, 0x88, 0x54, 0x01, 0x00, 0x00, 0x8B, 0x80, 0x58, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x38, 0x8B, 0x82, 0x5C, 0x01, 0x00, 0x00, 0x89, 0x4C, 0x24, 0x34, 0x89, 0x44, 0x24, 0x3C, 0x48, 0x8B, 0x82, 0x60, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x40, 0x48, 0x8B, 0x82, 0x68, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x48, 0x48, 0x8B, 0x82, 0x70, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x50, 0x8B, 0x82, 0x78, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x58, 0x84, 0xC0, 0x74, 0x2A, 0x48, 0x8B, 0x44, 0x24, 0x38, 0x48, 0xC1, 0xE8, 0x20, 0x85, 0xC0, 0x75, 0x1D, 0xE8, 0xD9, 0xD9, 0xE5, 0xFF, 0x48, 0x85, 0xC0, 0x74, 0x13, 0x48, 0x8D, 0x48, 0x10, 0xE8, 0xFB, 0xD3, 0xE5, 0xFF, 0xB9, 0x03, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x0F, 0x45, 0xD9, 0x8B, 0x1D, 0x1B, 0x0C, 0x00, 0x00, 0x83, 0x3D, 0x1C, 0x0C, 0x00, 0x00, 0x00, 0x74, 0x06, 0x8B, 0x1D, 0x10, 0x0C, 0x00, 0x00, 0x8B, 0xC3, 0x48, 0x83, 0xC4, 0x60, 0x5B, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC });
// Jump to another section by addding some code to replace the values (Jump 1)
InjectCode((void*)0x000000014038AFF4, { 0xE9, 0x87, 0x0B, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC });
// Jump to another section by addding some code to replace the values (Replace 1/2) while some reserving space for values
InjectCode((void*)0x000000014038BB40, { 0xFF, 0x05, 0x76, 0x00, 0x00, 0x00, 0x8B, 0x0D, 0x70, 0x00, 0x00, 0x00, 0xBA, 0x02, 0x00, 0x00, 0x00, 0x83, 0x3D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x74, 0x02, 0xFF, 0xC2, 0x39, 0xD1, 0x0F, 0x4D, 0xCA, 0x89, 0x48, 0x08, 0xB9, 0x0E, 0x00, 0x00, 0x00, 0xE8, 0x92, 0x98, 0xE0, 0xFF, 0xB0, 0x01, 0x48, 0x83, 0xC4, 0x28, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x44, 0x89, 0x61, 0x08, 0x44, 0x88, 0x61, 0x0C, 0x4C, 0x89, 0x61, 0x10, 0x44, 0x89, 0x25, 0x29, 0x00, 0x00, 0x00, 0xE9, 0x68, 0xF4, 0xFF, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
// Use the value from our own address instead of the original one
InjectCode((void*)0x00000001403F65AF, { 0x48, 0x8D, 0x05, 0x4A, 0x18, 0xDA, 0x00, 0x8B, 0x1D, 0x00, 0x56 });
// Jump to another section by addding some code to replace the values (Jump 2)
InjectCode((void*)0x00000001403F6638, { 0xE9, 0x03, 0x55, 0xF9, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC });
DWORD StageCountProtect;
VirtualProtect((int32_t*)0x14038BBB0, 0x10, PAGE_EXECUTE_READWRITE, &StageCountProtect);
int* ESM = (int*)0x000000014038BBB0;
if (nEStageManagerEncore)
ESM[1] = nEStageManager;
else
ESM[0] = nEStageManager;
ESM[2] = nEStageManagerEncore;
printf("[Patches] Enhanced Stage Manager enabled\n");
}
return TRUE;
}
PluginConfig::PluginConfigOption config[] = {
{ PluginConfig::CONFIG_NUMERIC, new PluginConfig::PluginConfigNumericData{ L"enhanced_stage_manager", L"patches", CONFIG_FILE, L"Stages:", L"Number of stages to play.\n\n0 = maximum", 0, 0, INT_MAX } },
{ PluginConfig::CONFIG_BOOLEAN, new PluginConfig::PluginConfigBooleanData{ L"enhanced_stage_manager_encore", L"patches", CONFIG_FILE, L"Encore", L"Enable Encore stages.", false } },
};
extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void)
{
return L"Enhanced Stages";
}
extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void)
{
return L"Allows you to play as many times in a row as you want.\n\nOriginal implementation by korenkonder.";
}
extern "C" __declspec(dllexport) PluginConfig::PluginConfigArray GetPluginOptions(void)
{
return PluginConfig::PluginConfigArray{ _countof(config), config };
}
@@ -0,0 +1,28 @@
#include <windows.h>
#include <string>
#include <vector>
void InjectCode(void* address, const std::vector<uint8_t> data)
{
const size_t byteCount = data.size() * sizeof(uint8_t);
DWORD oldProtect;
VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(address, data.data(), byteCount);
VirtualProtect(address, byteCount, oldProtect, nullptr);
}
std::wstring ExePath() {
WCHAR buffer[MAX_PATH];
GetModuleFileNameW(NULL, buffer, MAX_PATH);
return std::wstring(buffer);
}
std::wstring DirPath() {
std::wstring exepath = ExePath();
std::wstring::size_type pos = exepath.find_last_of(L"\\/");
return exepath.substr(0, pos);
}
std::wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\EnhancedStageManager.ini";
LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str();
@@ -98,21 +98,6 @@ Guest + Normal=Ospite + Normale
NO_SCROLLING_SFX_NAME=Disabilita suono di scorrimento
NO_SCROLLING_SFX_HINT=Disabilita l'effetto sonoro di scorrimento.
ENHANCED_STAGE_MANAGER_NAME=Numero di stage:
ENHANCED_STAGE_MANAGER_HINT=Imposta il numero di stage (Predefinito: 0).
ENHANCED_STAGE_MANAGER_ENCORE_NAME=Encore (bis)
ENHANCED_STAGE_MANAGER_ENCORE_HINT=Disabilita gli stage Encore.
FORCE_MOUTH_NAME=Stile labiale:
FORCE_MOUTH_HINT=Imposta le animazioni della bocca.
FORCE_EXPRESSIONS_NAME=Stile espressioni:
FORCE_EXPRESSIONS_HINT=Imposta le espressioni facciali.
FORCE_LOOK_NAME=Stile sguardo:
FORCE_LOOK_HINT=Imposta lo sguardo.
NO_HAND_SCALING_NAME=Non ridimensionare le mani
NO_HAND_SCALING_HINT=Disabilita la scalatura dinamica delle mani.
DEFAULT_HAND_SIZE_NAME=Dimensione mani predefinita
DEFAULT_HAND_SIZE_HINT=Predefinita: -1\nPDA: 12200
SING_MISSED_NAME=Canta note mancate
SING_MISSED_HINT=Canta le note mancate.
@@ -94,21 +94,6 @@ Guest + Normal=Hóspede + Normal
NO_SCROLLING_SFX_NAME=Desativar Som de Navegação
NO_SCROLLING_SFX_HINT=Desativa o som de navegação da lista de músicas.
ENHANCED_STAGE_MANAGER_NAME=Número de Estágios:
ENHANCED_STAGE_MANAGER_HINT=Configura o número de estágios (Padrão: 0).
ENHANCED_STAGE_MANAGER_ENCORE_NAME=Encore (Bis)
ENHANCED_STAGE_MANAGER_ENCORE_HINT=Habilita estágios Encore.
FORCE_MOUTH_NAME=Estilo da Boca:
FORCE_MOUTH_HINT=Muda as animações da boca dos personagens.
FORCE_EXPRESSIONS_NAME=Estilo de Expressões:
FORCE_EXPRESSIONS_HINT=Muda as expressões dos personagens.
FORCE_LOOK_NAME=Estilo dos Olhos:
FORCE_LOOK_HINT=Muda as animações dos olhos dos personagens.
NO_HAND_SCALING_NAME=Sem Escala das Mãos
NO_HAND_SCALING_HINT=Desativa a escala de tamanho das mãos dos personagens.
DEFAULT_HAND_SIZE_NAME=Tamanho das Mãos Padrão
DEFAULT_HAND_SIZE_HINT=Padrão: -1\nPDA: 12200
SING_MISSED_NAME=Cantar Notas Perdidas
SING_MISSED_HINT=Os vocais não vão parar ao perder notas.
@@ -88,21 +88,6 @@ QUICK_START_HINT=Skip one or more menus.
NO_SCROLLING_SFX_NAME=Disable Scrolling SFX
NO_SCROLLING_SFX_HINT=Disable the scrolling sound effect.
ENHANCED_STAGE_MANAGER_NAME=Number of Stages:
ENHANCED_STAGE_MANAGER_HINT=Set the number of stages (0 = default).
ENHANCED_STAGE_MANAGER_ENCORE_NAME=Encore
ENHANCED_STAGE_MANAGER_ENCORE_HINT=Enable encore stages.
FORCE_MOUTH_NAME=Mouth Type:
FORCE_MOUTH_HINT=Change the mouth animations.
FORCE_EXPRESSIONS_NAME=Expression Type:
FORCE_EXPRESSIONS_HINT=Change the expressions.
FORCE_LOOK_NAME=Look Type:
FORCE_LOOK_HINT=Change the look animations.
NO_HAND_SCALING_NAME=No Hand Scaling
NO_HAND_SCALING_HINT=Disable scripted hand scaling.
DEFAULT_HAND_SIZE_NAME=Default Hand Size:
DEFAULT_HAND_SIZE_HINT=-1: default\n12200: PDA
SING_MISSED_NAME=Sing Missed Notes
SING_MISSED_HINT=Sing missed notes.
@@ -84,21 +84,6 @@ Guest + Normal=访客模式+正常模式
NO_SCROLLING_SFX_NAME=停用滑动音效
NO_SCROLLING_SFX_HINT=停用在选歌界面的滑动音效
ENHANCED_STAGE_MANAGER_NAME=游玩次数:
ENHANCED_STAGE_MANAGER_HINT=设置一次投币 (游戏) 最多可以游玩的次数 (0 = 默认)
ENHANCED_STAGE_MANAGER_ENCORE_NAME=启用 EncoreStage
ENHANCED_STAGE_MANAGER_ENCORE_HINT=启用 Encore Stage\n(在 EncoreStage 下所有难度的歌曲最低达成率均为 80%)
FORCE_MOUTH_NAME=嘴部动作设定:
FORCE_MOUTH_HINT=调整模型的嘴部动作样式
FORCE_EXPRESSIONS_NAME=表情设定:
FORCE_EXPRESSIONS_HINT=调整模型的表情样式
FORCE_LOOK_NAME=外观设定:
FORCE_LOOK_HINT=调整外观样式
NO_HAND_SCALING_NAME=停用手部缩放
NO_HAND_SCALING_HINT=停用手部缩放
DEFAULT_HAND_SIZE_NAME=默认手部大小:
DEFAULT_HAND_SIZE_HINT=默认值:-1\nPDA:12200
SING_MISSED_NAME=停用停止歌唱
SING_MISSED_HINT=停用当 Note 判定为 Miss 时,歌姬暂停歌唱的功能
@@ -251,11 +251,9 @@ ConfigOptionBase* optionsArray[] = {
ConfigOptionBase* options2Array[] = {
new OptionMetaSectionLabel(L"SECTION_PV_SELECTOR"),
#ifndef MINIMALIST
new DropdownOption(L"quick_start", PATCHES_SECTION, CONFIG_FILE, L"QUICK_START_NAME", L"QUICK_START_HINT", 1, std::vector<LPCWSTR>({ L"Disabled", L"Guest", L"Guest + Normal" })),
#endif
new BooleanOption(L"freeplay", PATCHES_SECTION, CONFIG_FILE, L"FREEPLAY_NAME", L"FREEPLAY_HINT", true, false),
#ifndef MINIMALIST
new DropdownOption(L"quick_start", PATCHES_SECTION, CONFIG_FILE, L"QUICK_START_NAME", L"QUICK_START_HINT", 1, std::vector<LPCWSTR>({ L"Disabled", L"Guest", L"Guest + Normal" })),
new BooleanOption(L"no_scrolling_sfx", PATCHES_SECTION, CONFIG_FILE, L"NO_SCROLLING_SFX_NAME", L"NO_SCROLLING_SFX_HINT", false, false),
new BooleanOption(L"unlock_pseudo", PATCHES_SECTION, CONFIG_FILE, L"UNLOCK_PSEUDO_NAME", L"UNLOCK_PSEUDO_HINT", false, false),
#endif
@@ -263,11 +261,6 @@ ConfigOptionBase* options2Array[] = {
new OptionMetaSpacer(8),
new OptionMetaSectionLabel(L"SECTION_ESM"),
new NumericOption(L"Enhanced_Stage_Manager", PATCHES_SECTION, CONFIG_FILE, L"ENHANCED_STAGE_MANAGER_NAME", L"ENHANCED_STAGE_MANAGER_HINT", 0, 0, INT_MAX),
new BooleanOption(L"Enhanced_Stage_Manager_Encore", PATCHES_SECTION, CONFIG_FILE, L"ENHANCED_STAGE_MANAGER_ENCORE_NAME", L"ENHANCED_STAGE_MANAGER_ENCORE_HINT", true, false),
#ifndef MINIMALIST
new BooleanOption(L"sing_missed", PATCHES_SECTION, CONFIG_FILE, L"SING_MISSED_NAME", L"SING_MISSED_HINT", false, false),
#endif
new BooleanOption(L"autopause", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"AUTOPAUSE_NAME", L"AUTOPAUSE_HINT", true, true),
new OptionMetaSeparator(),
new OptionMetaSpacer(8),
@@ -290,19 +283,6 @@ ConfigOptionBase* options2Array[] = {
new BooleanOption(L"card", PATCHES_SECTION, CONFIG_FILE, L"CARD_NAME", L"CARD_HINT", false, false),
#endif
new BooleanOption(L"dwgui_scaling", PATCHES_SECTION, CONFIG_FILE, L"DWGUI_SCALING_NAME", L"DWGUI_SCALING_HINT", false, false),
#ifndef MINIMALIST
new OptionMetaSeparator(),
new OptionMetaSpacer(8),
new OptionMetaSectionLabel(L"SECTION_PV_PATCHES"),
new DropdownOption(L"force_mouth", PATCHES_SECTION, CONFIG_FILE, L"FORCE_MOUTH_NAME", L"FORCE_MOUTH_HINT", 0, std::vector<LPCWSTR>({ L"Default", L"Force PDA", L"Force FT" })),
new DropdownOption(L"force_expressions", PATCHES_SECTION, CONFIG_FILE, L"FORCE_EXPRESSIONS_NAME", L"FORCE_EXPRESSIONS_HINT", 0, std::vector<LPCWSTR>({ L"Default", L"Force PDA", L"Force FT" })),
new DropdownOption(L"force_look", PATCHES_SECTION, CONFIG_FILE, L"FORCE_LOOK_NAME", L"FORCE_LOOK_HINT", 0, std::vector<LPCWSTR>({ L"Default", L"Force PDA", L"Force FT" })),
new BooleanOption(L"no_hand_scaling", PATCHES_SECTION, CONFIG_FILE, L"NO_HAND_SCALING_NAME", L"NO_HAND_SCALING_HINT", false, false),
new NumericOption(L"default_hand_size", PATCHES_SECTION, CONFIG_FILE, L"DEFAULT_HAND_SIZE_NAME", L"DEFAULT_HAND_SIZE_HINT", -1, -1, INT_MAX),
new OptionMetaSeparator(),
new OptionMetaSpacer(8),
#endif
};
ConfigOptionBase* playerdataArray[] = {