This commit is contained in:
Aronwk 2025-05-18 23:36:05 -05:00
parent 80a4f77441
commit 4627168871
6 changed files with 93 additions and 87 deletions

View File

@ -0,0 +1,11 @@
#ifndef __ECHATMODE__H__
#define __ECHATMODE__H__
#include <cstdint>
enum class eChatMode : uint8_t {
RESTRICTED = 0,
UNRESTRICTED = 1
};
#endif //!__ECHATMODE__H__

View File

@ -46,28 +46,26 @@ namespace ClientPackets {
RakNet::BitStream data; RakNet::BitStream data;
data.Write<uint32_t>(7); //LDF key count data.Write<uint32_t>(7); // LDF key count
LDFData<LWOOBJID>(u"objid", objid).WriteToPacket(data); LDFData<LWOOBJID>(u"objid", objid).WriteToPacket(data);
LDFData<LOT>(u"template", templateID).WriteToPacket(data);; LDFData<LOT>(u"template", templateID).WriteToPacket(data);
LDFData<std::u16string>(u"name", name).WriteToPacket(data);; LDFData<std::u16string>(u"name", name).WriteToPacket(data);
LDFData<int32_t>(u"gmlevel", static_cast<int32_t>(gmLevel)).WriteToPacket(data);; LDFData<int32_t>(u"gmlevel", static_cast<int32_t>(gmLevel)).WriteToPacket(data);
LDFData<int32_t>(u"chatmode", static_cast<int32_t>(chatMode)).WriteToPacket(data);; LDFData<int32_t>(u"chatmode", static_cast<int32_t>(chatMode)).WriteToPacket(data);
LDFData<std::string>(u"xmlData", xmlData).WriteToPacket(data);; LDFData<std::string_view>(u"xmlData", xmlData).WriteToPacket(data);
LDFData<int64_t>(u"reputation", reputation).WriteToPacket(data);; LDFData<int64_t>(u"reputation", reputation).WriteToPacket(data);
//Compress the data before sending:
// Compress the data before sending:
const uint32_t reservedSize = ZCompression::GetMaxCompressedLength(data.GetNumberOfBytesUsed()); const uint32_t reservedSize = ZCompression::GetMaxCompressedLength(data.GetNumberOfBytesUsed());
uint8_t* compressedData = new uint8_t[reservedSize]; uint8_t* compressedData = new uint8_t[reservedSize];
if (!compressedData) { if (!compressedData) throw std::runtime_error("Failed to allocate memory for compressed data");
throw std::runtime_error("Failed to allocate memory for compressed data");
}
size_t size = ZCompression::Compress(data.GetData(), data.GetNumberOfBytesUsed(), compressedData, reservedSize); size_t size = ZCompression::Compress(data.GetData(), data.GetNumberOfBytesUsed(), compressedData, reservedSize);
assert(size <= reservedSize); assert(size <= reservedSize);
bitStream.Write<uint32_t>(size + 9); //size of data + header bytes (8) bitStream.Write<uint32_t>(size + 9); // size of data + header bytes (8)
bitStream.Write<uint8_t>(1); //compressed boolean, true bitStream.Write<uint8_t>(1); // compressed boolean, true
bitStream.Write<uint32_t>(data.GetNumberOfBytesUsed()); bitStream.Write<uint32_t>(data.GetNumberOfBytesUsed());
bitStream.Write<uint32_t>(size); bitStream.Write<uint32_t>(size);
@ -91,14 +89,16 @@ namespace ClientPackets {
bitStream.Write(LUWString(receiver, 42)); bitStream.Write(LUWString(receiver, 42));
// Write the rejected words
// There has to be 64 items written so we need to pad the rest with 0s
int toWrite = 64;
for (auto it : rejectedWords) { for (auto it : rejectedWords) {
if (toWrite <= 0) return;
bitStream.Write<uint8_t>(it.first); // start index bitStream.Write<uint8_t>(it.first); // start index
bitStream.Write<uint8_t>(it.second); // length bitStream.Write<uint8_t>(it.second); // length
toWrite--;
} }
for (toWrite; toWrite <= 0; toWrite--) {
// Pad out the rest of the packet
// The client expects 64 items, so we need to write 64 - rejectedWords.size() empty items
for (int i = rejectedWords.size(); 64 > i; i++) {
bitStream.Write<uint16_t>(0); bitStream.Write<uint16_t>(0);
} }

View File

@ -74,12 +74,12 @@ namespace ClientPackets {
}; };
struct CreateCharacter : public LUBitStream { struct CreateCharacter : public LUBitStream {
LWOOBJID objid = 0; LWOOBJID objid = LWOOBJID_EMPTY;
LOT templateID = 1; LOT templateID = 1;
std::u16string name; std::u16string name;
eGameMasterLevel gmLevel = eGameMasterLevel::CIVILIAN; eGameMasterLevel gmLevel = eGameMasterLevel::CIVILIAN;
int32_t chatMode = 0; int32_t chatMode = 0;
std::string xmlData; std::string_view xmlData;
int64_t reputation = 0; int64_t reputation = 0;
CreateCharacter() : LUBitStream(eConnectionType::CLIENT, MessageType::Client::CREATE_CHARACTER) {}; CreateCharacter() : LUBitStream(eConnectionType::CLIENT, MessageType::Client::CREATE_CHARACTER) {};

View File

@ -9,6 +9,8 @@
#include "Character.h" #include "Character.h"
#include "dChatFilter.h" #include "dChatFilter.h"
#include "ChatPackets.h" #include "ChatPackets.h"
#include "ClientPackets.h"
#include "Database.h"
namespace WorldPackets { namespace WorldPackets {
@ -160,7 +162,7 @@ namespace WorldPackets {
} }
bool StringCheck::Deserialize(RakNet::BitStream& bitStream) { bool StringCheck::Deserialize(RakNet::BitStream& bitStream) {
VALIDATE_READ(bitStream.Read(chatLevel)); VALIDATE_READ(bitStream.Read(chatMode));
VALIDATE_READ(bitStream.Read(requestID)); VALIDATE_READ(bitStream.Read(requestID));
for (uint32_t i = 0; i < 42; ++i) { for (uint32_t i = 0; i < 42; ++i) {
@ -187,6 +189,58 @@ namespace WorldPackets {
} }
void StringCheck::Handle() { void StringCheck::Handle() {
auto* entity = Game::entityManager->GetEntity(objectID);
if (!entity) {
LOG("Unable to get player to handle string check request");
return;
}
auto* character = entity->GetCharacter();
if (!character) {
LOG("Unable to get character to handle string check request");
return;
}
auto* user = character->GetParentUser();
if (!user) {
LOG("Unable to get user to handle string check request");
return;
}
// Check if the player has restricted chat access
if (character->HasPermission(ePermissionMap::RestrictedChatAccess)) {
ChatPackets::SendSystemMessage(
entity->GetSystemAddress(),
u"This character has restricted chat access."
);
return;
}
bool isBestFriend = false;
if (chatMode == eChatMode::UNRESTRICTED) {
// Check if the receiver is a best friend
LWOOBJID idOfReceiver = LWOOBJID_EMPTY;
{
auto characterIdFetch = Database::Get()->GetCharacterInfo(receiver);
if (characterIdFetch) idOfReceiver = characterIdFetch->id;
}
const auto& bffMap = user->GetIsBestFriendMap();
if (bffMap.find(receiver) == bffMap.end() && idOfReceiver != LWOOBJID_EMPTY) {
auto bffInfo = Database::Get()->GetBestFriendStatus(entity->GetObjectID(), idOfReceiver);
if (bffInfo) isBestFriend = bffInfo->bestFriendStatus == 3;
if (isBestFriend) user->UpdateBestFriendValue(receiver, true);
} else if (bffMap.find(receiver) != bffMap.end()) {
isBestFriend = true;
}
}
const auto segments = Game::chatFilter->IsSentenceOkay(message, entity->GetGMLevel(), !(isBestFriend && chatMode == eChatMode::UNRESTRICTED));
bool bAllClean = segments.empty();
if (user->GetIsMuted()) bAllClean = false;
user->SetLastChatMessageApproved(bAllClean);
ClientPackets::ChatModerationString response;
response.receiver = receiver;
response.rejectedWords = segments;
response.Send(entity->GetSystemAddress());
} }
} }

View File

@ -4,6 +4,7 @@
#include "dCommonVars.h" #include "dCommonVars.h"
#include "BitStreamUtils.h" #include "BitStreamUtils.h"
#include "MessageType/World.h" #include "MessageType/World.h"
#include "eChatMode.h"
class Entity; class Entity;
enum class eLanguageCodeID : int32_t { enum class eLanguageCodeID : int32_t {
@ -62,7 +63,7 @@ namespace WorldPackets {
}; };
struct StringCheck : public LUBitStream { struct StringCheck : public LUBitStream {
uint8_t chatLevel = 0; eChatMode chatMode = eChatMode::RESTRICTED;
uint8_t requestID = 0; uint8_t requestID = 0;
std::string receiver; std::string receiver;
std::string message; std::string message;

View File

@ -1043,7 +1043,7 @@ void HandlePacket(Packet* packet) {
createCharacter.name = username; createCharacter.name = username;
createCharacter.gmLevel = c->GetGMLevel(); createCharacter.gmLevel = c->GetGMLevel();
createCharacter.xmlData = c->GetXMLData(); createCharacter.xmlData = c->GetXMLData();
createCharacter.reputation = player->GetComponent<CharacterComponent>()->GetReputation(); createCharacter.reputation = characterComponent->GetReputation();
createCharacter.Send(packet->systemAddress); createCharacter.Send(packet->systemAddress);
ClientPackets::ServerState serverState; ClientPackets::ServerState serverState;
@ -1230,7 +1230,8 @@ void HandlePacket(Packet* packet) {
LOG("Unable to get user to parse position update"); LOG("Unable to get user to parse position update");
return; return;
} }
positionUpdate.objectID = user->GetLastUsedChar()->GetObjectID(); positionUpdate.objectID = user->GetLastUsedChar()->GetObjectID();
positionUpdate.Handle();
break; break;
} }
@ -1277,75 +1278,14 @@ void HandlePacket(Packet* packet) {
WorldPackets::StringCheck request; WorldPackets::StringCheck request;
request.Deserialize(inStream); request.Deserialize(inStream);
// TODO: Find a good home for the logic in this case.
User* user = UserManager::Instance()->GetUser(packet->systemAddress);
if (!user) {
LOG("Unable to get user to parse chat moderation request");
return;
}
auto* entity = PlayerManager::GetPlayer(packet->systemAddress); auto* entity = PlayerManager::GetPlayer(packet->systemAddress);
if (entity == nullptr) { if (entity == nullptr) {
LOG("Unable to get player to parse chat moderation request"); LOG("Unable to get player to parse chat moderation request");
return; return;
} }
// Check if the player has restricted chat access request.objectID = entity->GetObjectID();
auto* character = entity->GetCharacter(); request.Handle();
if (character->HasPermission(ePermissionMap::RestrictedChatAccess)) {
// Send a message to the player
ChatPackets::SendSystemMessage(
packet->systemAddress,
u"This character has restricted chat access."
);
return;
}
bool isBestFriend = false;
if (request.chatLevel == 1) {
// Private chat
LWOOBJID idOfReceiver = LWOOBJID_EMPTY;
{
auto characterIdFetch = Database::Get()->GetCharacterInfo(request.receiver);
if (characterIdFetch) {
idOfReceiver = characterIdFetch->id;
}
}
const auto& bffMap = user->GetIsBestFriendMap();
if (bffMap.find(request.receiver) == bffMap.end() && idOfReceiver != LWOOBJID_EMPTY) {
auto bffInfo = Database::Get()->GetBestFriendStatus(entity->GetObjectID(), idOfReceiver);
if (bffInfo) {
isBestFriend = bffInfo->bestFriendStatus == 3;
}
if (isBestFriend) {
user->UpdateBestFriendValue(request.receiver, true);
}
} else if (bffMap.find(request.receiver) != bffMap.end()) {
isBestFriend = true;
}
}
const auto segments = Game::chatFilter->IsSentenceOkay(request.message, entity->GetGMLevel(), !(isBestFriend && request.chatLevel == 1));
bool bAllClean = segments.empty();
if (user->GetIsMuted()) {
bAllClean = false;
}
user->SetLastChatMessageApproved(bAllClean);
ClientPackets::ChatModerationString response;
response.receiver = request.receiver;
response.rejectedWords = segments;
response.Send(packet->systemAddress);
break; break;
} }