From 5ddb62e2754e29fa95455b6319e7075467787a94 Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Sat, 23 May 2020 22:48:29 -0400 Subject: [PATCH] Make adding replay timers to new members optional Not all expeditions with a replay timer lockout add it to newly added members automatically This adds the Expedition::SetReplayLockoutOnMemberJoin(bool) method to the quest api so it can be disabled --- common/servertalk.h | 8 +++ utils/sql/git/required/wip_expeditions.sql | 1 + world/zoneserver.cpp | 1 + zone/expedition.cpp | 62 ++++++++++++++++++---- zone/expedition.h | 11 ++-- zone/expedition_database.cpp | 17 ++++++ zone/expedition_database.h | 1 + zone/lua_expedition.cpp | 6 +++ zone/lua_expedition.h | 1 + zone/worldserver.cpp | 1 + 10 files changed, 95 insertions(+), 14 deletions(-) diff --git a/common/servertalk.h b/common/servertalk.h index 031885132..7f73d1115 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -157,6 +157,7 @@ #define ServerOP_ExpeditionRemoveCharLockouts 0x040d #define ServerOP_ExpeditionSaveInvite 0x040e #define ServerOP_ExpeditionRequestInvite 0x040f +#define ServerOP_ExpeditionReplayOnJoin 0x0410 #define ServerOP_DzCharacterChange 0x0450 #define ServerOP_DzRemoveAllCharacters 0x0451 @@ -2054,6 +2055,13 @@ struct ServerExpeditionLockout_Struct { char event_name[256]; }; +struct ServerExpeditionSetting_Struct { + uint32 expedition_id; + uint32 sender_zone_id; + uint16 sender_instance_id; + uint8 enabled; +}; + struct ServerExpeditionCharacterName_Struct { char character_name[64]; char expedition_name[128]; diff --git a/utils/sql/git/required/wip_expeditions.sql b/utils/sql/git/required/wip_expeditions.sql index 4810b1ade..f492ebe2c 100644 --- a/utils/sql/git/required/wip_expeditions.sql +++ b/utils/sql/git/required/wip_expeditions.sql @@ -6,6 +6,7 @@ CREATE TABLE `expedition_details` ( `min_players` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0, `max_players` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0, `has_replay_timer` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0, + `add_replay_on_join` TINYINT(3) UNSIGNED NOT NULL DEFAULT 1, PRIMARY KEY (`id`), UNIQUE INDEX `instance_id` (`instance_id`), CONSTRAINT `FK_expedition_details_instance_list` FOREIGN KEY (`instance_id`) REFERENCES `instance_list` (`id`) ON DELETE SET NULL diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 6f3b1a9e1..df8ecb27a 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1375,6 +1375,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { case ServerOP_ExpeditionMemberChange: case ServerOP_ExpeditionMemberSwap: case ServerOP_ExpeditionMemberStatus: + case ServerOP_ExpeditionReplayOnJoin: case ServerOP_ExpeditionDzCompass: case ServerOP_ExpeditionDzSafeReturn: case ServerOP_ExpeditionDzZoneIn: diff --git a/zone/expedition.cpp b/zone/expedition.cpp index 7ba767386..02e1e3057 100644 --- a/zone/expedition.cpp +++ b/zone/expedition.cpp @@ -160,7 +160,7 @@ void Expedition::CacheExpeditions(MySQLRequestResult& results) if (expedition_id != last_expedition_id) { auto leader_id = static_cast(strtoul(row[3], nullptr, 10)); - ExpeditionMember leader{ leader_id, row[7] }; // id, name + ExpeditionMember leader{ leader_id, row[8] }; // id, name auto instance_id = row[1] ? strtoul(row[1], nullptr, 10) : 0; // can be null from fk constraint DynamicZone dynamic_zone = DynamicZone::LoadDzFromDatabase(instance_id); @@ -175,6 +175,9 @@ void Expedition::CacheExpeditions(MySQLRequestResult& results) (strtoul(row[6], nullptr, 10) != 0) // has_replay_timer )); + bool add_replay_on_join = (strtoul(row[7], nullptr, 10) != 0); + + expedition->SetReplayLockoutOnMemberJoin(add_replay_on_join); expedition->LoadMembers(); expedition->SendUpdatesToZoneMembers(); @@ -188,17 +191,17 @@ void Expedition::CacheExpeditions(MySQLRequestResult& results) last_expedition_id = expedition_id; // optional lockouts from left join - if (row[8] && row[9] && row[10] && row[11]) + if (row[9] && row[10] && row[11] && row[12]) { auto it = zone->expedition_cache.find(last_expedition_id); if (it != zone->expedition_cache.end()) { it->second->AddInternalLockout(ExpeditionLockoutTimer{ row[2], // expedition_name - row[8], // event_name - strtoull(row[9], nullptr, 10), // expire_time - static_cast(strtoul(row[10], nullptr, 10)), // original duration - (strtoul(row[11], nullptr, 10) != 0) // is_inherited + row[9], // event_name + strtoull(row[10], nullptr, 10), // expire_time + static_cast(strtoul(row[11], nullptr, 10)), // original duration + (strtoul(row[12], nullptr, 10) != 0) // is_inherited }); } } @@ -392,6 +395,17 @@ ExpeditionMember Expedition::GetMemberData(const std::string& character_name) return member_data; } +void Expedition::SetReplayLockoutOnMemberJoin(bool add_on_join, bool update_db) +{ + m_add_replay_on_join = add_on_join; + + if (update_db) + { + ExpeditionDatabase::UpdateReplayLockoutOnJoin(m_id, add_on_join); + SendWorldSettingChanged(ServerOP_ExpeditionReplayOnJoin, m_add_replay_on_join); + } +} + void Expedition::AddReplayLockout(uint32_t seconds) { AddLockout(DZ_REPLAY_TIMER_NAME, seconds); @@ -774,12 +788,15 @@ void Expedition::DzInviteResponse(Client* add_client, bool accepted, const std:: if (!lockout.IsInherited() && !add_client->HasExpeditionLockout(m_expedition_name, lockout.GetEventName())) { - // replay timers are added to characters immediately on joining with - // a fresh expire time using the original duration + // replay timers are optionally added to new members immediately on + // join with a fresh expire time using the original duration. if (m_has_replay_timer && lockout.IsReplayTimer()) { - add_client->AddNewExpeditionLockout( - lockout.GetExpeditionName(), lockout.GetEventName(), lockout.GetDuration()); + if (m_add_replay_on_join) + { + add_client->AddNewExpeditionLockout( + lockout.GetExpeditionName(), lockout.GetEventName(), lockout.GetDuration()); + } } else { @@ -1499,6 +1516,18 @@ void Expedition::SendWorldMemberSwapped( worldserver.SendPacket(pack.get()); } +void Expedition::SendWorldSettingChanged(uint16_t server_opcode, bool setting_value) +{ + uint32_t pack_size = sizeof(ServerExpeditionSetting_Struct); + auto pack = std::unique_ptr(new ServerPacket(server_opcode, pack_size)); + auto buf = reinterpret_cast(pack->pBuffer); + buf->expedition_id = GetID(); + buf->sender_zone_id = zone ? zone->GetZoneID() : 0; + buf->sender_instance_id = zone ? zone->GetInstanceID() : 0; + buf->enabled = setting_value; + worldserver.SendPacket(pack.get()); +} + void Expedition::SendWorldGetOnlineMembers() { // request online status of all characters in our expedition tracked by world @@ -1649,6 +1678,19 @@ void Expedition::HandleWorldMessage(ServerPacket* pack) } break; } + case ServerOP_ExpeditionReplayOnJoin: + { + auto buf = reinterpret_cast(pack->pBuffer); + if (zone && !zone->IsZone(buf->sender_zone_id, buf->sender_instance_id)) + { + auto expedition = Expedition::FindCachedExpeditionByID(buf->expedition_id); + if (expedition) + { + expedition->SetReplayLockoutOnMemberJoin(buf->enabled); + } + } + break; + } case ServerOP_ExpeditionGetOnlineMembers: { // reply from world for online member statuses request diff --git a/zone/expedition.h b/zone/expedition.h index ce1e243f8..811a4a3ad 100644 --- a/zone/expedition.h +++ b/zone/expedition.h @@ -113,6 +113,7 @@ public: bool HasLockout(const std::string& event_name); bool HasReplayLockout(); void RemoveLockout(const std::string& event_name); + void SetReplayLockoutOnMemberJoin(bool add_on_join, bool update_db = false); void SendClientExpeditionInfo(Client* client); void SendWorldPendingInvite(const ExpeditionInvite& invite, const std::string& add_name); @@ -163,6 +164,7 @@ private: void SendWorldMemberChanged(const std::string& char_name, uint32_t char_id, bool remove); void SendWorldMemberStatus(uint32_t character_id, ExpeditionMemberStatus status); void SendWorldMemberSwapped(const std::string& remove_char_name, uint32_t remove_char_id, const std::string& add_char_name, uint32_t add_char_id); + void SendWorldSettingChanged(uint16_t server_opcode, bool setting_value); void TryAddClient(Client* add_client, std::string inviter_name, std::string orig_add_name, std::string swap_remove_name, Client* leader_client = nullptr); void UpdateMemberStatus(uint32_t update_character_id, ExpeditionMemberStatus status); @@ -175,10 +177,11 @@ private: std::unique_ptr CreateMemberListStatusPacket(const std::string& name, ExpeditionMemberStatus status); std::unique_ptr CreateLeaderNamePacket(); - uint32_t m_id = 0; - uint32_t m_min_players = 0; - uint32_t m_max_players = 0; - bool m_has_replay_timer = false; + uint32_t m_id = 0; + uint32_t m_min_players = 0; + uint32_t m_max_players = 0; + bool m_has_replay_timer = false; + bool m_add_replay_on_join = true; std::string m_expedition_name; DynamicZone m_dynamiczone { DynamicZoneType::Expedition }; ExpeditionMember m_leader; diff --git a/zone/expedition_database.cpp b/zone/expedition_database.cpp index 4ecda739d..9b54df7ed 100644 --- a/zone/expedition_database.cpp +++ b/zone/expedition_database.cpp @@ -62,6 +62,7 @@ MySQLRequestResult ExpeditionDatabase::LoadExpedition(uint32_t expedition_id) expedition_details.min_players, expedition_details.max_players, expedition_details.has_replay_timer, + expedition_details.add_replay_on_join, character_data.name leader_name, expedition_lockouts.event_name, UNIX_TIMESTAMP(expedition_lockouts.expire_time), @@ -93,6 +94,7 @@ MySQLRequestResult ExpeditionDatabase::LoadAllExpeditions() expedition_details.min_players, expedition_details.max_players, expedition_details.has_replay_timer, + expedition_details.add_replay_on_join, character_data.name leader_name, expedition_lockouts.event_name, UNIX_TIMESTAMP(expedition_lockouts.expire_time), @@ -656,3 +658,18 @@ void ExpeditionDatabase::UpdateMemberRemoved(uint32_t expedition_id, uint32_t ch LogExpeditions("Failed to remove [{}] from expedition [{}]", character_id, expedition_id); } } + +void ExpeditionDatabase::UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join) +{ + LogExpeditionsDetail("Updating replay lockout on join [{}] for expedition [{}]", add_on_join, expedition_id); + + auto query = fmt::format(SQL( + UPDATE expedition_details SET add_replay_on_join = {} WHERE id = {}; + ), add_on_join, expedition_id); + + auto results = database.QueryDatabase(query); + if (!results.Success()) + { + LogExpeditions("Failed to update expedition [{}] replay timer setting", expedition_id); + } +} diff --git a/zone/expedition_database.h b/zone/expedition_database.h index d47ab09f3..ea1788574 100644 --- a/zone/expedition_database.h +++ b/zone/expedition_database.h @@ -68,6 +68,7 @@ namespace ExpeditionDatabase void InsertMembers(uint32_t expedition_id, const std::vector& members); void UpdateLeaderID(uint32_t expedition_id, uint32_t leader_id); void UpdateMemberRemoved(uint32_t expedition_id, uint32_t character_id); + void UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join); }; #endif diff --git a/zone/lua_expedition.cpp b/zone/lua_expedition.cpp index d6dbccc5d..469021b7c 100644 --- a/zone/lua_expedition.cpp +++ b/zone/lua_expedition.cpp @@ -125,6 +125,11 @@ void Lua_Expedition::SetCompass(std::string zone_name, float x, float y, float z return self->SetDzCompass(zone_name, x, y, z, true); } +void Lua_Expedition::SetReplayLockoutOnMemberJoin(bool enable) { + Lua_Safe_Call_Void(); + self->SetReplayLockoutOnMemberJoin(enable, true); +} + void Lua_Expedition::SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading) { Lua_Safe_Call_Void(); return self->SetDzSafeReturn(zone_id, x, y, z, heading, true); @@ -161,6 +166,7 @@ luabind::scope lua_register_expedition() { .def("RemoveLockout", (void(Lua_Expedition::*)(std::string))&Lua_Expedition::RemoveLockout) .def("SetCompass", (void(Lua_Expedition::*)(uint32_t, float, float, float))&Lua_Expedition::SetCompass) .def("SetCompass", (void(Lua_Expedition::*)(std::string, float, float, float))&Lua_Expedition::SetCompass) + .def("SetReplayLockoutOnMemberJoin", (void(Lua_Expedition::*)(bool))&Lua_Expedition::SetReplayLockoutOnMemberJoin) .def("SetSafeReturn", (void(Lua_Expedition::*)(uint32_t, float, float, float, float))&Lua_Expedition::SetSafeReturn) .def("SetSafeReturn", (void(Lua_Expedition::*)(std::string, float, float, float, float))&Lua_Expedition::SetSafeReturn) .def("SetZoneInLocation", (void(Lua_Expedition::*)(float, float, float, float))&Lua_Expedition::SetZoneInLocation); diff --git a/zone/lua_expedition.h b/zone/lua_expedition.h index f7fa1f90a..c344b6d31 100644 --- a/zone/lua_expedition.h +++ b/zone/lua_expedition.h @@ -68,6 +68,7 @@ public: void RemoveLockout(std::string event_name); void SetCompass(uint32 zone_id, float x, float y, float z); void SetCompass(std::string zone_name, float x, float y, float z); + void SetReplayLockoutOnMemberJoin(bool enable); void SetSafeReturn(uint32 zone_id, float x, float y, float z, float heading); void SetSafeReturn(std::string zone_name, float x, float y, float z, float heading); void SetZoneInLocation(float x, float y, float z, float heading); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index fa005ea6e..7503ed037 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -2906,6 +2906,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) case ServerOP_ExpeditionMemberChange: case ServerOP_ExpeditionMemberSwap: case ServerOP_ExpeditionMemberStatus: + case ServerOP_ExpeditionReplayOnJoin: case ServerOP_ExpeditionGetOnlineMembers: case ServerOP_ExpeditionDzAddPlayer: case ServerOP_ExpeditionDzMakeLeader: