mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-10-13 02:48:19 +00:00
Merge branch 'main' into fix/cmake-libs-2
This commit is contained in:
@@ -15,4 +15,4 @@ target_link_libraries(WorldServer ${COMMON_LIBRARIES}
|
||||
dUtilities
|
||||
dGameMessages
|
||||
dInventory
|
||||
dGame dChatFilter dZoneManager dPhysics Detour Recast tinyxml2 dWorldServer dNavigation)
|
||||
dGame dChatFilter dZoneManager dPhysics Detour Recast tinyxml2 dWorldServer dNavigation)
|
||||
|
@@ -29,7 +29,6 @@
|
||||
#include <csignal>
|
||||
|
||||
#include "AuthPackets.h"
|
||||
#include "PacketUtils.h"
|
||||
#include "BitStreamUtils.h"
|
||||
#include "WorldPackets.h"
|
||||
#include "UserManager.h"
|
||||
@@ -77,11 +76,14 @@
|
||||
#include "CheatDetection.h"
|
||||
#include "eGameMasterLevel.h"
|
||||
#include "StringifiedEnum.h"
|
||||
#include "Server.h"
|
||||
#include "PositionUpdate.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "eLoginResponse.h"
|
||||
|
||||
namespace Game {
|
||||
Logger* logger = nullptr;
|
||||
dServer* server = nullptr;
|
||||
dpWorld* physicsWorld = nullptr;
|
||||
dChatFilter* chatFilter = nullptr;
|
||||
dConfig* config = nullptr;
|
||||
AssetManager* assetManager = nullptr;
|
||||
@@ -102,8 +104,8 @@ void WorldShutdownProcess(uint32_t zoneId);
|
||||
void FinalizeShutdown();
|
||||
void SendShutdownMessageToMaster();
|
||||
|
||||
Logger* SetupLogger(uint32_t zoneID, uint32_t instanceID);
|
||||
void HandlePacketChat(Packet* packet);
|
||||
void HandleMasterPacket(Packet* packet);
|
||||
void HandlePacket(Packet* packet);
|
||||
|
||||
struct tempSessionInfo {
|
||||
@@ -143,14 +145,11 @@ int main(int argc, char** argv) {
|
||||
if (argument == "-port") ourPort = atoi(argv[i + 1]);
|
||||
}
|
||||
|
||||
//Create all the objects we need to run our service:
|
||||
Game::logger = SetupLogger(zoneID, instanceID);
|
||||
if (!Game::logger) return EXIT_FAILURE;
|
||||
|
||||
//Read our config:
|
||||
Game::config = new dConfig("worldconfig.ini");
|
||||
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
|
||||
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
|
||||
|
||||
//Create all the objects we need to run our service:
|
||||
Server::SetupLogger("WorldServer_" + std::to_string(zoneID) + "_" + std::to_string(instanceID));
|
||||
if (!Game::logger) return EXIT_FAILURE;
|
||||
|
||||
LOG("Starting World server...");
|
||||
LOG("Version: %s", Game::projectVersion.c_str());
|
||||
@@ -182,7 +181,7 @@ int main(int argc, char** argv) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
CDClientManager::Instance();
|
||||
CDClientManager::Instance().LoadValuesFromDatabase();
|
||||
|
||||
Diagnostics::SetProduceMemoryDump(Game::config->GetValue("generate_dump") == "1");
|
||||
|
||||
@@ -257,7 +256,7 @@ int main(int argc, char** argv) {
|
||||
Game::zoneManager = new dZoneManager();
|
||||
//Load our level:
|
||||
if (zoneID != 0) {
|
||||
dpWorld::Instance().Initialize(zoneID);
|
||||
dpWorld::Initialize(zoneID);
|
||||
Game::zoneManager->Initialize(LWOZONEID(zoneID, instanceID, cloneID));
|
||||
g_CloneID = cloneID;
|
||||
|
||||
@@ -388,7 +387,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
if (zoneID != 0 && deltaTime > 0.0f) {
|
||||
Metrics::StartMeasurement(MetricVariable::Physics);
|
||||
dpWorld::Instance().StepWorld(deltaTime);
|
||||
dpWorld::StepWorld(deltaTime);
|
||||
Metrics::EndMeasurement(MetricVariable::Physics);
|
||||
|
||||
Metrics::StartMeasurement(MetricVariable::UpdateEntities);
|
||||
@@ -412,7 +411,7 @@ int main(int argc, char** argv) {
|
||||
//Check for packets here:
|
||||
packet = Game::server->ReceiveFromMaster();
|
||||
if (packet) { //We can get messages not handle-able by the dServer class, so handle them if we returned anything.
|
||||
HandlePacket(packet);
|
||||
HandleMasterPacket(packet);
|
||||
Game::server->DeallocateMasterPacket(packet);
|
||||
}
|
||||
|
||||
@@ -529,18 +528,6 @@ int main(int argc, char** argv) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Logger* SetupLogger(uint32_t zoneID, uint32_t instanceID) {
|
||||
std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/WorldServer_" + std::to_string(zoneID) + "_" + std::to_string(instanceID) + "_" + std::to_string(time(nullptr)) + ".log")).string();
|
||||
bool logToConsole = false;
|
||||
bool logDebugStatements = false;
|
||||
#ifdef _DEBUG
|
||||
logToConsole = true;
|
||||
logDebugStatements = true;
|
||||
#endif
|
||||
|
||||
return new Logger(logPath, logToConsole, logDebugStatements);
|
||||
}
|
||||
|
||||
void HandlePacketChat(Packet* packet) {
|
||||
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
||||
LOG("Lost our connection to chat, zone(%i), instance(%i)", Game::server->GetZoneID(), Game::server->GetInstanceID());
|
||||
@@ -672,6 +659,132 @@ void HandlePacketChat(Packet* packet) {
|
||||
}
|
||||
}
|
||||
|
||||
void HandleMasterPacket(Packet* packet) {
|
||||
|
||||
if (static_cast<eConnectionType>(packet->data[1]) != eConnectionType::MASTER || packet->length < 4) return;
|
||||
switch (static_cast<eMasterMessageType>(packet->data[3])) {
|
||||
case eMasterMessageType::REQUEST_PERSISTENT_ID_RESPONSE: {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
uint64_t requestID;
|
||||
inStream.Read(requestID);
|
||||
uint32_t objectID;
|
||||
inStream.Read(objectID);
|
||||
ObjectIDManager::HandleRequestPersistentIDResponse(requestID, objectID);
|
||||
break;
|
||||
}
|
||||
|
||||
case eMasterMessageType::SESSION_KEY_RESPONSE: {
|
||||
//Read our session key and to which user it belongs:
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
uint32_t sessionKey = 0;
|
||||
inStream.Read(sessionKey);
|
||||
LUWString username;
|
||||
inStream.Read(username);
|
||||
|
||||
//Find them:
|
||||
auto it = m_PendingUsers.find(username.GetAsString());
|
||||
if (it == m_PendingUsers.end()) return;
|
||||
|
||||
//Convert our key:
|
||||
std::string userHash = std::to_string(sessionKey);
|
||||
userHash = md5(userHash);
|
||||
|
||||
//Verify it:
|
||||
if (userHash != it->second.hash) {
|
||||
LOG("SOMEONE IS TRYING TO HACK? SESSION KEY MISMATCH: ours: %s != master: %s", userHash.c_str(), it->second.hash.c_str());
|
||||
Game::server->Disconnect(it->second.sysAddr, eServerDisconnectIdentifiers::INVALID_SESSION_KEY);
|
||||
return;
|
||||
} else {
|
||||
LOG("User %s authenticated with correct key.", username.GetAsString().c_str());
|
||||
|
||||
UserManager::Instance()->DeleteUser(packet->systemAddress);
|
||||
|
||||
//Create our user and send them in:
|
||||
UserManager::Instance()->CreateUser(it->second.sysAddr, username.GetAsString(), userHash);
|
||||
|
||||
auto zone = Game::zoneManager->GetZone();
|
||||
if (zone) {
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
float z = 0.0f;
|
||||
|
||||
if (zone->GetZoneID().GetMapID() == 1100) {
|
||||
auto pos = zone->GetSpawnPos();
|
||||
x = pos.x;
|
||||
y = pos.y;
|
||||
z = pos.z;
|
||||
}
|
||||
|
||||
WorldPackets::SendLoadStaticZone(it->second.sysAddr, x, y, z, zone->GetChecksum(), Game::zoneManager->GetZoneID());
|
||||
}
|
||||
|
||||
if (Game::server->GetZoneID() == 0) {
|
||||
//Since doing this reroute breaks the client's request, we have to call this manually.
|
||||
UserManager::Instance()->RequestCharacterList(it->second.sysAddr);
|
||||
}
|
||||
|
||||
m_PendingUsers.erase(username.GetAsString());
|
||||
|
||||
//Notify master:
|
||||
{
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::PLAYER_ADDED);
|
||||
bitStream.Write((LWOMAPID)Game::server->GetZoneID());
|
||||
bitStream.Write((LWOINSTANCEID)instanceID);
|
||||
Game::server->SendToMaster(&bitStream);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case eMasterMessageType::AFFIRM_TRANSFER_REQUEST: {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
uint64_t requestID;
|
||||
inStream.Read(requestID);
|
||||
LOG("Got affirmation request of transfer %llu", requestID);
|
||||
|
||||
CBITSTREAM;
|
||||
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::AFFIRM_TRANSFER_RESPONSE);
|
||||
bitStream.Write(requestID);
|
||||
Game::server->SendToMaster(&bitStream);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case eMasterMessageType::SHUTDOWN: {
|
||||
Game::lastSignal = -1;
|
||||
LOG("Got shutdown request from master, zone (%i), instance (%i)", Game::server->GetZoneID(), Game::server->GetInstanceID());
|
||||
break;
|
||||
}
|
||||
|
||||
case eMasterMessageType::NEW_SESSION_ALERT: {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
uint32_t sessionKey = inStream.Read(sessionKey);
|
||||
|
||||
LUString username;
|
||||
inStream.Read(username);
|
||||
LOG("Got new session alert for user %s", username.string.c_str());
|
||||
//Find them:
|
||||
User* user = UserManager::Instance()->GetUser(username.string.c_str());
|
||||
if (!user) {
|
||||
LOG("But they're not logged in?");
|
||||
return;
|
||||
}
|
||||
|
||||
//Check the key:
|
||||
if (sessionKey != std::atoi(user->GetSessionKey().c_str())) {
|
||||
LOG("But the session key is invalid!", username.string.c_str());
|
||||
Game::server->Disconnect(user->GetSystemAddress(), eServerDisconnectIdentifiers::INVALID_SESSION_KEY);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG("Unknown packet ID from master %i", int(packet->data[3]));
|
||||
}
|
||||
}
|
||||
|
||||
void HandlePacket(Packet* packet) {
|
||||
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
||||
auto user = UserManager::Instance()->GetUser(packet->systemAddress);
|
||||
@@ -686,7 +799,7 @@ void HandlePacket(Packet* packet) {
|
||||
auto* entity = Game::entityManager->GetEntity(c->GetObjectID());
|
||||
|
||||
if (!entity) {
|
||||
entity = Player::GetPlayer(packet->systemAddress);
|
||||
entity = PlayerManager::GetPlayer(packet->systemAddress);
|
||||
}
|
||||
|
||||
if (entity) {
|
||||
@@ -730,159 +843,23 @@ void HandlePacket(Packet* packet) {
|
||||
}
|
||||
}
|
||||
|
||||
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::MASTER) {
|
||||
switch (static_cast<eMasterMessageType>(packet->data[3])) {
|
||||
case eMasterMessageType::REQUEST_PERSISTENT_ID_RESPONSE: {
|
||||
uint64_t requestID = PacketUtils::ReadU64(8, packet);
|
||||
uint32_t objectID = PacketUtils::ReadU32(16, packet);
|
||||
ObjectIDManager::HandleRequestPersistentIDResponse(requestID, objectID);
|
||||
break;
|
||||
}
|
||||
|
||||
case eMasterMessageType::REQUEST_ZONE_TRANSFER_RESPONSE: {
|
||||
uint64_t requestID = PacketUtils::ReadU64(8, packet);
|
||||
ZoneInstanceManager::Instance()->HandleRequestZoneTransferResponse(requestID, packet);
|
||||
break;
|
||||
}
|
||||
|
||||
case eMasterMessageType::SESSION_KEY_RESPONSE: {
|
||||
//Read our session key and to which user it belongs:
|
||||
RakNet::BitStream inStream(packet->data, packet->length, false);
|
||||
uint64_t header = inStream.Read(header);
|
||||
uint32_t sessionKey = 0;
|
||||
std::string username;
|
||||
|
||||
inStream.Read(sessionKey);
|
||||
username = PacketUtils::ReadString(12, packet, false);
|
||||
|
||||
//Find them:
|
||||
auto it = m_PendingUsers.find(username);
|
||||
if (it == m_PendingUsers.end()) return;
|
||||
|
||||
//Convert our key:
|
||||
std::string userHash = std::to_string(sessionKey);
|
||||
userHash = md5(userHash);
|
||||
|
||||
//Verify it:
|
||||
if (userHash != it->second.hash) {
|
||||
LOG("SOMEONE IS TRYING TO HACK? SESSION KEY MISMATCH: ours: %s != master: %s", userHash.c_str(), it->second.hash.c_str());
|
||||
Game::server->Disconnect(it->second.sysAddr, eServerDisconnectIdentifiers::INVALID_SESSION_KEY);
|
||||
return;
|
||||
} else {
|
||||
LOG("User %s authenticated with correct key.", username.c_str());
|
||||
|
||||
UserManager::Instance()->DeleteUser(packet->systemAddress);
|
||||
|
||||
//Create our user and send them in:
|
||||
UserManager::Instance()->CreateUser(it->second.sysAddr, username, userHash);
|
||||
|
||||
auto zone = Game::zoneManager->GetZone();
|
||||
if (zone) {
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
float z = 0.0f;
|
||||
|
||||
if (zone->GetZoneID().GetMapID() == 1100) {
|
||||
auto pos = zone->GetSpawnPos();
|
||||
x = pos.x;
|
||||
y = pos.y;
|
||||
z = pos.z;
|
||||
}
|
||||
|
||||
WorldPackets::SendLoadStaticZone(it->second.sysAddr, x, y, z, zone->GetChecksum());
|
||||
}
|
||||
|
||||
if (Game::server->GetZoneID() == 0) {
|
||||
//Since doing this reroute breaks the client's request, we have to call this manually.
|
||||
UserManager::Instance()->RequestCharacterList(it->second.sysAddr);
|
||||
}
|
||||
|
||||
m_PendingUsers.erase(username);
|
||||
|
||||
//Notify master:
|
||||
{
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::PLAYER_ADDED);
|
||||
bitStream.Write((LWOMAPID)Game::server->GetZoneID());
|
||||
bitStream.Write((LWOINSTANCEID)instanceID);
|
||||
Game::server->SendToMaster(&bitStream);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case eMasterMessageType::AFFIRM_TRANSFER_REQUEST: {
|
||||
const uint64_t requestID = PacketUtils::ReadU64(8, packet);
|
||||
|
||||
LOG("Got affirmation request of transfer %llu", requestID);
|
||||
|
||||
CBITSTREAM;
|
||||
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::AFFIRM_TRANSFER_RESPONSE);
|
||||
bitStream.Write(requestID);
|
||||
Game::server->SendToMaster(&bitStream);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case eMasterMessageType::SHUTDOWN: {
|
||||
Game::lastSignal = -1;
|
||||
LOG("Got shutdown request from master, zone (%i), instance (%i)", Game::server->GetZoneID(), Game::server->GetInstanceID());
|
||||
break;
|
||||
}
|
||||
|
||||
case eMasterMessageType::NEW_SESSION_ALERT: {
|
||||
RakNet::BitStream inStream(packet->data, packet->length, false);
|
||||
uint64_t header = inStream.Read(header);
|
||||
uint32_t sessionKey = inStream.Read(sessionKey);
|
||||
|
||||
std::string username;
|
||||
|
||||
uint32_t len;
|
||||
inStream.Read(len);
|
||||
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
char character; inStream.Read<char>(character);
|
||||
username += character;
|
||||
}
|
||||
|
||||
//Find them:
|
||||
User* user = UserManager::Instance()->GetUser(username.c_str());
|
||||
if (!user) {
|
||||
LOG("Got new session alert for user %s, but they're not logged in.", username.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
//Check the key:
|
||||
if (sessionKey != std::atoi(user->GetSessionKey().c_str())) {
|
||||
LOG("Got new session alert for user %s, but the session key is invalid.", username.c_str());
|
||||
Game::server->Disconnect(user->GetSystemAddress(), eServerDisconnectIdentifiers::INVALID_SESSION_KEY);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG("Unknown packet ID from master %i", int(packet->data[3]));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (static_cast<eConnectionType>(packet->data[1]) != eConnectionType::WORLD) return;
|
||||
|
||||
switch (static_cast<eWorldMessageType>(packet->data[3])) {
|
||||
case eWorldMessageType::VALIDATION: {
|
||||
std::string username = PacketUtils::ReadString(0x08, packet, true);
|
||||
std::string sessionKey = PacketUtils::ReadString(74, packet, true);
|
||||
std::string clientDatabaseChecksum = PacketUtils::ReadString(packet->length - 33, packet, false);
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
LUWString username;
|
||||
inStream.Read(username);
|
||||
|
||||
LUWString sessionKey;
|
||||
// sometimes client puts a null terminator at the end of the checksum and sometimes doesn't, weird
|
||||
clientDatabaseChecksum = clientDatabaseChecksum.substr(0, 32);
|
||||
inStream.Read(sessionKey);
|
||||
LUString clientDatabaseChecksum(32);
|
||||
inStream.Read(clientDatabaseChecksum);
|
||||
|
||||
// If the check is turned on, validate the client's database checksum.
|
||||
if (Game::config->GetValue("check_fdb") == "1" && !databaseChecksum.empty()) {
|
||||
auto accountInfo = Database::Get()->GetAccountInfo(username);
|
||||
auto accountInfo = Database::Get()->GetAccountInfo(username.GetAsString());
|
||||
if (!accountInfo) {
|
||||
LOG("Client's account does not exist in the database, aborting connection.");
|
||||
Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::CHARACTER_NOT_FOUND);
|
||||
@@ -890,24 +867,42 @@ void HandlePacket(Packet* packet) {
|
||||
}
|
||||
|
||||
// Developers may skip this check
|
||||
if (accountInfo->maxGmLevel < eGameMasterLevel::DEVELOPER && clientDatabaseChecksum != databaseChecksum) {
|
||||
LOG("Client's database checksum does not match the server's, aborting connection.");
|
||||
Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::WRONG_GAME_VERSION);
|
||||
return;
|
||||
if (clientDatabaseChecksum.string != databaseChecksum) {
|
||||
|
||||
if (accountInfo->maxGmLevel < eGameMasterLevel::DEVELOPER) {
|
||||
LOG("Client's database checksum does not match the server's, aborting connection.");
|
||||
std::vector<Stamp> stamps;
|
||||
|
||||
// Using the LoginResponse here since the UI is still in the login screen state
|
||||
// and we have a way to send a message about the client mismatch.
|
||||
AuthPackets::SendLoginResponse(
|
||||
Game::server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH,
|
||||
Game::config->GetValue("cdclient_mismatch_message"), "", 0, "", stamps);
|
||||
return;
|
||||
} else {
|
||||
AMFArrayValue args;
|
||||
|
||||
args.Insert("title", Game::config->GetValue("cdclient_mismatch_title"));
|
||||
args.Insert("message", Game::config->GetValue("cdclient_mismatch_message"));
|
||||
|
||||
GameMessages::SendUIMessageServerToSingleClient("ToggleAnnounce", args, packet->systemAddress);
|
||||
LOG("Account (%s) with GmLevel (%s) does not have a matching FDB, but is a developer and will skip this check."
|
||||
, username.GetAsString().c_str(), StringifiedEnum::ToString(accountInfo->maxGmLevel).data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Request the session info from Master:
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_SESSION_KEY);
|
||||
bitStream.Write(LUString(username, 64));
|
||||
bitStream.Write(username);
|
||||
Game::server->SendToMaster(&bitStream);
|
||||
|
||||
//Insert info into our pending list
|
||||
tempSessionInfo info;
|
||||
info.sysAddr = SystemAddress(packet->systemAddress);
|
||||
info.hash = sessionKey;
|
||||
m_PendingUsers.insert(std::make_pair(username, info));
|
||||
info.hash = sessionKey.GetAsString();
|
||||
m_PendingUsers.insert(std::make_pair(username.GetAsString(), info));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1026,7 +1021,10 @@ void HandlePacket(Packet* packet) {
|
||||
info.lot = 1;
|
||||
Entity* player = Game::entityManager->CreateEntity(info, UserManager::Instance()->GetUser(packet->systemAddress));
|
||||
|
||||
WorldPackets::SendCreateCharacter(packet->systemAddress, player, c->GetXMLData(), username, c->GetGMLevel());
|
||||
auto* characterComponent = player->GetComponent<CharacterComponent>();
|
||||
if (!characterComponent) return;
|
||||
|
||||
WorldPackets::SendCreateCharacter(packet->systemAddress, player->GetComponent<CharacterComponent>()->GetReputation(), player->GetObjectID(), c->GetXMLData(), username, c->GetGMLevel());
|
||||
WorldPackets::SendServerState(packet->systemAddress);
|
||||
|
||||
const auto respawnPoint = player->GetCharacter()->GetRespawnPoint(Game::zoneManager->GetZone()->GetWorldID());
|
||||
@@ -1039,8 +1037,6 @@ void HandlePacket(Packet* packet) {
|
||||
|
||||
Game::entityManager->ConstructAllEntities(packet->systemAddress);
|
||||
|
||||
auto* characterComponent = player->GetComponent<CharacterComponent>();
|
||||
if (!characterComponent) return;
|
||||
characterComponent->RocketUnEquip(player);
|
||||
|
||||
// Do charxml fixes here
|
||||
@@ -1117,7 +1113,6 @@ void HandlePacket(Packet* packet) {
|
||||
|
||||
SystemAddress sysAddr = packet->systemAddress;
|
||||
SEND_PACKET;
|
||||
// PacketUtils::SavePacket("lxfml packet " + std::to_string(bbbModel.id) + ".bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1149,6 +1144,7 @@ void HandlePacket(Packet* packet) {
|
||||
bitStream.Write(zone.GetInstanceID());
|
||||
bitStream.Write(zone.GetCloneID());
|
||||
bitStream.Write(player->GetParentUser()->GetMuteExpire());
|
||||
bitStream.Write(player->GetGMLevel());
|
||||
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
}
|
||||
@@ -1163,7 +1159,16 @@ void HandlePacket(Packet* packet) {
|
||||
}
|
||||
|
||||
case eWorldMessageType::POSITION_UPDATE: {
|
||||
ClientPackets::HandleClientPositionUpdate(packet->systemAddress, packet);
|
||||
auto positionUpdate = ClientPackets::HandleClientPositionUpdate(packet);
|
||||
|
||||
User* user = UserManager::Instance()->GetUser(packet->systemAddress);
|
||||
if (!user) {
|
||||
LOG("Unable to get user to parse position update");
|
||||
return;
|
||||
}
|
||||
|
||||
Entity* entity = Game::entityManager->GetEntity(user->GetLastUsedChar()->GetObjectID());
|
||||
if (entity) entity->ProcessPositionUpdate(positionUpdate);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1211,7 +1216,74 @@ void HandlePacket(Packet* packet) {
|
||||
}
|
||||
|
||||
case eWorldMessageType::STRING_CHECK: {
|
||||
ClientPackets::HandleChatModerationRequest(packet->systemAddress, packet);
|
||||
auto request = ClientPackets::HandleChatModerationRequest(packet);
|
||||
|
||||
// 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);
|
||||
|
||||
if (entity == nullptr) {
|
||||
LOG("Unable to get player to parse chat moderation request");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the player has restricted chat access
|
||||
auto* character = entity->GetCharacter();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint8_t, uint8_t>> segments = Game::chatFilter->IsSentenceOkay(request.message, entity->GetGMLevel(), !(isBestFriend && request.chatLevel == 1));
|
||||
|
||||
bool bAllClean = segments.empty();
|
||||
|
||||
if (user->GetIsMuted()) {
|
||||
bAllClean = false;
|
||||
}
|
||||
|
||||
user->SetLastChatMessageApproved(bAllClean);
|
||||
WorldPackets::SendChatModerationResponse(packet->systemAddress, bAllClean, request.requestID, request.receiver, segments);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1219,7 +1291,29 @@ void HandlePacket(Packet* packet) {
|
||||
if (chatDisabled) {
|
||||
ChatPackets::SendMessageFail(packet->systemAddress);
|
||||
} else {
|
||||
ClientPackets::HandleChatMessage(packet->systemAddress, packet);
|
||||
auto chatMessage = ClientPackets::HandleChatMessage(packet);
|
||||
|
||||
// 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 message");
|
||||
return;
|
||||
}
|
||||
|
||||
if (user->GetIsMuted()) {
|
||||
user->GetLastUsedChar()->SendMuteNotice();
|
||||
return;
|
||||
}
|
||||
std::string playerName = user->GetLastUsedChar()->GetName();
|
||||
bool isMythran = user->GetLastUsedChar()->GetGMLevel() > eGameMasterLevel::CIVILIAN;
|
||||
bool isOk = Game::chatFilter->IsSentenceOkay(GeneralUtils::UTF16ToWTF8(chatMessage.message), user->GetLastUsedChar()->GetGMLevel()).empty();
|
||||
LOG_DEBUG("Msg: %s was approved previously? %i", GeneralUtils::UTF16ToWTF8(chatMessage.message).c_str(), user->GetLastChatMessageApproved());
|
||||
if (!isOk) return;
|
||||
if (!isOk && !isMythran) return;
|
||||
|
||||
std::string sMessage = GeneralUtils::UTF16ToWTF8(chatMessage.message);
|
||||
LOG("%s: %s", playerName.c_str(), sMessage.c_str());
|
||||
ChatPackets::SendChatMessage(packet->systemAddress, chatMessage.chatChannel, playerName, user->GetLoggedInChar(), isMythran, chatMessage.message);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1245,7 +1339,37 @@ void HandlePacket(Packet* packet) {
|
||||
|
||||
|
||||
case eWorldMessageType::UI_HELP_TOP_5: {
|
||||
ClientPackets::SendTop5HelpIssues(packet);
|
||||
auto language = ClientPackets::SendTop5HelpIssues(packet);
|
||||
// TODO: Handle different languages in a nice way
|
||||
// 0: en_US
|
||||
// 1: pl_US
|
||||
// 2: de_DE
|
||||
// 3: en_GB
|
||||
|
||||
// TODO: Find a good home for the logic in this case.
|
||||
auto* user = UserManager::Instance()->GetUser(packet->systemAddress);
|
||||
if (!user) return;
|
||||
auto* character = user->GetLastUsedChar();
|
||||
if (!character) return;
|
||||
auto* entity = character->GetEntity();
|
||||
if (!entity) return;
|
||||
|
||||
AMFArrayValue data;
|
||||
// Summaries
|
||||
data.Insert("Summary0", Game::config->GetValue("help_0_summary"));
|
||||
data.Insert("Summary1", Game::config->GetValue("help_1_summary"));
|
||||
data.Insert("Summary2", Game::config->GetValue("help_2_summary"));
|
||||
data.Insert("Summary3", Game::config->GetValue("help_3_summary"));
|
||||
data.Insert("Summary4", Game::config->GetValue("help_4_summary"));
|
||||
|
||||
// Descriptions
|
||||
data.Insert("Description0", Game::config->GetValue("help_0_description"));
|
||||
data.Insert("Description1", Game::config->GetValue("help_1_description"));
|
||||
data.Insert("Description2", Game::config->GetValue("help_2_description"));
|
||||
data.Insert("Description3", Game::config->GetValue("help_3_description"));
|
||||
data.Insert("Description4", Game::config->GetValue("help_4_description"));
|
||||
|
||||
GameMessages::SendUIMessageServerToSingleClient(entity, packet->systemAddress, "UIHelpTop5", data);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1261,7 +1385,7 @@ void WorldShutdownProcess(uint32_t zoneId) {
|
||||
for (auto i = 0; i < Game::server->GetReplicaManager()->GetParticipantCount(); ++i) {
|
||||
const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(i);
|
||||
|
||||
auto* entity = Player::GetPlayer(player);
|
||||
auto* entity = PlayerManager::GetPlayer(player);
|
||||
LOG("Saving data!");
|
||||
if (entity != nullptr && entity->GetCharacter() != nullptr) {
|
||||
auto* skillComponent = entity->GetComponent<SkillComponent>();
|
||||
@@ -1314,6 +1438,7 @@ void FinalizeShutdown() {
|
||||
|
||||
//Delete our objects here:
|
||||
Metrics::Clear();
|
||||
dpWorld::Shutdown();
|
||||
Database::Destroy("WorldServer");
|
||||
if (Game::chatFilter) delete Game::chatFilter;
|
||||
Game::chatFilter = nullptr;
|
||||
|
Reference in New Issue
Block a user