eqemu-server/zone/worldserver.cpp
Knightly 7ab909ee47 Standardize Licensing
- License was intended to be GPLv3 per earlier commit of GPLv3 LICENSE FILE
- This is confirmed by the inclusion of libraries that are incompatible with GPLv2
- This is also confirmed by KLS and the agreement of KLS's predecessors
- Added GPLv3 license headers to the compilable source files
- Removed Folly licensing in strings.h since the string functions do not match the Folly functions and are standard functions - this must have been left over from previous implementations
- Removed individual contributor license headers since the project has been under the "developer" mantle for many years
- Removed comments on files that were previously automatically generated since they've been manually modified multiple times and there are no automatic scripts referencing them (removed in 2023)
2026-04-01 17:09:57 -07:00

4700 lines
138 KiB
C++

/* EQEmu: EQEmulator
Copyright (C) 2001-2026 EQEmu Development Team
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "worldserver.h"
#include "common/eq_packet_structs.h"
#include "common/events/player_event_logs.h"
#include "common/misc_functions.h"
#include "common/patches/patches.h"
#include "common/profanity_manager.h"
#include "common/repositories/guild_tributes_repository.h"
#include "common/rulesys.h"
#include "common/say_link.h"
#include "common/server_reload_types.h"
#include "common/servertalk.h"
#include "common/shared_tasks.h"
#include "common/skill_caps.h"
#include "zone/bot_command.h"
#include "zone/client.h"
#include "zone/command.h"
#include "zone/corpse.h"
#include "zone/dialogue_window.h"
#include "zone/dynamic_zone.h"
#include "zone/entity.h"
#include "zone/guild_mgr.h"
#include "zone/mob.h"
#include "zone/petitions.h"
#include "zone/queryserv.h"
#include "zone/quest_parser_collection.h"
#include "zone/raids.h"
#include "zone/shared_task_zone_messaging.h"
#include "zone/string_ids.h"
#include "zone/titles.h"
#include "zone/zone_config.h"
#include "zone/zone.h"
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <iostream>
extern EntityList entity_list;
extern Zone *zone;
extern volatile bool is_zone_loaded;
extern WorldServer worldserver;
extern uint32 numclients;
extern volatile bool RunLoops;
extern QuestParserCollection *parse;
extern QueryServ *QServ;
void Shutdown();
// QuestParserCollection *parse = 0;
WorldServer::WorldServer()
{
cur_groupid = 0;
last_groupid = 0;
oocmuted = false;
}
WorldServer::~WorldServer() {
}
void WorldServer::Process()
{
if (!m_reload_queue.empty()) {
m_reload_mutex.lock();
for (auto it = m_reload_queue.begin(); it != m_reload_queue.end(); ) {
if (it->second.reload_at_unix < std::time(nullptr)) {
ProcessReload(it->second);
it = m_reload_queue.erase(it);
break;
} else {
++it;
}
}
m_reload_mutex.unlock();
}
}
void WorldServer::Connect()
{
m_connection = std::make_unique<EQ::Net::ServertalkClient>(Config->WorldIP, Config->WorldTCPPort, false, "Zone", Config->SharedKey);
m_connection->OnConnect([this](EQ::Net::ServertalkClient *client) {
OnConnected();
});
m_connection->OnMessage(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
}
bool WorldServer::SendPacket(ServerPacket *pack)
{
m_connection->SendPacket(pack);
return true;
}
std::string WorldServer::GetIP() const
{
return m_connection->Handle()->RemoteIP();
}
uint16 WorldServer::GetPort() const
{
return m_connection->Handle()->RemotePort();
}
bool WorldServer::Connected() const
{
return m_connection->Connected();
}
void WorldServer::SetZoneData(uint32 iZoneID, uint32 iInstanceID) {
auto pack = new ServerPacket(ServerOP_SetZone, sizeof(SetZone_Struct));
SetZone_Struct* szs = (SetZone_Struct*)pack->pBuffer;
szs->zoneid = iZoneID;
szs->instanceid = iInstanceID;
if (zone) {
szs->staticzone = zone->IsStaticZone();
}
SendPacket(pack);
safe_delete(pack);
}
void WorldServer::OnConnected() {
ServerPacket* pack;
/* Tell the launcher what our information is */
pack = new ServerPacket(ServerOP_SetLaunchName, sizeof(LaunchName_Struct));
LaunchName_Struct* ln = (LaunchName_Struct*)pack->pBuffer;
strn0cpy(ln->launcher_name, m_launcherName.c_str(), 32);
strn0cpy(ln->zone_name, m_launchedName.c_str(), 16);
SendPacket(pack);
safe_delete(pack);
/* Tell the Worldserver basic information about this zone process */
pack = new ServerPacket(ServerOP_SetConnectInfo, sizeof(ServerConnectInfo));
ServerConnectInfo* sci = (ServerConnectInfo*)pack->pBuffer;
auto config = ZoneConfig::get();
sci->port = ZoneConfig::get()->ZonePort;
if (config->WorldAddress.length() > 0) {
strn0cpy(sci->address, config->WorldAddress.c_str(), 250);
}
if (config->LocalAddress.length() > 0) {
strn0cpy(sci->local_address, config->LocalAddress.c_str(), 250);
}
/* Fetch process ID */
if (getpid()) {
sci->process_id = getpid();
}
else {
sci->process_id = 0;
}
SendPacket(pack);
safe_delete(pack);
if (is_zone_loaded) {
SetZoneData(zone->GetZoneID(), zone->GetInstanceID());
entity_list.UpdateWho(true);
SendEmoteMessage(
0,
0,
Chat::Yellow,
fmt::format(
"Zone Connected | {}",
zone->GetZoneDescription()
).c_str()
);
zone->GetTimeSync();
}
else {
SetZoneData(0);
}
pack = new ServerPacket(ServerOP_LSZoneBoot, sizeof(ZoneBoot_Struct));
ZoneBoot_Struct* zbs = (ZoneBoot_Struct*)pack->pBuffer;
strcpy(zbs->compile_time, LAST_MODIFIED);
SendPacket(pack);
safe_delete(pack);
}
/* Zone Process Packets from World */
void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
{
ServerPacket tpack(opcode, p);
ServerPacket *pack = &tpack;
switch (opcode) {
case 0:
case ServerOP_KeepAlive: {
break;
}
case ServerOP_SetConnectInfo: {
if (pack->size != sizeof(ServerConnectInfo))
break;
ServerConnectInfo* sci = (ServerConnectInfo*)pack->pBuffer;
if (sci->port == 0) {
LogError("World did not have a port to assign from this server, the port range was not large enough.");
Shutdown();
}
else {
LogInfo("World assigned Port [{}] for this zone", sci->port);
ZoneConfig::SetZonePort(sci->port);
EQEmuLogSys::Instance()->SetDiscordHandler(&Zone::DiscordWebhookMessageHandler);
}
break;
}
case ServerOP_ChannelMessage: {
if (!is_zone_loaded)
break;
ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*)pack->pBuffer;
if (scm->deliverto[0] == 0) {
entity_list.ChannelMessageFromWorld(scm->from, scm->to, scm->chan_num, scm->guilddbid, scm->language, scm->lang_skill, scm->message);
}
else {
Client* client = entity_list.GetClientByName(scm->deliverto);
if (client && client->Connected()) {
if (scm->chan_num == ChatChannel_TellEcho) {
if (scm->queued == 1) // tell was queued
client->Tell_StringID(QUEUED_TELL, scm->to, scm->message);
else if (scm->queued == 2) // tell queue was full
client->Tell_StringID(QUEUE_TELL_FULL, scm->to, scm->message);
else if (scm->queued == 3) // person was offline
client->MessageString(Chat::EchoTell, TOLD_NOT_ONLINE, scm->to);
else // normal tell echo "You told Soanso, 'something'"
// tell echo doesn't use language, so it looks normal to you even if nobody can understand your tells
client->ChannelMessageSend(scm->from, scm->to, scm->chan_num, Language::CommonTongue, Language::MaxValue, scm->message);
}
else if (scm->chan_num == ChatChannel_Tell) {
client->ChannelMessageSend(scm->from, scm->to, scm->chan_num, scm->language, scm->lang_skill, scm->message);
if (scm->queued == 0) { // this is not a queued tell
// if it's a tell, echo back to acknowledge it and make it show on the sender's client
scm->chan_num = ChatChannel_TellEcho;
memset(scm->deliverto, 0, sizeof(scm->deliverto));
strcpy(scm->deliverto, scm->from);
SendPacket(pack);
}
}
else {
client->ChannelMessageSend(scm->from, scm->to, scm->chan_num, scm->language, scm->lang_skill, scm->message);
}
}
}
break;
}
case ServerOP_VoiceMacro: {
if (!is_zone_loaded)
break;
ServerVoiceMacro_Struct* svm = (ServerVoiceMacro_Struct*)pack->pBuffer;
auto outapp = new EQApplicationPacket(OP_VoiceMacroOut, sizeof(VoiceMacroOut_Struct));
VoiceMacroOut_Struct* vmo = (VoiceMacroOut_Struct*)outapp->pBuffer;
strcpy(vmo->From, svm->From);
vmo->Type = svm->Type;
vmo->Voice = svm->Voice;
vmo->MacroNumber = svm->MacroNumber;
switch (svm->Type) {
case VoiceMacroTell: {
Client* c = entity_list.GetClientByName(svm->To);
if (!c)
break;
c->QueuePacket(outapp);
break;
}
case VoiceMacroGroup: {
Group* g = entity_list.GetGroupByID(svm->GroupID);
if (!g)
break;
for (unsigned int i = 0; i < MAX_GROUP_MEMBERS; i++) {
if (g->members[i] && g->members[i]->IsClient())
g->members[i]->CastToClient()->QueuePacket(outapp);
}
break;
}
case VoiceMacroRaid: {
Raid *r = entity_list.GetRaidByID(svm->RaidID);
if (!r) {
break;
}
for (const auto& m: r->members) {
if (m.is_bot) {
continue;
}
if (m.member) {
m.member->QueuePacket(outapp);
}
}
break;
}
}
safe_delete(outapp);
break;
}
case ServerOP_SpawnCondition: {
if (pack->size != sizeof(ServerSpawnCondition_Struct))
break;
if (!is_zone_loaded)
break;
ServerSpawnCondition_Struct* ssc = (ServerSpawnCondition_Struct*)pack->pBuffer;
zone->spawn_conditions.SetCondition(zone->GetShortName(), zone->GetInstanceID(), ssc->condition_id, ssc->value, true);
break;
}
case ServerOP_SpawnEvent: {
if (pack->size != sizeof(ServerSpawnEvent_Struct))
break;
if (!is_zone_loaded)
break;
ServerSpawnEvent_Struct* sse = (ServerSpawnEvent_Struct*)pack->pBuffer;
zone->spawn_conditions.ReloadEvent(sse->event_id);
break;
}
case ServerOP_AcceptWorldEntrance: {
if (pack->size != sizeof(WorldToZone_Struct))
break;
if (!is_zone_loaded)
break;
WorldToZone_Struct* wtz = (WorldToZone_Struct*)pack->pBuffer;
if (zone->GetMaxClients() != 0 && numclients >= zone->GetMaxClients())
wtz->response = -1;
else
wtz->response = 1;
SendPacket(pack);
break;
}
case ServerOP_ZoneToZoneRequest: {
if (pack->size != sizeof(ZoneToZone_Struct))
break;
if (!is_zone_loaded)
break;
ZoneToZone_Struct* ztz = (ZoneToZone_Struct*)pack->pBuffer;
LogZoning(
"ZoneToZone client [{}] guild_id [{}] requested_zone [{}] requested_zone_id [{}] requested_instance_id [{}] current_zone [{}] current_zone_id [{}] current_instance_id [{}] response [{}] admin [{}] ignorerestrictions [{}]",
ztz->name,
ztz->guild_id,
ZoneName(ztz->requested_zone_id),
ztz->requested_zone_id,
ztz->requested_instance_id,
ZoneName(ztz->current_zone_id),
ztz->current_zone_id,
ztz->current_instance_id,
ztz->response,
ztz->admin,
ztz->ignorerestrictions
);
// the client was rejected by the world server
// zone was not ready for some reason
if (ztz->current_zone_id == zone->GetZoneID() && ztz->current_instance_id == zone->GetInstanceID()) {
// it's a response
Entity* entity = entity_list.GetClientByName(ztz->name);
if (entity == 0)
break;
EQApplicationPacket *outapp;
outapp = new EQApplicationPacket(OP_ZoneChange, sizeof(ZoneChange_Struct));
ZoneChange_Struct* zc2 = (ZoneChange_Struct*)outapp->pBuffer;
if (ztz->response <= 0) {
zc2->success = ZoningMessage::ZoneNotReady;
entity->CastToMob()->SetZone(ztz->current_zone_id, ztz->current_instance_id);
entity->CastToClient()->SetZoning(false);
entity->CastToClient()->SetLockSavePosition(false);
LogZoning("ZoneToZone (ZoneNotReady) client [{}] guild_id [{}] requested_zone [{}] requested_zone_id [{}] requested_instance_id [{}] current_zone [{}] current_zone_id [{}] current_instance_id [{}] response [{}] admin [{}] ignorerestrictions [{}] ",
ztz->name,
ztz->guild_id,
ZoneName(ztz->requested_zone_id),
ztz->requested_zone_id,
ztz->requested_instance_id,
ZoneName(ztz->current_zone_id),
ztz->current_zone_id,
ztz->current_instance_id,
ztz->response,
ztz->admin,
ztz->ignorerestrictions
);
}
else {
entity->CastToClient()->UpdateWho(1);
strn0cpy(zc2->char_name, entity->CastToMob()->GetName(), 64);
zc2->zoneID = ztz->requested_zone_id;
zc2->instanceID = ztz->requested_instance_id;
zc2->success = 1;
// This block is necessary to clean up any merc objects owned by a Client. Maybe we should do this for bots, too?
if (entity->CastToClient()->GetMerc() != nullptr)
{
entity->CastToClient()->GetMerc()->ProcessClientZoneChange(entity->CastToClient());
}
entity->CastToMob()->SetZone(ztz->requested_zone_id, ztz->requested_instance_id);
if (ztz->ignorerestrictions == 3)
entity->CastToClient()->GoToSafeCoords(ztz->requested_zone_id, ztz->requested_instance_id);
}
outapp->priority = 6;
entity->CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
switch (ztz->response)
{
case -2: {
entity->CastToClient()->Message(Chat::Red, "You do not own the required locations to enter this zone.");
break;
}
case -1: {
entity->CastToClient()->Message(Chat::Red, "The zone is currently full, please try again later.");
break;
}
case 0: {
entity->CastToClient()->Message(Chat::Red, "All zone servers are taken at this time, please try again later.");
break;
}
}
}
// the client was accepted by the world server
else {
// it's a request
ztz->response = 0;
if (zone->GetMaxClients() != 0 && numclients >= zone->GetMaxClients())
ztz->response = -1;
else {
ztz->response = 1;
}
SendPacket(pack);
break;
}
break;
}
case ServerOP_WhoAllReply: {
if (!is_zone_loaded)
break;
WhoAllReturnStruct* wars = (WhoAllReturnStruct*)pack->pBuffer;
if (wars && wars->id != 0 && wars->id<0xFFFFFFFF) {
Client* client = entity_list.GetClientByID(wars->id);
if (client) {
if (pack->size == 64)//no results
client->MessageString(Chat::White, WHOALL_NO_RESULTS);
else {
auto outapp = new EQApplicationPacket(OP_WhoAllResponse, pack->size);
memcpy(outapp->pBuffer, pack->pBuffer, pack->size);
client->QueuePacket(outapp);
safe_delete(outapp);
}
}
else {
LogDebug("[CLIENT] id=[{}], playerineqstring=[{}], playersinzonestring=[{}]. Dumping WhoAllReturnStruct:",
wars->id, wars->playerineqstring, wars->playersinzonestring);
}
}
else
LogError("WhoAllReturnStruct: Could not get return struct!");
break;
}
case ServerOP_EmoteMessage: {
if (!is_zone_loaded)
break;
ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*)pack->pBuffer;
if (sem->to[0] != 0) {
if (strcasecmp(sem->to, zone->GetShortName()) == 0)
entity_list.MessageStatus(
sem->guilddbid,
sem->minstatus,
sem->type,
(char*)sem->message
);
else {
Client* client = entity_list.GetClientByName(sem->to);
if (client) {
char* newmessage = 0;
if (strstr(sem->message, "^") == 0)
client->Message(sem->type, (char*)sem->message);
else {
for (newmessage = strtok((char*)sem->message, "^"); newmessage != nullptr; newmessage = strtok(nullptr, "^"))
client->Message(sem->type, newmessage);
}
}
}
}
else {
char* newmessage = 0;
if (strstr(sem->message, "^") == 0) {
entity_list.MessageStatus(
sem->guilddbid,
sem->minstatus,
sem->type,
sem->message
);
} else {
for (newmessage = strtok((char*)sem->message, "^"); newmessage != nullptr; newmessage = strtok(nullptr, "^")) {
entity_list.MessageStatus(
sem->guilddbid,
sem->minstatus,
sem->type,
newmessage
);
}
}
}
break;
}
case ServerOP_Motd: {
if (pack->size != sizeof(ServerMotd_Struct))
break;
ServerMotd_Struct *smotd = (ServerMotd_Struct *)pack->pBuffer;
SerializeBuffer buf(100);
buf.WriteString(smotd->motd);
auto outapp = std::make_unique<EQApplicationPacket>(OP_MOTD, buf);
entity_list.QueueClients(0, outapp.get());
break;
}
case ServerOP_ShutdownAll: {
entity_list.Save();
Shutdown();
break;
}
case ServerOP_ZoneShutdown: {
if (pack->size != sizeof(ServerZoneStateChange_Struct)) {
LogError("Wrong size on ServerOP_ZoneShutdown. Got: [{}] Expected: [{}]", pack->size, sizeof(ServerZoneStateChange_Struct));
break;
}
if (!is_zone_loaded) {
SetZoneData(0);
} else {
SendEmoteMessage(
0,
0,
Chat::Yellow,
fmt::format(
"Zone Shutdown | {}",
zone->GetZoneDescription()
).c_str()
);
auto *s = (ServerZoneStateChange_Struct *) pack->pBuffer;
LogInfo("Zone shutdown by {}.", s->admin_name);
zone->Shutdown();
}
break;
}
case ServerOP_ZoneBootup: {
if (pack->size != sizeof(ServerZoneStateChange_Struct)) {
LogError("Wrong size on ServerOP_ZoneShutdown. Got: [{}] Expected: [{}]", pack->size, sizeof(ServerZoneStateChange_Struct));
break;
}
auto *s = (ServerZoneStateChange_Struct *) pack->pBuffer;
if (is_zone_loaded) {
SetZoneData(zone->GetZoneID(), zone->GetInstanceID());
if (s->zone_id != zone->GetZoneID()) {
SendEmoteMessage(
s->admin_name,
0,
Chat::White,
fmt::format(
"Zone Bootup Failed | {} Already running",
zone->GetZoneDescription()
).c_str()
);
}
break;
}
if (s->admin_name[0] != 0) {
LogInfo("Zone bootup by {}.", s->admin_name);
}
Zone::Bootup(s->zone_id, s->instance_id, s->is_static);
if (zone) {
zone->SetZoneServerId(s->zone_server_id);
}
break;
}
case ServerOP_ZoneIncClient: {
if (pack->size != sizeof(ServerZoneIncomingClient_Struct)) {
std::cout << "Wrong size on ServerOP_ZoneIncClient. Got: " << pack->size << ", Expected: " << sizeof(ServerZoneIncomingClient_Struct) << std::endl;
break;
}
ServerZoneIncomingClient_Struct* szic = (ServerZoneIncomingClient_Struct*)pack->pBuffer;
if (is_zone_loaded) {
SetZoneData(zone->GetZoneID(), zone->GetInstanceID());
if (szic->zoneid == zone->GetZoneID()) {
auto client = entity_list.GetClientByLSID(szic->lsid);
if (client) {
client->Kick("Dropped by world CLE subsystem");
client->Save();
}
zone->RemoveAuth(szic->lsid);
zone->AddAuth(szic);
}
}
else {
if ((Zone::Bootup(szic->zoneid, szic->instanceid))) {
zone->AddAuth(szic);
}
}
break;
}
case ServerOP_DropClient: {
if (pack->size != sizeof(ServerZoneDropClient_Struct)) {
break;
}
ServerZoneDropClient_Struct* drop = (ServerZoneDropClient_Struct*)pack->pBuffer;
if (zone) {
zone->RemoveAuth(drop->lsid);
auto client = entity_list.GetClientByLSID(drop->lsid);
if (client) {
client->Kick("Dropped by world CLE subsystem");
client->Save();
}
}
break;
}
case ServerOP_ZonePlayer: {
ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*)pack->pBuffer;
auto client = entity_list.GetClientByName(szp->name);
if (client) {
if (!strcasecmp(szp->adminname, szp->name)) {
client->Message(
Chat::White,
fmt::format(
"Zoning to {} ({}).",
ZoneLongName(
ZoneID(szp->zone)
),
ZoneID(szp->zone)
).c_str()
);
} else if (client->GetAnon() == 1 && client->Admin() > szp->adminrank) {
break;
} else {
std::string name = Strings::ToLower(szp->name);
name[0] = toupper(name[0]);
SendEmoteMessage(
szp->adminname,
0,
Chat::White,
fmt::format(
"Summoning {} to {:.2f}, {:.2f}, {:.2f} in {} ({}).",
name,
szp->x_pos,
szp->y_pos,
szp->z_pos,
ZoneLongName(
ZoneID(szp->zone)
),
ZoneID(szp->zone)
).c_str()
);
}
if (!szp->instance_id) {
client->MovePC(ZoneID(szp->zone), szp->instance_id, szp->x_pos, szp->y_pos, szp->z_pos, client->GetHeading(), szp->ignorerestrictions, GMSummon);
} else {
if (database.GetInstanceID(client->CharacterID(), ZoneID(szp->zone))) {
client->RemoveFromInstance(database.GetInstanceID(client->CharacterID(), ZoneID(szp->zone)));
}
client->AssignToInstance(szp->instance_id);
client->MovePC(ZoneID(szp->zone), szp->instance_id, szp->x_pos, szp->y_pos, szp->z_pos, client->GetHeading(), szp->ignorerestrictions, GMSummon);
}
}
break;
}
case ServerOP_KickPlayer: {
ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*)pack->pBuffer;
Client* client;
if (strlen(skp->name)) {
client = entity_list.GetClientByName(skp->name);
} else if (skp->account_id) {
client = entity_list.GetClientByAccID(skp->account_id);
}
if (client) {
if (skp->adminrank >= client->Admin()) {
client->WorldKick();
SendEmoteMessage(
skp->adminname,
0,
Chat::White,
fmt::format(
"Remote Kick | {} booted{}.",
skp->name,
is_zone_loaded ?
fmt::format(
" in {}",
zone->GetZoneDescription()
) :
""
).c_str()
);
} else if (client->GetAnon() != 1) {
SendEmoteMessage(
skp->adminname,
0,
Chat::White,
fmt::format(
"Remote Kick | Your Status Level is not high enough to kick {}.",
skp->name
).c_str()
);
}
}
break;
}
case ServerOP_KillPlayer: {
ServerKillPlayer_Struct* skp = (ServerKillPlayer_Struct*)pack->pBuffer;
Client* client = entity_list.GetClientByName(skp->target);
if (client) {
if (skp->admin >= client->Admin()) {
client->GMKill();
SendEmoteMessage(
skp->gmname,
0,
Chat::White,
fmt::format(
"Remote Kill | {} killed{}",
skp->target,
is_zone_loaded ?
fmt::format(
"in {}",
zone->GetZoneDescription()
) :
""
).c_str()
);
} else if (client->GetAnon() != 1) {
SendEmoteMessage(
skp->gmname,
0,
Chat::White,
fmt::format(
"Remote Kill | Your Status Level is not high enough to kill {}",
skp->target
).c_str()
);
}
}
break;
}
case ServerOP_OnlineGuildMembersResponse:
case ServerOP_RefreshGuild:
case ServerOP_DeleteGuild:
case ServerOP_GuildCharRefresh:
case ServerOP_GuildMemberUpdate:
case ServerOP_GuildPermissionUpdate:
case ServerOP_GuildRankUpdate:
case ServerOP_GuildRankNameChange:
case ServerOP_LFGuildUpdate:
case ServerOP_GuildMemberLevelUpdate:
case ServerOP_GuildMemberPublicNote:
case ServerOP_GuildChannel:
case ServerOP_GuildURL:
case ServerOP_GuildMemberRemove:
case ServerOP_GuildMemberAdd:
case ServerOP_GuildSendGuildList:
case ServerOP_GuildMembersList:
{
guild_mgr.ProcessWorldPacket(pack);
break;
}
case ServerOP_FlagUpdate: {
Client* client = entity_list.GetClientByAccID(*((uint32*)pack->pBuffer));
if (client) {
client->UpdateAdmin();
}
break;
}
case ServerOP_GMGoto: {
if (pack->size != sizeof(ServerGMGoto_Struct)) {
std::cout << "Wrong size on ServerOP_GMGoto. Got: " << pack->size << ", Expected: " << sizeof(ServerGMGoto_Struct) << std::endl;
break;
}
if (!is_zone_loaded)
break;
ServerGMGoto_Struct* gmg = (ServerGMGoto_Struct*)pack->pBuffer;
Client* client = entity_list.GetClientByName(gmg->gotoname);
if (client) {
SendEmoteMessage(
gmg->myname,
0,
Chat::Red,
fmt::format(
"Summoning you to {} in {} at {:.2f}, {:.2f}, {:.2f}",
client->GetCleanName(),
zone->GetZoneDescription(),
client->GetX(),
client->GetY(),
client->GetZ()
).c_str()
);
auto outpack = new ServerPacket(ServerOP_ZonePlayer, sizeof(ServerZonePlayer_Struct));
ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*)outpack->pBuffer;
strcpy(szp->adminname, gmg->myname);
strcpy(szp->name, gmg->myname);
strcpy(szp->zone, zone->GetShortName());
szp->instance_id = zone->GetInstanceID();
szp->x_pos = client->GetX();
szp->y_pos = client->GetY();
szp->z_pos = client->GetZ();
SendPacket(outpack);
safe_delete(outpack);
}
else {
SendEmoteMessage(
gmg->myname,
0,
Chat::Red,
fmt::format(
"Error: {} not found.",
gmg->gotoname
).c_str()
);
}
break;
}
case ServerOP_MultiLineMsg: {
ServerMultiLineMsg_Struct* mlm = (ServerMultiLineMsg_Struct*)pack->pBuffer;
Client* client = entity_list.GetClientByName(mlm->to);
if (client) {
auto outapp = new EQApplicationPacket(OP_MultiLineMsg, strlen(mlm->message));
strcpy((char*)outapp->pBuffer, mlm->message);
client->QueuePacket(outapp);
safe_delete(outapp);
}
break;
}
case ServerOP_Uptime: {
if (pack->size != sizeof(ServerUptime_Struct)) {
std::cout << "Wrong size on ServerOP_Uptime. Got: " << pack->size << ", Expected: " << sizeof(ServerUptime_Struct) << std::endl;
break;
}
ServerUptime_Struct* sus = (ServerUptime_Struct*)pack->pBuffer;
uint32 ms = Timer::GetCurrentTime();
std::string time_string = Strings::MillisecondsToTime(ms);
SendEmoteMessage(
sus->adminname,
0,
Chat::White,
fmt::format(
"Zoneserver {} | Uptime: {}",
sus->zoneserverid,
time_string
).c_str()
);
}
case ServerOP_Petition: {
std::cout << "Got Server Requested Petition List Refresh" << std::endl;
ServerPetitionUpdate_Struct* sus = (ServerPetitionUpdate_Struct*)pack->pBuffer;
// this was typoed to = instead of ==, not that it acts any different now though..
if (sus->status == 0) PetitionList::Instance()->ReadDatabase();
else if (sus->status == 1) PetitionList::Instance()->ReadDatabase(); // Until I fix this to be better....
break;
}
case ServerOP_RezzPlayer: {
RezzPlayer_Struct* srs = (RezzPlayer_Struct*)pack->pBuffer;
if (srs->rezzopcode == OP_RezzRequest)
{
// The Rezz request has arrived in the zone the player to be rezzed is currently in,
// so we send the request to their client which will bring up the confirmation box.
Client* client = entity_list.GetClientByName(srs->rez.your_name);
if (client)
{
if (client->IsRezzPending())
{
auto Response = new ServerPacket(ServerOP_RezzPlayerReject,
strlen(srs->rez.rezzer_name) + 1);
char *Buffer = (char *)Response->pBuffer;
sprintf(Buffer, "%s", srs->rez.rezzer_name);
worldserver.SendPacket(Response);
safe_delete(Response);
break;
}
//pendingrezexp is the amount of XP on the corpse. Setting it to a value >= 0
//also serves to inform Client::OPRezzAnswer to expect a packet.
client->SetPendingRezzData(srs->exp, srs->dbid, srs->rez.spellid, srs->rez.corpse_name);
LogSpells("[WorldServer::HandleMessage] OP_RezzRequest in zone [{}] for [{}] spellid [{}]",
zone->GetShortName(), client->GetName(), srs->rez.spellid);
auto outapp = new EQApplicationPacket(OP_RezzRequest,
sizeof(Resurrect_Struct));
memcpy(outapp->pBuffer, &srs->rez, sizeof(Resurrect_Struct));
client->QueuePacket(outapp);
safe_delete(outapp);
break;
}
}
if (srs->rezzopcode == OP_RezzComplete) {
// We get here when the Rezz complete packet has come back via the world server
// to the zone that the corpse is in.
Corpse* corpse = entity_list.GetCorpseByName(srs->rez.corpse_name);
if (corpse && corpse->IsCorpse()) {
LogSpells("[WorldServer::HandleMessage] OP_RezzComplete received in zone [{}] for corpse [{}]",
zone->GetShortName(), srs->rez.corpse_name);
LogSpells("[WorldServer::HandleMessage] Found corpse. Marking corpse as rezzed if needed");
// I don't know why Rezzed is not set to true in CompleteRezz().
if (!IsEffectInSpell(srs->rez.spellid, SpellEffect::SummonToCorpse)) {
corpse->IsRezzed(true);
corpse->CompleteResurrection();
}
}
}
break;
}
case ServerOP_RezzPlayerReject:
{
char *Rezzer = (char *)pack->pBuffer;
Client* c = entity_list.GetClientByName(Rezzer);
if (c)
c->MessageString(Chat::SpellWornOff, REZZ_ALREADY_PENDING);
break;
}
case ServerOP_ZoneReboot: {
std::cout << "Got Server Requested Zone reboot" << std::endl;
ServerZoneReboot_Struct* zb = (ServerZoneReboot_Struct*)pack->pBuffer;
break;
}
case ServerOP_SyncWorldTime: {
if (zone != 0 && !zone->is_zone_time_localized) {
LogInfo("[{}] Received Message SyncWorldTime", __FUNCTION__);
eqTimeOfDay* newtime = (eqTimeOfDay*)pack->pBuffer;
zone->zone_time.SetCurrentEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime);
auto outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct));
TimeOfDay_Struct* time_of_day = (TimeOfDay_Struct*)outapp->pBuffer;
zone->zone_time.GetCurrentEQTimeOfDay(time(0), time_of_day);
entity_list.QueueClients(0, outapp, false);
safe_delete(outapp);
char time_message[255];
time_t current_time = time(nullptr);
TimeOfDay_Struct eq_time{};
zone->zone_time.GetCurrentEQTimeOfDay(current_time, &eq_time);
sprintf(time_message, "EQTime [%02d:%s%d %s]",
((eq_time.hour - 1) % 12) == 0 ? 12 : ((eq_time.hour - 1) % 12),
(eq_time.minute < 10) ? "0" : "",
eq_time.minute,
(eq_time.hour >= 13) ? "pm" : "am"
);
LogInfo("Time Broadcast Packet: {}", time_message);
zone->SetZoneHasCurrentTime(true);
}
if (zone && zone->is_zone_time_localized) {
LogInfo("Received request to sync time from world, but our time is localized currently");
}
break;
}
case ServerOP_RefreshCensorship: {
if (!EQ::ProfanityManager::LoadProfanityList(&database))
LogError("Received request to refresh the profanity list..but, the action failed");
break;
}
case ServerOP_ChangeWID: {
if (pack->size != sizeof(ServerChangeWID_Struct)) {
std::cout << "Wrong size on ServerChangeWID_Struct. Got: " << pack->size << ", Expected: " << sizeof(ServerChangeWID_Struct) << std::endl;
break;
}
ServerChangeWID_Struct* scw = (ServerChangeWID_Struct*)pack->pBuffer;
Client* client = entity_list.GetClientByCharID(scw->charid);
if (client)
client->SetWID(scw->newwid);
break;
}
case ServerOP_OOCMute: {
auto o = (ServerOOCMute_Struct *) pack->pBuffer;
oocmuted = o->is_muted;
break;
}
case ServerOP_Revoke: {
RevokeStruct* rev = (RevokeStruct*)pack->pBuffer;
Client* client = entity_list.GetClientByName(rev->name);
if (client) {
SendEmoteMessage(
rev->adminname,
0,
Chat::White,
fmt::format(
"Zone {} | {} {}.",
zone->GetZoneDescription(),
rev->toggle ? "Revoking" : "Unrevoking",
client->GetCleanName()
).c_str()
);
client->SetRevoked(rev->toggle);
}
break;
}
case ServerOP_GroupIDReply: {
ServerGroupIDReply_Struct* ids = (ServerGroupIDReply_Struct*)pack->pBuffer;
cur_groupid = ids->start;
last_groupid = ids->end;
break;
}
case ServerOP_GroupLeave: {
ServerGroupLeave_Struct* gl = (ServerGroupLeave_Struct*)pack->pBuffer;
if (zone) {
if (gl->zoneid == zone->GetZoneID() && gl->instance_id == zone->GetInstanceID())
break;
entity_list.SendGroupLeave(gl->gid, gl->member_name);
}
break;
}
case ServerOP_GroupInvite: {
// A player in another zone invited a player in this zone to join their group.
GroupInvite_Struct* gis = (GroupInvite_Struct*)pack->pBuffer;
Mob *Invitee = entity_list.GetMob(gis->invitee_name);
if (Invitee && Invitee->IsClient() && Invitee->CastToClient()->MercOnlyOrNoGroup() && !Invitee->IsRaidGrouped())
{
auto outapp = new EQApplicationPacket(OP_GroupInvite, sizeof(GroupInvite_Struct));
memcpy(outapp->pBuffer, gis, sizeof(GroupInvite_Struct));
Invitee->CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
}
break;
}
case ServerOP_GroupFollow: {
// Player in another zone accepted a group invitation from a player in this zone.
ServerGroupFollow_Struct* sgfs = (ServerGroupFollow_Struct*)pack->pBuffer;
Mob* Inviter = entity_list.GetClientByName(sgfs->gf.name1);
if (Inviter && Inviter->IsClient())
{
Group* group = entity_list.GetGroupByClient(Inviter->CastToClient());
if (!group)
{
//Make new group
group = new Group(Inviter);
if (!group)
{
break;
}
entity_list.AddGroup(group);
if (group->GetID() == 0) {
Inviter->Message(Chat::Red, "Unable to get new group id. Cannot create group.");
break;
}
group->AddToGroup(Inviter);
database.SetGroupLeaderName(group->GetID(), Inviter->GetName());
group->UpdateGroupAAs();
if (Inviter->CastToClient()->ClientVersion() < EQ::versions::ClientVersion::SoD)
{
auto outapp =
new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct));
auto outgj = (GroupJoin_Struct*)outapp->pBuffer;
strcpy(outgj->membername, Inviter->GetName());
strcpy(outgj->yourname, Inviter->GetName());
outgj->action = groupActInviteInitial; // 'You have formed the group'.
group->GetGroupAAs(&outgj->leader_aas);
Inviter->CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
}
else
{
// SoD and later
Inviter->CastToClient()->SendGroupCreatePacket();
Inviter->CastToClient()->SendGroupLeaderChangePacket(Inviter->GetName());
Inviter->CastToClient()->SendGroupJoinAcknowledge();
}
group->GetXTargetAutoMgr()->merge(*Inviter->CastToClient()->GetXTargetAutoMgr());
Inviter->CastToClient()->GetXTargetAutoMgr()->clear();
Inviter->CastToClient()->SetXTargetAutoMgr(group->GetXTargetAutoMgr());
}
if (!group)
{
break;
}
auto outapp = new EQApplicationPacket(OP_GroupFollow, sizeof(GroupGeneric_Struct));
GroupGeneric_Struct *gg = (GroupGeneric_Struct *)outapp->pBuffer;
strn0cpy(gg->name1, sgfs->gf.name1, sizeof(gg->name1));
strn0cpy(gg->name2, sgfs->gf.name2, sizeof(gg->name2));
Inviter->CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
if (!group->AddMember(nullptr, sgfs->gf.name2, sgfs->CharacterID))
break;
if (Inviter->CastToClient()->IsLFP())
Inviter->CastToClient()->UpdateLFP();
auto pack2 = new ServerPacket(ServerOP_GroupJoin, sizeof(ServerGroupJoin_Struct));
auto gj = (ServerGroupJoin_Struct*)pack2->pBuffer;
gj->gid = group->GetID();
gj->zoneid = zone->GetZoneID();
gj->instance_id = zone->GetInstanceID();
strn0cpy(gj->member_name, sgfs->gf.name2, sizeof(gj->member_name));
worldserver.SendPacket(pack2);
safe_delete(pack2);
// Send acknowledgement back to the Invitee to let them know we have added them to the group.
auto pack3 =
new ServerPacket(ServerOP_GroupFollowAck, sizeof(ServerGroupFollowAck_Struct));
ServerGroupFollowAck_Struct* sgfas = (ServerGroupFollowAck_Struct*)pack3->pBuffer;
strn0cpy(sgfas->Name, sgfs->gf.name2, sizeof(sgfas->Name));
worldserver.SendPacket(pack3);
safe_delete(pack3);
}
break;
}
case ServerOP_GroupFollowAck: {
// The Inviter (in another zone) has successfully added the Invitee (in this zone) to the group.
ServerGroupFollowAck_Struct* sgfas = (ServerGroupFollowAck_Struct*)pack->pBuffer;
Client *client = entity_list.GetClientByName(sgfas->Name);
if (!client) {
break;
}
uint32 groupid = database.GetGroupID(client->GetName());
Group* group = nullptr;
if (groupid > 0)
{
group = entity_list.GetGroupByID(groupid);
if (!group)
{ //nobody from our group is here... start a new group
group = new Group(groupid);
if (group->GetID() != 0)
entity_list.AddGroup(group, groupid);
else
safe_delete(group);
}
if (group)
group->UpdatePlayer(client);
else
{
if (client->GetMerc()) {
Group::RemoveFromGroup(client->GetMerc());
}
Group::RemoveFromGroup(client); //cannot re-establish group, kill it
}
}
if (group)
{
if (client->GetMerc())
{
client->GetMerc()->MercJoinClientGroup();
}
database.RefreshGroupFromDB(client);
group->SendHPManaEndPacketsTo(client);
// If the group leader is not set, pull the group leader information from the database.
if (!group->GetLeader())
{
char ln[64];
char MainTankName[64];
char AssistName[64];
char PullerName[64];
char NPCMarkerName[64];
char mentoree_name[64];
int mentor_percent;
GroupLeadershipAA_Struct GLAA;
memset(ln, 0, 64);
database.GetGroupLeadershipInfo(group->GetID(), ln, MainTankName, AssistName, PullerName, NPCMarkerName, mentoree_name, &mentor_percent, &GLAA);
Client *lc = entity_list.GetClientByName(ln);
if (lc)
group->SetLeader(lc);
group->SetMainTank(MainTankName);
group->SetMainAssist(AssistName);
group->SetPuller(PullerName);
group->SetNPCMarker(NPCMarkerName);
group->SetGroupAAs(&GLAA);
group->SetGroupMentor(mentor_percent, mentoree_name);
client->JoinGroupXTargets(group);
}
}
else if (client->GetMerc())
{
client->GetMerc()->MercJoinClientGroup();
}
break;
}
case ServerOP_GroupCancelInvite: {
GroupCancel_Struct* sgcs = (GroupCancel_Struct*)pack->pBuffer;
Mob* Inviter = entity_list.GetClientByName(sgcs->name1);
if (Inviter && Inviter->IsClient())
{
auto outapp = new EQApplicationPacket(OP_GroupCancelInvite, sizeof(GroupCancel_Struct));
memcpy(outapp->pBuffer, sgcs, sizeof(GroupCancel_Struct));
Inviter->CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
}
break;
}
case ServerOP_GroupJoin: {
auto gj = (ServerGroupJoin_Struct*)pack->pBuffer;
if (zone) {
if (gj->zoneid == zone->GetZoneID() && gj->instance_id == zone->GetInstanceID())
break;
Group* g = entity_list.GetGroupByID(gj->gid);
if (g)
g->AddMember(gj->member_name);
entity_list.SendGroupJoin(gj->gid, gj->member_name);
}
break;
}
case ServerOP_ForceGroupUpdate: {
ServerForceGroupUpdate_Struct* fgu = (ServerForceGroupUpdate_Struct*)pack->pBuffer;
if (zone) {
if (fgu->origZoneID == zone->GetZoneID() && fgu->instance_id == zone->GetInstanceID())
break;
entity_list.ForceGroupUpdate(fgu->gid);
}
break;
}
case ServerOP_IsOwnerOnline: {
auto o = (ServerIsOwnerOnline_Struct*)pack->pBuffer;
if (zone) {
if (o->zone_id != zone->GetZoneID()) {
break;
}
Corpse* c = entity_list.GetCorpseByID(o->corpse_id);
if (c && o->online) {
c->SetOwnerOnline(true);
} else if (c) {
c->SetOwnerOnline(false);
}
}
break;
}
case ServerOP_OOZGroupMessage: {
ServerGroupChannelMessage_Struct* gcm = (ServerGroupChannelMessage_Struct*)pack->pBuffer;
if (zone) {
if (gcm->zoneid == zone->GetZoneID() && gcm->instanceid == zone->GetInstanceID())
break;
entity_list.GroupMessage(gcm->groupid, gcm->from, gcm->message);
}
break;
}
case ServerOP_DisbandGroup: {
ServerDisbandGroup_Struct* sd = (ServerDisbandGroup_Struct*)pack->pBuffer;
if (zone) {
if (sd->zoneid == zone->GetZoneID() && sd->instance_id == zone->GetInstanceID())
break;
Group *g = entity_list.GetGroupByID(sd->groupid);
if (g)
g->DisbandGroup();
}
break;
}
case ServerOP_RaidAdd: {
auto rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
if (zone) {
if (rga->zoneid == zone->GetZoneID() && rga->instance_id == zone->GetInstanceID())
break;
Raid *r = entity_list.GetRaidByID(rga->rid);
if (r) {
r->LearnMembers();
r->VerifyRaid();
r->SendRaidAddAll(rga->playername);
}
}
break;
}
case ServerOP_RaidRemove: {
auto rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
if (zone) {
if (rga->zoneid == zone->GetZoneID() && rga->instance_id == zone->GetInstanceID())
break;
Raid *r = entity_list.GetRaidByID(rga->rid);
if (r) {
r->SendRaidRemoveAll(rga->playername);
Client *rem = entity_list.GetClientByName(rga->playername);
if (rem) {
rem->LeaveRaidXTargets(r);
r->SendRaidDisband(rem);
}
r->LearnMembers();
r->VerifyRaid();
}
}
break;
}
case ServerOP_RaidDisband: {
auto rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
if (zone) {
if (rga->zoneid == zone->GetZoneID() && rga->instance_id == zone->GetInstanceID())
break;
Raid *r = entity_list.GetRaidByID(rga->rid);
if (r) {
r->SendRaidDisbandAll();
r->LearnMembers();
r->VerifyRaid();
}
}
break;
}
case ServerOP_RaidLockFlag: {
auto rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
if (zone) {
if (rga->zoneid == zone->GetZoneID() && rga->instance_id == zone->GetInstanceID())
break;
Raid *r = entity_list.GetRaidByID(rga->rid);
if (r) {
r->GetRaidDetails(); //update our details
if (rga->gid)
r->SendRaidLock();
else
r->SendRaidUnlock();
}
}
break;
}
case ServerOP_RaidChangeGroup: {
auto rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
if (zone) {
if (rga->zoneid == zone->GetZoneID() && rga->instance_id == zone->GetInstanceID())
break;
Raid *r = entity_list.GetRaidByID(rga->rid);
if (r) {
r->LearnMembers();
r->VerifyRaid();
Client *c = entity_list.GetClientByName(rga->playername);
if (c) {
r->SendRaidDisband(c);
r->SendRaidRemoveAll(rga->playername);
r->SendRaidCreate(c);
r->SendMakeLeaderPacketTo(r->leadername, c);
r->SendBulkRaid(c);
r->SendRaidAddAll(rga->playername);
if (r->IsLocked()) { r->SendRaidLockTo(c); }
}
else {
r->SendRaidRemoveAll(rga->playername);
r->SendRaidAddAll(rga->playername);
}
}
}
break;
}
case ServerOP_UpdateGroup: {
auto rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
if (zone) {
if (rga->zoneid == zone->GetZoneID() && rga->instance_id == zone->GetInstanceID())
break;
Raid *r = entity_list.GetRaidByID(rga->rid);
if (r) {
r->GroupUpdate(rga->gid, false);
}
}
break;
}
case ServerOP_RaidGroupLeader: {
auto rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
if (zone) {
if (rga->zoneid == zone->GetZoneID() && rga->instance_id == zone->GetInstanceID())
break;
}
break;
}
case ServerOP_RaidLeader: {
auto rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
if (zone) {
if (rga->zoneid == zone->GetZoneID() && rga->instance_id == zone->GetInstanceID())
break;
Raid *r = entity_list.GetRaidByID(rga->rid);
if (r) {
Client *c = entity_list.GetClientByName(rga->playername);
strn0cpy(r->leadername, rga->playername, 64);
if (c) {
r->SetLeader(c);
}
r->LearnMembers();
r->VerifyRaid();
r->SendMakeLeaderPacket(rga->playername);
}
}
break;
}
case ServerOP_DetailsChange: {
auto rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
if (zone) {
if (rga->zoneid == zone->GetZoneID() && rga->instance_id == zone->GetInstanceID())
break;
Raid *r = entity_list.GetRaidByID(rga->rid);
if (r) {
r->GetRaidDetails();
r->LearnMembers();
r->VerifyRaid();
}
}
break;
}
case ServerOP_RaidGroupDisband: {
auto rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
if (zone) {
if (rga->zoneid == zone->GetZoneID() && rga->instance_id == zone->GetInstanceID())
break;
Client *c = entity_list.GetClientByName(rga->playername);
if (c)
{
auto outapp =
new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate_Struct));
auto gu = (GroupUpdate_Struct*)outapp->pBuffer;
gu->action = groupActDisband;
strn0cpy(gu->leadersname, c->GetName(), 64);
strn0cpy(gu->yourname, c->GetName(), 64);
c->FastQueuePacket(&outapp);
}
}
break;
}
case ServerOP_RaidGroupAdd: {
auto rga = (ServerRaidGroupAction_Struct*)pack->pBuffer;
if (zone) {
Raid *r = entity_list.GetRaidByID(rga->rid);
if (r) {
r->LearnMembers();
r->VerifyRaid();
auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct));
auto gj = (GroupJoin_Struct*)outapp->pBuffer;
strn0cpy(gj->membername, rga->membername, 64);
gj->action = groupActJoin;
for (const auto& m : r->members) {
if (m.is_bot) {
continue;
}
if (m.member && strcmp(m.member->GetName(), rga->membername) != 0) {
if ((rga->gid < MAX_RAID_GROUPS) && rga->gid == m.group_number) {
strn0cpy(gj->yourname, m.member->GetName(), 64);
m.member->QueuePacket(outapp);
}
}
}
safe_delete(outapp);
}
}
break;
}
case ServerOP_RaidGroupRemove: {
auto rga = (ServerRaidGroupAction_Struct*)pack->pBuffer;
if (zone) {
Raid *r = entity_list.GetRaidByID(rga->rid);
if (r) {
r->LearnMembers();
r->VerifyRaid();
auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct));
auto gj = (GroupJoin_Struct*)outapp->pBuffer;
strn0cpy(gj->membername, rga->membername, 64);
gj->action = groupActLeave;
for (const auto& m : r->members) {
if (m.is_bot) {
continue;
}
if (m.member && strcmp(m.member->GetName(), rga->membername) != 0) {
if ((rga->gid < MAX_RAID_GROUPS) && rga->gid == m.group_number) {
strn0cpy(gj->yourname, m.member->GetName(), 64);
m.member->QueuePacket(outapp);
}
}
}
safe_delete(outapp);
}
}
break;
}
case ServerOP_RaidGroupSay: {
auto rmsg = (ServerRaidMessage_Struct*)pack->pBuffer;
if (zone) {
Raid *r = entity_list.GetRaidByID(rmsg->rid);
if (r) {
for (const auto& m :r->members) {
if (m.is_bot) {
continue;
}
if (m.member && strcmp(m.member->GetName(), rmsg->from) != 0) {
if (m.group_number == rmsg->gid) {
if (m.member->GetFilter(FilterGroupChat) != 0) {
m.member->ChannelMessageSend(rmsg->from, m.member->GetName(), ChatChannel_Group, rmsg->language, rmsg->lang_skill, rmsg->message);
}
}
}
}
}
}
break;
}
case ServerOP_RaidSay: {
auto rmsg = (ServerRaidMessage_Struct*)pack->pBuffer;
if (zone) {
Raid *r = entity_list.GetRaidByID(rmsg->rid);
if (r) {
for (const auto& m :r->members) {
if (m.is_bot) {
continue;
}
if (m.member) {
if (strcmp(rmsg->from, m.member->GetName()) != 0) {
if (!m.is_bot && m.member->GetFilter(FilterGroupChat) != 0) {
m.member->ChannelMessageSend(rmsg->from, m.member->GetName(), ChatChannel_Raid, rmsg->language, rmsg->lang_skill, rmsg->message);
}
}
}
}
}
}
break;
}
case ServerOP_RaidMOTD: {
ServerRaidMOTD_Struct *rmotd = (ServerRaidMOTD_Struct *)pack->pBuffer;
if (!zone)
break;
Raid *r = entity_list.GetRaidByID(rmotd->rid);
if (!r)
break;
r->SetRaidMOTD(std::string(rmotd->motd));
r->SendRaidMOTD();
break;
}
case ServerOP_RaidNote: {
auto snote = (ServerRaidNote_Struct*)pack->pBuffer;
if (snote->rid > 0) {
Raid* r = entity_list.GetRaidByID(snote->rid);
if (r) {
r->SendRaidNotes();
}
}
break;
}
case ServerOP_SpawnPlayerCorpse: {
auto *s = (SpawnPlayerCorpse_Struct *) pack->pBuffer;
Corpse *c = database.LoadCharacterCorpse(s->player_corpse_id);
if (c) {
c->Spawn();
}
else {
LogError("Unable to load player corpse id [{}] for zone [{}]", s->player_corpse_id, zone->GetShortName());
}
break;
}
case ServerOP_Consent: {
ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer;
bool found_corpse = false;
for (auto const& it : entity_list.GetCorpseList()) {
if (it.second->IsPlayerCorpse() && strcmp(it.second->GetOwnerName(), s->ownername) == 0) {
if (s->consent_type == EQ::consent::Normal) {
if (s->permission == 1) {
it.second->AddConsentName(s->grantname);
}
else {
it.second->RemoveConsentName(s->grantname);
}
}
else if (s->consent_type == EQ::consent::Group) {
it.second->SetConsentGroupID(s->consent_id);
}
else if (s->consent_type == EQ::consent::Raid) {
it.second->SetConsentRaidID(s->consent_id);
}
else if (s->consent_type == EQ::consent::Guild) {
it.second->SetConsentGuildID(s->consent_id);
}
found_corpse = true;
}
}
if (found_corpse) {
// forward the grant/deny message for this zone to both owner and granted
auto outapp = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)outapp->pBuffer;
memcpy(outapp->pBuffer, s, sizeof(ServerOP_Consent_Struct));
if (zone) {
strn0cpy(scs->zonename, zone->GetLongName(), sizeof(scs->zonename));
}
worldserver.SendPacket(outapp);
safe_delete(outapp);
}
break;
}
case ServerOP_Consent_Response: {
ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer;
Client* owner_client = entity_list.GetClientByName(s->ownername);
Client* grant_client = nullptr;
if (s->consent_type == EQ::consent::Normal) {
grant_client = entity_list.GetClientByName(s->grantname);
}
if (owner_client || grant_client) {
auto outapp = new EQApplicationPacket(OP_ConsentResponse, sizeof(ConsentResponse_Struct));
ConsentResponse_Struct* crs = (ConsentResponse_Struct*)outapp->pBuffer;
strn0cpy(crs->grantname, s->grantname, sizeof(crs->grantname));
strn0cpy(crs->ownername, s->ownername, sizeof(crs->ownername));
crs->permission = s->permission;
strn0cpy(crs->zonename, s->zonename, sizeof(crs->zonename));
if (owner_client) {
owner_client->QueuePacket(outapp); // confirmation message to the owner
}
if (grant_client) {
grant_client->QueuePacket(outapp); // message to the client being granted/denied
}
safe_delete(outapp);
}
break;
}
case ServerOP_LFGMatches: {
HandleLFGMatches(pack);
break;
}
case ServerOP_LFPMatches: {
HandleLFPMatches(pack);
break;
}
case ServerOP_UpdateSpawn: {
if (zone)
{
UpdateSpawnTimer_Struct *ust = (UpdateSpawnTimer_Struct*)pack->pBuffer;
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
iterator.Reset();
while (iterator.MoreElements())
{
if (iterator.GetData()->GetID() == ust->id)
{
if (!iterator.GetData()->NPCPointerValid())
{
iterator.GetData()->SetTimer(ust->duration);
}
break;
}
iterator.Advance();
}
}
break;
}
case ServerOP_InstanceUpdateTime:
{
ServerInstanceUpdateTime_Struct *iut = (ServerInstanceUpdateTime_Struct*)pack->pBuffer;
if (zone)
{
if (zone->GetInstanceID() == iut->instance_id)
{
zone->SetInstanceTimer(iut->new_duration);
}
}
break;
}
case ServerOP_DepopAllPlayersCorpses:
{
ServerDepopAllPlayersCorpses_Struct *sdapcs = (ServerDepopAllPlayersCorpses_Struct *)pack->pBuffer;
if (zone && !((zone->GetZoneID() == sdapcs->ZoneID) && (zone->GetInstanceID() == sdapcs->InstanceID)))
entity_list.RemoveAllCorpsesByCharID(sdapcs->CharacterID);
break;
}
case ServerOP_DepopPlayerCorpse:
{
ServerDepopPlayerCorpse_Struct *sdpcs = (ServerDepopPlayerCorpse_Struct *)pack->pBuffer;
if (zone && !((zone->GetZoneID() == sdpcs->ZoneID) && (zone->GetInstanceID() == sdpcs->InstanceID)))
entity_list.RemoveCorpseByDBID(sdpcs->DBID);
break;
}
case ServerOP_SpawnStatusChange:
{
if (zone)
{
ServerSpawnStatusChange_Struct *ssc = (ServerSpawnStatusChange_Struct*)pack->pBuffer;
if (ssc->instance_id != zone->GetInstanceID()) {
break;
}
LinkedListIterator<Spawn2 *> iterator(zone->spawn2_list);
iterator.Reset();
Spawn2 *found_spawn = nullptr;
while (iterator.MoreElements()) {
Spawn2 *cur = iterator.GetData();
if (cur->GetID() == ssc->id) {
found_spawn = cur;
break;
}
iterator.Advance();
}
if (found_spawn) {
if (ssc->new_status == 0) {
found_spawn->Disable();
}
else {
found_spawn->Enable();
}
}
}
break;
}
case ServerOP_QGlobalUpdate:
{
if (pack->size != sizeof(ServerQGlobalUpdate_Struct))
{
break;
}
if (zone)
{
ServerQGlobalUpdate_Struct *qgu = (ServerQGlobalUpdate_Struct*)pack->pBuffer;
if (qgu->from_zone_id != zone->GetZoneID() || qgu->from_instance_id != zone->GetInstanceID())
{
QGlobal temp;
temp.npc_id = qgu->npc_id;
temp.char_id = qgu->char_id;
temp.zone_id = qgu->zone_id;
temp.expdate = qgu->expdate;
temp.name.assign(qgu->name);
temp.value.assign(qgu->value);
entity_list.UpdateQGlobal(qgu->id, temp);
zone->UpdateQGlobal(qgu->id, temp);
}
}
break;
}
case ServerOP_QGlobalDelete:
{
if (pack->size != sizeof(ServerQGlobalDelete_Struct))
{
break;
}
if (zone)
{
ServerQGlobalDelete_Struct *qgd = (ServerQGlobalDelete_Struct*)pack->pBuffer;
if (qgd->from_zone_id != zone->GetZoneID() || qgd->from_instance_id != zone->GetInstanceID())
{
entity_list.DeleteQGlobal(std::string((char*)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id);
zone->DeleteQGlobal(std::string((char*)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id);
}
}
break;
}
case ServerOP_AdventureRequestAccept:
{
ServerAdventureRequestAccept_Struct *ars = (ServerAdventureRequestAccept_Struct*)pack->pBuffer;
Client *c = entity_list.GetClientByName(ars->leader);
if (c)
{
c->NewAdventure(ars->id, ars->theme, ars->text, ars->member_count, (const char*)(pack->pBuffer + sizeof(ServerAdventureRequestAccept_Struct)));
c->ClearPendingAdventureRequest();
}
break;
}
case ServerOP_AdventureRequestDeny:
{
ServerAdventureRequestDeny_Struct *ars = (ServerAdventureRequestDeny_Struct*)pack->pBuffer;
Client *c = entity_list.GetClientByName(ars->leader);
if (c)
{
c->SendAdventureError(ars->reason);
c->ClearPendingAdventureRequest();
}
break;
}
case ServerOP_AdventureCreateDeny:
{
Client *c = entity_list.GetClientByName((const char*)pack->pBuffer);
if (c)
{
c->ClearPendingAdventureData();
c->ClearPendingAdventureCreate();
}
break;
}
case ServerOP_AdventureData:
{
Client *c = entity_list.GetClientByName((const char*)pack->pBuffer);
if (c)
{
c->ClearAdventureData();
auto adv_data = new char[pack->size];
memcpy(adv_data, pack->pBuffer, pack->size);
c->SetAdventureData(adv_data);
c->ClearPendingAdventureData();
c->ClearPendingAdventureCreate();
c->SendAdventureDetails();
}
break;
}
case ServerOP_AdventureDataClear:
{
Client *c = entity_list.GetClientByName((const char*)pack->pBuffer);
if (c)
{
if (c->HasAdventureData())
{
c->ClearAdventureData();
c->SendAdventureError("You are not currently assigned to an adventure.");
}
}
break;
}
case ServerOP_AdventureClickDoorReply:
{
ServerPlayerClickedAdventureDoorReply_Struct *adr = (ServerPlayerClickedAdventureDoorReply_Struct*)pack->pBuffer;
Client *c = entity_list.GetClientByName(adr->player);
if (c)
{
c->ClearPendingAdventureDoorClick();
c->MovePC(adr->zone_id, adr->instance_id, adr->x, adr->y, adr->z, adr->h, 0);
}
break;
}
case ServerOP_AdventureClickDoorError:
{
Client *c = entity_list.GetClientByName((const char*)pack->pBuffer);
if (c)
{
c->ClearPendingAdventureDoorClick();
c->MessageString(Chat::Red, 5141);
}
break;
}
case ServerOP_AdventureLeaveReply:
{
Client *c = entity_list.GetClientByName((const char*)pack->pBuffer);
if (c)
{
c->ClearPendingAdventureLeave();
c->ClearCurrentAdventure();
}
break;
}
case ServerOP_AdventureLeaveDeny:
{
Client *c = entity_list.GetClientByName((const char*)pack->pBuffer);
if (c)
{
c->ClearPendingAdventureLeave();
c->Message(Chat::Red, "You cannot leave this adventure at this time.");
}
break;
}
case ServerOP_AdventureCountUpdate:
{
ServerAdventureCountUpdate_Struct *ac = (ServerAdventureCountUpdate_Struct*)pack->pBuffer;
Client *c = entity_list.GetClientByName(ac->player);
if (c)
{
c->SendAdventureCount(ac->count, ac->total);
}
break;
}
case ServerOP_AdventureZoneData:
{
if (zone)
{
safe_delete(zone->adv_data);
zone->adv_data = new char[pack->size];
memcpy(zone->adv_data, pack->pBuffer, pack->size);
ServerZoneAdventureDataReply_Struct* ds = (ServerZoneAdventureDataReply_Struct*)zone->adv_data;
}
break;
}
case ServerOP_AdventureFinish:
{
ServerAdventureFinish_Struct *af = (ServerAdventureFinish_Struct*)pack->pBuffer;
Client *c = entity_list.GetClientByName(af->player);
if (c)
{
c->AdventureFinish(af->win, af->theme, af->points);
}
break;
}
case ServerOP_AdventureLeaderboard:
{
Client *c = entity_list.GetClientByName((const char*)pack->pBuffer);
if (c)
{
auto outapp = new EQApplicationPacket(OP_AdventureLeaderboardReply,
sizeof(AdventureLeaderboard_Struct));
memcpy(outapp->pBuffer, pack->pBuffer + 64, sizeof(AdventureLeaderboard_Struct));
c->FastQueuePacket(&outapp);
}
break;
}
case ServerOP_ServerReloadRequest:
{
auto o = (ServerReload::Request*) pack->pBuffer;
QueueReload(*o);
break;
}
case ServerOP_CameraShake:
{
if (zone)
{
ServerCameraShake_Struct *scss = (ServerCameraShake_Struct*)pack->pBuffer;
entity_list.CameraEffect(scss->duration, scss->intensity);
}
break;
}
case ServerOP_QueryServGeneric:
{
pack->SetReadPosition(8);
char From[64];
pack->ReadString(From);
Client *c = entity_list.GetClientByName(From);
if (!c)
return;
uint32 Type = pack->ReadUInt32();;
switch (Type)
{
case QSG_LFGuild:
{
c->HandleLFGuildResponse(pack);
break;
}
default:
break;
}
break;
}
case ServerOP_UCSServerStatusReply:
{
auto ucsss = (UCSServerStatus_Struct *) pack->pBuffer;
if (zone) {
zone->SetUCSServerAvailable((ucsss->available != 0), ucsss->timestamp);
LogInfo("UCS Server is now [{}]", (ucsss->available == 1 ? "online" : "offline"));
for (auto &e : entity_list.GetClientList()) {
e.second->ReconnectUCS();
}
}
break;
}
case ServerOP_CZDialogueWindow:
{
auto s = (CZDialogueWindow_Struct*) pack->pBuffer;
if (s->update_type == CZUpdateType_Character) {
Client* c = entity_list.GetClientByCharID(s->update_identifier);
if (c) {
DialogueWindow::Render(c, s->message);
}
} else if (s->update_type == CZUpdateType_Group) {
Group* g = entity_list.GetGroupByID(s->update_identifier);
if (g) {
for (const auto& m : g->members) {
if (m && m->IsClient()) {
DialogueWindow::Render(m->CastToClient(), s->message);
}
}
}
} else if (s->update_type == CZUpdateType_Raid) {
Raid* r = entity_list.GetRaidByID(s->update_identifier);
if (r) {
for (const auto& m : r->members) {
if (m.member && m.member->IsClient()) {
DialogueWindow::Render(m.member->CastToClient(), s->message);
}
}
}
} else if (s->update_type == CZUpdateType_Guild) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->IsInGuild(s->update_identifier)) {
DialogueWindow::Render(c.second, s->message);
}
}
} else if (s->update_type == CZUpdateType_Expedition) {
for (const auto& c: entity_list.GetClientList()) {
if (c.second->GetExpedition() && c.second->GetExpedition()->GetID() == s->update_identifier) {
DialogueWindow::Render(c.second, s->message);
}
}
} else if (s->update_type == CZUpdateType_ClientName) {
Client* c = entity_list.GetClientByName(s->client_name);
if (c) {
DialogueWindow::Render(c, s->message);
}
}
break;
}
case ServerOP_CZLDoNUpdate:
{
auto u = (CZLDoNUpdate_Struct*) pack->pBuffer;
if (u->update_type == CZUpdateType_Character) {
Client* c = entity_list.GetClientByCharID(u->update_identifier);
if (c) {
switch (u->update_subtype) {
case CZLDoNUpdateSubtype_AddLoss:
c->UpdateLDoNWinLoss(u->theme_id, false);
break;
case CZLDoNUpdateSubtype_AddPoints:
c->UpdateLDoNPoints(u->theme_id, u->points);
break;
case CZLDoNUpdateSubtype_AddWin:
c->UpdateLDoNWinLoss(u->theme_id, true);
break;
case CZLDoNUpdateSubtype_RemoveLoss:
c->UpdateLDoNWinLoss(u->theme_id, false, true);
break;
case CZLDoNUpdateSubtype_RemoveWin:
c->UpdateLDoNWinLoss(u->theme_id, true, true);
break;
default:
break;
}
}
break;
} else if (u->update_type == CZUpdateType_Group) {
Group* g = entity_list.GetGroupByID(u->update_identifier);
if (g) {
for (const auto& m : g->members) {
if (m && m->IsClient()) {
switch (u->update_subtype) {
case CZLDoNUpdateSubtype_AddLoss:
m->CastToClient()->UpdateLDoNWinLoss(u->theme_id, false);
break;
case CZLDoNUpdateSubtype_AddPoints:
m->CastToClient()->UpdateLDoNPoints(u->theme_id, u->points);
break;
case CZLDoNUpdateSubtype_AddWin:
m->CastToClient()->UpdateLDoNWinLoss(u->theme_id, true);
break;
case CZLDoNUpdateSubtype_RemoveLoss:
m->CastToClient()->UpdateLDoNWinLoss(u->theme_id, false, true);
break;
case CZLDoNUpdateSubtype_RemoveWin:
m->CastToClient()->UpdateLDoNWinLoss(u->theme_id, true, true);
break;
default:
break;
}
}
}
}
} else if (u->update_type == CZUpdateType_Raid) {
Raid* r = entity_list.GetRaidByID(u->update_identifier);
if (r) {
for (const auto& m : r->members) {
if (m.member && m.member->IsClient()) {
switch (u->update_subtype) {
case CZLDoNUpdateSubtype_AddLoss:
m.member->UpdateLDoNWinLoss(u->theme_id, false);
break;
case CZLDoNUpdateSubtype_AddPoints:
m.member->UpdateLDoNPoints(u->theme_id, u->points);
break;
case CZLDoNUpdateSubtype_AddWin:
m.member->UpdateLDoNWinLoss(u->theme_id, true);
break;
case CZLDoNUpdateSubtype_RemoveLoss:
m.member->UpdateLDoNWinLoss(u->theme_id, false, true);
break;
case CZLDoNUpdateSubtype_RemoveWin:
m.member->UpdateLDoNWinLoss(u->theme_id, true, true);
break;
default:
break;
}
}
}
}
} else if (u->update_type == CZUpdateType_Guild) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->IsInGuild(u->update_identifier)) {
switch (u->update_subtype) {
case CZLDoNUpdateSubtype_AddLoss:
c.second->UpdateLDoNWinLoss(u->theme_id, false);
break;
case CZLDoNUpdateSubtype_AddPoints:
c.second->UpdateLDoNPoints(u->theme_id, u->points);
break;
case CZLDoNUpdateSubtype_AddWin:
c.second->UpdateLDoNWinLoss(u->theme_id, true);
break;
case CZLDoNUpdateSubtype_RemoveLoss:
c.second->UpdateLDoNWinLoss(u->theme_id, false, true);
break;
case CZLDoNUpdateSubtype_RemoveWin:
c.second->UpdateLDoNWinLoss(u->theme_id, true, true);
break;
default:
break;
}
}
}
} else if (u->update_type == CZUpdateType_Expedition) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->GetExpedition() && c.second->GetExpedition()->GetID() == u->update_identifier) {
switch (u->update_subtype) {
case CZLDoNUpdateSubtype_AddLoss:
c.second->UpdateLDoNWinLoss(u->theme_id, false);
break;
case CZLDoNUpdateSubtype_AddPoints:
c.second->UpdateLDoNPoints(u->theme_id, u->points);
break;
case CZLDoNUpdateSubtype_AddWin:
c.second->UpdateLDoNWinLoss(u->theme_id, true);
break;
case CZLDoNUpdateSubtype_RemoveLoss:
c.second->UpdateLDoNWinLoss(u->theme_id, false, true);
break;
case CZLDoNUpdateSubtype_RemoveWin:
c.second->UpdateLDoNWinLoss(u->theme_id, true, true);
break;
default:
break;
}
}
}
} else if (u->update_type == CZUpdateType_ClientName) {
Client* c = entity_list.GetClientByName(u->client_name);
if (c) {
switch (u->update_subtype) {
case CZLDoNUpdateSubtype_AddLoss:
c->UpdateLDoNWinLoss(u->theme_id, false);
break;
case CZLDoNUpdateSubtype_AddPoints:
c->UpdateLDoNPoints(u->theme_id, u->points);
break;
case CZLDoNUpdateSubtype_AddWin:
c->UpdateLDoNWinLoss(u->theme_id, true);
break;
case CZLDoNUpdateSubtype_RemoveLoss:
c->UpdateLDoNWinLoss(u->theme_id, false, true);
break;
case CZLDoNUpdateSubtype_RemoveWin:
c->UpdateLDoNWinLoss(u->theme_id, true, true);
break;
default:
break;
}
}
break;
}
break;
}
case ServerOP_CZMarquee:
{
auto s = (CZMarquee_Struct*) pack->pBuffer;
if (s->update_type == CZUpdateType_Character) {
Client* c = entity_list.GetClientByCharID(s->update_identifier);
if (c) {
c->SendMarqueeMessage(s->type, s->priority, s->fade_in, s->fade_out, s->duration, s->message);
}
} else if (s->update_type == CZUpdateType_Group) {
Group* g = entity_list.GetGroupByID(s->update_identifier);
if (g) {
for (const auto& m : g->members) {
if (m && m->IsClient()) {
m->CastToClient()->SendMarqueeMessage(
s->type,
s->priority,
s->fade_in,
s->fade_out,
s->duration,
s->message
);
}
}
}
} else if (s->update_type == CZUpdateType_Raid) {
Raid* r = entity_list.GetRaidByID(s->update_identifier);
if (r) {
for (const auto& m : r->members) {
if (m.member && m.member->IsClient()) {
m.member->CastToClient()->SendMarqueeMessage(
s->type,
s->priority,
s->fade_in,
s->fade_out,
s->duration,
s->message
);
}
}
}
} else if (s->update_type == CZUpdateType_Guild) {
for (const auto& c: entity_list.GetClientList()) {
if (c.second->IsInGuild(s->update_identifier)) {
c.second->SendMarqueeMessage(
s->type,
s->priority,
s->fade_in,
s->fade_out,
s->duration,
s->message
);
}
}
} else if (s->update_type == CZUpdateType_Expedition) {
for (const auto& c: entity_list.GetClientList()) {
if (c.second->GetExpedition() && c.second->GetExpedition()->GetID() == s->update_identifier) {
c.second->SendMarqueeMessage(
s->type,
s->priority,
s->fade_in,
s->fade_out,
s->duration,
s->message
);
}
}
} else if (s->update_type == CZUpdateType_ClientName) {
Client* c = entity_list.GetClientByName(s->client_name);
if (c) {
c->SendMarqueeMessage(s->type, s->priority, s->fade_in, s->fade_out, s->duration, s->message);
}
}
break;
}
case ServerOP_CZMessage:
{
auto s = (CZMessage_Struct*) pack->pBuffer;
if (s->update_type == CZUpdateType_Character) {
Client* c = entity_list.GetClientByCharID(s->update_identifier);
if (c) {
c->Message(s->type, s->message);
}
} else if (s->update_type == CZUpdateType_Group) {
Group* g = entity_list.GetGroupByID(s->update_identifier);
if (g) {
for (const auto& m : g->members) {
if (m && m->IsClient()) {
m->CastToClient()->Message(s->type, s->message);
}
}
}
} else if (s->update_type == CZUpdateType_Raid) {
Raid* r = entity_list.GetRaidByID(s->update_identifier);
if (r) {
for (const auto& m : r->members) {
if (m.member && m.member->IsClient()) {
m.member->CastToClient()->Message(s->type, s->message);
}
}
}
} else if (s->update_type == CZUpdateType_Guild) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->IsInGuild(s->update_identifier)) {
c.second->Message(s->type, s->message);
}
}
} else if (s->update_type == CZUpdateType_Expedition) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->GetExpedition() && c.second->GetExpedition()->GetID() == s->update_identifier) {
c.second->Message(s->type, s->message);
}
}
} else if (s->update_type == CZUpdateType_ClientName) {
Client* c = entity_list.GetClientByName(s->client_name);
if (c) {
c->Message(s->type, s->message);
}
}
break;
}
case ServerOP_CZMove:
{
auto s = (CZMove_Struct*) pack->pBuffer;
if (Strings::IsNumber(s->client_name) || Strings::IsNumber(s->zone_short_name)) {
break;
}
if (s->update_type == CZUpdateType_Character) {
Client* c = entity_list.GetClientByCharID(s->update_identifier);
if (c) {
switch (s->update_subtype) {
case CZMoveUpdateSubtype_MoveZone:
c->MoveZone(s->zone_short_name.c_str(), s->coordinates);
break;
case CZMoveUpdateSubtype_MoveZoneInstance:
c->MoveZoneInstance(s->instance_id, s->coordinates);
break;
}
}
} else if (s->update_type == CZUpdateType_Group) {
Group* g = entity_list.GetGroupByID(s->update_identifier);
if (g) {
for (const auto& m : g->members) {
if (m && m->IsClient()) {
switch (s->update_subtype) {
case CZMoveUpdateSubtype_MoveZone:
m->CastToClient()->MoveZone(s->zone_short_name.c_str(), s->coordinates);
break;
case CZMoveUpdateSubtype_MoveZoneInstance:
m->CastToClient()->MoveZoneInstance(s->instance_id, s->coordinates);
break;
}
}
}
}
} else if (s->update_type == CZUpdateType_Raid) {
Raid* r = entity_list.GetRaidByID(s->update_identifier);
if (r) {
for (const auto& m : r->members) {
if (m.member && m.member->IsClient()) {
switch (s->update_subtype) {
case CZMoveUpdateSubtype_MoveZone:
m.member->CastToClient()->MoveZone(s->zone_short_name.c_str(), s->coordinates);
break;
case CZMoveUpdateSubtype_MoveZoneInstance:
m.member->CastToClient()->MoveZoneInstance(s->instance_id, s->coordinates);
break;
}
}
}
}
} else if (s->update_type == CZUpdateType_Guild) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->IsInGuild(s->update_identifier)) {
switch (s->update_subtype) {
case CZMoveUpdateSubtype_MoveZone:
c.second->MoveZone(s->zone_short_name.c_str(), s->coordinates);
break;
case CZMoveUpdateSubtype_MoveZoneInstance:
c.second->MoveZoneInstance(s->instance_id, s->coordinates);
break;
}
}
}
} else if (s->update_type == CZUpdateType_Expedition) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->GetExpedition() && c.second->GetExpeditionID() == s->update_identifier) {
switch (s->update_subtype) {
case CZMoveUpdateSubtype_MoveZone:
c.second->MoveZone(s->zone_short_name.c_str(), s->coordinates);
break;
case CZMoveUpdateSubtype_MoveZoneInstance:
c.second->MoveZoneInstance(s->instance_id, s->coordinates);
break;
}
}
}
} else if (s->update_type == CZUpdateType_ClientName) {
Client* c = entity_list.GetClientByName(s->client_name.c_str());
if (c) {
switch (s->update_subtype) {
case CZMoveUpdateSubtype_MoveZone:
c->MoveZone(s->zone_short_name.c_str(), s->coordinates);
break;
case CZMoveUpdateSubtype_MoveZoneInstance:
c->MoveZoneInstance(s->instance_id, s->coordinates);
break;
}
}
}
break;
}
case ServerOP_CZSetEntityVariable:
{
auto s = (CZSetEntityVariable_Struct*) pack->pBuffer;
if (s->update_type == CZUpdateType_Character) {
Client* c = entity_list.GetClientByCharID(s->update_identifier);
if (c) {
c->SetEntityVariable(s->variable_name, s->variable_value);
}
} else if (s->update_type == CZUpdateType_Group) {
Group* g = entity_list.GetGroupByID(s->update_identifier);
if (g) {
for (const auto& m : g->members) {
if (m && m->IsClient()) {
m->SetEntityVariable(s->variable_name, s->variable_value);
}
}
}
} else if (s->update_type == CZUpdateType_Raid) {
Raid* r = entity_list.GetRaidByID(s->update_identifier);
if (r) {
for (const auto& m : r->members) {
if (m.member && m.member->IsClient()) {
m.member->CastToClient()->SetEntityVariable(s->variable_name, s->variable_value);
}
}
}
} else if (s->update_type == CZUpdateType_Guild) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->IsInGuild(s->update_identifier)) {
c.second->SetEntityVariable(s->variable_name, s->variable_value);
}
}
} else if (s->update_type == CZUpdateType_Expedition) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->GetExpedition() && c.second->GetExpedition()->GetID() == s->update_identifier) {
c.second->SetEntityVariable(s->variable_name, s->variable_value);
}
}
} else if (s->update_type == CZUpdateType_ClientName) {
Client* c = entity_list.GetClientByName(s->client_name);
if (c) {
c->SetEntityVariable(s->variable_name, s->variable_value);
}
} else if (s->update_type == CZUpdateType_NPC) {
NPC* n = entity_list.GetNPCByNPCTypeID(s->update_identifier);
if (n) {
n->SetEntityVariable(s->variable_name, s->variable_value);
}
}
break;
}
case ServerOP_CZSignal:
{
auto s = (CZSignal_Struct*) pack->pBuffer;
if (s->update_type == CZUpdateType_Character) {
Client* c = entity_list.GetClientByCharID(s->update_identifier);
if (c) {
c->Signal(s->signal_id);
}
} else if (s->update_type == CZUpdateType_Group) {
Group* g = entity_list.GetGroupByID(s->update_identifier);
if (g) {
for (const auto& m : g->members) {
if (m && m->IsClient()) {
m->CastToClient()->Signal(s->signal_id);
}
}
}
} else if (s->update_type == CZUpdateType_Raid) {
Raid* r = entity_list.GetRaidByID(s->update_identifier);
if (r) {
for (const auto& m : r->members) {
if (m.member && m.member->IsClient()) {
m.member->CastToClient()->Signal(s->signal_id);
}
}
}
} else if (s->update_type == CZUpdateType_Guild) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->IsInGuild(s->update_identifier)) {
c.second->Signal(s->signal_id);
}
}
} else if (s->update_type == CZUpdateType_Expedition) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->GetExpedition() && c.second->GetExpedition()->GetID() == s->update_identifier) {
c.second->Signal(s->signal_id);
}
}
} else if (s->update_type == CZUpdateType_ClientName) {
Client* c = entity_list.GetClientByName(s->client_name);
if (c) {
c->Signal(s->signal_id);
}
} else if (s->update_type == CZUpdateType_NPC) {
NPC* n = entity_list.GetNPCByNPCTypeID(s->update_identifier);
if (n) {
n->SignalNPC(s->signal_id);
}
}
break;
}
case ServerOP_CZSpell:
{
auto s = (CZSpell_Struct*) pack->pBuffer;
if (s->update_type == CZUpdateType_Character) {
Client* c = entity_list.GetClientByCharID(s->update_identifier);
if (c) {
switch (s->update_subtype) {
case CZSpellUpdateSubtype_Cast:
c->ApplySpellBuff(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnBots)) {
for (const auto& b : entity_list.GetBotListByCharacterID(c->CharacterID())) {
b->ApplySpellBuff(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (b->HasPet()) {
b->GetPet()->ApplySpellBuff(s->spell_id);
}
}
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnMercs)) {
if (c->GetMerc()) {
c->GetMerc()->ApplySpellBuff(s->spell_id);
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (c->HasPet()) {
c->GetPet()->ApplySpellBuff(s->spell_id);
}
}
break;
case CZSpellUpdateSubtype_Remove:
c->BuffFadeBySpellID(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnBots)) {
for (const auto& b : entity_list.GetBotListByCharacterID(c->CharacterID())) {
b->BuffFadeBySpellID(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (b->HasPet()) {
b->GetPet()->BuffFadeBySpellID(s->spell_id);
}
}
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnMercs)) {
if (c->GetMerc()) {
c->GetMerc()->BuffFadeBySpellID(s->spell_id);
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (c->HasPet()) {
c->GetPet()->BuffFadeBySpellID(s->spell_id);
}
}
break;
}
}
} else if (s->update_type == CZUpdateType_Group) {
Group* g = entity_list.GetGroupByID(s->update_identifier);
if (g) {
for (const auto& m : g->members) {
if (
m &&
(
m->IsClient() ||
(m->IsBot() && RuleB(Zone, AllowCrossZoneSpellsOnBots)) ||
(m->IsMerc() && RuleB(Zone, AllowCrossZoneSpellsOnMercs))
)
) {
switch (s->update_subtype) {
case CZSpellUpdateSubtype_Cast:
m->ApplySpellBuff(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (m->HasPet()) {
m->GetPet()->ApplySpellBuff(s->spell_id);
}
}
break;
case CZSpellUpdateSubtype_Remove:
m->BuffFadeBySpellID(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (m->HasPet()) {
m->GetPet()->BuffFadeBySpellID(s->spell_id);
}
}
break;
}
}
}
}
} else if (s->update_type == CZUpdateType_Raid) {
Raid* r = entity_list.GetRaidByID(s->update_identifier);
if (r) {
for (const auto& m : r->members) {
if (
m.member &&
(
m.member->IsClient() ||
(m.member->IsBot() && RuleB(Zone, AllowCrossZoneSpellsOnBots)) ||
(m.member->IsMerc() && RuleB(Zone, AllowCrossZoneSpellsOnMercs))
)
){
switch (s->update_subtype) {
case CZSpellUpdateSubtype_Cast:
m.member->ApplySpellBuff(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (m.member->HasPet()) {
m.member->GetPet()->ApplySpellBuff(s->spell_id);
}
}
break;
case CZSpellUpdateSubtype_Remove:
m.member->BuffFadeBySpellID(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (m.member->HasPet()) {
m.member->GetPet()->BuffFadeBySpellID(s->spell_id);
}
}
break;
}
}
}
}
} else if (s->update_type == CZUpdateType_Guild) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->IsInGuild(s->update_identifier)) {
switch (s->update_subtype) {
case CZSpellUpdateSubtype_Cast:
c.second->ApplySpellBuff(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnBots)) {
for (const auto& b : entity_list.GetBotListByCharacterID(c.second->CharacterID())) {
b->ApplySpellBuff(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (b->HasPet()) {
b->GetPet()->ApplySpellBuff(s->spell_id);
}
}
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnMercs)) {
if (c.second->GetMerc()) {
c.second->GetMerc()->ApplySpellBuff(s->spell_id);
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (c.second->HasPet()) {
c.second->GetPet()->ApplySpellBuff(s->spell_id);
}
}
break;
case CZSpellUpdateSubtype_Remove:
c.second->BuffFadeBySpellID(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnBots)) {
for (const auto& b : entity_list.GetBotListByCharacterID(c.second->CharacterID())) {
b->BuffFadeBySpellID(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (b->HasPet()) {
b->GetPet()->BuffFadeBySpellID(s->spell_id);
}
}
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnMercs)) {
if (c.second->GetMerc()) {
c.second->GetMerc()->BuffFadeBySpellID(s->spell_id);
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (c.second->HasPet()) {
c.second->GetPet()->BuffFadeBySpellID(s->spell_id);
}
}
break;
}
}
}
} else if (s->update_type == CZUpdateType_Expedition) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->GetExpedition() && c.second->GetExpedition()->GetID() == s->update_identifier) {
switch (s->update_subtype) {
case CZSpellUpdateSubtype_Cast:
c.second->ApplySpellBuff(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnBots)) {
for (const auto& b : entity_list.GetBotListByCharacterID(c.second->CharacterID())) {
b->ApplySpellBuff(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (b->HasPet()) {
b->GetPet()->ApplySpellBuff(s->spell_id);
}
}
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnMercs)) {
if (c.second->GetMerc()) {
c.second->GetMerc()->ApplySpellBuff(s->spell_id);
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (c.second->HasPet()) {
c.second->GetPet()->ApplySpellBuff(s->spell_id);
}
}
break;
case CZSpellUpdateSubtype_Remove:
c.second->BuffFadeBySpellID(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnBots)) {
for (const auto& b : entity_list.GetBotListByCharacterID(c.second->CharacterID())) {
b->BuffFadeBySpellID(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (b->HasPet()) {
b->GetPet()->BuffFadeBySpellID(s->spell_id);
}
}
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnMercs)) {
if (c.second->GetMerc()) {
c.second->GetMerc()->BuffFadeBySpellID(s->spell_id);
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (c.second->HasPet()) {
c.second->GetPet()->BuffFadeBySpellID(s->spell_id);
}
}
break;
}
}
}
} else if (s->update_type == CZUpdateType_ClientName) {
Client* c = entity_list.GetClientByName(s->client_name);
if (c) {
switch (s->update_subtype) {
case CZSpellUpdateSubtype_Cast:
c->ApplySpellBuff(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnBots)) {
for (const auto& b : entity_list.GetBotListByCharacterID(c->CharacterID())) {
b->ApplySpellBuff(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (b->HasPet()) {
b->GetPet()->ApplySpellBuff(s->spell_id);
}
}
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnMercs)) {
if (c->GetMerc()) {
c->GetMerc()->ApplySpellBuff(s->spell_id);
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (c->HasPet()) {
c->GetPet()->ApplySpellBuff(s->spell_id);
}
}
break;
case CZSpellUpdateSubtype_Remove:
c->BuffFadeBySpellID(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnBots)) {
for (const auto& b : entity_list.GetBotListByCharacterID(c->CharacterID())) {
b->BuffFadeBySpellID(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (b->HasPet()) {
b->GetPet()->BuffFadeBySpellID(s->spell_id);
}
}
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnMercs)) {
if (c->GetMerc()) {
c->GetMerc()->BuffFadeBySpellID(s->spell_id);
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (c->HasPet()) {
c->GetPet()->BuffFadeBySpellID(s->spell_id);
}
}
break;
}
}
}
break;
}
case ServerOP_CZTaskUpdate:
{
auto u = (CZTaskUpdate_Struct*) pack->pBuffer;
if (u->update_type == CZUpdateType_Character) {
Client* c = entity_list.GetClientByCharID(u->update_identifier);
if (c) {
switch (u->update_subtype) {
case CZTaskUpdateSubtype_ActivityReset:
c->ResetTaskActivity(u->task_identifier, u->task_subidentifier);
break;
case CZTaskUpdateSubtype_ActivityUpdate:
c->UpdateTaskActivity(u->task_identifier, u->task_subidentifier, u->update_count);
break;
case CZTaskUpdateSubtype_AssignTask:
c->AssignTask(u->task_identifier, u->task_subidentifier, u->enforce_level_requirement);
break;
case CZTaskUpdateSubtype_DisableTask:
c->DisableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case CZTaskUpdateSubtype_EnableTask:
c->EnableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case CZTaskUpdateSubtype_FailTask:
c->FailTask(u->task_identifier);
break;
case CZTaskUpdateSubtype_RemoveTask:
c->RemoveTaskByTaskID(u->task_identifier);
break;
}
}
} else if (u->update_type == CZUpdateType_Group) {
auto client_group = entity_list.GetGroupByID(u->update_identifier);
if (client_group) {
for (int member_index = 0; member_index < MAX_GROUP_MEMBERS; member_index++) {
if (client_group->members[member_index] && client_group->members[member_index]->IsClient()) {
auto group_member = client_group->members[member_index]->CastToClient();
switch (u->update_subtype) {
case CZTaskUpdateSubtype_ActivityReset:
group_member->ResetTaskActivity(u->task_identifier, u->task_subidentifier);
break;
case CZTaskUpdateSubtype_ActivityUpdate:
group_member->UpdateTaskActivity(u->task_identifier, u->task_subidentifier, u->update_count);
break;
case CZTaskUpdateSubtype_AssignTask:
group_member->AssignTask(u->task_identifier, u->task_subidentifier, u->enforce_level_requirement);
break;
case CZTaskUpdateSubtype_DisableTask:
group_member->DisableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case CZTaskUpdateSubtype_EnableTask:
group_member->EnableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case CZTaskUpdateSubtype_FailTask:
group_member->FailTask(u->task_identifier);
break;
case CZTaskUpdateSubtype_RemoveTask:
group_member->RemoveTaskByTaskID(u->task_identifier);
break;
}
}
}
}
} else if (u->update_type == CZUpdateType_Raid) {
Raid* r = entity_list.GetRaidByID(u->update_identifier);
if (r) {
for (const auto& m : r->members) {
if (m.member && m.member->IsClient()) {
switch (u->update_subtype) {
case CZTaskUpdateSubtype_ActivityReset:
m.member->CastToClient()->ResetTaskActivity(u->task_identifier, u->task_subidentifier);
break;
case CZTaskUpdateSubtype_ActivityUpdate:
m.member->CastToClient()->UpdateTaskActivity(u->task_identifier, u->task_subidentifier, u->update_count);
break;
case CZTaskUpdateSubtype_AssignTask:
m.member->CastToClient()->AssignTask(u->task_identifier, u->task_subidentifier, u->enforce_level_requirement);
break;
case CZTaskUpdateSubtype_DisableTask:
m.member->CastToClient()->DisableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case CZTaskUpdateSubtype_EnableTask:
m.member->CastToClient()->EnableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case CZTaskUpdateSubtype_FailTask:
m.member->CastToClient()->FailTask(u->task_identifier);
break;
case CZTaskUpdateSubtype_RemoveTask:
m.member->CastToClient()->RemoveTaskByTaskID(u->task_identifier);
break;
}
}
}
}
} else if (u->update_type == CZUpdateType_Guild) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->IsInGuild(u->update_identifier)) {
switch (u->update_subtype) {
case CZTaskUpdateSubtype_ActivityReset:
c.second->ResetTaskActivity(u->task_identifier, u->task_subidentifier);
break;
case CZTaskUpdateSubtype_ActivityUpdate:
c.second->UpdateTaskActivity(u->task_identifier, u->task_subidentifier, u->update_count);
break;
case CZTaskUpdateSubtype_AssignTask:
c.second->AssignTask(u->task_identifier, u->task_subidentifier, u->enforce_level_requirement);
break;
case CZTaskUpdateSubtype_DisableTask:
c.second->DisableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case CZTaskUpdateSubtype_EnableTask:
c.second->EnableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case CZTaskUpdateSubtype_FailTask:
c.second->FailTask(u->task_identifier);
break;
case CZTaskUpdateSubtype_RemoveTask:
c.second->RemoveTaskByTaskID(u->task_identifier);
break;
}
}
}
} else if (u->update_type == CZUpdateType_Expedition) {
for (const auto& c : entity_list.GetClientList()) {
if (c.second->GetExpedition() && c.second->GetExpedition()->GetID() == u->update_identifier) {
switch (u->update_subtype) {
case CZTaskUpdateSubtype_ActivityReset:
c.second->ResetTaskActivity(u->task_identifier, u->task_subidentifier);
break;
case CZTaskUpdateSubtype_ActivityUpdate:
c.second->UpdateTaskActivity(u->task_identifier, u->task_subidentifier, u->update_count);
break;
case CZTaskUpdateSubtype_AssignTask:
c.second->AssignTask(u->task_identifier, u->task_subidentifier, u->enforce_level_requirement);
break;
case CZTaskUpdateSubtype_DisableTask:
c.second->DisableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case CZTaskUpdateSubtype_EnableTask:
c.second->EnableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case CZTaskUpdateSubtype_FailTask:
c.second->FailTask(u->task_identifier);
break;
case CZTaskUpdateSubtype_RemoveTask:
c.second->RemoveTaskByTaskID(u->task_identifier);
break;
}
}
}
} else if (u->update_type == CZUpdateType_ClientName) {
Client* c = entity_list.GetClientByName(u->client_name);
if (c) {
switch (u->update_subtype) {
case CZTaskUpdateSubtype_ActivityReset:
c->ResetTaskActivity(u->task_identifier, u->task_subidentifier);
break;
case CZTaskUpdateSubtype_ActivityUpdate:
c->UpdateTaskActivity(u->task_identifier, u->task_subidentifier, u->update_count);
break;
case CZTaskUpdateSubtype_AssignTask:
c->AssignTask(u->task_identifier, u->task_subidentifier, u->enforce_level_requirement);
break;
case CZTaskUpdateSubtype_DisableTask:
c->DisableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case CZTaskUpdateSubtype_EnableTask:
c->EnableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case CZTaskUpdateSubtype_FailTask:
c->FailTask(u->task_identifier);
break;
case CZTaskUpdateSubtype_RemoveTask:
c->RemoveTaskByTaskID(u->task_identifier);
break;
}
}
}
break;
}
case ServerOP_WWDialogueWindow:
{
auto s = (WWDialogueWindow_Struct*) pack->pBuffer;
for (const auto& c : entity_list.GetClientList()) {
if (
c.second->Admin() >= s->min_status &&
(c.second->Admin() <= s->max_status || s->max_status == AccountStatus::Player)
) {
DialogueWindow::Render(c.second, s->message);
}
}
break;
}
case ServerOP_WWLDoNUpdate:
{
auto u = (WWLDoNUpdate_Struct*) pack->pBuffer;
for (const auto& c : entity_list.GetClientList()) {
if (
c.second->Admin() >= u->min_status &&
(c.second->Admin() <= u->max_status || u->max_status == AccountStatus::Player)
) {
switch (u->update_type) {
case WWLDoNUpdateType_AddLoss:
c.second->UpdateLDoNWinLoss(u->theme_id, false);
break;
case WWLDoNUpdateType_AddPoints:
c.second->UpdateLDoNPoints(u->theme_id, u->points);
break;
case WWLDoNUpdateType_AddWin:
c.second->UpdateLDoNWinLoss(u->theme_id, true);
break;
case WWLDoNUpdateType_RemoveLoss:
c.second->UpdateLDoNWinLoss(u->theme_id, false, true);
break;
case WWLDoNUpdateType_RemoveWin:
c.second->UpdateLDoNWinLoss(u->theme_id, true, true);
break;
}
}
}
break;
}
case ServerOP_WWMarquee:
{
auto s = (WWMarquee_Struct*) pack->pBuffer;
for (const auto& c : entity_list.GetClientList()) {
if (
c.second->Admin() >= s->min_status &&
(c.second->Admin() <= s->max_status || s->max_status == AccountStatus::Player)
) {
c.second->SendMarqueeMessage(s->type, s->priority, s->fade_in, s->fade_out, s->duration, s->message);
}
}
break;
}
case ServerOP_WWMessage:
{
auto s = (WWMessage_Struct*) pack->pBuffer;
for (const auto& c : entity_list.GetClientList()) {
if (
c.second->Admin() >= s->min_status &&
(c.second->Admin() <= s->max_status || s->max_status == AccountStatus::Player)
) {
c.second->Message(s->type, s->message);
}
}
break;
}
case ServerOP_WWMove:
{
auto s = (WWMove_Struct*) pack->pBuffer;
for (const auto& c : entity_list.GetClientList()) {
if (
c.second->Admin() >= s->min_status &&
(c.second->Admin() <= s->max_status || s->max_status == AccountStatus::Player)
) {
switch (s->update_type) {
case WWMoveUpdateType_MoveZone:
c.second->MoveZone(s->zone_short_name);
break;
case WWMoveUpdateType_MoveZoneInstance:
c.second->MoveZoneInstance(s->instance_id);
break;
}
}
}
break;
}
case ServerOP_WWSetEntityVariable:
{
auto s = (WWSetEntityVariable_Struct*) pack->pBuffer;
if (s->update_type == WWSetEntityVariableUpdateType_Character) {
for (const auto& c : entity_list.GetClientList()) {
if (
c.second->Admin() >= s->min_status &&
(c.second->Admin() <= s->max_status || s->max_status == AccountStatus::Player)
) {
c.second->SetEntityVariable(s->variable_name, s->variable_value);
}
}
} else if (s->update_type == WWSetEntityVariableUpdateType_NPC) {
for (const auto& n : entity_list.GetNPCList()) {
n.second->SetEntityVariable(s->variable_name, s->variable_value);
}
}
break;
}
case ServerOP_WWSignal:
{
auto s = (WWSignal_Struct*) pack->pBuffer;
if (s->update_type == WWSignalUpdateType_Character) {
for (const auto& c : entity_list.GetClientList()) {
if (
c.second->Admin() >= s->min_status &&
(c.second->Admin() <= s->max_status || s->max_status == AccountStatus::Player)
) {
c.second->Signal(s->signal_id);
}
}
} else if (s->update_type == WWSignalUpdateType_NPC) {
for (const auto& n : entity_list.GetNPCList()) {
n.second->SignalNPC(s->signal_id);
}
}
break;
}
case ServerOP_WWSpell: {
auto s = (WWSpell_Struct *) pack->pBuffer;
for (const auto& c : entity_list.GetClientList()) {
if (
c.second->Admin() >= s->min_status &&
(c.second->Admin() <= s->max_status || s->max_status == AccountStatus::Player)
) {
if (s->update_type == WWSpellUpdateType_Cast) {
c.second->ApplySpellBuff(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnBots)) {
for (const auto& b : entity_list.GetBotListByCharacterID(c.second->CharacterID())) {
b->ApplySpellBuff(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (b->HasPet()) {
b->GetPet()->ApplySpellBuff(s->spell_id);
}
}
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnMercs)) {
if (c.second->GetMerc()) {
c.second->GetMerc()->ApplySpellBuff(s->spell_id);
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (c.second->HasPet()) {
c.second->GetPet()->ApplySpellBuff(s->spell_id);
}
}
} else if (s->update_type == WWSpellUpdateType_Remove) {
c.second->BuffFadeBySpellID(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnBots)) {
for (const auto& b : entity_list.GetBotListByCharacterID(c.second->CharacterID())) {
b->BuffFadeBySpellID(s->spell_id);
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (b->HasPet()) {
b->GetPet()->BuffFadeBySpellID(s->spell_id);
}
}
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnMercs)) {
if (c.second->GetMerc()) {
c.second->GetMerc()->BuffFadeBySpellID(s->spell_id);
}
}
if (RuleB(Zone, AllowCrossZoneSpellsOnPets)) {
if (c.second->HasPet()) {
c.second->GetPet()->BuffFadeBySpellID(s->spell_id);
}
}
}
}
}
break;
}
case ServerOP_WWTaskUpdate:
{
auto u = (WWTaskUpdate_Struct*) pack->pBuffer;
for (const auto& c : entity_list.GetClientList()) {
if (
c.second->Admin() >= u->min_status &&
(c.second->Admin() <= u->max_status || u->max_status == AccountStatus::Player)
) {
switch (u->update_type) {
case WWTaskUpdateType_ActivityReset:
c.second->ResetTaskActivity(u->task_identifier, u->task_subidentifier);
break;
case WWTaskUpdateType_ActivityUpdate:
c.second->UpdateTaskActivity(u->task_identifier, u->task_subidentifier, u->update_count);
break;
case WWTaskUpdateType_AssignTask:
c.second->AssignTask(u->task_identifier, u->task_subidentifier, u->enforce_level_requirement);
break;
case WWTaskUpdateType_DisableTask:
c.second->DisableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case WWTaskUpdateType_EnableTask:
c.second->EnableTask(1, reinterpret_cast<int*>(&u->task_identifier));
break;
case WWTaskUpdateType_FailTask:
c.second->FailTask(u->task_identifier);
break;
case WWTaskUpdateType_RemoveTask:
c.second->RemoveTaskByTaskID(u->task_identifier);
break;
}
}
}
break;
}
case ServerOP_UpdateSchedulerEvents: {
LogScheduler("Received signal from world to update");
if (GetScheduler()) {
m_zone_scheduler->LoadScheduledEvents();
}
break;
}
case ServerOP_HotReloadQuests:
{
if (!zone) {
break;
}
auto *hot_reload_quests = (HotReloadQuestsStruct *) pack->pBuffer;
LogHotReloadDetail(
"Receiving request [HotReloadQuests] | request_zone [{}] current_zone [{}]",
hot_reload_quests->zone_short_name,
zone->GetShortName()
);
std::string request_zone_short_name = hot_reload_quests->zone_short_name;
std::string local_zone_short_name = zone->GetShortName();
bool can_reload_global_script = (request_zone_short_name == "all" && RuleB(HotReload, QuestsAutoReloadGlobalScripts));
if (request_zone_short_name == local_zone_short_name || can_reload_global_script) {
zone->SetQuestHotReloadQueued(true);
} else if (request_zone_short_name == "all") {
std::string reload_quest_saylink = Saylink::Silent("#reload quest", "Locally");
std::string reload_world_saylink = Saylink::Silent("#reload world 1", "Globally");
for (const auto& [client_id, client] : entity_list.GetClientList()) {
if (client->Admin() < AccountStatus::ApprenticeGuide) {
continue;
}
client->Message(Chat::Yellow, fmt::format(
"A quest, plugin, or global script has changed. Reload: [{}] [{}]",
reload_quest_saylink,
reload_world_saylink
).c_str());
}
}
break;
}
case ServerOP_ChangeSharedMem:
{
std::string hotfix_name = std::string((char*)pack->pBuffer);
LogInfo("Loading items");
if (!content_db.LoadItems(hotfix_name)) {
LogError("Loading items failed!");
}
LogInfo("Loading spells");
if (!content_db.LoadSpells(hotfix_name, &SPDAT_RECORDS, &spells)) {
LogError("Loading spells failed!");
}
break;
}
case ServerOP_CZClientMessageString:
{
auto s = reinterpret_cast<CZClientMessageString_Struct*>(pack->pBuffer);
Client* c = entity_list.GetClientByName(s->client_name);
if (c) {
c->MessageString(s);
}
break;
}
case ServerOP_DzCreated:
case ServerOP_DzDeleted:
case ServerOP_DzAddPlayer:
case ServerOP_DzMakeLeader:
case ServerOP_DzAddRemoveMember:
case ServerOP_DzSwapMembers:
case ServerOP_DzRemoveAllMembers:
case ServerOP_DzDurationUpdate:
case ServerOP_DzGetMemberStatuses:
case ServerOP_DzGetBulkMemberStatuses:
case ServerOP_DzSetCompass:
case ServerOP_DzSetSafeReturn:
case ServerOP_DzSetZoneIn:
case ServerOP_DzSetSwitchID:
case ServerOP_DzUpdateMemberStatus:
case ServerOP_DzLeaderChanged:
case ServerOP_DzExpireWarning:
case ServerOP_DzMovePC:
case ServerOP_DzLock:
case ServerOP_DzReplayOnJoin:
case ServerOP_DzLockout:
case ServerOP_DzLockoutDuration:
case ServerOP_DzCharacterLockout:
{
DynamicZone::HandleWorldMessage(pack);
break;
}
case ServerOP_SharedTaskAcceptNewTask:
case ServerOP_SharedTaskUpdate:
case ServerOP_SharedTaskQuit:
case ServerOP_SharedTaskMemberlist:
case ServerOP_SharedTaskMemberChange:
case ServerOP_SharedTaskInvitePlayer:
case ServerOP_SharedTaskPurgeAllCommand:
case ServerOP_SharedTaskFailed:
{
SharedTaskZoneMessaging::HandleWorldMessage(pack);
break;
}
case ServerOP_GuildTributeUpdate: {
GuildTributeUpdate* in = (GuildTributeUpdate*)pack->pBuffer;
auto guild = guild_mgr.GetGuildByGuildID(in->guild_id);
if (guild) {
guild->tribute.favor = in->favor;
guild->tribute.id_1 = in->tribute_id_1;
guild->tribute.id_2 = in->tribute_id_2;
guild->tribute.id_1_tier = in->tribute_id_1_tier;
guild->tribute.id_2_tier = in->tribute_id_2_tier;
guild->tribute.time_remaining = in->time_remaining;
guild->tribute.enabled = in->enabled;
}
EQApplicationPacket* outapp = new EQApplicationPacket(OP_GuildSendActiveTributes, sizeof(GuildTributeSendActive_Struct));
GuildTributeSendActive_Struct* out = (GuildTributeSendActive_Struct*)outapp->pBuffer;
out->not_used = in->guild_id;
out->guild_favor = in->favor;
out->tribute_enabled = in->enabled;
out->tribute_timer = in->time_remaining;
out->tribute_id_1 = in->tribute_id_1;
out->tribute_id_2 = in->tribute_id_2;
out->tribute_id_1_tier = in->tribute_id_1_tier;
out->tribute_id_2_tier = in->tribute_id_2_tier;
entity_list.QueueClientsGuild(outapp, in->guild_id);
safe_delete(outapp);
break;
}
case ServerOP_GuildTributeActivate: {
GuildTributeUpdate* in = (GuildTributeUpdate*)pack->pBuffer;
auto guild = guild_mgr.GetGuildByGuildID(in->guild_id);
if (guild) {
guild->tribute.favor = in->favor;
guild->tribute.id_1 = in->tribute_id_1;
guild->tribute.id_2 = in->tribute_id_2;
guild->tribute.id_1_tier = in->tribute_id_1_tier;
guild->tribute.id_2_tier = in->tribute_id_2_tier;
guild->tribute.time_remaining = in->time_remaining;
guild->tribute.enabled = in->enabled;
}
EQApplicationPacket* outapp = new EQApplicationPacket(OP_GuildTributeToggleReply, sizeof(GuildTributeSendActive_Struct));
GuildTributeSendActive_Struct* out = (GuildTributeSendActive_Struct*)outapp->pBuffer;
out->not_used = in->guild_id;
out->guild_favor = in->favor;
out->tribute_enabled = in->enabled;
out->tribute_timer = in->time_remaining;
out->tribute_id_1 = in->tribute_id_1;
out->tribute_id_2 = in->tribute_id_2;
out->tribute_id_1_tier = in->tribute_id_1_tier;
out->tribute_id_2_tier = in->tribute_id_2_tier;
entity_list.QueueClientsGuild(outapp, in->guild_id);
safe_delete(outapp);
for (auto& c : entity_list.GetClientList()) {
if (c.second->IsInGuild(in->guild_id)) {
c.second->DoGuildTributeUpdate();
}
}
break;
}
case ServerOP_GuildTributeUpdateDonations: {
auto in = (GuildTributeUpdate *) pack->pBuffer;
auto outapp = new EQApplicationPacket(OP_GuildOptInOut, sizeof(GuildTributeOptInOutReply_Struct));
auto data = (GuildTributeOptInOutReply_Struct *) outapp->pBuffer;
data->guild_id = in->guild_id;
data->no_donations = in->member_favor;
data->tribute_toggle = in->member_enabled ? true : false;
data->tribute_trophy_toggle = 0; // not yet implemented
data->time = in->member_time;
data->command = 1;
strn0cpy(data->player_name, in->player_name, sizeof(data->player_name));
entity_list.QueueClientsGuild(outapp, in->guild_id);
safe_delete(outapp);
outapp = new EQApplicationPacket(OP_GuildTributeToggleReply, sizeof(GuildTributeSendActive_Struct));
auto out = (GuildTributeSendActive_Struct *) outapp->pBuffer;
auto guild = guild_mgr.GetGuildByGuildID(in->guild_id);
if (!guild) {
safe_delete(outapp)
return;
}
out->not_used = in->guild_id;
out->guild_favor = guild->tribute.favor;
out->tribute_enabled = guild->tribute.enabled;
out->tribute_timer = guild->tribute.time_remaining;
out->tribute_id_1 = guild->tribute.id_1;
out->tribute_id_2 = guild->tribute.id_2;
out->tribute_id_1_tier = guild->tribute.id_1_tier;
out->tribute_id_2_tier = guild->tribute.id_2_tier;
entity_list.QueueClientsGuild(outapp, in->guild_id);
safe_delete(outapp)
break;
}
case ServerOP_GuildTributeOptInToggle:
{
GuildTributeMemberToggle* in = (GuildTributeMemberToggle*)pack->pBuffer;
EQApplicationPacket* outapp = new EQApplicationPacket(OP_GuildOptInOut, sizeof(GuildTributeOptInOutReply_Struct));
GuildTributeOptInOutReply_Struct* data = (GuildTributeOptInOutReply_Struct*)outapp->pBuffer;
data->guild_id = in->guild_id;
strn0cpy(data->player_name, in->player_name, sizeof(data->player_name));
data->no_donations = in->no_donations;
data->tribute_toggle = in->tribute_toggle ? true : false;
data->tribute_trophy_toggle = 0; //not yet implemented
data->time = in->member_last_donated;
data->command = in->command;
entity_list.QueueClientsGuild(outapp, in->guild_id);
safe_delete(outapp);
auto guild = guild_mgr.GetGuildByGuildID(in->guild_id);
auto client = entity_list.GetClientByCharID(in->char_id);
if (guild && client) {
client->SetGuildTributeOptIn(in->tribute_toggle ? true : false);
EQApplicationPacket* outapp = new EQApplicationPacket(OP_GuildTributeToggleReply, sizeof(GuildTributeSendActive_Struct));
GuildTributeSendActive_Struct* out = (GuildTributeSendActive_Struct*)outapp->pBuffer;
out->not_used = in->guild_id;
out->guild_favor = guild->tribute.favor;
out->tribute_enabled = guild->tribute.enabled;
out->tribute_timer = guild->tribute.time_remaining;
out->tribute_id_1 = guild->tribute.id_1;
out->tribute_id_2 = guild->tribute.id_2;
out->tribute_id_1_tier = guild->tribute.id_1_tier;
out->tribute_id_2_tier = guild->tribute.id_2_tier;
client->QueuePacket(outapp);
safe_delete(outapp);
//send deactivate and then activate
client->DoGuildTributeUpdate();
}
break;
}
case ServerOP_GuildTributeFavAndTimer:
{
GuildTributeFavorTimer_Struct* in = (GuildTributeFavorTimer_Struct*)pack->pBuffer;
auto guild = guild_mgr.GetGuildByGuildID(in->guild_id);
if (guild) {
guild->tribute.favor = in->guild_favor;
guild->tribute.time_remaining = in->tribute_timer;
auto outapp = new EQApplicationPacket(OP_GuildTributeFavorAndTimer, sizeof(GuildTributeFavorTimer_Struct));
GuildTributeFavorTimer_Struct* gtsa = (GuildTributeFavorTimer_Struct*)outapp->pBuffer;
gtsa->guild_id = in->guild_id;
gtsa->guild_favor = guild->tribute.favor;
gtsa->tribute_timer = guild->tribute.time_remaining;
gtsa->trophy_timer = 0; //not yet implemented
entity_list.QueueClientsGuild(outapp, in->guild_id);
safe_delete(outapp);
}
break;
}
case ServerOP_RequestGuildActiveTributes:
{
GuildTributeUpdate* in = (GuildTributeUpdate*)pack->pBuffer;
auto guild = guild_mgr.GetGuildByGuildID(in->guild_id);
if (guild) {
auto outapp = new EQApplicationPacket(OP_GuildSendActiveTributes, sizeof(GuildTributeSendActive_Struct));
GuildTributeSendActive_Struct* gtsa = (GuildTributeSendActive_Struct*)outapp->pBuffer;
guild->tribute.enabled = in->enabled;
guild->tribute.favor = in->favor;
guild->tribute.id_1 = in->tribute_id_1;
guild->tribute.id_2 = in->tribute_id_2;
guild->tribute.id_1_tier = in->tribute_id_1_tier;
guild->tribute.id_2_tier = in->tribute_id_2_tier;
guild->tribute.time_remaining = in->time_remaining;
gtsa->guild_favor = guild->tribute.favor;
gtsa->tribute_timer = guild->tribute.time_remaining;
gtsa->tribute_enabled = guild->tribute.enabled;
gtsa->tribute_id_1 = guild->tribute.id_1;
gtsa->tribute_id_1_tier = guild->tribute.id_1_tier;
gtsa->tribute_id_2 = guild->tribute.id_2;
gtsa->tribute_id_2_tier = guild->tribute.id_2_tier;
entity_list.QueueClientsGuild(outapp, in->guild_id);
safe_delete(outapp);
}
break;
}
case ServerOP_RequestGuildFavorAndTimer:
{
GuildTributeFavorTimer_Struct* in = (GuildTributeFavorTimer_Struct*)pack->pBuffer;
auto guild = guild_mgr.GetGuildByGuildID(in->guild_id);
if (guild) {
guild->tribute.favor = in->guild_favor;
guild->tribute.time_remaining = in->tribute_timer;
auto outapp = new EQApplicationPacket(OP_GuildTributeFavorAndTimer, sizeof(GuildTributeFavorTimer_Struct));
GuildTributeFavorTimer_Struct* gtsa = (GuildTributeFavorTimer_Struct*)outapp->pBuffer;
gtsa->guild_id = in->guild_id;
gtsa->guild_favor = guild->tribute.favor;
gtsa->tribute_timer = guild->tribute.time_remaining;
gtsa->trophy_timer = 0; //not yet implemented
entity_list.QueueClientsGuild(outapp, in->guild_id);
safe_delete(outapp);
}
break;
}
case ServerOP_ParcelDelivery: {
auto in = (Parcel_Struct *) pack->pBuffer;
if (strlen(in->send_to) == 0) {
LogError(
"ServerOP_ParcelDelivery pack received with incorrect character_name of {}.",
in->send_to
);
return;
}
for (auto const &c: entity_list.GetClientList()) {
if (strcasecmp(c.second->GetCleanName(), in->send_to) == 0) {
c.second->MessageString(
Chat::Yellow,
PARCEL_DELIVERY_ARRIVED
);
c.second->SendParcelStatus();
if (c.second->GetEngagedWithParcelMerchant()) {
c.second->SendParcel(*in);
}
return;
}
}
break;
}
case ServerOP_ParcelPrune: {
for (auto const &c: entity_list.GetClientList()) {
if (c.second->GetEngagedWithParcelMerchant()) {
c.second->Message(
Chat::Red,
"Parcel data has been updated. Please re-open the Merchant Window."
);
c.second->SetEngagedWithParcelMerchant(false);
c.second->DoParcelCancel();
auto out = new EQApplicationPacket(OP_ShopEndConfirm);
c.second->QueuePacket(out);
safe_delete(out);
return;
}
}
break;
}
case ServerOP_TraderMessaging: {
auto in = (TraderMessaging_Struct *) pack->pBuffer;
for (auto const &c: entity_list.GetClientList()) {
if (c.second->ClientVersion() >= EQ::versions::ClientVersion::RoF2) {
auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(BecomeTrader_Struct));
auto out = (BecomeTrader_Struct *) outapp->pBuffer;
out->entity_id = in->entity_id;
out->zone_id = in->zone_id;
out->zone_instance_id = in->instance_id;
out->trader_id = in->trader_id;
strn0cpy(out->trader_name, in->trader_name, sizeof(out->trader_name));
switch (in->action) {
case TraderOn: {
out->action = AddTraderToBazaarWindow;
if (c.second->GetTraderCount() <
EQ::constants::StaticLookup(c.second->ClientVersion())->BazaarTraderLimit) {
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
if (out->zone_id == Zones::BAZAAR &&
out->zone_instance_id == c.second->GetInstanceID()) {
c.second->IncrementTraderCount();
c.second->QueuePacket(outapp, true, Mob::CLIENT_CONNECTED);
}
}
else {
c.second->IncrementTraderCount();
c.second->QueuePacket(outapp, true, Mob::CLIENT_CONNECTED);
}
}
break;
}
case TraderOff: {
out->action = RemoveTraderFromBazaarWindow;
if (c.second->GetTraderCount() <=
EQ::constants::StaticLookup(c.second->ClientVersion())->BazaarTraderLimit) {
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
if (out->zone_id == Zones::BAZAAR &&
out->zone_instance_id == c.second->GetInstanceID()) {
c.second->DecrementTraderCount();
c.second->QueuePacket(outapp, true, Mob::CLIENT_CONNECTED);
}
}
else {
c.second->DecrementTraderCount();
c.second->QueuePacket(outapp, true, Mob::CLIENT_CONNECTED);
}
}
break;
}
default: {
out->action = 0;
c.second->QueuePacket(outapp, true, Mob::CLIENT_CONNECTED);
}
}
safe_delete(outapp);
}
if (zone && zone->GetZoneID() == Zones::BAZAAR && in->instance_id == zone->GetInstanceID()) {
if (in->action == TraderOn) {
c.second->SendBecomeTrader(TraderOn, in->entity_id);
}
else {
c.second->SendBecomeTrader(TraderOff, in->entity_id);
}
}
}
break;
}
case ServerOP_BazaarPurchase: {
auto in = (BazaarPurchaseMessaging_Struct *) pack->pBuffer;
auto trader_pc = entity_list.GetClientByCharID(in->trader_buy_struct.trader_id);
if (!trader_pc) {
LogTrading("Request trader_id <red>[{}] could not be found in zone_id <red>[{}]",
in->trader_buy_struct.trader_id,
zone->GetZoneID()
);
return;
}
if (trader_pc->IsThereACustomer()) {
auto customer = entity_list.GetClientByID(trader_pc->GetCustomerID());
if (customer) {
customer->CancelTraderTradeWindow();
}
}
auto item_sn = Strings::ToUnsignedBigInt(in->trader_buy_struct.serial_number);
auto outapp = std::make_unique<EQApplicationPacket>(OP_Trader, static_cast<uint32>(sizeof(TraderBuy_Struct)));
auto data = (TraderBuy_Struct *) outapp->pBuffer;
memcpy(data, &in->trader_buy_struct, sizeof(TraderBuy_Struct));
if (trader_pc->ClientVersion() < EQ::versions::ClientVersion::RoF) {
data->price = in->trader_buy_struct.price * in->trader_buy_struct.quantity;
}
TraderRepository::UpdateActiveTransaction(database, in->id, false);
auto item = trader_pc->FindTraderItemBySerialNumber(item_sn);
if (item && PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::TRADER_SELL)) {
auto e = PlayerEvent::TraderSellEvent{
.item_id = item ? item->GetID() : 0,
.augment_1_id = item->GetAugmentItemID(0),
.augment_2_id = item->GetAugmentItemID(1),
.augment_3_id = item->GetAugmentItemID(2),
.augment_4_id = item->GetAugmentItemID(3),
.augment_5_id = item->GetAugmentItemID(4),
.augment_6_id = item->GetAugmentItemID(5),
.item_name = in->trader_buy_struct.item_name,
.buyer_id = in->buyer_id,
.buyer_name = in->trader_buy_struct.buyer_name,
.price = in->trader_buy_struct.price,
.quantity = in->trader_buy_struct.quantity,
.charges = item ? item->IsStackable() ? 1 : item->GetCharges() : 0,
.total_cost = (in->trader_buy_struct.price * in->trader_buy_struct.quantity),
.player_money_balance = trader_pc->GetCarriedMoney(),
};
RecordPlayerEventLogWithClient(trader_pc, PlayerEvent::TRADER_SELL, e);
}
trader_pc->RemoveItemBySerialNumber(item_sn, in->trader_buy_struct.quantity);
trader_pc->AddMoneyToPP(in->trader_buy_struct.price * in->trader_buy_struct.quantity, true);
trader_pc->QueuePacket(outapp.get());
break;
}
case ServerOP_BuyerMessaging: {
auto in = (BuyerMessaging_Struct *) pack->pBuffer;
switch (in->action) {
case Barter_AddToBarterWindow: {
auto outapp = std::make_unique<EQApplicationPacket>(
OP_Barter,
static_cast<uint32>(sizeof(BuyerAddBuyertoBarterWindow_Struct))
);
auto emu = (BuyerAddBuyertoBarterWindow_Struct *) outapp->pBuffer;
emu->action = Barter_AddToBarterWindow;
emu->buyer_entity_id = in->buyer_entity_id;
emu->buyer_id = in->buyer_id;
emu->zone_id = in->zone_id;
strn0cpy(emu->buyer_name, in->buyer_name, sizeof(emu->buyer_name));
entity_list.QueueClients(nullptr, outapp.get());
break;
}
case Barter_RemoveFromBarterWindow: {
auto outapp = std::make_unique<EQApplicationPacket>(
OP_Barter,
static_cast<uint32>(sizeof(BuyerRemoveBuyerFromBarterWindow_Struct))
);
auto emu = (BuyerRemoveBuyerFromBarterWindow_Struct *) outapp->pBuffer;
emu->action = Barter_RemoveFromBarterWindow;
emu->buyer_id = in->buyer_id;
entity_list.QueueClients(nullptr, outapp.get());
break;
}
case Barter_FailedTransaction: {
auto seller = entity_list.GetClientByID(in->seller_entity_id);
auto buyer = entity_list.GetClientByID(in->buyer_entity_id);
BuyerLineSellItem_Struct sell_line{};
sell_line.item_id = in->buy_item_id;
sell_line.item_quantity = in->buy_item_qty;
sell_line.item_cost = in->buy_item_cost;
sell_line.seller_name = in->seller_name;
sell_line.buyer_name = in->buyer_name;
sell_line.seller_quantity = in->seller_quantity;
sell_line.slot = in->slot;
sell_line.purchase_method = in->purchase_method;
strn0cpy(sell_line.item_name, in->item_name, sizeof(sell_line.item_name));
uint64 total_cost = (uint64) sell_line.item_cost * (uint64) sell_line.seller_quantity;
std::unique_ptr<EQ::ItemInstance> inst(database.CreateItem(in->buy_item_id, in->seller_quantity));
switch (in->sub_action) {
case Barter_FailedBuyerChecks:
case Barter_FailedSellerChecks: {
if (seller) {
LogTradingDetail("Significant barter transaction failure.");
seller->Message(
Chat::Red,
"Significant barter transaction error. Transaction rolled back."
);
seller->SendBarterBuyerClientMessage(
sell_line,
Barter_SellerTransactionComplete,
Barter_Failure,
Barter_Failure
);
if (PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::BARTER_TRANSACTION)) {
PlayerEvent::BarterTransaction e{};
e.status = "Failed Barter Transaction";
e.item_id = sell_line.item_id;
e.item_quantity = sell_line.seller_quantity;
e.item_name = sell_line.item_name;
e.trade_items = sell_line.trade_items;
for (auto &i: e.trade_items) {
i *= sell_line.seller_quantity;
}
e.total_cost = (uint64) sell_line.item_cost * (uint64) in->seller_quantity;
e.buyer_name = sell_line.buyer_name;
e.seller_name = sell_line.seller_name;
RecordPlayerEventLogWithClient(seller, PlayerEvent::BARTER_TRANSACTION, e);
}
}
if (buyer) {
LogError("Significant barter transaction failure. Replacing {} and {} {} to {}",
buyer->DetermineMoneyString(total_cost),
sell_line.seller_quantity,
sell_line.item_name,
buyer->GetCleanName());
buyer->AddMoneyToPP(total_cost, true);
buyer->RemoveItem(sell_line.item_id, sell_line.seller_quantity);
buyer->Message(
Chat::Red,
"Significant barter transaction error. Transaction rolled back."
);
buyer->SendBarterBuyerClientMessage(
sell_line,
Barter_BuyerTransactionComplete,
Barter_Failure,
Barter_Failure
);
if (PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::BARTER_TRANSACTION)) {
PlayerEvent::BarterTransaction e{};
e.status = "Failed Barter Transaction";
e.item_id = sell_line.item_id;
e.item_quantity = sell_line.seller_quantity;
e.item_name = sell_line.item_name;
e.trade_items = sell_line.trade_items;
for (auto &i: e.trade_items) {
i *= sell_line.seller_quantity;
}
e.total_cost = (uint64) sell_line.item_cost * (uint64) in->seller_quantity;
e.buyer_name = sell_line.buyer_name;
e.seller_name = sell_line.seller_name;
RecordPlayerEventLogWithClient(buyer, PlayerEvent::BARTER_TRANSACTION, e);
}
}
break;
}
default: {
if (seller) {
seller->SendBarterBuyerClientMessage(
sell_line,
Barter_SellerTransactionComplete,
Barter_Failure,
Barter_Failure
);
}
if (buyer) {
buyer->SendBarterBuyerClientMessage(
sell_line,
Barter_BuyerTransactionComplete,
Barter_Failure,
Barter_Failure
);
}
}
}
break;
}
case Barter_SellItem: {
auto buyer = entity_list.GetClientByID(in->buyer_entity_id);
if (!buyer) {
in->action = Barter_FailedTransaction;
in->sub_action = Barter_BuyerCouldNotBeFound;
worldserver.SendPacket(pack);
return;
}
if (buyer->IsThereACustomer()) {
auto customer = entity_list.GetClientByID(buyer->GetCustomerID());
if (customer) {
customer->CancelBuyerTradeWindow();
}
}
BuyerLineSellItem_Struct sell_line{};
sell_line.item_id = in->buy_item_id;
sell_line.item_quantity = in->buy_item_qty;
sell_line.item_cost = in->buy_item_cost;
sell_line.seller_name = in->seller_name;
sell_line.buyer_name = in->buyer_name;
sell_line.buyer_entity_id = in->buyer_entity_id;
sell_line.seller_quantity = in->seller_quantity;
sell_line.slot = in->slot;
strn0cpy(sell_line.item_name, in->item_name, sizeof(sell_line.item_name));
if (!buyer->DoBarterBuyerChecks(sell_line)) {
in->action = Barter_FailedTransaction;
in->sub_action = Barter_FailedBuyerChecks;
worldserver.SendPacket(pack);
break;
}
BuyerLineSellItem_Struct blis{};
blis.enabled = 1;
blis.item_toggle = 1;
blis.item_cost = in->buy_item_cost;
blis.item_id = in->buy_item_id;
blis.item_quantity = in->buy_item_qty;
blis.item_icon = in->buy_item_icon;
blis.slot = in->slot;
blis.seller_quantity = in->seller_quantity;
blis.buyer_entity_id = in->buyer_entity_id;
strn0cpy(blis.item_name, in->item_name, sizeof(blis.item_name));
uint64 total_cost = (uint64) sell_line.item_cost * (uint64) sell_line.seller_quantity;
std::unique_ptr<EQ::ItemInstance> inst(database.CreateItem(in->buy_item_id, in->seller_quantity));
if (inst->IsStackable()) {
if (!buyer->PutItemInInventoryWithStacking(inst.get())) {
buyer->Message(Chat::Red, "Error putting item in your inventory.");
buyer->AddMoneyToPP(total_cost, true);
in->action = Barter_FailedTransaction;
in->sub_action = Barter_FailedBuyerChecks;
worldserver.SendPacket(pack);
break;
}
}
else {
for (int i = 1; i <= sell_line.seller_quantity; i++) {
inst->SetCharges(1);
if (!buyer->PutItemInInventoryWithStacking(inst.get())) {
buyer->Message(Chat::Red, "Error putting item in your inventory.");
buyer->AddMoneyToPP(total_cost, true);
in->action = Barter_FailedTransaction;
in->sub_action = Barter_FailedBuyerChecks;
worldserver.SendPacket(pack);
goto exit_loop;
}
}
}
if (!buyer->TakeMoneyFromPP(total_cost, false)) {
in->action = Barter_FailedTransaction;
in->sub_action = Barter_FailedBuyerChecks;
worldserver.SendPacket(pack);
break;
}
buyer->SendWindowUpdatesToSellerAndBuyer(blis);
buyer->SendBarterBuyerClientMessage(
sell_line,
Barter_BuyerTransactionComplete,
Barter_Success,
Barter_Success
);
if (PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::BARTER_TRANSACTION)) {
PlayerEvent::BarterTransaction e{};
e.status = "Successful Barter Transaction";
e.item_id = sell_line.item_id;
e.item_quantity = sell_line.seller_quantity;
e.item_name = sell_line.item_name;
e.trade_items = sell_line.trade_items;
for (auto &i: e.trade_items) {
i *= sell_line.seller_quantity;
}
e.total_cost = (uint64) sell_line.item_cost * (uint64) in->seller_quantity;
e.buyer_name = sell_line.buyer_name;
e.seller_name = sell_line.seller_name;
RecordPlayerEventLogWithClient(buyer, PlayerEvent::BARTER_TRANSACTION, e);
}
in->action = Barter_BuyerTransactionComplete;
worldserver.SendPacket(pack);
exit_loop:
break;
}
case Barter_BuyerTransactionComplete: {
auto seller = entity_list.GetClientByID(in->seller_entity_id);
if (!seller) {
in->action = Barter_FailedTransaction;
in->sub_action = Barter_SellerCouldNotBeFound;
worldserver.SendPacket(pack);
return;
}
BuyerLineSellItem_Struct sell_line{};
sell_line.item_id = in->buy_item_id;
sell_line.item_quantity = in->buy_item_qty;
sell_line.item_cost = in->buy_item_cost;
sell_line.seller_name = in->seller_name;
sell_line.buyer_name = in->buyer_name;
sell_line.seller_quantity = in->seller_quantity;
sell_line.slot = in->slot;
strn0cpy(sell_line.item_name, in->item_name, sizeof(sell_line.item_name));
if (!seller->DoBarterSellerChecks(sell_line)) {
in->action = Barter_FailedTransaction;
in->action = Barter_FailedSellerChecks;
worldserver.SendPacket(pack);
return;
}
uint64 total_cost = (uint64) sell_line.item_cost * (uint64) sell_line.seller_quantity;
seller->RemoveItem(in->buy_item_id, in->seller_quantity);
seller->AddMoneyToPP(total_cost, false);
seller->SendBarterBuyerClientMessage(
sell_line,
Barter_SellerTransactionComplete,
Barter_Success,
Barter_Success
);
if (PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::BARTER_TRANSACTION)) {
PlayerEvent::BarterTransaction e{};
e.status = "Successful Barter Transaction";
e.item_id = sell_line.item_id;
e.item_quantity = sell_line.seller_quantity;
e.item_name = sell_line.item_name;
e.trade_items = sell_line.trade_items;
for (auto &i: e.trade_items) {
i *= sell_line.seller_quantity;
}
e.total_cost = (uint64) sell_line.item_cost * (uint64) in->seller_quantity;
e.buyer_name = sell_line.buyer_name;
e.seller_name = sell_line.seller_name;
RecordPlayerEventLogWithClient(seller, PlayerEvent::BARTER_TRANSACTION, e);
}
break;
}
}
}
default: {
LogInfo("Unknown ZS Opcode [{}] size [{}]", (int) pack->opcode, pack->size);
break;
}
}
}
bool WorldServer::SendChannelMessage(Client* from, const char* to, uint8 chan_num, uint32 guilddbid, uint8 language, uint8 lang_skill, const char* message, ...) {
if (!worldserver.Connected()) {
return false;
}
va_list argptr;
auto length = strlen(message) + 1;
char* buffer = new char[length];
va_start(argptr, message);
vsnprintf(buffer, length, message, argptr);
va_end(argptr);
buffer[length - 1] = '\0';
auto pack = new ServerPacket(ServerOP_ChannelMessage, sizeof(ServerChannelMessage_Struct) + length);
ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*)pack->pBuffer;
if (from == 0) {
strcpy(scm->from, "ZServer");
scm->fromadmin = AccountStatus::Player;
}
else {
strcpy(scm->from, from->GetName());
scm->fromadmin = from->Admin();
}
if (to == 0) {
scm->to[0] = 0;
scm->deliverto[0] = '\0';
}
else {
strn0cpy(scm->to, to, sizeof(scm->to));
strn0cpy(scm->deliverto, to, sizeof(scm->deliverto));
}
scm->noreply = false;
scm->chan_num = chan_num;
scm->guilddbid = guilddbid;
scm->language = language;
scm->lang_skill = lang_skill;
scm->queued = 0;
strcpy(scm->message, buffer);
bool ret = SendPacket(pack);
safe_delete(pack);
safe_delete_array(buffer);
return ret;
}
bool WorldServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, uint32 type, const char* message, ...) {
va_list argptr;
char buffer[4096] = { 0 };
va_start(argptr, message);
vsnprintf(buffer, sizeof(buffer) - 1, message, argptr);
va_end(argptr);
return SendEmoteMessage(
to,
to_guilddbid,
AccountStatus::Player,
type,
buffer
);
}
bool WorldServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...) {
va_list argptr;
char buffer[4096] = { 0 };
va_start(argptr, message);
vsnprintf(buffer, sizeof(buffer) - 1, message, argptr);
va_end(argptr);
if (!Connected() && to == 0) {
entity_list.MessageStatus(
to_guilddbid,
to_minstatus,
type,
buffer
);
return false;
}
auto pack = new ServerPacket(ServerOP_EmoteMessage, sizeof(ServerEmoteMessage_Struct) + strlen(buffer) + 1);
ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*)pack->pBuffer;
sem->type = type;
if (to != 0)
strcpy(sem->to, to);
sem->guilddbid = to_guilddbid;
sem->minstatus = to_minstatus;
strcpy(sem->message, buffer);
bool ret = SendPacket(pack);
safe_delete(pack);
return ret;
}
bool WorldServer::SendVoiceMacro(Client* From, uint32 Type, char* Target, uint32 MacroNumber, uint32 GroupOrRaidID) {
if (!worldserver.Connected() || !From)
return false;
auto pack = new ServerPacket(ServerOP_VoiceMacro, sizeof(ServerVoiceMacro_Struct));
ServerVoiceMacro_Struct* svm = (ServerVoiceMacro_Struct*)pack->pBuffer;
strcpy(svm->From, From->GetName());
switch (Type) {
case VoiceMacroTell:
strcpy(svm->To, Target);
break;
case VoiceMacroGroup:
svm->GroupID = GroupOrRaidID;
break;
case VoiceMacroRaid:
svm->RaidID = GroupOrRaidID;
break;
}
svm->Type = Type;
uint16 player_race = GetPlayerRaceValue(From->GetRace());
if (player_race == Race::Doug) {
player_race = From->GetBaseRace();
}
svm->Voice = (player_race * 2) + From->GetGender();
svm->MacroNumber = MacroNumber;
bool Ret = SendPacket(pack);
safe_delete(pack);
return Ret;
}
bool WorldServer::RezzPlayer(EQApplicationPacket* rpack, uint32 rezzexp, uint32 dbid, uint16 opcode)
{
LogSpells("rezzexp is [{}] (0 is normal for RezzComplete", rezzexp);
auto pack = new ServerPacket(ServerOP_RezzPlayer, sizeof(RezzPlayer_Struct));
RezzPlayer_Struct* sem = (RezzPlayer_Struct*)pack->pBuffer;
sem->rezzopcode = opcode;
sem->rez = *(Resurrect_Struct*)rpack->pBuffer;
sem->exp = rezzexp;
sem->dbid = dbid;
bool ret = SendPacket(pack);
if (ret)
LogSpells("Sending player rezz packet to world spellid:[{}]", sem->rez.spellid);
else
LogSpells("NOT Sending player rezz packet to world");
safe_delete(pack);
return ret;
}
void WorldServer::SendReloadTasks(uint8 reload_type, uint32 task_id) {
SendReload(ServerReload::Type::Tasks);
}
uint32 WorldServer::NextGroupID() {
//this system wastes a lot of potential group IDs (~5%), but
//if you are creating 2 billion groups in 1 run of the emu,
//something else is wrong...
if (cur_groupid >= last_groupid) {
//this is an error... This means that 50 groups were created before
//1 packet could make the zone->world->zone trip... so let it error.
LogError("Ran out of group IDs before the server sent us more");
return(0);
}
if (cur_groupid > (last_groupid - /*50*/995)) {
//running low, request more
auto pack = new ServerPacket(ServerOP_GroupIDReq);
SendPacket(pack);
safe_delete(pack);
}
printf("Handing out new group id %d\n", cur_groupid);
return(cur_groupid++);
}
void WorldServer::UpdateLFP(uint32 LeaderID, uint8 Action, uint8 MatchFilter, uint32 FromLevel, uint32 ToLevel, uint32 Classes,
const char *Comments, GroupLFPMemberEntry *LFPMembers) {
auto pack = new ServerPacket(ServerOP_LFPUpdate, sizeof(ServerLFPUpdate_Struct));
ServerLFPUpdate_Struct* sus = (ServerLFPUpdate_Struct*)pack->pBuffer;
sus->LeaderID = LeaderID;
sus->Action = Action;
sus->MatchFilter = MatchFilter;
sus->FromLevel = FromLevel;
sus->ToLevel = ToLevel;
sus->Classes = Classes;
strcpy(sus->Comments, Comments);
memcpy(sus->Members, LFPMembers, sizeof(sus->Members));
SendPacket(pack);
safe_delete(pack);
}
void WorldServer::UpdateLFP(uint32 LeaderID, GroupLFPMemberEntry *LFPMembers) {
UpdateLFP(LeaderID, LFPMemberUpdate, 0, 0, 0, 0, "", LFPMembers);
}
void WorldServer::StopLFP(uint32 LeaderID) {
GroupLFPMemberEntry LFPMembers[MAX_GROUP_MEMBERS];
UpdateLFP(LeaderID, LFPOff, 0, 0, 0, 0, "", LFPMembers);
}
void WorldServer::HandleLFGMatches(ServerPacket *pack) {
char *Buffer = (char *)pack->pBuffer;
int PacketLength = 4;
int Entries = (pack->size - 4) / sizeof(ServerLFGMatchesResponse_Struct);
uint32 EntityID = VARSTRUCT_DECODE_TYPE(uint32, Buffer);
Client* client = entity_list.GetClientByID(EntityID);
if (client) {
ServerLFGMatchesResponse_Struct* smrs = (ServerLFGMatchesResponse_Struct*)Buffer;
for (int i = 0; i<Entries; i++) {
PacketLength = PacketLength + 12 + strlen(smrs->Name) + strlen(smrs->Comments);
smrs++;
}
auto outapp = new EQApplicationPacket(OP_LFGGetMatchesResponse, PacketLength);
smrs = (ServerLFGMatchesResponse_Struct*)Buffer;
char *OutBuffer = (char *)outapp->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0x00074af); // Unknown
for (int i = 0; i<Entries; i++) {
VARSTRUCT_ENCODE_STRING(OutBuffer, smrs->Comments);
VARSTRUCT_ENCODE_STRING(OutBuffer, smrs->Name);
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, smrs->Class_);
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, smrs->Level);
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, smrs->Zone);
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, smrs->GuildID);
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, smrs->Anon);
smrs++;
}
client->QueuePacket(outapp);
safe_delete(outapp);
}
}
void WorldServer::HandleLFPMatches(ServerPacket *pack) {
char *Buffer = (char *)pack->pBuffer;
int PacketLength = 4;
int Entries = (pack->size - 4) / sizeof(ServerLFPMatchesResponse_Struct);
uint32 EntityID = VARSTRUCT_DECODE_TYPE(uint32, Buffer);
ServerLFPMatchesResponse_Struct* smrs = (ServerLFPMatchesResponse_Struct*)Buffer;
Client* client = entity_list.GetClientByID(EntityID);
if (client) {
for (int i = 0; i<Entries; i++) {
PacketLength += strlen(smrs->Comments) + 11;
for (unsigned int j = 0; j<MAX_GROUP_MEMBERS; j++) {
if (smrs->Members[j].Name[0] != '\0')
PacketLength += strlen(smrs->Members[j].Name) + 9;
}
smrs++;
}
auto outapp = new EQApplicationPacket(OP_LFPGetMatchesResponse, PacketLength);
smrs = (ServerLFPMatchesResponse_Struct*)Buffer;
char *OutBuffer = (char *)outapp->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0x00074af); // Unknown
for (int i = 0; i<Entries; i++) {
int MemberCount = 0;
for (unsigned int j = 0; j<MAX_GROUP_MEMBERS; j++)
if (smrs->Members[j].Name[0] != '\0')
MemberCount++;
VARSTRUCT_ENCODE_STRING(OutBuffer, smrs->Comments);
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, smrs->FromLevel);
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, smrs->ToLevel);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, smrs->Classes);
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, MemberCount);
for (unsigned int j = 0; j<MAX_GROUP_MEMBERS; j++) {
if (smrs->Members[j].Name[0] != '\0') {
VARSTRUCT_ENCODE_STRING(OutBuffer, smrs->Members[j].Name);
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, smrs->Members[j].Class);
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, smrs->Members[j].Level);
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, smrs->Members[j].Zone);
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, smrs->Members[j].GuildID);
}
}
smrs++;
}
client->QueuePacket(outapp);
safe_delete(outapp);
}
}
void WorldServer::RequestTellQueue(const char *who)
{
if (!who)
return;
auto pack = new ServerPacket(ServerOP_RequestTellQueue, sizeof(ServerRequestTellQueue_Struct));
ServerRequestTellQueue_Struct* rtq = (ServerRequestTellQueue_Struct*)pack->pBuffer;
strn0cpy(rtq->name, who, sizeof(rtq->name));
SendPacket(pack);
safe_delete(pack);
return;
}
ZoneEventScheduler *WorldServer::GetScheduler() const
{
return m_zone_scheduler;
}
void WorldServer::SetScheduler(ZoneEventScheduler *scheduler)
{
WorldServer::m_zone_scheduler = scheduler;
}
void WorldServer::SendReload(ServerReload::Type type, bool is_global)
{
static auto pack = ServerPacket(ServerOP_ServerReloadRequest, sizeof(ServerReload::Request));
auto reload = (ServerReload::Request*) pack.pBuffer;
reload->type = type;
reload->zone_server_id = 0;
if (!is_global && zone && zone->IsLoaded()) {
reload->zone_server_id = zone->GetZoneServerId();
}
SendPacket(&pack);
}
void WorldServer::QueueReload(ServerReload::Request r)
{
m_reload_mutex.lock();
int64_t reload_at = r.reload_at_unix - std::time(nullptr);
LogInfo(
"Queuing reload for [{}] ({}) to reload in [{}]",
ServerReload::GetName(r.type),
r.type,
reload_at > 0 ? Strings::SecondsToTime(reload_at) : "Now"
);
m_reload_queue[r.type] = r;
m_reload_mutex.unlock();
}
void WorldServer::ProcessReload(const ServerReload::Request& request)
{
LogInfo(
"Reloading [{}] ({}) zone booted required [{}]",
ServerReload::GetName(request.type),
request.type,
request.requires_zone_booted
);
if (request.requires_zone_booted) {
if (!zone || (zone && !zone->IsLoaded())) {
LogInfo("Zone not booted, skipping reload for [{}] ({})", ServerReload::GetName(request.type), request.type);
return;
}
}
zone->SendReloadMessage(ServerReload::GetName(request.type));
switch (request.type) {
case ServerReload::Type::AAData:
zone->LoadAlternateAdvancement();
entity_list.SendAlternateAdvancementStats();
break;
case ServerReload::Type::Opcodes:
ReloadAllPatches();
break;
case ServerReload::Type::AlternateCurrencies:
zone->LoadAlternateCurrencies();
break;
case ServerReload::Type::BaseData:
zone->ReloadBaseData();
break;
case ServerReload::Type::BlockedSpells:
zone->LoadZoneBlockedSpells();
break;
case ServerReload::Type::Commands:
command_init();
if (RuleB(Bots, Enabled) && database.DoesTableExist("bot_command_settings")) {
bot_command_init();
}
break;
case ServerReload::Type::ContentFlags:
WorldContentService::Instance()->SetExpansionContext()->ReloadContentFlags();
break;
case ServerReload::Type::DzTemplates:
zone->LoadDynamicZoneTemplates();
break;
case ServerReload::Type::Factions:
content_db.LoadFactionData();
zone->ReloadNPCFactions();
zone->ReloadFactionAssociations();
break;
case ServerReload::Type::LevelEXPMods:
zone->LoadLevelEXPMods();
break;
case ServerReload::Type::Logs:
EQEmuLogSys::Instance()->LoadLogDatabaseSettings();
PlayerEventLogs::Instance()->ReloadSettings();
break;
case ServerReload::Type::Loot:
zone->ReloadLootTables();
break;
case ServerReload::Type::Maps:
zone->ReloadMaps();
break;
case ServerReload::Type::Merchants:
entity_list.ReloadMerchants();
break;
case ServerReload::Type::NPCEmotes:
zone->LoadNPCEmotes(&zone->npc_emote_list);
break;
case ServerReload::Type::NPCSpells:
content_db.ClearNPCSpells();
for (auto &e: entity_list.GetNPCList()) {
e.second->ReloadSpells();
}
break;
case ServerReload::Type::PerlExportSettings:
parse->LoadPerlEventExportSettings(parse->perl_event_export_settings);
break;
case ServerReload::Type::Rules:
RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset(), true);
break;
case ServerReload::Type::SkillCaps:
SkillCaps::Instance()->ReloadSkillCaps();
break;
case ServerReload::Type::DataBucketsCache:
DataBucket::ClearCache();
break;
case ServerReload::Type::StaticZoneData:
case ServerReload::Type::Doors:
case ServerReload::Type::GroundSpawns:
case ServerReload::Type::Objects:
zone->ReloadStaticData();
break;
case ServerReload::Type::Tasks:
if (RuleB(Tasks, EnableTaskSystem)) {
entity_list.SaveAllClientsTaskState();
TaskManager::Instance()->LoadTasks();
entity_list.ReloadAllClientsTaskState();
TaskManager::Instance()->LoadTaskSets();
}
break;
case ServerReload::Type::Quests:
entity_list.ClearAreas();
parse->ReloadQuests(false);
break;
case ServerReload::Type::QuestsTimerReset:
entity_list.ClearAreas();
parse->ReloadQuests(true);
break;
case ServerReload::Type::Titles:
title_manager.LoadTitles();
break;
case ServerReload::Type::Traps:
entity_list.UpdateAllTraps(true, true);
break;
case ServerReload::Type::Variables:
database.LoadVariables();
break;
case ServerReload::Type::VeteranRewards:
zone->LoadVeteranRewards();
break;
case ServerReload::Type::WorldRepop:
parse->ReloadQuests();
if (zone && zone->IsLoaded()) {
entity_list.ClearAreas();
zone->Repop();
}
break;
case ServerReload::Type::WorldWithRespawn:
parse->ReloadQuests();
if (zone && zone->IsLoaded()) {
entity_list.ClearAreas();
zone->Repop();
zone->ClearSpawnTimers();
}
break;
case ServerReload::Type::ZonePoints:
content_db.LoadStaticZonePoints(&zone->zone_point_list, zone->GetShortName(), zone->GetInstanceVersion());
break;
case ServerReload::Type::ZoneData:
ZoneStore::Instance()->LoadZones(content_db);
zone->LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion());
break;
default:
break;
}
LogInfo("Reloaded [{}] ({})", ServerReload::GetName(request.type), request.type);
}