mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
* [Feature] Add additional Guild Features This adds the following guild features and design pattern - the existing guild system was used - guild features are based on RoF2 within source with translaters used to converted between client differences - backward compatible with Ti and UF, and allows for mixed client servers - Guild Back for Ti and UF is based on RoF2 Permissions for banking if Guild Leader does not use Ti/UF - Guild Ranks and Permissions are enabled. - Guild Tributes are enabled. - Event logging via rules for donating tribute items and plat - Rules to limit Guild Tributes based on max level of server - Rewrote guild communications to client using specific opcodes -- Server no longer sends a guild member list on each zone -- Guild window is updated when a member levels, rank changes, zone changes, banker/alt status using individual opcodes -- When a member is removed or added to a guild, a single opcode is sent to each guild member -- This reduces network traffic considerably Known issues: - Visual bug only. Guild Tributes window will display a 0 for level if tribute is above max level rule setting. - Visual bug only. Guild Mgmt Window will not display an online member if the player has 'show offline' unchecked and a guild member zones within the Notes/Tribute tab. This is resolved by selecting and de-selecting the 'Show Offline' checkbox. * Updated RoF2 Guild Comms Updated RoF2 Guild Comms Update RoF2 Opcodes Rewrote RoF2 Guild Communications using specific opcodes. Added database changes - they are irreversible * Formatting * Update base_guild_members_repository.h * Format GuildInfo * Format GuildAction enum * Formatting in clientlist * quantity vs quantity * desc vs description * Format structs * Inline struct values * Formatting * Formatting * Formatting fixes * Formatting items * Formatting * Formatting * struct formatting updates * Updated formatting * Updated - std:string items - naming conventions - magic numbers * Repo refactors Other formatting updates * Remove test guild commands * Updated #guild info command * Add new repo methods for Neckolla ReplaceOne and ReplaceMany * Fix guild_tributes repo * Update database_update_manifest.cpp * Phase 1 of final testing with RoF2 -> RoF2. Next phase will be inter compatibility review * Remove #guild testing commands * Fix uf translator error Rewrite LoadGuilds * Use extended repository * FIx guild window on member add * LoadGuild Changes * Update guild_base.cpp * Few small fixes for display issue with UF * Update guild_base.cpp * Update guild_members_repository.h * Update zoneserver.cpp * Update guild.cpp * Update entity.h * Switch formatting * Formatting * Update worldserver.cpp * Switch formatting * Formatting switch statement * Update guild.cpp * Formatting in guild_base * We don't need to validate m_db everywhere * More formatting / spacing issues * Switch format * Update guild_base.cpp * Fix an UF issue displaying incorrect guildtag as <> * Updated several constants, fixed a few issues with Ti/UF and guild tributes not being removed or sent when a member is removed/disbands from a guild. * Formatting and logging updates * Fix for Loadguilds and permissions after repo updates. * Cleanup unnecessary m_db checks * Updated logging to use player_event_logs * Updated to use the single opcodes for guild traffic for Ti/UF/RoF2. Several enhancements for guild functionality for more reusable code and readability. * Update to fix Demote Self and guild invites declining when option set to not accept guild invites * Potential fix for guild notes/tribute display issues when client has 'Show Offline' unchecked. * Updates to fox recent master changes Updates to fix recent master changes * Updates in response to comments * Further Updates in response to comments * Comment updates and refactor for SendAppearance functions * Comment updates * Update client spawn process for show guild name Add show guild tag to default spawn process * Update to use zone spawn packets for RoF2 Removed several unused functions as a result Updated MemberRankUpdate to properly update guild_show on rank change. Updated OP_GuildURLAndChannel opcode for UF/RoF2 * Cleanup of world changes Created function for repetitive zonelist sendpackets to only booted zones Re-Inserted accidental delete of scanclosemobs * Fixes * Further world cleanup * Fix a few test guild bank cases for backward compat Removed a duplicate db call Fixed a fallthrough issue * Update guild_mgr.cpp * Cleanup --------- Co-authored-by: Akkadius <akkadius1@gmail.com>
342 lines
12 KiB
C++
342 lines
12 KiB
C++
/**
|
|
* EQEmulator: Everquest Server Emulator
|
|
* Copyright (C) 2001-2019 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 <fmt/format.h>
|
|
#include "clientlist.h"
|
|
#include "cliententry.h"
|
|
#include "eqemu_api_world_data_service.h"
|
|
#include "zoneserver.h"
|
|
#include "zonelist.h"
|
|
#include "../common/database_schema.h"
|
|
#include "../common/zone_store.h"
|
|
#include "worlddb.h"
|
|
#include "wguild_mgr.h"
|
|
#include "world_config.h"
|
|
|
|
extern ZSList zoneserver_list;
|
|
extern ClientList client_list;
|
|
extern WorldGuildManager guild_mgr;
|
|
|
|
void callGetZoneList(Json::Value &response)
|
|
{
|
|
for (auto &zone: zoneserver_list.getZoneServerList()) {
|
|
Json::Value row;
|
|
|
|
if (!zone->IsConnected()) {
|
|
continue;
|
|
}
|
|
|
|
row["booting_up"] = zone->IsBootingUp();
|
|
row["client_address"] = zone->GetCAddress();
|
|
row["client_local_address"] = zone->GetCLocalAddress();
|
|
row["client_port"] = zone->GetCPort();
|
|
row["compile_time"] = zone->GetCompileTime();
|
|
row["id"] = zone->GetID();
|
|
row["instance_id"] = zone->GetInstanceID();
|
|
row["ip"] = zone->GetIP();
|
|
row["is_static_zone"] = zone->IsStaticZone();
|
|
row["launch_name"] = zone->GetLaunchName();
|
|
row["launched_name"] = zone->GetLaunchedName();
|
|
row["number_players"] = zone->NumPlayers();
|
|
row["port"] = zone->GetPort();
|
|
row["previous_zone_id"] = zone->GetPrevZoneID();
|
|
row["uuid"] = zone->GetUUID();
|
|
row["zone_id"] = zone->GetZoneID();
|
|
row["zone_long_name"] = zone->GetZoneLongName();
|
|
row["zone_name"] = zone->GetZoneName();
|
|
row["zone_os_pid"] = zone->GetZoneOSProcessID();
|
|
|
|
response.append(row);
|
|
}
|
|
}
|
|
|
|
void callGetDatabaseSchema(Json::Value &response)
|
|
{
|
|
Json::Value player_tables_json;
|
|
std::vector<std::string> player_tables = DatabaseSchema::GetPlayerTables();
|
|
for (const auto &table: player_tables) {
|
|
player_tables_json.append(table);
|
|
}
|
|
|
|
Json::Value content_tables_json;
|
|
std::vector<std::string> content_tables = DatabaseSchema::GetContentTables();
|
|
for (const auto &table: content_tables) {
|
|
content_tables_json.append(table);
|
|
}
|
|
|
|
Json::Value server_tables_json;
|
|
std::vector<std::string> server_tables = DatabaseSchema::GetServerTables();
|
|
for (const auto &table: server_tables) {
|
|
server_tables_json.append(table);
|
|
}
|
|
|
|
Json::Value login_tables_json;
|
|
std::vector<std::string> login_tables = DatabaseSchema::GetLoginTables();
|
|
for (const auto &table: login_tables) {
|
|
login_tables_json.append(table);
|
|
}
|
|
|
|
Json::Value state_tables_json;
|
|
std::vector<std::string> state_tables = DatabaseSchema::GetStateTables();
|
|
for (const auto &table: state_tables) {
|
|
state_tables_json.append(table);
|
|
}
|
|
|
|
Json::Value version_tables_json;
|
|
std::vector<std::string> version_tables = DatabaseSchema::GetVersionTables();
|
|
for (const auto &table: version_tables) {
|
|
version_tables_json.append(table);
|
|
}
|
|
|
|
Json::Value character_table_columns_json;
|
|
std::map<std::string, std::string> character_table = DatabaseSchema::GetCharacterTables();
|
|
for (const auto &ctc: character_table) {
|
|
character_table_columns_json[ctc.first] = ctc.second;
|
|
}
|
|
|
|
Json::Value schema;
|
|
|
|
schema["character_table_columns"] = character_table_columns_json;
|
|
schema["content_tables"] = content_tables_json;
|
|
schema["login_tables"] = login_tables_json;
|
|
schema["player_tables"] = player_tables_json;
|
|
schema["server_tables"] = server_tables_json;
|
|
schema["state_tables"] = state_tables_json;
|
|
schema["version_tables"] = version_tables_json;
|
|
|
|
response.append(schema);
|
|
}
|
|
|
|
void callGetClientList(Json::Value &response)
|
|
{
|
|
client_list.GetClientList(response);
|
|
}
|
|
|
|
|
|
struct Reload {
|
|
std::string command{};
|
|
uint16 opcode;
|
|
std::string desc{};
|
|
};
|
|
|
|
std::vector<Reload> reload_types = {
|
|
Reload{.command = "aa", .opcode = ServerOP_ReloadAAData, .desc = "Alternate Advancement"},
|
|
Reload{.command = "alternate_currencies", .opcode = ServerOP_ReloadAlternateCurrencies, .desc = "Alternate Currencies"},
|
|
Reload{.command = "base_data", .opcode = ServerOP_ReloadBaseData, .desc = "Base Data"},
|
|
Reload{.command = "blocked_spells", .opcode = ServerOP_ReloadBlockedSpells, .desc = "Blocked Spells"},
|
|
Reload{.command = "commands", .opcode = ServerOP_ReloadCommands, .desc = "Commands"},
|
|
Reload{.command = "data_buckets_cache", .opcode = ServerOP_ReloadDataBucketsCache, .desc = "Data Buckets Cache"},
|
|
Reload{.command = "doors", .opcode = ServerOP_ReloadDoors, .desc = "Doors"},
|
|
Reload{.command = "dztemplates", .opcode = ServerOP_ReloadDzTemplates, .desc = "Dynamic Zone Templates"},
|
|
Reload{.command = "ground_spawns", .opcode = ServerOP_ReloadGroundSpawns, .desc = "Ground Spawns"},
|
|
Reload{.command = "level_mods", .opcode = ServerOP_ReloadLevelEXPMods, .desc = "Level Mods"},
|
|
Reload{.command = "logs", .opcode = ServerOP_ReloadLogs, .desc = "Log Settings"},
|
|
Reload{.command = "loot", .opcode = ServerOP_ReloadLoot, .desc = "Loot"},
|
|
Reload{.command = "merchants", .opcode = ServerOP_ReloadMerchants, .desc = "Merchants"},
|
|
Reload{.command = "npc_emotes", .opcode = ServerOP_ReloadNPCEmotes, .desc = "NPC Emotes"},
|
|
Reload{.command = "objects", .opcode = ServerOP_ReloadObjects, .desc = "Objects"},
|
|
Reload{.command = "opcodes", .opcode = ServerOP_ReloadOpcodes, .desc = "Opcodes"},
|
|
Reload{.command = "perl_export", .opcode = ServerOP_ReloadPerlExportSettings, .desc = "Perl Event Export Settings"},
|
|
Reload{.command = "rules", .opcode = ServerOP_ReloadRules, .desc = "Rules"},
|
|
Reload{.command = "static", .opcode = ServerOP_ReloadStaticZoneData, .desc = "Static Zone Data"},
|
|
Reload{.command = "tasks", .opcode = ServerOP_ReloadTasks, .desc = "Tasks"},
|
|
Reload{.command = "titles", .opcode = ServerOP_ReloadTitles, .desc = "Titles"},
|
|
Reload{.command = "traps", .opcode = ServerOP_ReloadTraps, .desc = "Traps"},
|
|
Reload{.command = "variables", .opcode = ServerOP_ReloadVariables, .desc = "Variables"},
|
|
Reload{.command = "veteran_rewards", .opcode = ServerOP_ReloadVeteranRewards, .desc = "Veteran Rewards"},
|
|
Reload{.command = "world", .opcode = ServerOP_ReloadWorld, .desc = "World"},
|
|
Reload{.command = "zone_points", .opcode = ServerOP_ReloadZonePoints, .desc = "Zone Points"},
|
|
};
|
|
|
|
void getReloadTypes(Json::Value &response)
|
|
{
|
|
for (auto &c: reload_types) {
|
|
Json::Value v;
|
|
|
|
v["command"] = c.command;
|
|
v["opcode"] = c.opcode;
|
|
v["description"] = c.desc;
|
|
response.append(v);
|
|
}
|
|
}
|
|
|
|
|
|
void EQEmuApiWorldDataService::reload(Json::Value &r, const std::vector<std::string> &args)
|
|
{
|
|
std::vector<std::string> commands{};
|
|
commands.reserve(reload_types.size());
|
|
for (auto &c: reload_types) {
|
|
commands.emplace_back(c.command);
|
|
}
|
|
|
|
std::string command = !args[1].empty() ? args[1] : "";
|
|
if (command.empty()) {
|
|
message(r, fmt::format("Need to provide a type to reload. Example(s) [{}]", Strings::Implode("|", commands)));
|
|
return;
|
|
}
|
|
|
|
ServerPacket *pack = nullptr;
|
|
|
|
bool found_command = false;
|
|
for (auto &c: reload_types) {
|
|
if (command == c.command) {
|
|
if (c.command == "world") {
|
|
uint8 global_repop = ReloadWorld::NoRepop;
|
|
|
|
if (Strings::IsNumber(args[2])) {
|
|
global_repop = static_cast<uint8>(Strings::ToUnsignedInt(args[2]));
|
|
|
|
if (global_repop > ReloadWorld::ForceRepop) {
|
|
global_repop = ReloadWorld::ForceRepop;
|
|
}
|
|
}
|
|
|
|
message(
|
|
r,
|
|
fmt::format(
|
|
"Attempting to reload Quests {}worldwide.",
|
|
(
|
|
global_repop ?
|
|
(
|
|
global_repop == ReloadWorld::Repop ?
|
|
"and repop NPCs " :
|
|
"and forcefully repop NPCs "
|
|
) :
|
|
""
|
|
)
|
|
)
|
|
);
|
|
|
|
pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct));
|
|
auto RW = (ReloadWorld_Struct *) pack->pBuffer;
|
|
RW->global_repop = global_repop;
|
|
}
|
|
else {
|
|
pack = new ServerPacket(c.opcode, 0);
|
|
message(r, fmt::format("Reloading [{}] globally", c.desc));
|
|
|
|
if (c.opcode == ServerOP_ReloadLogs) {
|
|
LogSys.LoadLogDatabaseSettings();
|
|
}
|
|
else if (c.opcode == ServerOP_ReloadRules) {
|
|
RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset(), true);
|
|
}
|
|
}
|
|
|
|
found_command = true;
|
|
}
|
|
}
|
|
|
|
if (!found_command) {
|
|
message(r, fmt::format("Need to provide a type to reload. Example(s) [{}]", Strings::Implode("|", commands)));
|
|
return;
|
|
}
|
|
|
|
if (pack) {
|
|
zoneserver_list.SendPacket(pack);
|
|
}
|
|
|
|
safe_delete(pack);
|
|
}
|
|
|
|
void EQEmuApiWorldDataService::message(Json::Value &r, const std::string &message)
|
|
{
|
|
r["message"] = message;
|
|
}
|
|
|
|
void EQEmuApiWorldDataService::get(Json::Value &r, const std::vector<std::string> &args)
|
|
{
|
|
const std::string &m = args[0];
|
|
if (m == "get_zone_list") {
|
|
callGetZoneList(r);
|
|
}
|
|
if (m == "get_database_schema") {
|
|
callGetDatabaseSchema(r);
|
|
}
|
|
if (m == "get_client_list") {
|
|
callGetClientList(r);
|
|
}
|
|
if (m == "get_reload_types") {
|
|
getReloadTypes(r);
|
|
}
|
|
if (m == "reload") {
|
|
reload(r, args);
|
|
}
|
|
if (m == "get_guild_details") {
|
|
callGetGuildDetails(r, args);
|
|
}
|
|
if (m == "lock_status") {
|
|
r["locked"] = WorldConfig::get()->Locked;
|
|
}
|
|
}
|
|
|
|
void EQEmuApiWorldDataService::callGetGuildDetails(Json::Value &response, const std::vector<std::string> &args)
|
|
{
|
|
|
|
std::string command = !args[1].empty() ? args[1] : "";
|
|
if (command.empty()) {
|
|
return;
|
|
}
|
|
Json::Value row;
|
|
|
|
auto guild_id = Strings::ToUnsignedInt(command);
|
|
if (!guild_id) {
|
|
row = "useage is: api get_guild_details ### where ### is a valid guild id.";
|
|
return;
|
|
}
|
|
auto guild = guild_mgr.GetGuildByGuildID(guild_id);
|
|
if (!guild) {
|
|
row = fmt::format("Could not find guild id {}", guild_id);
|
|
return;
|
|
}
|
|
|
|
row["guild_id"] = command;
|
|
row["guild_name"] = guild->name;
|
|
row["leader_id"] = guild->leader;
|
|
row["min_status"] = guild->minstatus;
|
|
row["motd"] = guild->motd;
|
|
row["motd_setter"] = guild->motd_setter;
|
|
row["url"] = guild->url;
|
|
row["channel"] = guild->channel;
|
|
|
|
for (int i = GUILD_LEADER; i <= GUILD_RECRUIT; i++) {
|
|
row["Ranks"][i] = guild->rank_names[i].c_str();
|
|
}
|
|
|
|
for (int i = 1; i <= GUILD_MAX_FUNCTIONS; i++) {
|
|
row["functions"][i]["db_id"] = guild->functions[i].id;
|
|
row["functions"][i]["perm_id"] = guild->functions[i].perm_id;
|
|
row["functions"][i]["guild_id"] = guild->functions[i].guild_id;
|
|
row["functions"][i]["perm_value"] = guild->functions[i].perm_value;
|
|
}
|
|
|
|
row["tribute"]["favor"] = guild->tribute.favor;
|
|
row["tribute"]["id1"] = guild->tribute.id_1;
|
|
row["tribute"]["id1_tier"] = guild->tribute.id_1_tier;
|
|
row["tribute"]["id2"] = guild->tribute.id_2;
|
|
row["tribute"]["id2_tier"] = guild->tribute.id_2_tier;
|
|
row["tribute"]["time_remaining"] = guild->tribute.time_remaining;
|
|
row["tribute"]["enabled"] = guild->tribute.enabled;
|
|
|
|
client_list.GetGuildClientList(response, guild_id);
|
|
|
|
response.append(row);
|
|
}
|