Skip to content

Commit

Permalink
Add ability to limit client triggered events (via triggerServerEvent) (
Browse files Browse the repository at this point in the history
  • Loading branch information
Lpsd authored Nov 27, 2023
1 parent abec07a commit eae47fe
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 8 deletions.
31 changes: 31 additions & 0 deletions Server/mods/deathmatch/logic/CGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,9 @@ void CGame::DoPulse()
PrintLogOutputFromNetModule();
m_pScriptDebugging->UpdateLogOutput();

if (GetTickCount64_() + m_iClientTriggeredEventsIntervalMs > m_lClientTriggeredEventsLastCheck)
ProcessClientTriggeredEventSpam();

// Unlock the critical section again
Unlock();
}
Expand Down Expand Up @@ -1585,6 +1588,7 @@ void CGame::AddBuiltInEvents()
m_Events.AddEvent("onPlayerResourceStart", "resource", NULL, false);
m_Events.AddEvent("onPlayerProjectileCreation", "weaponType, posX, posY, posZ, force, target, rotX, rotY, rotZ, velX, velY, velZ", nullptr, false);
m_Events.AddEvent("onPlayerDetonateSatchels", "", nullptr, false);
m_Events.AddEvent("onPlayerTriggerEventThreshold", "", nullptr, false);

// Ped events
m_Events.AddEvent("onPedVehicleEnter", "vehicle, seat, jacked", NULL, false);
Expand Down Expand Up @@ -2568,6 +2572,8 @@ void CGame::Packet_LuaEvent(CLuaEventPacket& Packet)
}
else
m_pScriptDebugging->LogError(NULL, "Client (%s) triggered serverside event %s, but event is not added serverside", pCaller->GetNick(), szName);

RegisterClientTriggeredEventUsage(pCaller);
}
}

Expand Down Expand Up @@ -4699,3 +4705,28 @@ void CGame::HandleCrashDumpEncryption()
}
#endif
}

void CGame::RegisterClientTriggeredEventUsage(CPlayer* pPlayer)
{
if (!pPlayer)
return;

auto iter = m_mapClientTriggeredEvents.find(pPlayer);

if (iter == m_mapClientTriggeredEvents.end())
m_mapClientTriggeredEvents.insert({pPlayer, 0});

m_mapClientTriggeredEvents[pPlayer]++;
}

void CGame::ProcessClientTriggeredEventSpam()
{
for (const auto& [player, count]: m_mapClientTriggeredEvents)
{
if (player && player->IsPlayer() && !player->IsBeingDeleted() && count > m_iMaxClientTriggeredEventsPerInterval)
player->CallEvent("onPlayerTriggerEventThreshold", {});
}

m_mapClientTriggeredEvents.clear();
m_lClientTriggeredEventsLastCheck = GetTickCount64_();
}
10 changes: 10 additions & 0 deletions Server/mods/deathmatch/logic/CGame.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ class CGame
bool IsBelowMinimumClient(const CMtaVersion& strVersion);
bool IsBelowRecommendedClient(const CMtaVersion& strVersion);
void ApplyAseSetting();
void ApplyPlayerTriggeredEventIntervalChange();
bool IsUsingMtaServerConf() { return m_bUsingMtaServerConf; }

void SetDevelopmentMode(bool enabled) { m_DevelopmentModeEnabled = enabled; }
Expand Down Expand Up @@ -508,6 +509,9 @@ class CGame

static void PlayerCompleteConnect(CPlayer* pPlayer);

void ProcessClientTriggeredEventSpam();
void RegisterClientTriggeredEventUsage(CPlayer* pPlayer);

// Technically, this could be put somewhere else. It's a callback function
// which the voice server library will call to send out data.

Expand Down Expand Up @@ -658,4 +662,10 @@ class CGame

bool m_DevelopmentModeEnabled;
bool m_showClientTransferBox = true;

int m_iMaxClientTriggeredEventsPerInterval = 100;
int m_iClientTriggeredEventsIntervalMs = 1000;
long long m_lClientTriggeredEventsLastCheck = 0;

std::map<CPlayer*, int> m_mapClientTriggeredEvents;
};
20 changes: 14 additions & 6 deletions Server/mods/deathmatch/logic/CMainConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -847,12 +847,7 @@ bool CMainConfig::AddMissingSettings()
if (!g_pGame->IsUsingMtaServerConf())
return false;

// Load template
const char* szTemplateText =
#include MTA_SERVER_CONF_TEMPLATE
;
SString strTemplateFilename = PathJoin(g_pServerInterface->GetServerModPath(), "resource-cache", "conf.template");
FileSave(strTemplateFilename, szTemplateText);
SString strTemplateFilename = PathJoin(g_pServerInterface->GetServerModPath(), "mtaserver.conf.template");
CXMLFile* pFileTemplate = g_pServerInterface->GetXML()->CreateXML(strTemplateFilename);
CXMLNode* pRootNodeTemplate = pFileTemplate && pFileTemplate->Parse() ? pFileTemplate->GetRootNode() : nullptr;
if (!pRootNodeTemplate)
Expand Down Expand Up @@ -1463,6 +1458,8 @@ const std::vector<SIntSetting>& CMainConfig::GetIntSettingList()
{true, true, 0, 1, 1, "filter_duplicate_log_lines", &m_bFilterDuplicateLogLinesEnabled, NULL},
{false, false, 0, 1, 1, "database_credentials_protection", &m_bDatabaseCredentialsProtectionEnabled, NULL},
{false, false, 0, 0, 1, "fakelag", &m_bFakeLagCommandEnabled, NULL},
{true, true, 50, 1000, 5000, "player_triggered_event_interval", &m_iPlayerTriggeredEventIntervalMs, &CMainConfig::OnPlayerTriggeredEventIntervalChange},
{true, true, 1, 100, 1000, "max_player_triggered_events_per_interval", &m_iMaxPlayerTriggeredEventsPerInterval, &CMainConfig::OnPlayerTriggeredEventIntervalChange},
};

static std::vector<SIntSetting> settingsList;
Expand Down Expand Up @@ -1506,3 +1503,14 @@ void CGame::ApplyAseSetting()
m_pLanBroadcast = m_pASE->InitLan();
}
}

void CMainConfig::OnPlayerTriggeredEventIntervalChange()
{
g_pGame->ApplyPlayerTriggeredEventIntervalChange();
}

void CGame::ApplyPlayerTriggeredEventIntervalChange()
{
m_iClientTriggeredEventsIntervalMs = m_pMainConfig->GetPlayerTriggeredEventInterval();
m_iMaxClientTriggeredEventsPerInterval = m_pMainConfig->GetMaxPlayerTriggeredEventsPerInterval();
}
6 changes: 6 additions & 0 deletions Server/mods/deathmatch/logic/CMainConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ class CMainConfig : public CXMLConfig
const std::vector<SIntSetting>& GetIntSettingList();
void OnTickRateChange();
void OnAseSettingChange();
void OnPlayerTriggeredEventIntervalChange();

int GetPlayerTriggeredEventInterval() const { return m_iPlayerTriggeredEventIntervalMs; }
int GetMaxPlayerTriggeredEventsPerInterval() const { return m_iMaxPlayerTriggeredEventsPerInterval; }

private:
void RegisterCommand(const char* szName, FCommandHandler* pFunction, bool bRestricted, const char* szConsoleHelpText);
Expand Down Expand Up @@ -221,4 +225,6 @@ class CMainConfig : public CXMLConfig
int m_bFilterDuplicateLogLinesEnabled;
int m_bDatabaseCredentialsProtectionEnabled;
int m_bFakeLagCommandEnabled;
int m_iPlayerTriggeredEventIntervalMs;
int m_iMaxPlayerTriggeredEventsPerInterval;
};
7 changes: 7 additions & 0 deletions Server/mods/deathmatch/mtaserver.conf
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,13 @@
Values: 0 - Off, 1 - Enabled. Default - 1 -->
<database_credentials_protection>1</database_credentials_protection>

<!-- These parameters specify the maximum amount of events that can be triggered by the client (via triggerServerEvent) within the given interval.
Note: The interval is given in milliseconds
Interval range: 50 to 5000. Default: 1000
Max events per interval range: 1 to 1000. Default: 100 -->
<player_triggered_event_interval>1000</player_triggered_event_interval>
<max_player_triggered_events_per_interval>100</max_player_triggered_events_per_interval>

<!-- Specifies the module(s) which are loaded with the server. To load several modules, add more <module>
parameter(s). Optional parameter. -->
<!-- <module src="sample_win32.dll"/> -->
Expand Down
9 changes: 7 additions & 2 deletions Server/mods/deathmatch/mtaserver.conf.template
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
R"=====(
<!-- This file is compiled into the server binary.
It is used for inserting missing settings into mtaserver.conf at server startup -->
<config>
Expand Down Expand Up @@ -265,5 +264,11 @@ R"=====(
*NOTE* This only protects resources which use dbConnect with mysql
Values: 0 - Off, 1 - Enabled. Default - 1 -->
<database_credentials_protection>1</database_credentials_protection>

<!-- These parameters specify the maximum amount of events that can be triggered by the client (via triggerServerEvent) within the given interval.
Note: The interval is given in milliseconds
Interval range: 50 to 5000. Default: 1000
Max events per interval range: 1 to 1000. Default: 100 -->
<player_triggered_event_interval>1000</player_triggered_event_interval>
<max_player_triggered_events_per_interval>100</max_player_triggered_events_per_interval>
</config>
)====="
1 change: 1 addition & 0 deletions utils/buildactions/compose_files.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ newaction {

-- Copy configs
os.copydir("Server/mods/deathmatch", OUTPUT_DIR.."/server/mods/deathmatch", "*.conf")
os.copydir("Server/mods/deathmatch", OUTPUT_DIR.."/server/mods/deathmatch", "mtaserver.conf.template")
os.copydir("Server/mods/deathmatch", OUTPUT_DIR.."/server/mods/deathmatch", "*.xml")

-- Copy compiled binaries
Expand Down
7 changes: 7 additions & 0 deletions utils/buildactions/install_data.lua
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ newaction {
return
end

local success, message = os.copydir("Server/mods/deathmatch", BIN_DIR.."/server/mods/deathmatch", "mtaserver.conf.template", false, true)
if not success then
errormsg("ERROR: Couldn't copy server config files", "\n"..message)
os.exit(1)
return
end

local success, message = os.copydir("Server/mods/deathmatch", BIN_DIR.."/server/mods/deathmatch", "*.xml", false, true)
if not success then
errormsg("ERROR: Couldn't copy server xml files", "\n"..message)
Expand Down

0 comments on commit eae47fe

Please sign in to comment.