mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-09-23 22:43:43 +00:00
feat: Add cheat detection knowledge (#2034)
* feat: Add cheat detection knowledge tested that getting kicked correctly displays the reasons why and their corresponding values tested that a user with developer permissions is not kicked for said funness tested that logs are correct for those funness values which i could actually trigger * fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
26
dCommon/dEnums/eFunnessTypes.h
Normal file
26
dCommon/dEnums/eFunnessTypes.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef EFUNNESSTYPES_H
|
||||||
|
#define EFUNNESSTYPES_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// Most of these are guesses from the client, some are unused (maybe server side only?) and
|
||||||
|
// some are really hard to pin a definition down for because they are buried in havok stuff
|
||||||
|
enum class eFunnessTypes : int32_t {
|
||||||
|
DebuggerActive = 1,
|
||||||
|
CharacterPosLength = 2,
|
||||||
|
CharacterVelLength = 5,
|
||||||
|
CharacterRunMultiplier = 6,
|
||||||
|
CharacterGravityScale = 7,
|
||||||
|
Unknown_9 = 9,
|
||||||
|
Unknown_10 = 10,
|
||||||
|
RacingBoostTimeTooLong = 12,
|
||||||
|
SomeRacingManipCheat = 13,
|
||||||
|
FdbFailedChecksum = 14,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CaughtFunness {
|
||||||
|
eFunnessTypes cheatType{};
|
||||||
|
float cheatInfo{};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!EFUNNESSTYPES_H
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "eGameMasterLevel.h"
|
#include "eGameMasterLevel.h"
|
||||||
#include "BitStreamUtils.h"
|
#include "BitStreamUtils.h"
|
||||||
#include "MessageType/Chat.h"
|
#include "MessageType/Chat.h"
|
||||||
|
#include "StringifiedEnum.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
@@ -127,11 +128,16 @@ void User::SetMuteExpire(time_t value) {
|
|||||||
m_MuteExpire = value;
|
m_MuteExpire = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void User::UserOutOfSync() {
|
void User::UserOutOfSync(const CaughtFunness& funness) {
|
||||||
|
m_CaughtFunness.push_back(funness);
|
||||||
m_AmountOfTimesOutOfSync++;
|
m_AmountOfTimesOutOfSync++;
|
||||||
if (m_AmountOfTimesOutOfSync > m_MaxDesyncAllowed) {
|
if (m_AmountOfTimesOutOfSync > m_MaxDesyncAllowed) {
|
||||||
//YEET
|
//YEET
|
||||||
LOG("User %s was out of sync %i times out of %i, disconnecting for suspected speedhacking.", m_Username.c_str(), m_AmountOfTimesOutOfSync, m_MaxDesyncAllowed);
|
LOG("User %s was out of sync %i times out of %i, disconnecting for the following reasons: {", m_Username.c_str(), m_AmountOfTimesOutOfSync, m_MaxDesyncAllowed);
|
||||||
|
for (const auto [cheatType, cheatInfo] : m_CaughtFunness) {
|
||||||
|
LOG(" Reason %s value %f", StringifiedEnum::ToString(cheatType).data(), cheatInfo);
|
||||||
|
}
|
||||||
|
LOG("}");
|
||||||
Game::server->Disconnect(this->m_SystemAddress, eServerDisconnectIdentifiers::PLAY_SCHEDULE_TIME_DONE);
|
Game::server->Disconnect(this->m_SystemAddress, eServerDisconnectIdentifiers::PLAY_SCHEDULE_TIME_DONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include "RakNetTypes.h"
|
#include "RakNetTypes.h"
|
||||||
#include "dCommonVars.h"
|
#include "dCommonVars.h"
|
||||||
|
#include "eFunnessTypes.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ public:
|
|||||||
// Added for GameMessageHandler
|
// Added for GameMessageHandler
|
||||||
std::unordered_map<uint32_t, BehaviorParams> uiBehaviorHandles;
|
std::unordered_map<uint32_t, BehaviorParams> uiBehaviorHandles;
|
||||||
|
|
||||||
void UserOutOfSync();
|
void UserOutOfSync(const CaughtFunness& funness);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t m_AccountID;
|
uint32_t m_AccountID;
|
||||||
@@ -75,6 +76,7 @@ private:
|
|||||||
const int m_MaxDesyncAllowed = 12;
|
const int m_MaxDesyncAllowed = 12;
|
||||||
uint64_t m_MuteExpire;
|
uint64_t m_MuteExpire;
|
||||||
std::chrono::steady_clock::time_point m_LastMuteCheck{};
|
std::chrono::steady_clock::time_point m_LastMuteCheck{};
|
||||||
|
std::vector<CaughtFunness> m_CaughtFunness{};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // USER_H
|
#endif // USER_H
|
||||||
|
|||||||
@@ -82,6 +82,7 @@
|
|||||||
#include "SlashCommandHandler.h"
|
#include "SlashCommandHandler.h"
|
||||||
#include "InventoryComponent.h"
|
#include "InventoryComponent.h"
|
||||||
#include "Item.h"
|
#include "Item.h"
|
||||||
|
#include "eFunnessTypes.h"
|
||||||
|
|
||||||
namespace Game {
|
namespace Game {
|
||||||
Logger* logger = nullptr;
|
Logger* logger = nullptr;
|
||||||
@@ -1427,16 +1428,61 @@ void HandlePacket(Packet* packet) {
|
|||||||
//Could be insane lag, but I'mma just YEET them as it's usually speedhacking.
|
//Could be insane lag, but I'mma just YEET them as it's usually speedhacking.
|
||||||
//This is updated to now count the amount of times we've been caught "speedhacking" to kick with a delay
|
//This is updated to now count the amount of times we've been caught "speedhacking" to kick with a delay
|
||||||
//This is hopefully going to fix the random disconnects people face sometimes.
|
//This is hopefully going to fix the random disconnects people face sometimes.
|
||||||
if (Game::config->GetValue("disable_anti_speedhack") == "1") {
|
|
||||||
|
CINSTREAM_SKIP_HEADER;
|
||||||
|
CaughtFunness funness;
|
||||||
|
inStream.Read(funness.cheatInfo);
|
||||||
|
inStream.Read(funness.cheatType);
|
||||||
|
const auto [cheatType, cheatInfo] = funness;
|
||||||
|
LOG_DEBUG("Received cheat type %s with info %f", StringifiedEnum::ToString(cheatType).data(), cheatInfo);
|
||||||
|
const auto disabledCheats = Game::config->GetValue("disable_anti_speedhack") == "1";
|
||||||
|
|
||||||
|
User* user = UserManager::Instance()->GetUser(packet->systemAddress);
|
||||||
|
if (!user) {
|
||||||
|
Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::KICK);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
User* user = UserManager::Instance()->GetUser(packet->systemAddress);
|
const auto* const character = user->GetLastUsedChar();
|
||||||
if (user) {
|
if (character) {
|
||||||
user->UserOutOfSync();
|
const auto dcUser = [](const User& user, const SystemAddress& sysAddr) {
|
||||||
} else {
|
if (user.GetMaxGMLevel() < eGameMasterLevel::DEVELOPER) {
|
||||||
Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::KICK);
|
Game::server->Disconnect(sysAddr, eServerDisconnectIdentifiers::KICK);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (cheatType == eFunnessTypes::DebuggerActive) {
|
||||||
|
LOG("Player %s was detected to be using a debugger (funness thread was %f seconds longer than expected deviation).", character->GetName().c_str(), cheatInfo);
|
||||||
|
// Immediately kick unless they are a gm
|
||||||
|
if (!disabledCheats) dcUser(*user, packet->systemAddress);
|
||||||
|
} else if (cheatType == eFunnessTypes::FdbFailedChecksum) {
|
||||||
|
LOG("Player %s has failed the fdb checksum after passing it to sign into this server, highly likely cheating.", character->GetName().c_str());
|
||||||
|
// Immedately kick unless they are a gm
|
||||||
|
if (!disabledCheats) dcUser(*user, packet->systemAddress);
|
||||||
|
} else if (cheatType == eFunnessTypes::RacingBoostTimeTooLong) {
|
||||||
|
if (cheatInfo == 0.0f) LOG("Player %s has enabled a speedboost for far too long (> 3.501 seconds).", character->GetName().c_str());
|
||||||
|
else if (cheatInfo == 1.0f) LOG("Unknown racing boost/speed variable was tampered with.");
|
||||||
|
else if (cheatInfo == 2.0f) LOG("Player vehicle top speed was tampered with.");
|
||||||
|
if (!disabledCheats) dcUser(*user, packet->systemAddress);
|
||||||
|
} else if (cheatType == eFunnessTypes::SomeRacingManipCheat) {
|
||||||
|
if (cheatInfo >= 0.0f && cheatInfo <= 6.0f) LOG("Cheat RNG value A does not match what it should be %f.", cheatInfo);
|
||||||
|
else if (cheatInfo >= 7.0f && cheatInfo <= 10.0f) LOG("Cheat RNG value B does not match what it should be %f.", cheatInfo);
|
||||||
|
} else if (cheatType == eFunnessTypes::Unknown_9) {
|
||||||
|
LOG("Racing cheat 9 detected with value %f.", cheatInfo);
|
||||||
|
} else if (cheatType == eFunnessTypes::Unknown_10) {
|
||||||
|
LOG("Racing cheat 10 detected with value %f.", cheatInfo);
|
||||||
|
} else if (cheatType == eFunnessTypes::CharacterPosLength) {
|
||||||
|
LOG("Detected pos length of %f which is greater than the expected value 1.0f, not normal!", cheatInfo);
|
||||||
|
} else if (cheatType == eFunnessTypes::CharacterVelLength) {
|
||||||
|
LOG("Detected vel length of %f which is greater than the expected value 1.0f, not normal!", cheatInfo);
|
||||||
|
} else if (cheatType == eFunnessTypes::CharacterGravityScale) {
|
||||||
|
LOG("Detected gravity scale difference of %f which is greater than the expected value of 0.0f, not normal!", cheatInfo);
|
||||||
|
} else if (cheatType == eFunnessTypes::CharacterRunMultiplier) {
|
||||||
|
LOG("Detected run multiplier difference of %f which is greater than the expected value 0.0f, not normal!", cheatInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!disabledCheats && user->GetMaxGMLevel() < eGameMasterLevel::DEVELOPER) user->UserOutOfSync(funness);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user