[FrameTime] Introduce safer frame waiting mechanism
This commit is contained in:
parent
0aaf8b8730
commit
fbac207190
@ -55,6 +55,7 @@ namespace Components
|
|||||||
Loader::Register(new Discovery());
|
Loader::Register(new Discovery());
|
||||||
Loader::Register(new Exception());
|
Loader::Register(new Exception());
|
||||||
Loader::Register(new FastFiles());
|
Loader::Register(new FastFiles());
|
||||||
|
Loader::Register(new FrameTime());
|
||||||
Loader::Register(new Gametypes());
|
Loader::Register(new Gametypes());
|
||||||
Loader::Register(new Materials());
|
Loader::Register(new Materials());
|
||||||
Loader::Register(new Threading());
|
Loader::Register(new Threading());
|
||||||
|
@ -67,6 +67,7 @@ namespace Components
|
|||||||
#include "Modules\Discovery.hpp"
|
#include "Modules\Discovery.hpp"
|
||||||
#include "Modules\Exception.hpp"
|
#include "Modules\Exception.hpp"
|
||||||
#include "Modules\FastFiles.hpp"
|
#include "Modules\FastFiles.hpp"
|
||||||
|
#include "Modules\FrameTime.hpp"
|
||||||
#include "Modules\Gametypes.hpp"
|
#include "Modules\Gametypes.hpp"
|
||||||
#include "Modules\Materials.hpp"
|
#include "Modules\Materials.hpp"
|
||||||
#include "Modules\Singleton.hpp"
|
#include "Modules\Singleton.hpp"
|
||||||
|
@ -9,7 +9,14 @@ namespace Components
|
|||||||
|
|
||||||
bool Dedicated::IsEnabled()
|
bool Dedicated::IsEnabled()
|
||||||
{
|
{
|
||||||
return Flags::HasFlag("dedicated");
|
static Utils::Value<bool> flag;
|
||||||
|
|
||||||
|
if (!flag.isValid())
|
||||||
|
{
|
||||||
|
flag.set(Flags::HasFlag("dedicated"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return flag.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dedicated::InitDedicatedServer()
|
void Dedicated::InitDedicatedServer()
|
||||||
|
@ -20,6 +20,7 @@ namespace Components
|
|||||||
Var() : dvar(0) {};
|
Var() : dvar(0) {};
|
||||||
Var(const Var &obj) { this->dvar = obj.dvar; };
|
Var(const Var &obj) { this->dvar = obj.dvar; };
|
||||||
Var(Game::dvar_t* _dvar) : dvar(_dvar) {};
|
Var(Game::dvar_t* _dvar) : dvar(_dvar) {};
|
||||||
|
Var(DWORD ppdvar) : Var(*reinterpret_cast<Game::dvar_t**>(ppdvar)) {};
|
||||||
Var(std::string dvarName);
|
Var(std::string dvarName);
|
||||||
|
|
||||||
template<typename T> T get();
|
template<typename T> T get();
|
||||||
|
131
src/Components/Modules/FrameTime.cpp
Normal file
131
src/Components/Modules/FrameTime.cpp
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#include "STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
void FrameTime::NetSleep(int msec)
|
||||||
|
{
|
||||||
|
if (msec < 0) msec = 0;
|
||||||
|
|
||||||
|
fd_set fdr;
|
||||||
|
FD_ZERO(&fdr);
|
||||||
|
|
||||||
|
SOCKET highestfd = INVALID_SOCKET;
|
||||||
|
if (*Game::ip_socket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
FD_SET(*Game::ip_socket, &fdr);
|
||||||
|
highestfd = *Game::ip_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (highestfd == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
// windows ain't happy when select is called without valid FDs
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(msec));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeval timeout;
|
||||||
|
timeout.tv_sec = msec / 1000;
|
||||||
|
timeout.tv_usec = (msec % 1000) * 1000;
|
||||||
|
|
||||||
|
int retval = select(highestfd + 1, &fdr, NULL, NULL, &timeout);
|
||||||
|
|
||||||
|
if (retval == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
Logger::Print("Warning: select() syscall failed: %s\n", Game::NET_ErrorString());
|
||||||
|
}
|
||||||
|
else if (retval > 0)
|
||||||
|
{
|
||||||
|
// process packets
|
||||||
|
if (Dvar::Var(0x1AD7934).get<bool>()) // com_sv_running
|
||||||
|
{
|
||||||
|
Utils::Hook::Call<void()>(0x458160)();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Utils::Hook::Call<void()>(0x49F0B0)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameTime::SVFrameWaitFunc()
|
||||||
|
{
|
||||||
|
int sv_residualTime = *reinterpret_cast<int*>(0x2089E14);
|
||||||
|
|
||||||
|
if (sv_residualTime < 50)
|
||||||
|
{
|
||||||
|
FrameTime::NetSleep(50 - sv_residualTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __declspec(naked) FrameTime::SVFrameWaitStub()
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
pushad
|
||||||
|
call FrameTime::SVFrameWaitFunc
|
||||||
|
popad
|
||||||
|
|
||||||
|
push 4CD420h
|
||||||
|
retn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int FrameTime::ComTimeVal(int minMsec)
|
||||||
|
{
|
||||||
|
int timeVal = Game::Sys_Milliseconds() - *reinterpret_cast<uint32_t*>(0x1AD8F3C); // com_frameTime
|
||||||
|
return (timeVal >= minMsec ? 0 : minMsec - timeVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t FrameTime::ComFrameWait(int minMsec)
|
||||||
|
{
|
||||||
|
int timeVal;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
timeVal = FrameTime::ComTimeVal(minMsec);
|
||||||
|
FrameTime::NetSleep(timeVal < 1 ? 0 : timeVal - 1);
|
||||||
|
} while (FrameTime::ComTimeVal(minMsec));
|
||||||
|
|
||||||
|
uint32_t lastTime = *Game::com_frameTime;
|
||||||
|
Utils::Hook::Call<void()>(0x43D140)(); // Com_EventLoop
|
||||||
|
*Game::com_frameTime = Game::Sys_Milliseconds();
|
||||||
|
|
||||||
|
return *Game::com_frameTime - lastTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __declspec(naked) FrameTime::ComFrameWaitStub()
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
push ecx
|
||||||
|
pushad
|
||||||
|
|
||||||
|
push edi
|
||||||
|
call FrameTime::ComFrameWait
|
||||||
|
add esp, 4
|
||||||
|
|
||||||
|
mov[esp + 20h], eax
|
||||||
|
popad
|
||||||
|
pop eax
|
||||||
|
mov ecx, eax
|
||||||
|
|
||||||
|
mov edx, 1AD7934h // com_sv_running
|
||||||
|
cmp byte ptr[edx + 10h], 0
|
||||||
|
|
||||||
|
push 47DDC1h
|
||||||
|
retn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameTime::FrameTime()
|
||||||
|
{
|
||||||
|
if (Dedicated::IsEnabled())
|
||||||
|
{
|
||||||
|
Utils::Hook(0x4BAAAD, FrameTime::SVFrameWaitStub, HOOK_CALL).install()->quick();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Utils::Hook(0x47DD80, FrameTime::ComFrameWaitStub, HOOK_JUMP).install()->quick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
src/Components/Modules/FrameTime.hpp
Normal file
22
src/Components/Modules/FrameTime.hpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
class FrameTime : public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FrameTime();
|
||||||
|
|
||||||
|
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
|
||||||
|
const char* getName() { return "FrameTime"; };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void SVFrameWaitStub();
|
||||||
|
static void SVFrameWaitFunc();
|
||||||
|
|
||||||
|
static void NetSleep(int msec);
|
||||||
|
|
||||||
|
static int ComTimeVal(int minMsec);
|
||||||
|
static uint32_t ComFrameWait(int minMsec);
|
||||||
|
static void ComFrameWaitStub();
|
||||||
|
};
|
||||||
|
}
|
@ -630,7 +630,14 @@ namespace Components
|
|||||||
|
|
||||||
bool ZoneBuilder::IsEnabled()
|
bool ZoneBuilder::IsEnabled()
|
||||||
{
|
{
|
||||||
return (Flags::HasFlag("zonebuilder") && !Dedicated::IsEnabled());
|
static Utils::Value<bool> flag;
|
||||||
|
|
||||||
|
if (!flag.isValid())
|
||||||
|
{
|
||||||
|
flag.set(Flags::HasFlag("zonebuilder"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (flag.get() && !Dedicated::IsEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZoneBuilder::BeginAssetTrace(std::string zone)
|
void ZoneBuilder::BeginAssetTrace(std::string zone)
|
||||||
|
@ -154,6 +154,7 @@ namespace Game
|
|||||||
|
|
||||||
NET_AdrToString_t NET_AdrToString = (NET_AdrToString_t)0x469880;
|
NET_AdrToString_t NET_AdrToString = (NET_AdrToString_t)0x469880;
|
||||||
NET_CompareAdr_t NET_CompareAdr = (NET_CompareAdr_t)0x4D0AA0;
|
NET_CompareAdr_t NET_CompareAdr = (NET_CompareAdr_t)0x4D0AA0;
|
||||||
|
NET_ErrorString_t NET_ErrorString = (NET_ErrorString_t)0x4E7720;
|
||||||
NET_Init_t NET_Init = (NET_Init_t)0x491860;
|
NET_Init_t NET_Init = (NET_Init_t)0x491860;
|
||||||
NET_IsLocalAddress_t NET_IsLocalAddress = (NET_IsLocalAddress_t)0x402BD0;
|
NET_IsLocalAddress_t NET_IsLocalAddress = (NET_IsLocalAddress_t)0x402BD0;
|
||||||
NET_StringToAdr_t NET_StringToAdr = (NET_StringToAdr_t)0x409010;
|
NET_StringToAdr_t NET_StringToAdr = (NET_StringToAdr_t)0x409010;
|
||||||
@ -304,6 +305,8 @@ namespace Game
|
|||||||
|
|
||||||
SOCKET* ip_socket = (SOCKET*)0x64A3008;
|
SOCKET* ip_socket = (SOCKET*)0x64A3008;
|
||||||
|
|
||||||
|
uint32_t* com_frameTime = (uint32_t*)0x1AD8F3C;
|
||||||
|
|
||||||
SafeArea* safeArea = (SafeArea*)0xA15F3C;
|
SafeArea* safeArea = (SafeArea*)0xA15F3C;
|
||||||
|
|
||||||
SpawnVar* spawnVars = (SpawnVar*)0x1A83DE8;
|
SpawnVar* spawnVars = (SpawnVar*)0x1A83DE8;
|
||||||
|
@ -380,6 +380,9 @@ namespace Game
|
|||||||
typedef bool(__cdecl * NET_CompareAdr_t)(netadr_t a, netadr_t b);
|
typedef bool(__cdecl * NET_CompareAdr_t)(netadr_t a, netadr_t b);
|
||||||
extern NET_CompareAdr_t NET_CompareAdr;
|
extern NET_CompareAdr_t NET_CompareAdr;
|
||||||
|
|
||||||
|
typedef const char* (__cdecl * NET_ErrorString_t)();
|
||||||
|
extern NET_ErrorString_t NET_ErrorString;
|
||||||
|
|
||||||
typedef void(__cdecl * NET_Init_t)();
|
typedef void(__cdecl * NET_Init_t)();
|
||||||
extern NET_Init_t NET_Init;
|
extern NET_Init_t NET_Init;
|
||||||
|
|
||||||
@ -646,6 +649,8 @@ namespace Game
|
|||||||
extern netadr_t* connectedHost;
|
extern netadr_t* connectedHost;
|
||||||
extern SOCKET* ip_socket;
|
extern SOCKET* ip_socket;
|
||||||
|
|
||||||
|
extern uint32_t* com_frameTime;
|
||||||
|
|
||||||
extern SafeArea* safeArea;
|
extern SafeArea* safeArea;
|
||||||
|
|
||||||
extern SpawnVar* spawnVars;
|
extern SpawnVar* spawnVars;
|
||||||
|
@ -52,4 +52,32 @@ namespace Utils
|
|||||||
private:
|
private:
|
||||||
std::vector<Slot<T>> slots;
|
std::vector<Slot<T>> slots;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Value
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Value() : hasValue(false) {}
|
||||||
|
Value(T _value) { this->set(_value); }
|
||||||
|
|
||||||
|
void set(T _value)
|
||||||
|
{
|
||||||
|
this->value = _value;
|
||||||
|
this->hasValue = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid()
|
||||||
|
{
|
||||||
|
return this->hasValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
T get()
|
||||||
|
{
|
||||||
|
return this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool hasValue;
|
||||||
|
T value;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user