Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to limit client triggered events (via triggerServerEvent) #3251

Merged
merged 2 commits into from Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 34 additions & 0 deletions Server/mods/deathmatch/logic/CGame.cpp
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,31 @@ void CGame::HandleCrashDumpEncryption()
}
#endif
}

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

auto iter = m_mapClientTriggeredEvents.find(pPlayer);

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

iter->second++;
TheNormalnij marked this conversation as resolved.
Show resolved Hide resolved
Lpsd marked this conversation as resolved.
Show resolved Hide resolved
}

void CGame::ProcessClientTriggeredEventSpam()
{
for (const auto& pair : m_mapClientTriggeredEvents)
Lpsd marked this conversation as resolved.
Show resolved Hide resolved
{
CPlayer* player = pair.first;
Lpsd marked this conversation as resolved.
Show resolved Hide resolved
int count = pair.second;

if (player && count > m_iMaxClientTriggeredEventsPerInterval)
player->CallEvent("onPlayerTriggerEventThreshold", {});
}

m_mapClientTriggeredEvents.clear();
m_lClientTriggeredEventsLastCheck = GetTickCount64_();
}
10 changes: 10 additions & 0 deletions Server/mods/deathmatch/logic/CGame.h
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
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
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
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
@@ -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
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
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