Implement initial expedition system

Add Expeditions logging category

Add handlers for all Dynamic Zone/Expedition related opcodes

Add FormatName string_util function to format character names

Add Zone::IsZone helper method

Add cross zone MessageString support with variable parameters

Add static Client method helpers for cross zone messaging

Add #dz gm command to debug expedition cache for current zone
This commit is contained in:
hg
2020-04-14 17:18:54 -04:00
parent a77f8b582e
commit da067be2fa
31 changed files with 4011 additions and 12 deletions
+2
View File
@@ -9,6 +9,7 @@ SET(world_sources
console.cpp
eql_config.cpp
eqemu_api_world_data_service.cpp
expedition.cpp
launcher_link.cpp
launcher_list.cpp
lfplist.cpp
@@ -39,6 +40,7 @@ SET(world_headers
console.h
eql_config.h
eqemu_api_world_data_service.h
expedition.h
launcher_link.h
launcher_list.h
lfplist.h
+136
View File
@@ -0,0 +1,136 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* 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; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "expedition.h"
#include "clientlist.h"
#include "cliententry.h"
#include "zonelist.h"
#include "zoneserver.h"
#include "worlddb.h"
#include "../common/servertalk.h"
#include "../common/string_util.h"
extern ClientList client_list;
extern ZSList zoneserver_list;
void Expedition::PurgeEmptyExpeditions()
{
std::string query = SQL(
DELETE expedition FROM expedition_details expedition
LEFT JOIN (
SELECT expedition_id, COUNT(IF(is_current_member = TRUE, 1, NULL)) member_count
FROM expedition_members
GROUP BY expedition_id
) AS expedition_members
ON expedition_members.expedition_id = expedition.id
WHERE expedition_members.expedition_id IS NULL OR expedition_members.member_count <= 0
);
auto results = database.QueryDatabase(query);
if (!results.Success())
{
LogExpeditions("Failed to purge empty expeditions");
}
}
void Expedition::PurgeExpiredCharacterLockouts()
{
std::string query = SQL(
DELETE FROM expedition_character_lockouts
WHERE expire_time <= NOW();
);
auto results = database.QueryDatabase(query);
if (!results.Success())
{
LogExpeditions("Failed to purge expired lockouts");
}
}
void Expedition::AddPlayer(ServerPacket* pack)
{
auto buf = reinterpret_cast<ServerDzCommand_Struct*>(pack->pBuffer);
ClientListEntry* invited_cle = client_list.FindCharacter(buf->target_name);
if (invited_cle && invited_cle->Server())
{
// continue in the add target's zone
buf->is_char_online = true;
invited_cle->Server()->SendPacket(pack);
}
else
{
// add target not online, return to inviter
ClientListEntry* inviter_cle = client_list.FindCharacter(buf->requester_name);
if (inviter_cle && inviter_cle->Server())
{
inviter_cle->Server()->SendPacket(pack);
}
}
}
void Expedition::MakeLeader(ServerPacket* pack)
{
auto buf = reinterpret_cast<ServerDzCommand_Struct*>(pack->pBuffer);
// notify requester (old leader) and new leader of the result
ZoneServer* new_leader_zs = nullptr;
ClientListEntry* new_leader_cle = client_list.FindCharacter(buf->target_name);
if (new_leader_cle && new_leader_cle->Server())
{
buf->is_char_online = true;
new_leader_zs = new_leader_cle->Server();
new_leader_zs->SendPacket(pack);
}
// if old and new leader are in the same zone only send one message
ClientListEntry* requester_cle = client_list.FindCharacter(buf->requester_name);
if (requester_cle && requester_cle->Server() && requester_cle->Server() != new_leader_zs)
{
requester_cle->Server()->SendPacket(pack);
}
}
void Expedition::GetOnlineMembers(ServerPacket* pack)
{
auto buf = reinterpret_cast<ServerExpeditionCharacters_Struct*>(pack->pBuffer);
// not efficient but only requested during caching
char zone_name[64] = {0};
std::vector<ClientListEntry*> all_clients;
all_clients.reserve(client_list.GetClientCount());
client_list.GetClients(zone_name, all_clients);
for (uint32_t i = 0; i < buf->count; ++i)
{
for (const auto& cle : all_clients)
{
if (cle && cle->CharID() == buf->entries[i].character_id)
{
buf->entries[i].character_zone_id = cle->zone();
buf->entries[i].character_instance_id = cle->instance();
buf->entries[i].character_online = true;
break;
}
}
}
zoneserver_list.SendPacket(buf->sender_zone_id, buf->sender_instance_id, pack);
}
+35
View File
@@ -0,0 +1,35 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* 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; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef WORLD_EXPEDITION_H
#define WORLD_EXPEDITION_H
class ServerPacket;
namespace Expedition
{
void PurgeEmptyExpeditions();
void PurgeExpiredCharacterLockouts();
void AddPlayer(ServerPacket* pack);
void MakeLeader(ServerPacket* pack);
void GetOnlineMembers(ServerPacket* pack);
};
#endif
+7
View File
@@ -88,6 +88,7 @@ union semun {
#include "queryserv.h"
#include "web_interface.h"
#include "console.h"
#include "expedition.h"
#include "../common/net/servertalk_server.h"
#include "../zone/data_bucket.h"
@@ -429,6 +430,10 @@ int main(int argc, char** argv) {
Timer PurgeInstanceTimer(450000);
PurgeInstanceTimer.Start(450000);
LogInfo("Purging expired expeditions");
Expedition::PurgeEmptyExpeditions(); //database.PurgeExpiredExpeditions();
Expedition::PurgeExpiredCharacterLockouts();
LogInfo("Loading char create info");
content_db.LoadCharacterCreateAllocations();
content_db.LoadCharacterCreateCombos();
@@ -599,6 +604,8 @@ int main(int argc, char** argv) {
if (PurgeInstanceTimer.Check()) {
database.PurgeExpiredInstances();
database.PurgeAllDeletedDataBuckets();
Expedition::PurgeEmptyExpeditions();
Expedition::PurgeExpiredCharacterLockouts();
}
if (EQTimeTimer.Check()) {
+39
View File
@@ -36,6 +36,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "ucs.h"
#include "queryserv.h"
#include "world_store.h"
#include "expedition.h"
extern ClientList client_list;
extern GroupLFPList LFPGroupList;
@@ -1355,6 +1356,44 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
cle->ProcessTellQueue();
break;
}
case ServerOP_CZClientMessage:
{
auto buf = reinterpret_cast<ServerCZClientMessage_Struct*>(pack->pBuffer);
client_list.SendPacket(buf->character_name, pack);
break;
}
case ServerOP_CZClientMessageString:
{
auto buf = reinterpret_cast<ServerCZClientMessageString_Struct*>(pack->pBuffer);
client_list.SendPacket(buf->character_name, pack);
break;
}
case ServerOP_ExpeditionCreate:
case ServerOP_ExpeditionDeleted:
case ServerOP_ExpeditionLeaderChanged:
case ServerOP_ExpeditionLockout:
case ServerOP_ExpeditionMemberChange:
case ServerOP_ExpeditionMemberSwap:
case ServerOP_ExpeditionMemberStatus:
{
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_ExpeditionGetOnlineMembers:
{
Expedition::GetOnlineMembers(pack);
break;
}
case ServerOP_ExpeditionDzAddPlayer:
{
Expedition::AddPlayer(pack);
break;
}
case ServerOP_ExpeditionDzMakeLeader:
{
Expedition::MakeLeader(pack);
break;
}
default:
{
LogInfo("Unknown ServerOPcode from zone {:#04x}, size [{}]", pack->opcode, pack->size);