mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-10-10 17:38:08 +00:00
feat: Add configurable restrictions for muted accounts (#1887)
* Add configurable restrictions for muted accounts * switched to and updated GetRandomElement * Update config option check * implement cached config values for mute settings and update handlers * Address review * Update dGame/dComponents/PetComponent.cpp Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> * Update dGame/dComponents/PetComponent.cpp Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> * reduce if argument chain --------- Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
#include "dPlatforms.h"
|
||||
#include "Game.h"
|
||||
#include "Logger.h"
|
||||
#include "DluAssert.h"
|
||||
|
||||
#include <glm/ext/vector_float3.hpp>
|
||||
|
||||
@@ -305,7 +306,7 @@ namespace GeneralUtils {
|
||||
template<typename Container>
|
||||
inline Container::value_type GetRandomElement(const Container& container) {
|
||||
DluAssert(!container.empty());
|
||||
return container[GenerateRandomNumber<typename Container::value_type>(0, container.size() - 1)];
|
||||
return container[GenerateRandomNumber<typename Container::size_type>(0, container.size() - 1)];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "BitStreamUtils.h"
|
||||
#include "CheatDetection.h"
|
||||
#include "CharacterComponent.h"
|
||||
#include "dConfig.h"
|
||||
#include "eCharacterVersion.h"
|
||||
|
||||
UserManager* UserManager::m_Address = nullptr;
|
||||
@@ -92,6 +93,23 @@ void UserManager::Initialize() {
|
||||
StripCR(line);
|
||||
m_PreapprovedNames.push_back(line);
|
||||
}
|
||||
|
||||
// Initialize cached config values and register a handler to update them on config reload
|
||||
// This avoids repeated lookups into dConfig at runtime.
|
||||
if (Game::config) {
|
||||
m_MuteAutoRejectNames = (Game::config->GetValue("mute_auto_reject_names") == "1");
|
||||
m_MuteRestrictTrade = (Game::config->GetValue("mute_restrict_trade") == "1");
|
||||
m_MuteRestrictMail = (Game::config->GetValue("mute_restrict_mail") == "1");
|
||||
|
||||
Game::config->AddConfigHandler([this]() {
|
||||
this->m_MuteAutoRejectNames = (Game::config->GetValue("mute_auto_reject_names") == "1");
|
||||
this->m_MuteRestrictTrade = (Game::config->GetValue("mute_restrict_trade") == "1");
|
||||
this->m_MuteRestrictMail = (Game::config->GetValue("mute_restrict_mail") == "1");
|
||||
});
|
||||
}
|
||||
else {
|
||||
LOG("Warning: dConfig not initialized before UserManager. Cached config values will not be available.");
|
||||
}
|
||||
}
|
||||
|
||||
UserManager::~UserManager() {
|
||||
@@ -301,7 +319,9 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
inStream.Read(eyes);
|
||||
inStream.Read(mouth);
|
||||
|
||||
const auto name = LUWStringName.GetAsString();
|
||||
const bool autoRejectNames = this->GetMuteAutoRejectNames() && u->GetIsMuted();
|
||||
|
||||
const auto name = autoRejectNames ? "" : LUWStringName.GetAsString();
|
||||
std::string predefinedName = GetPredefinedName(firstNameIndex, middleNameIndex, lastNameIndex);
|
||||
|
||||
LOT shirtLOT = FindCharShirtID(shirtColor, shirtStyle);
|
||||
@@ -319,6 +339,10 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
return;
|
||||
}
|
||||
|
||||
if (autoRejectNames) {
|
||||
LOG("AccountID: %i is muted, forcing use of predefined name", u->GetAccountID());
|
||||
}
|
||||
|
||||
if (name.empty()) {
|
||||
LOG("AccountID: %i is creating a character with predefined name: %s", u->GetAccountID(), predefinedName.c_str());
|
||||
} else {
|
||||
@@ -369,6 +393,7 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
|
||||
//Check to see if our name was pre-approved:
|
||||
bool nameOk = IsNamePreapproved(name);
|
||||
|
||||
if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
|
||||
|
||||
// If predefined name is invalid, change it to be their object id
|
||||
@@ -448,9 +473,10 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
|
||||
LUWString LUWStringName;
|
||||
inStream.Read(LUWStringName);
|
||||
const auto newName = LUWStringName.GetAsString();
|
||||
auto newName = LUWStringName.GetAsString();
|
||||
|
||||
Character* character = nullptr;
|
||||
const bool autoRejectNames = this->GetMuteAutoRejectNames() && u->GetIsMuted();
|
||||
|
||||
//Check if this user has this character:
|
||||
bool ownsCharacter = CheatDetection::VerifyLwoobjidIsSender(
|
||||
@@ -471,13 +497,30 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
if (!ownsCharacter || !character) {
|
||||
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::UNKNOWN_ERROR);
|
||||
} else if (ownsCharacter && character) {
|
||||
if (autoRejectNames) {
|
||||
// Create a random preapproved name (fallback to default if none available)
|
||||
if (!m_FirstNames.empty() && !m_MiddleNames.empty() && !m_LastNames.empty()) {
|
||||
std::string firstName = GeneralUtils::GetRandomElement(m_FirstNames);
|
||||
std::string middleName = GeneralUtils::GetRandomElement(m_MiddleNames);
|
||||
std::string lastName = GeneralUtils::GetRandomElement(m_LastNames);
|
||||
newName = firstName + middleName + lastName;
|
||||
} else {
|
||||
newName = "character" + std::to_string(objectID);
|
||||
}
|
||||
}
|
||||
|
||||
if (newName == character->GetName()) {
|
||||
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::NAME_UNAVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Database::Get()->GetCharacterInfo(newName)) {
|
||||
if (IsNamePreapproved(newName)) {
|
||||
if (autoRejectNames) {
|
||||
Database::Get()->SetCharacterName(objectID, newName);
|
||||
LOG("Character %s auto-renamed to preapproved name %s due to mute", character->GetName().c_str(), newName.c_str());
|
||||
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::SUCCESS);
|
||||
UserManager::RequestCharacterList(sysAddr);
|
||||
} else if (IsNamePreapproved(newName)) {
|
||||
Database::Get()->SetCharacterName(objectID, newName);
|
||||
LOG("Character %s now known as %s", character->GetName().c_str(), newName.c_str());
|
||||
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::SUCCESS);
|
||||
|
@@ -41,6 +41,11 @@ public:
|
||||
|
||||
size_t GetUserCount() const { return m_Users.size(); }
|
||||
|
||||
// Access cached config values
|
||||
bool GetMuteAutoRejectNames() const { return m_MuteAutoRejectNames; }
|
||||
bool GetMuteRestrictTrade() const { return m_MuteRestrictTrade; }
|
||||
bool GetMuteRestrictMail() const { return m_MuteRestrictMail; }
|
||||
|
||||
private:
|
||||
static UserManager* m_Address; //Singleton
|
||||
std::map<SystemAddress, User*> m_Users;
|
||||
@@ -50,6 +55,11 @@ private:
|
||||
std::vector<std::string> m_MiddleNames;
|
||||
std::vector<std::string> m_LastNames;
|
||||
std::vector<std::string> m_PreapprovedNames;
|
||||
|
||||
// Cached config values that can change on config reload
|
||||
bool m_MuteAutoRejectNames = false;
|
||||
bool m_MuteRestrictTrade = false;
|
||||
bool m_MuteRestrictMail = false;
|
||||
};
|
||||
|
||||
#endif // USERMANAGER_H
|
||||
|
@@ -10,9 +10,11 @@
|
||||
#include "InventoryComponent.h"
|
||||
#include "Item.h"
|
||||
#include "MissionComponent.h"
|
||||
#include "User.h"
|
||||
#include "SwitchComponent.h"
|
||||
#include "DestroyableComponent.h"
|
||||
#include "dpWorld.h"
|
||||
#include "UserManager.h"
|
||||
#include "PetDigServer.h"
|
||||
#include "ObjectIDManager.h"
|
||||
#include "eUnequippableActiveType.h"
|
||||
@@ -21,6 +23,7 @@
|
||||
#include "eUseItemResponse.h"
|
||||
#include "ePlayerFlag.h"
|
||||
|
||||
#include "GeneralUtils.h"
|
||||
#include "Game.h"
|
||||
#include "dConfig.h"
|
||||
#include "dChatFilter.h"
|
||||
@@ -553,10 +556,20 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) {
|
||||
}
|
||||
|
||||
void PetComponent::RequestSetPetName(std::u16string name) {
|
||||
const bool autoRejectNames = UserManager::Instance()->GetMuteAutoRejectNames();
|
||||
|
||||
if (m_Tamer == LWOOBJID_EMPTY) {
|
||||
if (m_Owner != LWOOBJID_EMPTY) {
|
||||
auto* owner = GetOwner();
|
||||
|
||||
// If auto reject names is on, and the user is muted, force use of predefined name
|
||||
if (autoRejectNames && owner && owner->GetCharacter() && owner->GetCharacter()->GetParentUser()->GetIsMuted()) {
|
||||
m_ModerationStatus = 2; // Approved
|
||||
std::string forcedName = "Pet";
|
||||
Database::Get()->SetPetNameModerationStatus(m_DatabaseId, IPetNames::Info{ forcedName, static_cast<int32_t>(m_ModerationStatus) });
|
||||
GameMessages::SendSetPetName(m_Owner, GeneralUtils::UTF8ToUTF16(m_Name), m_DatabaseId, owner->GetSystemAddress());
|
||||
GameMessages::SendSetPetNameModerated(m_Owner, m_DatabaseId, m_ModerationStatus, owner->GetSystemAddress());
|
||||
} else {
|
||||
m_ModerationStatus = 1; // Pending
|
||||
m_Name = "";
|
||||
|
||||
@@ -566,6 +579,7 @@ void PetComponent::RequestSetPetName(std::u16string name) {
|
||||
GameMessages::SendSetPetName(m_Owner, GeneralUtils::UTF8ToUTF16(m_Name), m_DatabaseId, owner->GetSystemAddress());
|
||||
GameMessages::SendSetPetNameModerated(m_Owner, m_DatabaseId, m_ModerationStatus, owner->GetSystemAddress());
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -586,11 +600,21 @@ void PetComponent::RequestSetPetName(std::u16string name) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If auto reject names is on, and the user is muted, force use of predefined name ELSE proceed with normal name check
|
||||
if (autoRejectNames && tamer->GetCharacter() && tamer->GetCharacter()->GetParentUser()->GetIsMuted()) {
|
||||
m_ModerationStatus = 2; // Approved
|
||||
m_Name = "";
|
||||
std::string forcedName = "Pet";
|
||||
|
||||
Database::Get()->SetPetNameModerationStatus(m_DatabaseId, IPetNames::Info{ forcedName, static_cast<int32_t>(m_ModerationStatus) });
|
||||
LOG("AccountID: %i is muted, forcing use of predefined pet name", tamer->GetCharacter()->GetParentUser()->GetAccountID());
|
||||
} else {
|
||||
m_ModerationStatus = 1; // Pending
|
||||
m_Name = "";
|
||||
|
||||
//Save our pet's new name to the db:
|
||||
SetPetNameForModeration(GeneralUtils::UTF16ToWTF8(name));
|
||||
}
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
|
||||
|
@@ -3243,12 +3243,13 @@ void GameMessages::SendServerTradeUpdate(LWOOBJID objectId, uint64_t coins, cons
|
||||
void GameMessages::HandleClientTradeRequest(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
// Check if the player has restricted trade access
|
||||
auto* character = entity->GetCharacter();
|
||||
const bool restrictTradeOnMute = UserManager::Instance()->GetMuteRestrictTrade();
|
||||
|
||||
if (character->HasPermission(ePermissionMap::RestrictedTradeAccess)) {
|
||||
if (character->HasPermission(ePermissionMap::RestrictedTradeAccess) || (restrictTradeOnMute && character->GetParentUser()->GetIsMuted())) {
|
||||
// Send a message to the player
|
||||
ChatPackets::SendSystemMessage(
|
||||
sysAddr,
|
||||
u"This character has restricted trade access."
|
||||
u"Your character has restricted trade access."
|
||||
);
|
||||
|
||||
return;
|
||||
@@ -3264,7 +3265,7 @@ void GameMessages::HandleClientTradeRequest(RakNet::BitStream& inStream, Entity*
|
||||
if (invitee != nullptr && invitee->IsPlayer()) {
|
||||
character = invitee->GetCharacter();
|
||||
|
||||
if (character->HasPermission(ePermissionMap::RestrictedTradeAccess)) {
|
||||
if (character->HasPermission(ePermissionMap::RestrictedTradeAccess) || (restrictTradeOnMute && character->GetParentUser()->GetIsMuted())) {
|
||||
// Send a message to the player
|
||||
ChatPackets::SendSystemMessage(
|
||||
sysAddr,
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include "GeneralUtils.h"
|
||||
#include "Database.h"
|
||||
#include "Game.h"
|
||||
#include "dConfig.h"
|
||||
#include "dServer.h"
|
||||
#include "Entity.h"
|
||||
#include "Character.h"
|
||||
@@ -28,6 +29,7 @@
|
||||
#include "ServiceType.h"
|
||||
#include "User.h"
|
||||
#include "StringifiedEnum.h"
|
||||
#include "UserManager.h"
|
||||
|
||||
namespace {
|
||||
const std::string DefaultSender = "%[MAIL_SYSTEM_NOTIFICATION]";
|
||||
@@ -72,7 +74,10 @@ namespace Mail {
|
||||
void SendRequest::Handle() {
|
||||
SendResponse response;
|
||||
auto* character = player->GetCharacter();
|
||||
if (character && !(character->HasPermission(ePermissionMap::RestrictedMailAccess) || character->GetParentUser()->GetIsMuted())) {
|
||||
const bool restrictMailOnMute = UserManager::Instance()->GetMuteRestrictMail() && character->GetParentUser()->GetIsMuted();
|
||||
const bool restrictedMailAccess = character->HasPermission(ePermissionMap::RestrictedMailAccess);
|
||||
|
||||
if (character && !(restrictedMailAccess || restrictMailOnMute)) {
|
||||
mailInfo.recipient = std::regex_replace(mailInfo.recipient, std::regex("[^0-9a-zA-Z]+"), "");
|
||||
auto receiverID = Database::Get()->GetCharacterInfo(mailInfo.recipient);
|
||||
|
||||
|
@@ -74,3 +74,9 @@ database_type=sqlite
|
||||
|
||||
# Skips the account creation check in master. Used for non-interactive setups.
|
||||
skip_account_creation=0
|
||||
# 0 or 1, restrict mail while account is muted
|
||||
mute_restrict_mail=1
|
||||
# 0 or 1, restrict trade while account is muted
|
||||
mute_restrict_trade=1
|
||||
# 0 or 1, automatically reject character and pet names submitted while muted
|
||||
mute_auto_reject_names=1
|
||||
|
Reference in New Issue
Block a user