mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-24 05:18:40 +00:00
[Feature] Add RoF2 Guild features (#3699)
* [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>
This commit is contained in:
+167
-39
@@ -6,7 +6,7 @@ extern WorldServer worldserver;
|
||||
#include "../guild_mgr.h"
|
||||
#include "../doors.h"
|
||||
|
||||
void command_guild(Client *c, const Seperator *sep)
|
||||
void command_guild(Client* c, const Seperator* sep)
|
||||
{
|
||||
const auto arguments = sep->argnum;
|
||||
if (!arguments) {
|
||||
@@ -30,6 +30,8 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
bool is_set_leader = !strcasecmp(sep->arg[1], "setleader");
|
||||
bool is_set_rank = !strcasecmp(sep->arg[1], "setrank");
|
||||
bool is_status = !strcasecmp(sep->arg[1], "status");
|
||||
bool is_details = !strcasecmp(sep->arg[1], "details");
|
||||
bool is_test = !strcasecmp(sep->arg[1], "test");
|
||||
if (
|
||||
!is_create &&
|
||||
!is_delete &&
|
||||
@@ -41,8 +43,10 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
!is_set &&
|
||||
!is_set_leader &&
|
||||
!is_set_rank &&
|
||||
!is_status
|
||||
) {
|
||||
!is_status &&
|
||||
!is_details &&
|
||||
!is_test
|
||||
) {
|
||||
SendGuildSubCommands(c);
|
||||
return;
|
||||
}
|
||||
@@ -50,12 +54,13 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
if (is_create) {
|
||||
if (arguments < 3) {
|
||||
c->Message(Chat::White, "Usage: #guild create [Character ID|Character Name] [Guild Name]");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
auto leader_id = (
|
||||
sep->IsNumber(2) ?
|
||||
Strings::ToUnsignedInt(sep->arg[2]) :
|
||||
database.GetCharacterID(sep->arg[2])
|
||||
);
|
||||
);
|
||||
auto leader_name = database.GetCharNameByID(leader_id);
|
||||
if (!leader_id || leader_name.empty()) {
|
||||
c->Message(
|
||||
@@ -80,7 +85,8 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
guild_id
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
auto guild_name = sep->argplus[3];
|
||||
auto guild_id = guild_mgr.CreateGuild(sep->argplus[3], leader_id);
|
||||
|
||||
@@ -94,7 +100,8 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
|
||||
if (guild_id == GUILD_NONE) {
|
||||
c->Message(Chat::White, "Guild creation failed.");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
@@ -123,10 +130,12 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (is_delete) {
|
||||
}
|
||||
else if (is_delete) {
|
||||
if (!sep->IsNumber(2)) {
|
||||
c->Message(Chat::White, "Usage: #guild delete [Guild ID]");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
auto guild_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
if (!guild_mgr.GuildExists(guild_id)) {
|
||||
c->Message(
|
||||
@@ -156,12 +165,15 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
} else if (is_help) {
|
||||
}
|
||||
else if (is_help) {
|
||||
SendGuildSubCommands(c);
|
||||
} else if (is_info) {
|
||||
}
|
||||
else if (is_info) {
|
||||
if (arguments != 2 && c->IsInAGuild()) {
|
||||
c->Message(Chat::White, "#guild info [Guild ID]");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
auto guild_id = GUILD_NONE;
|
||||
if (sep->IsNumber(2)) {
|
||||
guild_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
@@ -171,12 +183,15 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
guild_mgr.DescribeGuild(c, guild_id);
|
||||
}
|
||||
}
|
||||
} else if (is_list) {
|
||||
}
|
||||
else if (is_list) {
|
||||
guild_mgr.ListGuilds(c, std::string());
|
||||
} else if (is_rename) {
|
||||
}
|
||||
else if (is_rename) {
|
||||
if (!sep->IsNumber(2)) {
|
||||
c->Message(Chat::White, "Usage: #guild rename [Guild ID] [New Guild Name]");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
auto guild_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
if (!guild_mgr.GuildExists(guild_id)) {
|
||||
c->Message(
|
||||
@@ -208,28 +223,33 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
} else if (is_search) {
|
||||
}
|
||||
else if (is_search) {
|
||||
if (Strings::IsNumber(sep->arg[2])) {
|
||||
const auto guild_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
|
||||
guild_mgr.ListGuilds(c, guild_id);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
const std::string search_criteria = sep->argplus[2];
|
||||
|
||||
guild_mgr.ListGuilds(c, search_criteria);
|
||||
}
|
||||
} else if (is_set) {
|
||||
}
|
||||
else if (is_set) {
|
||||
if (
|
||||
arguments != 3 ||
|
||||
!sep->IsNumber(3)
|
||||
) {
|
||||
) {
|
||||
c->Message(Chat::White, "#guild set [Character ID|Character Name] [Guild ID] (Guild ID 0 is Guildless)");
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
auto guild_id = Strings::ToUnsignedInt(sep->arg[3]);
|
||||
if (!guild_id) {
|
||||
guild_id = GUILD_NONE;
|
||||
} else if (!guild_mgr.GuildExists(guild_id)) {
|
||||
}
|
||||
else if (!guild_mgr.GuildExists(guild_id)) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
@@ -244,7 +264,7 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
sep->IsNumber(2) ?
|
||||
Strings::ToUnsignedInt(sep->arg[2]) :
|
||||
database.GetCharacterID(sep->arg[2])
|
||||
);
|
||||
);
|
||||
auto character_name = database.GetCharNameByID(character_id);
|
||||
if (!character_id || character_name.empty()) {
|
||||
c->Message(
|
||||
@@ -264,7 +284,8 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
character_name,
|
||||
character_id
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
LogGuilds(
|
||||
"[{}]: Putting [{}] ([{}]) into guild [{}] ([{}]) with GM command",
|
||||
c->GetName(),
|
||||
@@ -287,7 +308,8 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
guild_id
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
guild_mgr.SetGuild(character_id, GUILD_NONE, 0);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
@@ -299,18 +321,20 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (is_set_leader) {
|
||||
}
|
||||
else if (is_set_leader) {
|
||||
if (
|
||||
arguments != 3 ||
|
||||
!sep->IsNumber(2)
|
||||
) {
|
||||
) {
|
||||
c->Message(Chat::White, "Usage: #guild setleader [Guild ID] [Character ID|Character Name]");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
auto leader_id = (
|
||||
sep->IsNumber(2) ?
|
||||
Strings::ToUnsignedInt(sep->arg[2]) :
|
||||
database.GetCharacterID(sep->arg[2])
|
||||
);
|
||||
);
|
||||
auto leader_name = database.GetCharNameByID(leader_id);
|
||||
if (!leader_id || leader_name.empty()) {
|
||||
c->Message(
|
||||
@@ -368,11 +392,13 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (is_set_rank) {
|
||||
}
|
||||
else if (is_set_rank) {
|
||||
auto rank = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[3]));
|
||||
if (!sep->IsNumber(3)) {
|
||||
c->Message(Chat::White, "#guild setrank [Character ID|Character Name] [Rank]");
|
||||
} else if (rank < 0 || rank > GUILD_MAX_RANK) {
|
||||
}
|
||||
else if (rank < 0 || rank > GUILD_MAX_RANK) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
@@ -380,12 +406,13 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
GUILD_MAX_RANK
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
auto character_id = (
|
||||
sep->IsNumber(2) ?
|
||||
Strings::ToUnsignedInt(sep->arg[2]) :
|
||||
database.GetCharacterID(sep->arg[2])
|
||||
);
|
||||
);
|
||||
auto character_name = database.GetCharNameByID(character_id);
|
||||
if (!character_id || character_name.empty()) {
|
||||
c->Message(
|
||||
@@ -430,7 +457,8 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
} else if (is_status) {
|
||||
}
|
||||
else if (is_status) {
|
||||
auto client = (
|
||||
t ?
|
||||
t :
|
||||
@@ -438,11 +466,12 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
arguments == 2 ?
|
||||
entity_list.GetClientByName(sep->arg[2]) :
|
||||
c
|
||||
)
|
||||
);
|
||||
)
|
||||
);
|
||||
if (!client) {
|
||||
c->Message(Chat::White, "You must target someone or specify a character name.");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (!client->IsInAGuild()) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
@@ -452,7 +481,8 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
c == t ? "are" : "is"
|
||||
).c_str()
|
||||
);
|
||||
} else if (guild_mgr.IsGuildLeader(client->GuildID(), client->CharacterID())) {
|
||||
}
|
||||
else if (guild_mgr.IsGuildLeader(client->GuildID(), client->CharacterID())) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
@@ -462,7 +492,8 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
guild_mgr.GetGuildNameByID(client->GuildID())
|
||||
).c_str()
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
@@ -476,12 +507,109 @@ void command_guild(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_details) {
|
||||
if (!sep->IsNumber(2)) {
|
||||
c->Message(Chat::White, "Usage: #guild details [Guild ID]");
|
||||
}
|
||||
else {
|
||||
auto guild_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
if (!guild_mgr.GuildExists(guild_id)) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Guild ID {} could not be found.",
|
||||
guild_id
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto guild = guild_mgr.GetGuildByGuildID(guild_id);
|
||||
if (!guild) {
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"Guild {} not found. #guild list can be used to get guild ids.",
|
||||
guild_id
|
||||
).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (guild) {
|
||||
c->Message(Chat::Yellow, fmt::format("Guild ID: {}.", sep->arg[2]).c_str());
|
||||
c->Message(Chat::Yellow, fmt::format("Guild Name: {}.", guild->name.c_str()).c_str());
|
||||
c->Message(Chat::Yellow, fmt::format("Guild Leader ID: {}.", guild->leader).c_str());
|
||||
c->Message(Chat::Yellow, fmt::format("Guild MinStatus: {}.", guild->minstatus).c_str());
|
||||
c->Message(Chat::Yellow, fmt::format("Guild MOTD: {}.", guild->motd.c_str()).c_str());
|
||||
c->Message(Chat::Yellow, fmt::format("Guild MOTD Setter:{}.", guild->motd_setter.c_str()).c_str());
|
||||
c->Message(Chat::Yellow, fmt::format("Guild Channel: {}.", guild->channel.c_str()).c_str());
|
||||
c->Message(Chat::Yellow, fmt::format("Guild URL: {}.", guild->url.c_str()).c_str());
|
||||
|
||||
for (int i = 1; i <= GUILD_MAX_RANK; i++) {
|
||||
c->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format("Guild Rank: {} - {}.", i, guild->rank_names[i].c_str()).c_str());
|
||||
}
|
||||
|
||||
c->Message(Chat::Yellow, "Guild Functions: {db_id} - {guild_id} - {perm_id} - {perm_value}.");
|
||||
for (int i = 1; i <= GUILD_MAX_FUNCTIONS; i++) {
|
||||
c->Message(
|
||||
Chat::Yellow, fmt::format(
|
||||
"Guild Function: {} - {} - {} - {}.",
|
||||
guild->functions[i].id,
|
||||
guild->functions[i].guild_id,
|
||||
guild->functions[i].perm_id,
|
||||
guild->functions[i].perm_value
|
||||
).c_str());
|
||||
}
|
||||
c->Message(Chat::Yellow, fmt::format("Guild Tribute: Favor {}", guild->tribute.favor).c_str());
|
||||
c->Message(
|
||||
Chat::Yellow, fmt::format(
|
||||
"Guild Tribute: Tribute 1 {}/{} - Tribute 2 {}/{}",
|
||||
guild->tribute.id_1,
|
||||
guild->tribute.id_1_tier,
|
||||
guild->tribute.id_2,
|
||||
guild->tribute.id_2_tier
|
||||
).c_str());
|
||||
c->Message(
|
||||
Chat::Yellow, fmt::format(
|
||||
"Guild Tribute: Time Remaining {} - Enabled {}",
|
||||
guild->tribute.time_remaining,
|
||||
guild->tribute.enabled
|
||||
).c_str());
|
||||
}
|
||||
for (auto &c1: entity_list.GetClientList()) {
|
||||
if (c1.second->GuildID() == guild_id) {
|
||||
c->Message(
|
||||
Chat::Yellow, fmt::format(
|
||||
"PlayerName: {} ID: {} Rank: {} OptIn: {} DirtyList: {}.",
|
||||
c1.second->GetCleanName(),
|
||||
c1.second->GuildID(),
|
||||
c1.second->GuildRank(),
|
||||
c1.second->GuildTributeOptIn(),
|
||||
c1.second->GetGuildListDirty()
|
||||
).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_test) {
|
||||
if (!sep->IsNumber(2)) {
|
||||
c->Message(Chat::White, "Usage: #guild test [Guild ID]");
|
||||
}
|
||||
else {
|
||||
auto guild_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
auto guild = guild_mgr.GetGuildByGuildID(guild_id);
|
||||
c->SendGuildMembersList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SendGuildSubCommands(Client *c)
|
||||
void SendGuildSubCommands(Client* c)
|
||||
{
|
||||
c->Message(Chat::White, "#guild create [Character ID|Character Name] [Guild Name]");
|
||||
c->Message(Chat::White, "#guild delete [Guild ID]");
|
||||
c->Message(Chat::White, "#guild details [Guild ID]");
|
||||
c->Message(Chat::White, "#guild help");
|
||||
c->Message(Chat::White, "#guild info [Guild ID]");
|
||||
c->Message(Chat::White, "#guild list");
|
||||
|
||||
Reference in New Issue
Block a user