Merge branch 'master' of somewhatlurker/PD-Loader into master
This commit is contained in:
@@ -145,32 +145,37 @@ ConfigOptionBase* internalResolutionArray[] = {
|
||||
};
|
||||
|
||||
ConfigOptionBase* optionsArray[] = {
|
||||
new BooleanOption(L"cursor", PATCHES_SECTION, CONFIG_FILE, L"Cursor", L"Enable or disable the mouse cursor.", true, false),
|
||||
|
||||
new BooleanOption(L"TAA", GRAPHICS_SECTION, CONFIG_FILE, L"TAA", L"Temporal Anti-Aliasing", true, false),
|
||||
new BooleanOption(L"MLAA", GRAPHICS_SECTION, CONFIG_FILE, L"MLAA", L"Morphological Anti-Aliasing", true, false),
|
||||
|
||||
new BooleanOption(L"hide_freeplay", PATCHES_SECTION, CONFIG_FILE, L"Hide \"FREE PLAY\"/\"CREDIT(S)\"", L"Hide the \"FREE PLAY\"/\"CREDIT(S)\" text.", false, false),
|
||||
new BooleanOption(L"freeplay", PATCHES_SECTION, CONFIG_FILE, L"FREE PLAY", L"Show \"FREE PLAY\" instead of \"CREDIT(S)\".", true, false),
|
||||
new BooleanOption(L"pdloadertext", PATCHES_SECTION, CONFIG_FILE, L"PD Loader FREE PLAY", L"Show the version of PD Loader instead of \"FREE PLAY\".", true, false),
|
||||
new BooleanOption(L"hide_volume", PATCHES_SECTION, CONFIG_FILE, L"Hide Volume Buttons", L"Hide the volume and SE control buttons.", false, false),
|
||||
new OptionMetaSpacer(8),
|
||||
|
||||
new BooleanOption(L"no_movies", PATCHES_SECTION, CONFIG_FILE, L"Disable Movies", L"Disable movies (enable this if the game hangs when loading certain PVs).", false, false),
|
||||
new BooleanOption(L"mp4_movies", PATCHES_SECTION, CONFIG_FILE, L"Custom MP4 Adv Movies", L"Enable MP4 (instead of WMV) advertise/attract movies.", false, false),
|
||||
new OptionMetaSpacer(8),
|
||||
|
||||
new BooleanOption(L"cursor", PATCHES_SECTION, CONFIG_FILE, L"Cursor", L"Enable or disable the mouse cursor.", true, false),
|
||||
new BooleanOption(L"hide_volume", PATCHES_SECTION, CONFIG_FILE, L"Hide Volume Buttons", L"Hide the volume and SE control buttons.", false, false),
|
||||
new BooleanOption(L"no_pv_ui", PATCHES_SECTION, CONFIG_FILE, L"Disable PV UI", L"Remove the photo controls during PV playback.", false, false),
|
||||
new BooleanOption(L"no_lyrics", PATCHES_SECTION, CONFIG_FILE, L"Disable Lyrics", L"Disable showing lyrics.", false, false),
|
||||
new BooleanOption(L"hide_pv_watermark", PATCHES_SECTION, CONFIG_FILE, L"Hide PV Watermark", L"Hide the watermark that's usually shown in PV viewing mode.", false, false),
|
||||
new BooleanOption(L"no_lyrics", PATCHES_SECTION, CONFIG_FILE, L"Disable Lyrics", L"Disable showing lyrics.", false, false),
|
||||
new BooleanOption(L"no_error", PATCHES_SECTION, CONFIG_FILE, L"Disable Error Banner", L"Disable the error banner on the attract screen.", true, false),
|
||||
new BooleanOption(L"hardware_slider", PATCHES_SECTION, CONFIG_FILE, L"Use Hardware Slider", L"Enable this if using a real arcade slider.\n(set the slider to port COM11)", false, false),
|
||||
|
||||
new NumericOption(L"Enhanced_Stage_Manager", GRAPHICS_SECTION, CONFIG_FILE, L"Number of stages:", L"Set the number of stages (0 = default).", 0, 0, INT_MAX),
|
||||
new BooleanOption(L"Enhanced_Stage_Manager_Encore", PATCHES_SECTION, CONFIG_FILE, L"Encore", L"Enable encore stages.", true, false),
|
||||
|
||||
new BooleanOption(L"skip", LAUNCHER_SECTION, CONFIG_FILE, L"Skip Launcher", L"Forces the launcher to be skipped, you can also use the --launch parameter instead of this.", false, false),
|
||||
|
||||
new DropdownOption(L"status_icons", PATCHES_SECTION, CONFIG_FILE, L"Status Icons:", L"Set the state of card reader and network status icons.", 3, std::vector<LPCWSTR>({ L"Default", L"Hidden", L"Error", L"OK", L"Partial OK" })),
|
||||
|
||||
new NumericOption(L"FPS.Limit", GRAPHICS_SECTION, CONFIG_FILE, L"FPS Limit:", L"Allows you to set a frame rate cap. Set to -1 to unlock the frame rate.", 60, -1, INT_MAX),
|
||||
new OptionMetaSpacer(8),
|
||||
|
||||
new BooleanOption(L"Enhanced_Stage_Manager_Encore", PATCHES_SECTION, CONFIG_FILE, L"Encore Stages", L"Enable encore stages.", true, false),
|
||||
new NumericOption(L"Enhanced_Stage_Manager", PATCHES_SECTION, CONFIG_FILE, L"Number of stages:", L"Set the number of stages (0 = default).", 0, 0, INT_MAX),
|
||||
new OptionMetaSpacer(8),
|
||||
|
||||
new BooleanOption(L"hardware_slider", PATCHES_SECTION, CONFIG_FILE, L"Use Hardware Slider", L"Enable this if using a real arcade slider.\n(set the slider to port COM11)", false, false),
|
||||
new OptionMetaSpacer(8),
|
||||
|
||||
new BooleanOption(L"TAA", GRAPHICS_SECTION, CONFIG_FILE, L"TAA", L"Temporal Anti-Aliasing", true, false),
|
||||
new BooleanOption(L"MLAA", GRAPHICS_SECTION, CONFIG_FILE, L"MLAA", L"Morphological Anti-Aliasing", true, false),
|
||||
new BooleanOption(L"FPS.Limit.LightMode", GRAPHICS_SECTION, CONFIG_FILE, L"Use Lightweight Limiter", L"Makes the FPS limiter use less CPU.\nMay have less consistent performance.", true, false),
|
||||
new NumericOption(L"FPS.Limit", GRAPHICS_SECTION, CONFIG_FILE, L"FPS Limit:", L"Allows you to set a frame rate cap. Set to -1 to unlock the frame rate.", 60, -1, INT_MAX),
|
||||
new NumericOption(L"frm.motion.rate", GRAPHICS_SECTION, CONFIG_FILE, L"FRM Motion Rate:", L"Sets the motion rate (fps) for the Frame Rate Manager component.\nLarger values should be smoother, but more CPU intensive and possibly buggier.", 300, 1, INT_MAX),
|
||||
new OptionMetaSpacer(8),
|
||||
|
||||
new StringOption(L"command_line", LAUNCHER_SECTION, CONFIG_FILE, L"Command Line:", L"Allows setting command line parameters for the game when using the launcher.\nDisabling the launcher will bypass this.", L"", false),
|
||||
};
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
#include "FrameRateManager.h"
|
||||
#include "FrameRateManager.h"
|
||||
#include "../Constants.h"
|
||||
#include "GameState.h"
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include "../framework.h"
|
||||
#include <vector>
|
||||
#include <codecvt>
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
FrameRateManager::FrameRateManager()
|
||||
{
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
std::wstring configPath = converter.from_bytes((TLAC::framework::GetModuleDirectory() + "/config.ini").c_str());
|
||||
float nMotionRate = GetPrivateProfileIntW(L"graphics", L"frm.motion.rate", 300, configPath.c_str());
|
||||
motionSpeedMultiplier = nMotionRate / 60.0f;
|
||||
}
|
||||
|
||||
FrameRateManager::~FrameRateManager()
|
||||
@@ -32,55 +38,142 @@ namespace TLAC::Components
|
||||
// This const variable is stored inside a data segment so we don't want to throw any access violations
|
||||
DWORD oldProtect;
|
||||
VirtualProtect((void*)AET_FRAME_DURATION_ADDRESS, sizeof(float), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
|
||||
|
||||
// fix auto speed for high fps
|
||||
InjectCode((void*)0x140192d7b, { 0x90, 0x90, 0x90 });
|
||||
|
||||
// fix frame speed slider initial value (should ignore effect of auto speed)
|
||||
InjectCode((void*)0x140338f2f, { 0xf3, 0x0f, 0x10, 0x0d, 0x61, 0x18, 0xba, 0x00 }); // MOVSS XMM1, dword ptr [0x140eda798] (raw framespeed)
|
||||
InjectCode((void*)0x140338f37, { 0x48, 0x8b, 0x8f, 0x80, 0x01, 0x00, 0x00 }); // MOV RCX, qword ptr [0x180 + RDI]
|
||||
|
||||
InjectCode((void*)0x140338ebe, { 0xf3, 0x0f, 0x10, 0x0d, 0xd2, 0x18, 0xba, 0x00 }); // MOVSS XMM1, dword ptr [0x140eda798] (raw framespeed)
|
||||
InjectCode((void*)0x140338ec6, { 0x48, 0x8b, 0x05, 0xfb, 0xb1, 0xe5, 0x00 }); // MOV RAX, qword ptr [0x1411940c8]
|
||||
InjectCode((void*)0x140338ecd, { 0x48, 0x8b, 0x88, 0x80, 0x01, 0x00, 0x00 }); // MOV RCX, qword ptr [0x180 + RAX]
|
||||
|
||||
|
||||
// fix AETs
|
||||
InjectCode((void*)0x140170394, { 0xF3, 0x0F, 0x5E, 0x05, 0x34, 0xA3, 0xD6, 0x00 }); // DIVSS XMM0, dword ptr [0x140eda6d0] (framerate)
|
||||
|
||||
// fix edit PV AETs (thanks lyb)
|
||||
InjectCode((void*)0x140192d30, { 0xF3, 0x0F, 0x10, 0x05, 0x5C, 0x02, 0x00, 0x00 }); // MOVSS XMM0, dword ptr [0x140192f94]
|
||||
|
||||
// fix ageage hair effect
|
||||
InjectCode((void*)0x14054352f, { 0xE8, 0x1C, 0xF8, 0xC4, 0xFF }); // CALL 0x140192d50 (getFrameSpeed)
|
||||
InjectCode((void*)0x140543534, { 0xF3, 0x0F, 0x59, 0xD8 }); // MULSS XMM3, XMM0
|
||||
InjectCode((void*)0x140543538, { 0xEB, 0xB6 }); // JMP 0x1405434f0
|
||||
|
||||
// fix wind effect
|
||||
InjectCode((void*)0x14053ca71, { 0xEB, 0x3F }); // JMP 0x14053cab2
|
||||
InjectCode((void*)0x14053cab2, { 0xF3, 0x0F, 0x10, 0x05, 0xFA, 0x53, 0x46, 0x00 }); // MOVSS XMM0, dword ptr [0x1409a1eb4] (60.0f)
|
||||
InjectCode((void*)0x14053caba, { 0xE9, 0x42, 0xFE, 0xFF, 0xFF }); // JMP 0x14053c901
|
||||
InjectCode((void*)0x14053c901, { 0xF3, 0x0F, 0x5E, 0x05, 0xC7, 0xDD, 0x99, 0x00 }); // DIVSS XMM0, dword ptr [0x140eda6d0] (framerate)
|
||||
InjectCode((void*)0x14053c909, { 0xE9, 0x68, 0x01, 0x00, 0x00 }); // JMP 0x14053ca76
|
||||
|
||||
|
||||
// below are patches for the alternate method (breaks physics)
|
||||
|
||||
//// run motions at motionSpeedMultiplier x rate
|
||||
// // skip unncessary code to free code space
|
||||
// InjectCode((void*)0x140194b2b, { 0xEB, 0x24 }); // JMP 0x140194b51
|
||||
|
||||
// InjectCode((void*)0x140194b2d, { 0xE8, 0x1E, 0xE2, 0xFF, 0xFF }); // CALL 0x140192d50
|
||||
// InjectCode((void*)0x140194b32, { // MOV ECX, &motionSpeedMultiplier
|
||||
// 0x48,
|
||||
// 0xB9,
|
||||
// (uint8_t)((uint64_t)&motionSpeedMultiplier & 0xFF),
|
||||
// (uint8_t)(((uint64_t)&motionSpeedMultiplier >> 8) & 0xFF),
|
||||
// (uint8_t)(((uint64_t)&motionSpeedMultiplier >> 16) & 0xFF),
|
||||
// (uint8_t)(((uint64_t)&motionSpeedMultiplier >> 24) & 0xFF),
|
||||
// (uint8_t)(((uint64_t)&motionSpeedMultiplier >> 32) & 0xFF),
|
||||
// (uint8_t)(((uint64_t)&motionSpeedMultiplier >> 40) & 0xFF),
|
||||
// (uint8_t)(((uint64_t)&motionSpeedMultiplier >> 48) & 0xFF),
|
||||
// (uint8_t)(((uint64_t)&motionSpeedMultiplier >> 56) & 0xFF),
|
||||
// });
|
||||
// InjectCode((void*)0x140194b3c, { 0x66, 0x67, 0x0F, 0x6E, 0x09 }); // MOVD XMM1, dword ptr [ECX]
|
||||
// InjectCode((void*)0x140194b41, { 0xF3, 0x0F, 0x59, 0xC1 }); // MULSS XMM0, XMM1
|
||||
// InjectCode((void*)0x140194b45, { 0xEB, 0xA1 }); // JMP 0x140194ae8
|
||||
|
||||
// // jump to new code
|
||||
// InjectCode((void*)0x140194ae3, { 0xEB, 0x48 }); // JMP 0x140194b2d
|
||||
|
||||
|
||||
//// // trying to fix physics (fail)
|
||||
//// InjectCode((void*)0x14011d537, { 0xF3, 0x0F, 0x10, 0x05, 0xB1, 0xFF, 0x9E, 0x00, 0x90 }); // change source to dword ptr [0x140b0d4f0]
|
||||
}
|
||||
|
||||
void FrameRateManager::Update()
|
||||
{
|
||||
float frameRate = 0.0f;
|
||||
frameRate = RoundFrameRate(GetGameFrameRate());
|
||||
// this alterante way makes physics slowmo, but overall may be better if that's fixed
|
||||
|
||||
*aetFrameDuration = 1.0f / frameRate;
|
||||
*pvFrameRate = frameRate;
|
||||
//// target framerate
|
||||
//*(float*)AUTO_FRAMESPEED_TARGET_FRAMERATE_ADDRESS = 60.0f;
|
||||
|
||||
bool inGame = *(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME;
|
||||
//// enable dynamic framerate
|
||||
//*(bool*)USE_AUTO_FRAMESPEED_ADDRESS = true;
|
||||
|
||||
if (inGame)
|
||||
//*pvFrameRate = 60.0f;
|
||||
|
||||
//*aetFrameDuration = 1.0f / GetGameFrameRate();
|
||||
|
||||
//bool inGame = *(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME;
|
||||
//if (inGame)
|
||||
//{
|
||||
// // This PV struct creates a copy of the PvFrameRate & PvFrameSpeed during the loading screen
|
||||
// // so we'll make sure to keep updating it as well.
|
||||
// // Each new motion also creates its own copy of these values but keeping track of the active motions is annoying
|
||||
// // and they usually change multiple times per PV anyway so this should suffice for now
|
||||
// float* pvStructPvFrameRate = (float*)(0x0000000140CDD978 + 0x2BF98);
|
||||
// float* pvStructPvFrameSpeed = (float*)(0x0000000140CDD978 + 0x2BF9C);
|
||||
|
||||
// *pvStructPvFrameRate = 60.0; // ?
|
||||
// *pvStructPvFrameSpeed = 1.0 / motionSpeedMultiplier;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
// this way breaks some anim speeds, but they're fixable
|
||||
// *aetFrameDuration = 1.0f / GetGameFrameRate();
|
||||
|
||||
if (*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME)
|
||||
{
|
||||
// During the GAME state the frame rate will be handled by the PvFrameRate instead
|
||||
|
||||
constexpr float defaultFrameSpeed = 1.0f;
|
||||
constexpr float defaultFrameRate = 60.0f;
|
||||
|
||||
// This PV struct creates a copy of the PvFrameRate & PvFrameSpeed during the loading screen
|
||||
// so we'll make sure to keep updating it as well.
|
||||
// Each new motion also creates its own copy of these values but keeping track of the active motions is annoying
|
||||
// and they usually change multiple times per PV anyway so this should suffice for now
|
||||
float* pvStructPvFrameRate = (float*)(0x0000000140CDD978 + 0x2BF98);
|
||||
float* pvStructPvFrameSpeed = (float*)(0x0000000140CDD978 + 0x2BF9C);
|
||||
|
||||
*pvStructPvFrameRate = *pvFrameRate;
|
||||
*pvStructPvFrameSpeed = (defaultFrameRate / *pvFrameRate);
|
||||
|
||||
*frameSpeed = defaultFrameSpeed;
|
||||
*pvFrameRate = 60.0f * motionSpeedMultiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
*frameSpeed = *aetFrameDuration / defaultAetFrameDuration;
|
||||
*pvFrameRate = 60.0f;
|
||||
}
|
||||
|
||||
if (*(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN || *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_DEMO)
|
||||
{
|
||||
// enable dynamic framerate
|
||||
*(bool*)USE_AUTO_FRAMESPEED_ADDRESS = true;
|
||||
|
||||
// target framerate
|
||||
*(float*)AUTO_FRAMESPEED_TARGET_FRAMERATE_ADDRESS = *pvFrameRate;
|
||||
|
||||
// trying to fix meltdown's water
|
||||
//if ((uint64_t*)0x1411943f8 != nullptr)
|
||||
//*(float*)(*(uint64_t*)0x1411943f8 + 0x1c) = (60.0f / GetGameFrameRate()) / 15.0f;
|
||||
//*(float*)(*(uint64_t*)0x1411943f8 + 0x10) = *(float*)(*(uint64_t*)0x1411943f8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// enable dynamic framerate
|
||||
*(bool*)USE_AUTO_FRAMESPEED_ADDRESS = true;
|
||||
|
||||
// target framerate
|
||||
*(float*)AUTO_FRAMESPEED_TARGET_FRAMERATE_ADDRESS = 60.0f;
|
||||
}
|
||||
}
|
||||
|
||||
float FrameRateManager::RoundFrameRate(float frameRate)
|
||||
void FrameRateManager::InjectCode(void* address, const std::vector<uint8_t> data)
|
||||
{
|
||||
constexpr float roundingThreshold = 4.0f;
|
||||
const size_t byteCount = data.size() * sizeof(uint8_t);
|
||||
|
||||
for (int i = 0; i < sizeof(commonRefreshRates) / sizeof(float); i++)
|
||||
{
|
||||
float refreshRate = commonRefreshRates[i];
|
||||
|
||||
if (frameRate > refreshRate - roundingThreshold && frameRate < refreshRate + roundingThreshold)
|
||||
frameRate = refreshRate;
|
||||
}
|
||||
|
||||
return frameRate;
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
memcpy(address, data.data(), byteCount);
|
||||
VirtualProtect(address, byteCount, oldProtect, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "EmulatorComponent.h"
|
||||
#include <vector>
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
@@ -19,16 +20,7 @@ namespace TLAC::Components
|
||||
float *frameSpeed;
|
||||
float *aetFrameDuration;
|
||||
float defaultAetFrameDuration;
|
||||
|
||||
float commonRefreshRates[5]
|
||||
{
|
||||
60.0f,
|
||||
75.0f,
|
||||
120.0f,
|
||||
144.0f,
|
||||
240.0f,
|
||||
};
|
||||
|
||||
float RoundFrameRate(float frameRate);
|
||||
float motionSpeedMultiplier = 5.0;
|
||||
void InjectCode(void* address, const std::vector<uint8_t> data);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ constexpr uint8_t JNE_OPCODE = 0x85;
|
||||
constexpr uint64_t ENGINE_UPDATE_INPUT_ADDRESS = 0x000000014018CBB0;
|
||||
|
||||
constexpr uint64_t CURRENT_GAME_STATE_ADDRESS = 0x0000000140EDA810;
|
||||
constexpr uint64_t CURRENT_GAME_SUB_STATE_ADDRESS = 0x0000000140EDA82C;
|
||||
constexpr uint64_t RESOLUTION_WIDTH_ADDRESS = 0x0000000140EDA8BC;
|
||||
constexpr uint64_t RESOLUTION_HEIGHT_ADDRESS = 0x0000000140EDA8C0;
|
||||
|
||||
@@ -20,6 +21,8 @@ constexpr uint64_t AET_FRAME_DURATION_ADDRESS = 0x00000001409A0A58;
|
||||
constexpr uint64_t PV_FRAME_RATE_ADDRESS = 0x0000000140EDA7CC;
|
||||
constexpr uint64_t FRAME_SPEED_ADDRESS = 0x0000000140EDA798;
|
||||
constexpr uint64_t FRAME_RATE_ADDRESS = 0x0000000140EDA6D0;
|
||||
constexpr uint64_t USE_AUTO_FRAMESPEED_ADDRESS = 0x0000000140EDA79C;
|
||||
constexpr uint64_t AUTO_FRAMESPEED_TARGET_FRAMERATE_ADDRESS = 0x0000000140EDA6CC;
|
||||
|
||||
constexpr uint64_t DW_GUI_DISPLAY_INSTANCE_PTR_ADDRESS = 0x0000000141190108;
|
||||
constexpr uint64_t INPUT_STATE_PTR_ADDRESS = 0x0000000140EDA330;
|
||||
|
||||
Reference in New Issue
Block a user