diff --git a/common/servertalk.h b/common/servertalk.h index 7f73d1115..8f1b64ac7 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -158,6 +158,7 @@ #define ServerOP_ExpeditionSaveInvite 0x040e #define ServerOP_ExpeditionRequestInvite 0x040f #define ServerOP_ExpeditionReplayOnJoin 0x0410 +#define ServerOP_ExpeditionLockState 0x0411 #define ServerOP_DzCharacterChange 0x0450 #define ServerOP_DzRemoveAllCharacters 0x0451 diff --git a/utils/sql/git/required/wip_expeditions.sql b/utils/sql/git/required/wip_expeditions.sql index f492ebe2c..035330f79 100644 --- a/utils/sql/git/required/wip_expeditions.sql +++ b/utils/sql/git/required/wip_expeditions.sql @@ -7,6 +7,7 @@ CREATE TABLE `expedition_details` ( `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, + `is_locked` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0, 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 df8ecb27a..c0f9f7ed6 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1372,6 +1372,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { case ServerOP_ExpeditionDeleted: case ServerOP_ExpeditionLeaderChanged: case ServerOP_ExpeditionLockout: + case ServerOP_ExpeditionLockState: case ServerOP_ExpeditionMemberChange: case ServerOP_ExpeditionMemberSwap: case ServerOP_ExpeditionMemberStatus: diff --git a/zone/expedition.cpp b/zone/expedition.cpp index 02e1e3057..1b1513ea9 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[8] }; // id, name + ExpeditionMember leader{ leader_id, row[9] }; // 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); @@ -176,8 +176,10 @@ void Expedition::CacheExpeditions(MySQLRequestResult& results) )); bool add_replay_on_join = (strtoul(row[7], nullptr, 10) != 0); + bool is_locked = (strtoul(row[8], nullptr, 10) != 0); expedition->SetReplayLockoutOnMemberJoin(add_replay_on_join); + expedition->SetLocked(is_locked); expedition->LoadMembers(); expedition->SendUpdatesToZoneMembers(); @@ -191,17 +193,17 @@ void Expedition::CacheExpeditions(MySQLRequestResult& results) last_expedition_id = expedition_id; // optional lockouts from left join - if (row[9] && row[10] && row[11] && row[12]) + if (row[10] && row[11] && row[12] && row[13]) { auto it = zone->expedition_cache.find(last_expedition_id); if (it != zone->expedition_cache.end()) { it->second->AddInternalLockout(ExpeditionLockoutTimer{ row[2], // expedition_name - 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 + row[10], // event_name + strtoull(row[11], nullptr, 10), // expire_time + static_cast(strtoul(row[12], nullptr, 10)), // original duration + (strtoul(row[13], nullptr, 10) != 0) // is_inherited }); } } @@ -760,7 +762,16 @@ void Expedition::DzInviteResponse(Client* add_client, bool accepted, const std:: } bool was_swap_invite = !swap_remove_name.empty(); - bool has_conflicts = ProcessAddConflicts(leader_client, add_client, was_swap_invite); + bool has_conflicts = m_is_locked; + + if (m_is_locked) + { + SendLeaderMessage(leader_client, Chat::Red, DZADD_NOT_ALLOWING); + } + else + { + has_conflicts = ProcessAddConflicts(leader_client, add_client, was_swap_invite); + } // error if swapping and character was already removed before the accept if (was_swap_invite && !HasMember(swap_remove_name)) @@ -902,7 +913,12 @@ void Expedition::DzAddPlayer( bool invite_failed = false; - if (add_char_name.empty()) + if (m_is_locked) + { + requester->MessageString(Chat::Red, DZADD_NOT_ALLOWING); + invite_failed = true; + } + else if (add_char_name.empty()) { requester->MessageString(Chat::Red, DZADD_NOT_ONLINE, add_char_name.c_str()); invite_failed = true; @@ -1068,6 +1084,17 @@ void Expedition::DzKickPlayers(Client* requester) requester->MessageString(Chat::Red, EXPEDITION_REMOVED, KICKPLAYERS_EVERYONE, m_expedition_name.c_str()); } +void Expedition::SetLocked(bool lock_expedition, bool update_db) +{ + m_is_locked = lock_expedition; + + if (update_db) + { + ExpeditionDatabase::UpdateLockState(m_id, lock_expedition); + SendWorldSettingChanged(ServerOP_ExpeditionLockState, m_is_locked); + } +} + void Expedition::SetNewLeader(uint32_t new_leader_id, const std::string& new_leader_name) { ExpeditionDatabase::UpdateLeaderID(m_id, new_leader_id); @@ -1678,6 +1705,7 @@ void Expedition::HandleWorldMessage(ServerPacket* pack) } break; } + case ServerOP_ExpeditionLockState: case ServerOP_ExpeditionReplayOnJoin: { auto buf = reinterpret_cast(pack->pBuffer); @@ -1686,7 +1714,14 @@ void Expedition::HandleWorldMessage(ServerPacket* pack) auto expedition = Expedition::FindCachedExpeditionByID(buf->expedition_id); if (expedition) { - expedition->SetReplayLockoutOnMemberJoin(buf->enabled); + if (pack->opcode == ServerOP_ExpeditionLockState) + { + expedition->SetLocked(buf->enabled); + } + else if (pack->opcode == ServerOP_ExpeditionReplayOnJoin) + { + expedition->SetReplayLockoutOnMemberJoin(buf->enabled); + } } } break; diff --git a/zone/expedition.h b/zone/expedition.h index 811a4a3ad..d6b30e376 100644 --- a/zone/expedition.h +++ b/zone/expedition.h @@ -107,6 +107,7 @@ public: void SetMemberStatus(Client* client, ExpeditionMemberStatus status); void SetNewLeader(uint32_t new_leader_id, const std::string& new_leader_name); void SwapMember(Client* add_client, const std::string& remove_char_name); + void SetLocked(bool lock_expedition, bool update_db = false); void AddLockout(const std::string& event_name, uint32_t seconds); void AddReplayLockout(uint32_t seconds); @@ -180,6 +181,7 @@ private: uint32_t m_id = 0; uint32_t m_min_players = 0; uint32_t m_max_players = 0; + bool m_is_locked = false; bool m_has_replay_timer = false; bool m_add_replay_on_join = true; std::string m_expedition_name; diff --git a/zone/expedition_database.cpp b/zone/expedition_database.cpp index 9b54df7ed..8dc5bb294 100644 --- a/zone/expedition_database.cpp +++ b/zone/expedition_database.cpp @@ -52,7 +52,6 @@ MySQLRequestResult ExpeditionDatabase::LoadExpedition(uint32_t expedition_id) { LogExpeditionsDetail("Loading expedition [{}]", expedition_id); - // no point caching expedition if no members, inner join instead of left std::string query = fmt::format(SQL( SELECT expedition_details.id, @@ -63,6 +62,7 @@ MySQLRequestResult ExpeditionDatabase::LoadExpedition(uint32_t expedition_id) expedition_details.max_players, expedition_details.has_replay_timer, expedition_details.add_replay_on_join, + expedition_details.is_locked, character_data.name leader_name, expedition_lockouts.event_name, UNIX_TIMESTAMP(expedition_lockouts.expire_time), @@ -95,6 +95,7 @@ MySQLRequestResult ExpeditionDatabase::LoadAllExpeditions() expedition_details.max_players, expedition_details.has_replay_timer, expedition_details.add_replay_on_join, + expedition_details.is_locked, character_data.name leader_name, expedition_lockouts.event_name, UNIX_TIMESTAMP(expedition_lockouts.expire_time), @@ -633,7 +634,7 @@ void ExpeditionDatabase::UpdateLeaderID(uint32_t expedition_id, uint32_t leader_ LogExpeditionsDetail("Updating leader [{}] for expedition [{}]", leader_id, expedition_id); auto query = fmt::format(SQL( - UPDATE expedition_details SET leader_id = {} WHERE id = {} + UPDATE expedition_details SET leader_id = {} WHERE id = {}; ), leader_id, expedition_id); auto results = database.QueryDatabase(query); @@ -643,6 +644,21 @@ void ExpeditionDatabase::UpdateLeaderID(uint32_t expedition_id, uint32_t leader_ } } +void ExpeditionDatabase::UpdateLockState(uint32_t expedition_id, bool is_locked) +{ + LogExpeditionsDetail("Updating lock state [{}] for expedition [{}]", is_locked, expedition_id); + + auto query = fmt::format(SQL( + UPDATE expedition_details SET is_locked = {} WHERE id = {}; + ), is_locked, expedition_id); + + auto results = database.QueryDatabase(query); + if (!results.Success()) + { + LogExpeditions("Failed to update expedition [{}] lock state", expedition_id); + } +} + void ExpeditionDatabase::UpdateMemberRemoved(uint32_t expedition_id, uint32_t character_id) { LogExpeditionsDetail("Removing member [{}] from expedition [{}]", character_id, expedition_id); diff --git a/zone/expedition_database.h b/zone/expedition_database.h index ea1788574..2fe68efa9 100644 --- a/zone/expedition_database.h +++ b/zone/expedition_database.h @@ -67,6 +67,7 @@ namespace ExpeditionDatabase void InsertMember(uint32_t expedition_id, uint32_t character_id); void InsertMembers(uint32_t expedition_id, const std::vector& members); void UpdateLeaderID(uint32_t expedition_id, uint32_t leader_id); + void UpdateLockState(uint32_t expedition_id, bool is_locked); void UpdateMemberRemoved(uint32_t expedition_id, uint32_t character_id); void UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join); }; diff --git a/zone/lua_expedition.cpp b/zone/lua_expedition.cpp index 469021b7c..a27ed0efa 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::SetLocked(bool lock_expedition) { + Lua_Safe_Call_Void(); + self->SetLocked(lock_expedition, true); +} + void Lua_Expedition::SetReplayLockoutOnMemberJoin(bool enable) { Lua_Safe_Call_Void(); self->SetReplayLockoutOnMemberJoin(enable, true); @@ -166,6 +171,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("SetLocked", (void(Lua_Expedition::*)(bool))&Lua_Expedition::SetLocked) .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) diff --git a/zone/lua_expedition.h b/zone/lua_expedition.h index c344b6d31..904d52dfe 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 SetLocked(bool lock_expedition); 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); diff --git a/zone/string_ids.h b/zone/string_ids.h index 5f1b89a02..40aa13057 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -323,6 +323,7 @@ #define EXPEDITION_EVENT_TIMER 3561 //%1 cannot be added to this expedition since they have recently experienced %2. They must wait another %3D:%4H:%5M until they can experience it again. They may be added to the expedition later, once %2 has been completed. #define LOOT_NOT_ALLOWED 3562 //You are not allowed to loot the item: %1. #define DZ_UNABLE_RETRIEVE_LEADER 3583 //Unable to retrieve dynamic zone leader to check permissions. +#define DZADD_NOT_ALLOWING 3585 //The expedition is not allowing players to be added. #define DZADD_NOT_ONLINE 3586 //%1 is not currently online. A player needs to be online to be added to a Dynamic Zone #define DZADD_EXCEED_MAX 3587 //You can not add another player since you currently have the maximum number of players allowed (%1) in this zone. #define DZADD_ALREADY_PART 3588 //You can not add %1 since they are already part of this zone. diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 7503ed037..d903db214 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -2903,6 +2903,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) case ServerOP_ExpeditionDeleted: case ServerOP_ExpeditionLeaderChanged: case ServerOP_ExpeditionLockout: + case ServerOP_ExpeditionLockState: case ServerOP_ExpeditionMemberChange: case ServerOP_ExpeditionMemberSwap: case ServerOP_ExpeditionMemberStatus: