Files
GTASource/rage/3rdparty/portcullis/portcullis.cpp

249 lines
6.0 KiB
C++
Raw Permalink Normal View History

2025-02-23 17:40:52 +08:00
#include "portcullis.h"
#if PORTCULLIS_ENABLE
#if __WIN32PC
#include <tchar.h> // for strcmp
#pragma warning(disable:4668)
#include <windows.h>
#pragma warning(error:4668)
#endif // __WIN32PC
#include "heartbeat/heartbeat.h"
#include "system/timer.h"
#if __WIN32PC
#if RSG_CPU_X64
#pragma comment (lib,"curl-7.28.0_x64.lib")
#else
#pragma comment (lib,"curl-7.28.0.lib")
#endif
#endif // __WIN32PC
namespace rage
{
extern sysThreadPool netThreadPool;
//////////////////////////////////////////////////////////////////////////
void portcullisWorkItem::DoWork()
{
m_result = true;
#if __WIN32PC
//@@: range PORTCULLISWORKITEM_DOWORK_COMPARE_RESULT {
static const char* gameName = "Paradise";
char* hbResult = Portcullis::SendHeartbeat(gameName);
if(!hbResult ||
hbResult[0] != 0x66 ||
hbResult[1] != 0x75 ||
hbResult[2] != 0x74 ||
hbResult[3] != 0x75 ||
hbResult[4] != 0x72 ||
hbResult[5] != 0x65 ||
hbResult[6] != 0x74 ||
hbResult[7] != 0x61 ||
hbResult[8] != 0x6b ||
hbResult[9] != 0x65 ||
hbResult[10] != 0x37 ||
hbResult[11] != 0x35) // "futuretake75"
{
// crash game now or ideally a little bit later
m_result = false;
}
//@@: } PORTCULLISWORKITEM_DOWORK_COMPARE_RESULT
#endif // __WIN32
//@@: location PORTCULLISWORKITEM_DOWORK_EXIT
m_checkDone = true;
}
bool portcullis::m_initialised = false;
#if SINGLE_THREAD_PORTCULLIS
bool portcullis::m_closeThread = false;
sysIpcThreadId portcullis::m_threadID = sysIpcThreadIdInvalid;
sysIpcSema portcullis::m_triggerCheck = sysIpcCreateSema(0);
sysIpcSema portcullis::m_threadClosed = sysIpcCreateSema(0);
#endif // SINGLE_THREAD_PORTCULLIS
bool portcullis::m_checkInProgress = false;
bool portcullis::m_checkSuccess = true;
int portcullis::m_failTolerance = 0;
netRandom portcullis::m_random;
//////////////////////////////////////////////////////////////////////////
void portcullis::Initialise()
{
//@@: location PORTCULLIS_INITIALISE_ENTRY
m_random.Reset(sysTimer::GetSystemMsTime());
#if 0 && !__FINAL
MessageBoxA(NULL, "Portcullis is enabled on this build\n If your PC has not been authorised then the game will crash randomly.\nNote: this message should NOT appear on a build sent out to a 3rd party (Final)", "Portcullis", MB_OK|MB_SETFOREGROUND|MB_TASKMODAL);
#endif // !__FINAL
// Get a random number of times the check is allowed to fail before it forces a crash
m_failTolerance = m_random.GetRanged(2, 3);
#if __WIN32PC
Portcullis::Initialize(NULL, true, NULL);
m_initialised = true;
#elif RSG_DURANGO
#endif
#if SINGLE_THREAD_PORTCULLIS
if(m_threadID == sysIpcThreadIdInvalid)
m_threadID = sysIpcCreateThread(&ThreadFunc, NULL, sysIpcMinThreadStackSize, PRIO_NORMAL, "");
#endif // SINGLE_THREAD_PORTCULLIS
}
//////////////////////////////////////////////////////////////////////////
void portcullis::DoHeartbeat()
{
#if SINGLE_THREAD_PORTCULLIS
static const char* gameName = "Paradise";
char* hbResult = Portcullis::SendHeartbeat(gameName);
if(!hbResult ||
hbResult[0] != 0x66 ||
hbResult[1] != 0x75 ||
hbResult[2] != 0x74 ||
hbResult[3] != 0x75 ||
hbResult[4] != 0x72 ||
hbResult[5] != 0x65 ||
hbResult[6] != 0x74 ||
hbResult[7] != 0x61 ||
hbResult[8] != 0x6b ||
hbResult[9] != 0x65 ||
hbResult[10] != 0x37 ||
hbResult[11] != 0x35) // "futuretake75"
{
// crash game now or ideally a little bit later
m_checkSuccess = false;
}
#endif // SINGLE_THREAD_PORTCULLIS
}
//////////////////////////////////////////////////////////////////////////
void portcullis::ThreadFunc(void*)
{
#if SINGLE_THREAD_PORTCULLIS
m_closeThread = false;
while(!m_closeThread)
{
sysIpcWaitSema(m_triggerCheck);
m_checkInProgress = true;
DoHeartbeat();
m_checkInProgress = false;
}
sysIpcSignalSema(m_threadClosed);
#endif // SINGLE_THREAD_PORTCULLIS
}
//////////////////////////////////////////////////////////////////////////
bool portcullis::DoCheck()
{
if(m_initialised == false)
{
//@@: location PORTCULLIS_DOCHECK_CALL_INITIALISE
Initialise();
}
int checkChance = m_random.GetRanged(0, 10000);
if(checkChance > 200) // Increase this to increase the chance of a check
return true; // No checking done
static portcullisWorkItem checkItem;
static int failCounter = 0;
// If a check has been done then see whether it has been successful
if(checkItem.CheckDone())
{
//@@: range PORTCULLIS_DOCHECK_CHECK_SUCCESSFUL {
if(!checkItem.CheckSuccessful())
{
++failCounter;
//@@: location PORTCULLIS_DOCHECK_CHECK_FAIL_COUNTER
if(failCounter > m_failTolerance)
return false; // Had a number of failures so return false
else
{
//MessageBoxA(NULL, "Portcullis check failed...", "Portcullis", MB_OK|MB_SETFOREGROUND|MB_TASKMODAL);
return true; // Pass for now...
}
}
failCounter = 0;
return true; // Check was successful so return true
//@@: } PORTCULLIS_DOCHECK_CHECK_SUCCESSFUL
}
// No check has been done recently so kick off a new one
if(!checkItem.CheckStarted())
{
//@@: range PORTCULLIS_DOCHECK_CHECK_2 {
checkChance = m_random.GetRanged(0, 10000);
if(checkChance > 9975) // Decrease this to increase the chance of a check
{
//@@: location PORTCULLIS_DOCHECK_QUEUE_WORK
checkItem.Started();
netThreadPool.QueueWork(&checkItem);
}
//@@: } PORTCULLIS_DOCHECK_CHECK_2
}
return true; // Nothing to report...
}
//////////////////////////////////////////////////////////////////////////
void portcullis::Shutdown()
{
//@@: location PORTCULLIS_SHUTDOWN_ENTRY
if(!m_initialised)
return;
#if SINGLE_THREAD_PORTCULLIS
// Signal to close the thread and kick off the thread for a final spin
if(m_threadID != sysIpcThreadIdInvalid)
{
m_closeThread = true;
sysIpcSignalSema(m_triggerCheck);
sysIpcWaitSema(m_threadClosed);
sysIpcWaitThreadExit(m_threadID);
}
#endif // SINGLE_THREAD_PORTCULLIS
#if __WIN32PC
Portcullis::Shutdown();
#endif // __WIN32PC
}
}
#endif // PORTCULLIS_ENABLE