diff --git a/common/dynamic_zone_base.cpp b/common/dynamic_zone_base.cpp index 8269c3b23..ee4ab82da 100644 --- a/common/dynamic_zone_base.cpp +++ b/common/dynamic_zone_base.cpp @@ -79,6 +79,7 @@ void DynamicZoneBase::LoadRepositoryResult(DynamicZonesRepository::DynamicZoneIn m_max_players = dz_entry.max_players; m_instance_id = dz_entry.instance_id; m_type = static_cast(dz_entry.type); + m_dz_switch_id = dz_entry.dz_switch_id; m_compass.zone_id = dz_entry.compass_zone_id; m_compass.x = dz_entry.compass_x; m_compass.y = dz_entry.compass_y; @@ -129,6 +130,7 @@ uint32_t DynamicZoneBase::SaveToDatabase() insert_dz.max_players = m_max_players; insert_dz.instance_id = m_instance_id, insert_dz.type = static_cast(m_type); + insert_dz.dz_switch_id = m_dz_switch_id; insert_dz.compass_zone_id = m_compass.zone_id; insert_dz.compass_x = m_compass.x; insert_dz.compass_y = m_compass.y; @@ -316,6 +318,17 @@ void DynamicZoneBase::SetZoneInLocation(float x, float y, float z, float heading SetZoneInLocation({ 0, x, y, z, heading }, update_db); } +void DynamicZoneBase::SetSwitchID(int dz_switch_id, bool update_db) +{ + m_dz_switch_id = dz_switch_id; + + if (update_db) + { + DynamicZonesRepository::UpdateSwitchID(GetDatabase(), m_id, dz_switch_id); + SendServerPacket(CreateServerDzSwitchIDPacket().get()); + } +} + void DynamicZoneBase::SetLeader(const DynamicZoneMember& new_leader, bool update_db) { m_leader = new_leader; @@ -403,6 +416,17 @@ std::unique_ptr DynamicZoneBase::CreateServerDzLocationPacket( return pack; } +std::unique_ptr DynamicZoneBase::CreateServerDzSwitchIDPacket() +{ + constexpr uint32_t pack_size = sizeof(ServerDzSwitchID_Struct); + auto pack = std::make_unique(ServerOP_DzSetSwitchID, pack_size); + auto buf = reinterpret_cast(pack->pBuffer); + buf->dz_id = GetID(); + buf->dz_switch_id = GetSwitchID(); + + return pack; +} + std::unique_ptr DynamicZoneBase::CreateServerMemberStatusPacket( uint32_t character_id, DynamicZoneMemberStatus status) { diff --git a/common/dynamic_zone_base.h b/common/dynamic_zone_base.h index eafea5ca0..0f06be8bf 100644 --- a/common/dynamic_zone_base.h +++ b/common/dynamic_zone_base.h @@ -85,6 +85,7 @@ public: uint16_t GetZoneID() const { return static_cast(m_zone_id); } uint32_t GetZoneIndex() const { return (m_instance_id << 16) | (m_zone_id & 0xffff); } uint32_t GetZoneVersion() const { return m_zone_version; } + int GetSwitchID() const { return m_dz_switch_id; } DynamicZoneType GetType() const { return m_type; } const std::string& GetLeaderName() const { return m_leader.name; } const std::string& GetName() const { return m_name; } @@ -127,6 +128,7 @@ public: void SetName(const std::string& name) { m_name = name; } void SetSafeReturn(const DynamicZoneLocation& location, bool update_db = false); void SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading, bool update_db = false); + void SetSwitchID(int dz_switch_id, bool update_db = false); void SetType(DynamicZoneType type) { m_type = type; } void SetUUID(std::string uuid) { m_uuid = std::move(uuid); } void SetZoneInLocation(const DynamicZoneLocation& location, bool update_db = false); @@ -141,6 +143,7 @@ protected: virtual void ProcessMemberAddRemove(const DynamicZoneMember& member, bool removed); virtual bool ProcessMemberStatusChange(uint32_t member_id, DynamicZoneMemberStatus status); virtual void ProcessRemoveAllMembers(bool silent = false) { m_members.clear(); } + virtual void ProcessSetSwitchID(int dz_switch_id) { m_dz_switch_id = dz_switch_id; } virtual bool SendServerPacket(ServerPacket* packet) = 0; void AddInternalMember(const DynamicZoneMember& member); @@ -153,6 +156,7 @@ protected: std::unique_ptr CreateServerDzCreatePacket(uint16_t origin_zone_id, uint16_t origin_instance_id); std::unique_ptr CreateServerDzLocationPacket(uint16_t server_opcode, const DynamicZoneLocation& location); + std::unique_ptr CreateServerDzSwitchIDPacket(); std::unique_ptr CreateServerMemberAddRemovePacket(const DynamicZoneMember& member, bool removed); std::unique_ptr CreateServerMemberStatusPacket(uint32_t character_id, DynamicZoneMemberStatus status); std::unique_ptr CreateServerMemberSwapPacket(const DynamicZoneMember& remove_member, const DynamicZoneMember& add_member); @@ -164,6 +168,7 @@ protected: uint32_t m_zone_version = 0; uint32_t m_min_players = 0; uint32_t m_max_players = 0; + int m_dz_switch_id = 0; bool m_never_expires = false; bool m_has_zonein = false; bool m_has_member_statuses = false; @@ -190,6 +195,7 @@ public: m_zone_version, m_min_players, m_max_players, + m_dz_switch_id, m_never_expires, m_has_zonein, m_has_member_statuses, diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 0ded635eb..b0fce1f49 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -5006,7 +5006,7 @@ struct DynamicZoneCompassEntry_Struct /*000*/ uint16 dz_zone_id; // target dz id pair /*002*/ uint16 dz_instance_id; /*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green) -/*008*/ uint32 unknown008; +/*008*/ uint32 dz_switch_id; /*012*/ float y; /*016*/ float x; /*020*/ float z; diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 08f7aee8d..67969d1dc 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -736,30 +736,6 @@ namespace RoF FINISH_ENCODE(); } - ENCODE(OP_DzCompass) - { - SETUP_VAR_ENCODE(DynamicZoneCompass_Struct); - ALLOC_VAR_ENCODE(structs::DynamicZoneCompass_Struct, - sizeof(structs::DynamicZoneCompass_Struct) + - sizeof(structs::DynamicZoneCompassEntry_Struct) * emu->count - ); - - OUT(client_id); - OUT(count); - - for (uint32 i = 0; i < emu->count; ++i) - { - OUT(entries[i].dz_zone_id); - OUT(entries[i].dz_instance_id); - OUT(entries[i].dz_type); - OUT(entries[i].x); - OUT(entries[i].y); - OUT(entries[i].z); - } - - FINISH_ENCODE(); - } - ENCODE(OP_DzExpeditionEndsWarning) { ENCODE_LENGTH_EXACT(ExpeditionExpireWarning); diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 8053fac07..6e418d113 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -785,30 +785,6 @@ namespace RoF2 FINISH_ENCODE(); } - ENCODE(OP_DzCompass) - { - SETUP_VAR_ENCODE(DynamicZoneCompass_Struct); - ALLOC_VAR_ENCODE(structs::DynamicZoneCompass_Struct, - sizeof(structs::DynamicZoneCompass_Struct) + - sizeof(structs::DynamicZoneCompassEntry_Struct) * emu->count - ); - - OUT(client_id); - OUT(count); - - for (uint32 i = 0; i < emu->count; ++i) - { - OUT(entries[i].dz_zone_id); - OUT(entries[i].dz_instance_id); - OUT(entries[i].dz_type); - OUT(entries[i].x); - OUT(entries[i].y); - OUT(entries[i].z); - } - - FINISH_ENCODE(); - } - ENCODE(OP_DzExpeditionEndsWarning) { ENCODE_LENGTH_EXACT(ExpeditionExpireWarning); diff --git a/common/patches/rof2_ops.h b/common/patches/rof2_ops.h index 130686cdf..4fa2e546a 100644 --- a/common/patches/rof2_ops.h +++ b/common/patches/rof2_ops.h @@ -59,7 +59,6 @@ E(OP_DeleteItem) E(OP_DeleteSpawn) E(OP_DisciplineUpdate) E(OP_DzChooseZone) -E(OP_DzCompass) E(OP_DzExpeditionEndsWarning) E(OP_DzExpeditionInfo) E(OP_DzExpeditionInvite) diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 42c1e5883..d3692ba0a 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -4989,7 +4989,7 @@ struct DynamicZoneCompassEntry_Struct /*000*/ uint16 dz_zone_id; // target dz id pair /*002*/ uint16 dz_instance_id; /*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green) -/*008*/ uint32 unknown008; +/*008*/ uint32 dz_switch_id; /*012*/ float y; /*016*/ float x; /*020*/ float z; diff --git a/common/patches/rof_ops.h b/common/patches/rof_ops.h index 7cca08e61..98f20f431 100644 --- a/common/patches/rof_ops.h +++ b/common/patches/rof_ops.h @@ -45,7 +45,6 @@ E(OP_DeleteItem) E(OP_DeleteSpawn) E(OP_DisciplineUpdate) E(OP_DzChooseZone) -E(OP_DzCompass) E(OP_DzExpeditionEndsWarning) E(OP_DzExpeditionInfo) E(OP_DzExpeditionInvite) diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 662cc3872..bfc91719d 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -4921,7 +4921,7 @@ struct DynamicZoneCompassEntry_Struct /*000*/ uint16 dz_zone_id; // target dz id pair /*002*/ uint16 dz_instance_id; /*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green) -/*008*/ uint32 unknown008; +/*008*/ uint32 dz_switch_id; /*012*/ float y; /*016*/ float x; /*020*/ float z; diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index ae7036664..0fc92130e 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -509,30 +509,6 @@ namespace SoD FINISH_ENCODE(); } - ENCODE(OP_DzCompass) - { - SETUP_VAR_ENCODE(DynamicZoneCompass_Struct); - ALLOC_VAR_ENCODE(structs::DynamicZoneCompass_Struct, - sizeof(structs::DynamicZoneCompass_Struct) + - sizeof(structs::DynamicZoneCompassEntry_Struct) * emu->count - ); - - OUT(client_id); - OUT(count); - - for (uint32 i = 0; i < emu->count; ++i) - { - OUT(entries[i].dz_zone_id); - OUT(entries[i].dz_instance_id); - OUT(entries[i].dz_type); - OUT(entries[i].x); - OUT(entries[i].y); - OUT(entries[i].z); - } - - FINISH_ENCODE(); - } - ENCODE(OP_DzExpeditionEndsWarning) { ENCODE_LENGTH_EXACT(ExpeditionExpireWarning); diff --git a/common/patches/sod_ops.h b/common/patches/sod_ops.h index c98ab5ff0..d70807cce 100644 --- a/common/patches/sod_ops.h +++ b/common/patches/sod_ops.h @@ -36,7 +36,6 @@ E(OP_Damage) E(OP_DeleteCharge) E(OP_DeleteItem) E(OP_DzChooseZone) -E(OP_DzCompass) E(OP_DzExpeditionEndsWarning) E(OP_DzExpeditionInfo) E(OP_DzExpeditionInvite) diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index 7b0e45e46..978fefb54 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -4276,7 +4276,7 @@ struct DynamicZoneCompassEntry_Struct /*000*/ uint16 dz_zone_id; // target dz id pair /*002*/ uint16 dz_instance_id; /*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green) -/*008*/ uint32 unknown008; +/*008*/ uint32 dz_switch_id; /*012*/ float y; /*016*/ float x; /*020*/ float z; diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index 94b676a12..251f64d79 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -497,30 +497,6 @@ namespace SoF FINISH_ENCODE(); } - ENCODE(OP_DzCompass) - { - SETUP_VAR_ENCODE(DynamicZoneCompass_Struct); - ALLOC_VAR_ENCODE(structs::DynamicZoneCompass_Struct, - sizeof(structs::DynamicZoneCompass_Struct) + - sizeof(structs::DynamicZoneCompassEntry_Struct) * emu->count - ); - - OUT(client_id); - OUT(count); - - for (uint32 i = 0; i < emu->count; ++i) - { - OUT(entries[i].dz_zone_id); - OUT(entries[i].dz_instance_id); - OUT(entries[i].dz_type); - OUT(entries[i].x); - OUT(entries[i].y); - OUT(entries[i].z); - } - - FINISH_ENCODE(); - } - ENCODE(OP_DzExpeditionEndsWarning) { ENCODE_LENGTH_EXACT(ExpeditionExpireWarning); diff --git a/common/patches/sof_ops.h b/common/patches/sof_ops.h index 0dd34e060..b68378996 100644 --- a/common/patches/sof_ops.h +++ b/common/patches/sof_ops.h @@ -37,7 +37,6 @@ E(OP_DeleteCharge) E(OP_DeleteItem) E(OP_DeleteSpawn) E(OP_DzChooseZone) -E(OP_DzCompass) E(OP_DzExpeditionEndsWarning) E(OP_DzExpeditionInfo) E(OP_DzExpeditionInvite) diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index 05dfba0c5..8e034e606 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -4186,7 +4186,7 @@ struct DynamicZoneCompassEntry_Struct /*000*/ uint16 dz_zone_id; // target dz id pair /*002*/ uint16 dz_instance_id; /*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green) -/*008*/ uint32 unknown008; +/*008*/ uint32 dz_switch_id; /*012*/ float y; /*016*/ float x; /*020*/ float z; diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index 2861bb861..542bf7282 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -440,30 +440,6 @@ namespace Titanium FINISH_ENCODE(); } - ENCODE(OP_DzCompass) - { - SETUP_VAR_ENCODE(DynamicZoneCompass_Struct); - ALLOC_VAR_ENCODE(structs::DynamicZoneCompass_Struct, - sizeof(structs::DynamicZoneCompass_Struct) + - sizeof(structs::DynamicZoneCompassEntry_Struct) * emu->count - ); - - OUT(client_id); - OUT(count); - - for (uint32 i = 0; i < emu->count; ++i) - { - OUT(entries[i].dz_zone_id); - OUT(entries[i].dz_instance_id); - OUT(entries[i].dz_type); - OUT(entries[i].x); - OUT(entries[i].y); - OUT(entries[i].z); - } - - FINISH_ENCODE(); - } - ENCODE(OP_DzExpeditionEndsWarning) { ENCODE_LENGTH_EXACT(ExpeditionExpireWarning); diff --git a/common/patches/titanium_ops.h b/common/patches/titanium_ops.h index 6f11063be..c747233fd 100644 --- a/common/patches/titanium_ops.h +++ b/common/patches/titanium_ops.h @@ -33,7 +33,6 @@ E(OP_DeleteCharge) E(OP_DeleteItem) E(OP_DeleteSpawn) E(OP_DzChooseZone) -E(OP_DzCompass) E(OP_DzExpeditionEndsWarning) E(OP_DzExpeditionInfo) E(OP_DzExpeditionInvite) diff --git a/common/patches/titanium_structs.h b/common/patches/titanium_structs.h index 1220877d5..6093af656 100644 --- a/common/patches/titanium_structs.h +++ b/common/patches/titanium_structs.h @@ -3396,7 +3396,7 @@ struct DynamicZoneCompassEntry_Struct /*000*/ uint16 dz_zone_id; // target dz id pair /*002*/ uint16 dz_instance_id; /*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green) -/*008*/ uint32 unknown008; +/*008*/ uint32 dz_switch_id; /*012*/ float y; /*016*/ float x; /*020*/ float z; diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 0b465ae75..236b89d52 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -639,30 +639,6 @@ namespace UF FINISH_ENCODE(); } - ENCODE(OP_DzCompass) - { - SETUP_VAR_ENCODE(DynamicZoneCompass_Struct); - ALLOC_VAR_ENCODE(structs::DynamicZoneCompass_Struct, - sizeof(structs::DynamicZoneCompass_Struct) + - sizeof(structs::DynamicZoneCompassEntry_Struct) * emu->count - ); - - OUT(client_id); - OUT(count); - - for (uint32 i = 0; i < emu->count; ++i) - { - OUT(entries[i].dz_zone_id); - OUT(entries[i].dz_instance_id); - OUT(entries[i].dz_type); - OUT(entries[i].x); - OUT(entries[i].y); - OUT(entries[i].z); - } - - FINISH_ENCODE(); - } - ENCODE(OP_DzExpeditionEndsWarning) { ENCODE_LENGTH_EXACT(ExpeditionExpireWarning); diff --git a/common/patches/uf_ops.h b/common/patches/uf_ops.h index 5d728f067..498b4f33d 100644 --- a/common/patches/uf_ops.h +++ b/common/patches/uf_ops.h @@ -39,7 +39,6 @@ E(OP_DeleteCharge) E(OP_DeleteItem) E(OP_DisciplineUpdate) E(OP_DzChooseZone) -E(OP_DzCompass) E(OP_DzExpeditionEndsWarning) E(OP_DzExpeditionInfo) E(OP_DzExpeditionInvite) diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index a4b5b510c..50fb1f392 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -4357,7 +4357,7 @@ struct DynamicZoneCompassEntry_Struct /*000*/ uint16 dz_zone_id; // target dz id pair /*002*/ uint16 dz_instance_id; /*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green) -/*008*/ uint32 unknown008; +/*008*/ uint32 dz_switch_id; /*012*/ float y; /*016*/ float x; /*020*/ float z; diff --git a/common/repositories/base/base_doors_repository.h b/common/repositories/base/base_doors_repository.h index 723b822e3..ebb9aa3b3 100644 --- a/common/repositories/base/base_doors_repository.h +++ b/common/repositories/base/base_doors_repository.h @@ -50,6 +50,7 @@ public: float buffer; int client_version_mask; int is_ldon_door; + int dz_switch_id; int min_expansion; int max_expansion; std::string content_flags; @@ -95,6 +96,7 @@ public: "buffer", "client_version_mask", "is_ldon_door", + "dz_switch_id", "min_expansion", "max_expansion", "content_flags", @@ -136,6 +138,7 @@ public: "buffer", "client_version_mask", "is_ldon_door", + "dz_switch_id", "min_expansion", "max_expansion", "content_flags", @@ -211,6 +214,7 @@ public: entry.buffer = 0; entry.client_version_mask = 4294967295; entry.is_ldon_door = 0; + entry.dz_switch_id = 0; entry.min_expansion = -1; entry.max_expansion = -1; entry.content_flags = ""; @@ -281,10 +285,11 @@ public: entry.buffer = static_cast(atof(row[28])); entry.client_version_mask = atoi(row[29]); entry.is_ldon_door = atoi(row[30]); - entry.min_expansion = atoi(row[31]); - entry.max_expansion = atoi(row[32]); - entry.content_flags = row[33] ? row[33] : ""; - entry.content_flags_disabled = row[34] ? row[34] : ""; + entry.dz_switch_id = atoi(row[31]); + entry.min_expansion = atoi(row[32]); + entry.max_expansion = atoi(row[33]); + entry.content_flags = row[34] ? row[34] : ""; + entry.content_flags_disabled = row[35] ? row[35] : ""; return entry; } @@ -348,10 +353,11 @@ public: update_values.push_back(columns[28] + " = " + std::to_string(doors_entry.buffer)); update_values.push_back(columns[29] + " = " + std::to_string(doors_entry.client_version_mask)); update_values.push_back(columns[30] + " = " + std::to_string(doors_entry.is_ldon_door)); - update_values.push_back(columns[31] + " = " + std::to_string(doors_entry.min_expansion)); - update_values.push_back(columns[32] + " = " + std::to_string(doors_entry.max_expansion)); - update_values.push_back(columns[33] + " = '" + Strings::Escape(doors_entry.content_flags) + "'"); - update_values.push_back(columns[34] + " = '" + Strings::Escape(doors_entry.content_flags_disabled) + "'"); + update_values.push_back(columns[31] + " = " + std::to_string(doors_entry.dz_switch_id)); + update_values.push_back(columns[32] + " = " + std::to_string(doors_entry.min_expansion)); + update_values.push_back(columns[33] + " = " + std::to_string(doors_entry.max_expansion)); + update_values.push_back(columns[34] + " = '" + Strings::Escape(doors_entry.content_flags) + "'"); + update_values.push_back(columns[35] + " = '" + Strings::Escape(doors_entry.content_flags_disabled) + "'"); auto results = db.QueryDatabase( fmt::format( @@ -404,6 +410,7 @@ public: insert_values.push_back(std::to_string(doors_entry.buffer)); insert_values.push_back(std::to_string(doors_entry.client_version_mask)); insert_values.push_back(std::to_string(doors_entry.is_ldon_door)); + insert_values.push_back(std::to_string(doors_entry.dz_switch_id)); insert_values.push_back(std::to_string(doors_entry.min_expansion)); insert_values.push_back(std::to_string(doors_entry.max_expansion)); insert_values.push_back("'" + Strings::Escape(doors_entry.content_flags) + "'"); @@ -468,6 +475,7 @@ public: insert_values.push_back(std::to_string(doors_entry.buffer)); insert_values.push_back(std::to_string(doors_entry.client_version_mask)); insert_values.push_back(std::to_string(doors_entry.is_ldon_door)); + insert_values.push_back(std::to_string(doors_entry.dz_switch_id)); insert_values.push_back(std::to_string(doors_entry.min_expansion)); insert_values.push_back(std::to_string(doors_entry.max_expansion)); insert_values.push_back("'" + Strings::Escape(doors_entry.content_flags) + "'"); @@ -536,10 +544,11 @@ public: entry.buffer = static_cast(atof(row[28])); entry.client_version_mask = atoi(row[29]); entry.is_ldon_door = atoi(row[30]); - entry.min_expansion = atoi(row[31]); - entry.max_expansion = atoi(row[32]); - entry.content_flags = row[33] ? row[33] : ""; - entry.content_flags_disabled = row[34] ? row[34] : ""; + entry.dz_switch_id = atoi(row[31]); + entry.min_expansion = atoi(row[32]); + entry.max_expansion = atoi(row[33]); + entry.content_flags = row[34] ? row[34] : ""; + entry.content_flags_disabled = row[35] ? row[35] : ""; all_entries.push_back(entry); } @@ -595,10 +604,11 @@ public: entry.buffer = static_cast(atof(row[28])); entry.client_version_mask = atoi(row[29]); entry.is_ldon_door = atoi(row[30]); - entry.min_expansion = atoi(row[31]); - entry.max_expansion = atoi(row[32]); - entry.content_flags = row[33] ? row[33] : ""; - entry.content_flags_disabled = row[34] ? row[34] : ""; + entry.dz_switch_id = atoi(row[31]); + entry.min_expansion = atoi(row[32]); + entry.max_expansion = atoi(row[33]); + entry.content_flags = row[34] ? row[34] : ""; + entry.content_flags_disabled = row[35] ? row[35] : ""; all_entries.push_back(entry); } diff --git a/common/repositories/base/base_dynamic_zones_repository.h b/common/repositories/base/base_dynamic_zones_repository.h index 55217dafe..69cd8d3fa 100644 --- a/common/repositories/base/base_dynamic_zones_repository.h +++ b/common/repositories/base/base_dynamic_zones_repository.h @@ -27,6 +27,7 @@ public: int leader_id; int min_players; int max_players; + int dz_switch_id; int compass_zone_id; float compass_x; float compass_y; @@ -59,6 +60,7 @@ public: "leader_id", "min_players", "max_players", + "dz_switch_id", "compass_zone_id", "compass_x", "compass_y", @@ -87,6 +89,7 @@ public: "leader_id", "min_players", "max_players", + "dz_switch_id", "compass_zone_id", "compass_x", "compass_y", @@ -149,6 +152,7 @@ public: entry.leader_id = 0; entry.min_players = 0; entry.max_players = 0; + entry.dz_switch_id = 0; entry.compass_zone_id = 0; entry.compass_x = 0; entry.compass_y = 0; @@ -206,20 +210,21 @@ public: entry.leader_id = atoi(row[5]); entry.min_players = atoi(row[6]); entry.max_players = atoi(row[7]); - entry.compass_zone_id = atoi(row[8]); - entry.compass_x = static_cast(atof(row[9])); - entry.compass_y = static_cast(atof(row[10])); - entry.compass_z = static_cast(atof(row[11])); - entry.safe_return_zone_id = atoi(row[12]); - entry.safe_return_x = static_cast(atof(row[13])); - entry.safe_return_y = static_cast(atof(row[14])); - entry.safe_return_z = static_cast(atof(row[15])); - entry.safe_return_heading = static_cast(atof(row[16])); - entry.zone_in_x = static_cast(atof(row[17])); - entry.zone_in_y = static_cast(atof(row[18])); - entry.zone_in_z = static_cast(atof(row[19])); - entry.zone_in_heading = static_cast(atof(row[20])); - entry.has_zone_in = atoi(row[21]); + entry.dz_switch_id = atoi(row[8]); + entry.compass_zone_id = atoi(row[9]); + entry.compass_x = static_cast(atof(row[10])); + entry.compass_y = static_cast(atof(row[11])); + entry.compass_z = static_cast(atof(row[12])); + entry.safe_return_zone_id = atoi(row[13]); + entry.safe_return_x = static_cast(atof(row[14])); + entry.safe_return_y = static_cast(atof(row[15])); + entry.safe_return_z = static_cast(atof(row[16])); + entry.safe_return_heading = static_cast(atof(row[17])); + entry.zone_in_x = static_cast(atof(row[18])); + entry.zone_in_y = static_cast(atof(row[19])); + entry.zone_in_z = static_cast(atof(row[20])); + entry.zone_in_heading = static_cast(atof(row[21])); + entry.has_zone_in = atoi(row[22]); return entry; } @@ -260,20 +265,21 @@ public: update_values.push_back(columns[5] + " = " + std::to_string(dynamic_zones_entry.leader_id)); update_values.push_back(columns[6] + " = " + std::to_string(dynamic_zones_entry.min_players)); update_values.push_back(columns[7] + " = " + std::to_string(dynamic_zones_entry.max_players)); - update_values.push_back(columns[8] + " = " + std::to_string(dynamic_zones_entry.compass_zone_id)); - update_values.push_back(columns[9] + " = " + std::to_string(dynamic_zones_entry.compass_x)); - update_values.push_back(columns[10] + " = " + std::to_string(dynamic_zones_entry.compass_y)); - update_values.push_back(columns[11] + " = " + std::to_string(dynamic_zones_entry.compass_z)); - update_values.push_back(columns[12] + " = " + std::to_string(dynamic_zones_entry.safe_return_zone_id)); - update_values.push_back(columns[13] + " = " + std::to_string(dynamic_zones_entry.safe_return_x)); - update_values.push_back(columns[14] + " = " + std::to_string(dynamic_zones_entry.safe_return_y)); - update_values.push_back(columns[15] + " = " + std::to_string(dynamic_zones_entry.safe_return_z)); - update_values.push_back(columns[16] + " = " + std::to_string(dynamic_zones_entry.safe_return_heading)); - update_values.push_back(columns[17] + " = " + std::to_string(dynamic_zones_entry.zone_in_x)); - update_values.push_back(columns[18] + " = " + std::to_string(dynamic_zones_entry.zone_in_y)); - update_values.push_back(columns[19] + " = " + std::to_string(dynamic_zones_entry.zone_in_z)); - update_values.push_back(columns[20] + " = " + std::to_string(dynamic_zones_entry.zone_in_heading)); - update_values.push_back(columns[21] + " = " + std::to_string(dynamic_zones_entry.has_zone_in)); + update_values.push_back(columns[8] + " = " + std::to_string(dynamic_zones_entry.dz_switch_id)); + update_values.push_back(columns[9] + " = " + std::to_string(dynamic_zones_entry.compass_zone_id)); + update_values.push_back(columns[10] + " = " + std::to_string(dynamic_zones_entry.compass_x)); + update_values.push_back(columns[11] + " = " + std::to_string(dynamic_zones_entry.compass_y)); + update_values.push_back(columns[12] + " = " + std::to_string(dynamic_zones_entry.compass_z)); + update_values.push_back(columns[13] + " = " + std::to_string(dynamic_zones_entry.safe_return_zone_id)); + update_values.push_back(columns[14] + " = " + std::to_string(dynamic_zones_entry.safe_return_x)); + update_values.push_back(columns[15] + " = " + std::to_string(dynamic_zones_entry.safe_return_y)); + update_values.push_back(columns[16] + " = " + std::to_string(dynamic_zones_entry.safe_return_z)); + update_values.push_back(columns[17] + " = " + std::to_string(dynamic_zones_entry.safe_return_heading)); + update_values.push_back(columns[18] + " = " + std::to_string(dynamic_zones_entry.zone_in_x)); + update_values.push_back(columns[19] + " = " + std::to_string(dynamic_zones_entry.zone_in_y)); + update_values.push_back(columns[20] + " = " + std::to_string(dynamic_zones_entry.zone_in_z)); + update_values.push_back(columns[21] + " = " + std::to_string(dynamic_zones_entry.zone_in_heading)); + update_values.push_back(columns[22] + " = " + std::to_string(dynamic_zones_entry.has_zone_in)); auto results = db.QueryDatabase( fmt::format( @@ -303,6 +309,7 @@ public: insert_values.push_back(std::to_string(dynamic_zones_entry.leader_id)); insert_values.push_back(std::to_string(dynamic_zones_entry.min_players)); insert_values.push_back(std::to_string(dynamic_zones_entry.max_players)); + insert_values.push_back(std::to_string(dynamic_zones_entry.dz_switch_id)); insert_values.push_back(std::to_string(dynamic_zones_entry.compass_zone_id)); insert_values.push_back(std::to_string(dynamic_zones_entry.compass_x)); insert_values.push_back(std::to_string(dynamic_zones_entry.compass_y)); @@ -354,6 +361,7 @@ public: insert_values.push_back(std::to_string(dynamic_zones_entry.leader_id)); insert_values.push_back(std::to_string(dynamic_zones_entry.min_players)); insert_values.push_back(std::to_string(dynamic_zones_entry.max_players)); + insert_values.push_back(std::to_string(dynamic_zones_entry.dz_switch_id)); insert_values.push_back(std::to_string(dynamic_zones_entry.compass_zone_id)); insert_values.push_back(std::to_string(dynamic_zones_entry.compass_x)); insert_values.push_back(std::to_string(dynamic_zones_entry.compass_y)); @@ -409,20 +417,21 @@ public: entry.leader_id = atoi(row[5]); entry.min_players = atoi(row[6]); entry.max_players = atoi(row[7]); - entry.compass_zone_id = atoi(row[8]); - entry.compass_x = static_cast(atof(row[9])); - entry.compass_y = static_cast(atof(row[10])); - entry.compass_z = static_cast(atof(row[11])); - entry.safe_return_zone_id = atoi(row[12]); - entry.safe_return_x = static_cast(atof(row[13])); - entry.safe_return_y = static_cast(atof(row[14])); - entry.safe_return_z = static_cast(atof(row[15])); - entry.safe_return_heading = static_cast(atof(row[16])); - entry.zone_in_x = static_cast(atof(row[17])); - entry.zone_in_y = static_cast(atof(row[18])); - entry.zone_in_z = static_cast(atof(row[19])); - entry.zone_in_heading = static_cast(atof(row[20])); - entry.has_zone_in = atoi(row[21]); + entry.dz_switch_id = atoi(row[8]); + entry.compass_zone_id = atoi(row[9]); + entry.compass_x = static_cast(atof(row[10])); + entry.compass_y = static_cast(atof(row[11])); + entry.compass_z = static_cast(atof(row[12])); + entry.safe_return_zone_id = atoi(row[13]); + entry.safe_return_x = static_cast(atof(row[14])); + entry.safe_return_y = static_cast(atof(row[15])); + entry.safe_return_z = static_cast(atof(row[16])); + entry.safe_return_heading = static_cast(atof(row[17])); + entry.zone_in_x = static_cast(atof(row[18])); + entry.zone_in_y = static_cast(atof(row[19])); + entry.zone_in_z = static_cast(atof(row[20])); + entry.zone_in_heading = static_cast(atof(row[21])); + entry.has_zone_in = atoi(row[22]); all_entries.push_back(entry); } @@ -455,20 +464,21 @@ public: entry.leader_id = atoi(row[5]); entry.min_players = atoi(row[6]); entry.max_players = atoi(row[7]); - entry.compass_zone_id = atoi(row[8]); - entry.compass_x = static_cast(atof(row[9])); - entry.compass_y = static_cast(atof(row[10])); - entry.compass_z = static_cast(atof(row[11])); - entry.safe_return_zone_id = atoi(row[12]); - entry.safe_return_x = static_cast(atof(row[13])); - entry.safe_return_y = static_cast(atof(row[14])); - entry.safe_return_z = static_cast(atof(row[15])); - entry.safe_return_heading = static_cast(atof(row[16])); - entry.zone_in_x = static_cast(atof(row[17])); - entry.zone_in_y = static_cast(atof(row[18])); - entry.zone_in_z = static_cast(atof(row[19])); - entry.zone_in_heading = static_cast(atof(row[20])); - entry.has_zone_in = atoi(row[21]); + entry.dz_switch_id = atoi(row[8]); + entry.compass_zone_id = atoi(row[9]); + entry.compass_x = static_cast(atof(row[10])); + entry.compass_y = static_cast(atof(row[11])); + entry.compass_z = static_cast(atof(row[12])); + entry.safe_return_zone_id = atoi(row[13]); + entry.safe_return_x = static_cast(atof(row[14])); + entry.safe_return_y = static_cast(atof(row[15])); + entry.safe_return_z = static_cast(atof(row[16])); + entry.safe_return_heading = static_cast(atof(row[17])); + entry.zone_in_x = static_cast(atof(row[18])); + entry.zone_in_y = static_cast(atof(row[19])); + entry.zone_in_z = static_cast(atof(row[20])); + entry.zone_in_heading = static_cast(atof(row[21])); + entry.has_zone_in = atoi(row[22]); all_entries.push_back(entry); } diff --git a/common/repositories/dynamic_zones_repository.h b/common/repositories/dynamic_zones_repository.h index 8af92bf25..af3f91bc1 100644 --- a/common/repositories/dynamic_zones_repository.h +++ b/common/repositories/dynamic_zones_repository.h @@ -75,6 +75,7 @@ public: int max_players; int instance_id; int type; + int dz_switch_id; int compass_zone_id; float compass_x; float compass_y; @@ -109,6 +110,7 @@ public: dynamic_zones.max_players, dynamic_zones.instance_id, dynamic_zones.type, + dynamic_zones.dz_switch_id, dynamic_zones.compass_zone_id, dynamic_zones.compass_x, dynamic_zones.compass_y, @@ -147,6 +149,7 @@ public: entry.max_players = strtol(row[col++], nullptr, 10); entry.instance_id = strtol(row[col++], nullptr, 10); entry.type = strtol(row[col++], nullptr, 10); + entry.dz_switch_id = strtol(row[col++], nullptr, 10); entry.compass_zone_id = strtol(row[col++], nullptr, 10); entry.compass_x = strtof(row[col++], nullptr); entry.compass_y = strtof(row[col++], nullptr); @@ -261,6 +264,18 @@ public: } } + static void UpdateSwitchID(Database& db, uint32_t dz_id, int dz_switch_id) + { + if (dz_id != 0) + { + std::string query = fmt::format(SQL( + UPDATE {} SET dz_switch_id = {} WHERE {} = {}; + ), TableName(), dz_switch_id, PrimaryKey(), dz_id); + + db.QueryDatabase(query); + } + } + struct DynamicZoneInstancePlayerCount { uint32_t id; diff --git a/common/servertalk.h b/common/servertalk.h index f8f6b85ef..e0a791466 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -169,6 +169,8 @@ #define ServerOP_DzExpireWarning 0x045b #define ServerOP_DzCreated 0x045c #define ServerOP_DzDeleted 0x045d +#define ServerOP_DzSetSwitchID 0x045e +#define ServerOP_DzMovePC 0x045f #define ServerOP_LSInfo 0x1000 #define ServerOP_LSStatus 0x1001 @@ -1671,6 +1673,13 @@ struct ServerDzMemberStatuses_Struct { ServerDzMemberStatusEntry_Struct entries[0]; }; +struct ServerDzMovePC_Struct { + uint32 dz_id; + uint16 sender_zone_id; + uint16 sender_instance_id; + uint32 character_id; +}; + struct ServerExpeditionLockout_Struct { uint32 expedition_id; uint64 expire_time; @@ -1752,6 +1761,11 @@ struct ServerDzLocation_Struct { float heading; }; +struct ServerDzSwitchID_Struct { + uint32 dz_id; + int dz_switch_id; +}; + struct ServerDzMember_Struct { uint32 dz_id; uint16 dz_zone_id; diff --git a/common/version.h b/common/version.h index da9c42c28..1d8180440 100644 --- a/common/version.h +++ b/common/version.h @@ -34,7 +34,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9193 +#define CURRENT_BINARY_DATABASE_VERSION 9194 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9029 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 5af93b53d..24d397417 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -447,6 +447,7 @@ 9191|2022_07_28_gm_state_changes.sql|SHOW COLUMNS FROM `account` LIKE 'invulnerable'|empty| 9192|2022_07_13_task_lock_activity.sql|SHOW COLUMNS FROM `tasks` LIKE 'lock_activity_id'|empty| 9193|2022_07_16_task_timer_groups.sql|SHOW COLUMNS FROM `tasks` LIKE 'replay_timer_group'|empty| +9194|2022_07_23_dz_switch_id.sql|SHOW COLUMNS FROM `doors` LIKE 'dz_switch_id'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2022_07_23_dz_switch_id.sql b/utils/sql/git/required/2022_07_23_dz_switch_id.sql new file mode 100644 index 000000000..55ecdce71 --- /dev/null +++ b/utils/sql/git/required/2022_07_23_dz_switch_id.sql @@ -0,0 +1,5 @@ +ALTER TABLE `doors` + ADD COLUMN `dz_switch_id` INT NOT NULL DEFAULT '0' AFTER `is_ldon_door`; + +ALTER TABLE `dynamic_zones` + ADD COLUMN `dz_switch_id` INT NOT NULL DEFAULT '0' AFTER `max_players`; diff --git a/world/dynamic_zone.cpp b/world/dynamic_zone.cpp index 945b41ec9..3a23c186d 100644 --- a/world/dynamic_zone.cpp +++ b/world/dynamic_zone.cpp @@ -197,6 +197,17 @@ void DynamicZone::HandleZoneMessage(ServerPacket* pack) zoneserver_list.SendPacket(pack); break; } + case ServerOP_DzSetSwitchID: + { + auto buf = reinterpret_cast(pack->pBuffer); + auto dz = DynamicZone::FindDynamicZoneByID(buf->dz_id); + if (dz) + { + dz->ProcessSetSwitchID(buf->dz_switch_id); + } + zoneserver_list.SendPacket(pack); + break; + } case ServerOP_DzAddRemoveMember: { auto buf = reinterpret_cast(pack->pBuffer); @@ -266,6 +277,16 @@ void DynamicZone::HandleZoneMessage(ServerPacket* pack) zoneserver_list.SendPacket(pack); break; } + case ServerOP_DzMovePC: + { + auto buf = reinterpret_cast(pack->pBuffer); + auto dz = DynamicZone::FindDynamicZoneByID(buf->dz_id); + if (dz && dz->HasMember(buf->character_id)) + { + zoneserver_list.SendPacket(buf->sender_zone_id, buf->sender_instance_id, pack); + } + break; + } }; } diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 9504b2f3a..5238628ce 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1417,6 +1417,8 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { case ServerOP_DzSetCompass: case ServerOP_DzSetSafeReturn: case ServerOP_DzSetZoneIn: + case ServerOP_DzSetSwitchID: + case ServerOP_DzMovePC: case ServerOP_DzUpdateMemberStatus: { DynamicZone::HandleZoneMessage(pack); break; diff --git a/zone/client.cpp b/zone/client.cpp index 346a4c719..d5a848f2b 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -10103,12 +10103,23 @@ void Client::SendDzCompassUpdate() // client may be associated with multiple dynamic zone compasses in this zone std::vector compass_entries; + // need to sort by local doorid in case multiple have same dz switch id (live only sends first) + // todo: just store zone's door list ordered and ditch this + std::vector switches; + switches.reserve(entity_list.GetDoorsList().size()); + for (const auto& door_pair : entity_list.GetDoorsList()) + { + switches.push_back(door_pair.second); + } + std::sort(switches.begin(), switches.end(), + [](Doors* lhs, Doors* rhs) { return lhs->GetDoorID() < rhs->GetDoorID(); }); + for (const auto& client_dz : GetDynamicZones()) { auto compass = client_dz->GetCompassLocation(); if (zone && zone->IsZone(compass.zone_id, 0)) { - DynamicZoneCompassEntry_Struct entry; + DynamicZoneCompassEntry_Struct entry{}; entry.dz_zone_id = client_dz->GetZoneID(); entry.dz_instance_id = client_dz->GetInstanceID(); entry.dz_type = static_cast(client_dz->GetType()); @@ -10118,12 +10129,36 @@ void Client::SendDzCompassUpdate() compass_entries.emplace_back(entry); } + + // if client has a dz with a switch id add compass to any switch locs that share it + if (client_dz->GetSwitchID() != 0) + { + // live only sends one if multiple in zone have the same switch id + auto it = std::find_if(switches.begin(), switches.end(), + [&](const auto& eqswitch) { + return eqswitch->GetDzSwitchID() == client_dz->GetSwitchID(); + }); + + if (it != switches.end()) + { + DynamicZoneCompassEntry_Struct entry{}; + entry.dz_zone_id = client_dz->GetZoneID(); + entry.dz_instance_id = client_dz->GetInstanceID(); + entry.dz_type = static_cast(client_dz->GetType()); + entry.dz_switch_id = client_dz->GetSwitchID(); + entry.x = (*it)->GetX(); + entry.y = (*it)->GetY(); + entry.z = (*it)->GetZ(); + + compass_entries.emplace_back(entry); + } + } } // compass set via MarkSingleCompassLocation() if (m_has_quest_compass) { - DynamicZoneCompassEntry_Struct entry; + DynamicZoneCompassEntry_Struct entry{}; entry.dz_zone_id = 0; entry.dz_instance_id = 0; entry.dz_type = 0; @@ -10253,6 +10288,27 @@ void Client::MovePCDynamicZone(uint32 zone_id, int zone_version, bool msg_if_inv } } +bool Client::TryMovePCDynamicZoneSwitch(int dz_switch_id) +{ + auto client_dzs = GetDynamicZones(); + + std::vector switch_dzs; + auto it = std::copy_if(client_dzs.begin(), client_dzs.end(), std::back_inserter(switch_dzs), + [&](const DynamicZone* dz) { return dz->GetSwitchID() == dz_switch_id; }); + + if (switch_dzs.size() == 1) + { + LogDynamicZonesDetail("Moving client [{}] to dz with switch id [{}]", GetName(), dz_switch_id); + switch_dzs.front()->MovePCInto(this, true); + } + else if (switch_dzs.size() > 1) + { + QueuePacket(CreateDzSwitchListPacket(switch_dzs).get()); + } + + return !switch_dzs.empty(); +} + std::unique_ptr Client::CreateDzSwitchListPacket( const std::vector& client_dzs) { diff --git a/zone/client.h b/zone/client.h index e1b8db9b7..bd75e3145 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1405,8 +1405,9 @@ public: void SetDzRemovalTimer(bool enable_timer); void SendDzCompassUpdate(); void GoToDzSafeReturnOrBind(const DynamicZone* dynamic_zone); - void MovePCDynamicZone(uint32 zone_id, int zone_version = -1, bool msg_if_invalid = true); - void MovePCDynamicZone(const std::string& zone_name, int zone_version = -1, bool msg_if_invalid = true); + void MovePCDynamicZone(uint32 zone_id, int zone_version = -1, bool msg_if_invalid = false); + void MovePCDynamicZone(const std::string& zone_name, int zone_version = -1, bool msg_if_invalid = false); + bool TryMovePCDynamicZoneSwitch(int dz_switch_id); std::vector GetDynamicZones(uint32_t zone_id = 0, int zone_version = -1); std::unique_ptr CreateDzSwitchListPacket(const std::vector& dzs); std::unique_ptr CreateCompassPacket(const std::vector& entries); diff --git a/zone/doors.cpp b/zone/doors.cpp index 8de6ca295..a22560a2b 100644 --- a/zone/doors.cpp +++ b/zone/doors.cpp @@ -67,6 +67,7 @@ Doors::Doors(const DoorsRepository::Doors& door) : invert_state = door.invert_state; destination_instance_id = door.dest_instance; is_ldon_door = door.is_ldon_door; + m_dz_switch_id = door.dz_switch_id; client_version_mask = door.client_version_mask; SetOpenState(false); @@ -207,7 +208,15 @@ void Doors::HandleClick(Client* sender, uint8 trigger) { } } - // todo: if IsDzDoor() call Client::MovePCDynamicZone(target_zone_id) (for systems that use dzs) + if (m_dz_switch_id != 0) + { + // todo: update task touch task events with matching dz switch id + if (sender->TryMovePCDynamicZoneSwitch(m_dz_switch_id)) + { + safe_delete(outapp); + return; + } + } uint32 required_key_item = GetKeyItem(); uint8 disable_add_to_key_ring = GetNoKeyring(); diff --git a/zone/doors.h b/zone/doors.h index a0d9c6364..b8a65ffdc 100644 --- a/zone/doors.h +++ b/zone/doors.h @@ -25,6 +25,7 @@ public: char *GetDoorName() { return door_name; } const glm::vec4 GetDestination() const { return m_Destination; } const glm::vec4 &GetPosition() const { return m_Position; } + int GetDzSwitchID() const { return m_dz_switch_id; } int GetIncline() { return incline; } int GetInvertState() { return invert_state; } uint8 GetDoorID() { return door_id; } @@ -91,6 +92,7 @@ private: int destination_instance_id; glm::vec4 m_Destination; uint8 is_ldon_door; + int m_dz_switch_id = 0; uint32 client_version_mask; }; #endif diff --git a/zone/dynamic_zone.cpp b/zone/dynamic_zone.cpp index a7f2bb822..9243f7b82 100644 --- a/zone/dynamic_zone.cpp +++ b/zone/dynamic_zone.cpp @@ -363,6 +363,16 @@ void DynamicZone::HandleWorldMessage(ServerPacket* pack) } break; } + case ServerOP_DzSetSwitchID: + { + auto buf = reinterpret_cast(pack->pBuffer); + auto dz = DynamicZone::FindDynamicZoneByID(buf->dz_id); + if (dz) + { + dz->ProcessSetSwitchID(buf->dz_switch_id); + } + break; + } case ServerOP_DzGetMemberStatuses: { // reply from world for online member statuses request for async zone member updates @@ -414,6 +424,20 @@ void DynamicZone::HandleWorldMessage(ServerPacket* pack) } break; } + case ServerOP_DzMovePC: + { + auto buf = reinterpret_cast(pack->pBuffer); + auto dz = DynamicZone::FindDynamicZoneByID(buf->dz_id); + if (dz) + { + Client* client = entity_list.GetClientByCharID(buf->character_id); + if (client) + { + dz->MovePCInto(client, false); + } + } + break; + } } } @@ -517,6 +541,12 @@ void DynamicZone::SendCompassUpdateToZoneMembers() } } +void DynamicZone::ProcessSetSwitchID(int dz_switch_id) +{ + DynamicZoneBase::ProcessSetSwitchID(dz_switch_id); + SendCompassUpdateToZoneMembers(); +} + void DynamicZone::SendLeaderNameToZoneMembers() { auto outapp_leader = CreateLeaderNamePacket(); @@ -777,3 +807,23 @@ bool DynamicZone::CanClientLootCorpse(Client* client, uint32_t npc_type_id, uint return true; } + +void DynamicZone::MovePCInto(Client* client, bool world_verify) const +{ + if (!world_verify) + { + DynamicZoneLocation zonein = GetZoneInLocation(); + ZoneMode zone_mode = HasZoneInLocation() ? ZoneMode::ZoneSolicited : ZoneMode::ZoneToSafeCoords; + client->MovePC(GetZoneID(), GetInstanceID(), zonein.x, zonein.y, zonein.z, zonein.heading, 0, zone_mode); + } + else + { + ServerPacket pack(ServerOP_DzMovePC, sizeof(ServerDzMovePC_Struct)); + auto buf = reinterpret_cast(pack.pBuffer); + buf->dz_id = GetID(); + buf->sender_zone_id = static_cast(zone->GetZoneID()); + buf->sender_instance_id = static_cast(zone->GetInstanceID()); + buf->character_id = client->CharacterID(); + worldserver.SendPacket(&pack); + } +} diff --git a/zone/dynamic_zone.h b/zone/dynamic_zone.h index de23ce238..bbe21cd46 100644 --- a/zone/dynamic_zone.h +++ b/zone/dynamic_zone.h @@ -53,6 +53,7 @@ public: void DoAsyncZoneMemberUpdates(); bool CanClientLootCorpse(Client* client, uint32_t npc_type_id, uint32_t entity_id); bool IsCurrentZoneDzInstance() const; + void MovePCInto(Client* client, bool world_verify = false) const; void RegisterOnClientAddRemove(std::function on_client_addremove); void SendClientWindowUpdate(Client* client); void SendLeaderNameToZoneMembers(); @@ -76,6 +77,7 @@ protected: void ProcessMemberAddRemove(const DynamicZoneMember& member, bool removed) override; bool ProcessMemberStatusChange(uint32_t member_id, DynamicZoneMemberStatus status) override; void ProcessRemoveAllMembers(bool silent = false) override; + void ProcessSetSwitchID(int dz_switch_id) override; bool SendServerPacket(ServerPacket* packet) override; private: diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index e706fa98f..869afc44d 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -1949,6 +1949,11 @@ Lua_Expedition Lua_Client::CreateExpedition(luabind::object expedition_table) { dz.SetZoneInLocation(zonein_loc); } + if (luabind::type(expedition_table["switchid"]) == LUA_TNUMBER) + { + dz.SetSwitchID(luabind::object_cast(expedition_table["switchid"])); + } + bool disable_messages = false; if (luabind::type(expedition_info["disable_messages"]) == LUA_TBOOLEAN) { @@ -2140,6 +2145,11 @@ void Lua_Client::CreateTaskDynamicZone(int task_id, luabind::object dz_table) { dz.SetZoneInLocation(zonein_loc); } + if (luabind::type(dz_table["switchid"]) == LUA_TNUMBER) + { + dz.SetSwitchID(luabind::object_cast(dz_table["switchid"])); + } + self->CreateTaskDynamicZone(task_id, dz); } diff --git a/zone/lua_expedition.cpp b/zone/lua_expedition.cpp index 0ed63782b..6955e54cb 100644 --- a/zone/lua_expedition.cpp +++ b/zone/lua_expedition.cpp @@ -212,6 +212,12 @@ void Lua_Expedition::SetSecondsRemaining(uint32_t seconds_remaining) self->GetDynamicZone()->SetSecondsRemaining(seconds_remaining); } +void Lua_Expedition::SetSwitchID(int dz_switch_id) +{ + Lua_Safe_Call_Void(); + self->GetDynamicZone()->SetSwitchID(dz_switch_id, true); +} + void Lua_Expedition::SetZoneInLocation(float x, float y, float z, float heading) { Lua_Safe_Call_Void(); self->GetDynamicZone()->SetZoneInLocation(x, y, z, heading, true); @@ -269,6 +275,7 @@ luabind::scope lua_register_expedition() { .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("SetSecondsRemaining", &Lua_Expedition::SetSecondsRemaining) + .def("SetSwitchID", &Lua_Expedition::SetSwitchID) .def("SetZoneInLocation", (void(Lua_Expedition::*)(float, float, float, float))&Lua_Expedition::SetZoneInLocation) .def("UpdateLockoutDuration", (void(Lua_Expedition::*)(std::string, uint32_t))&Lua_Expedition::UpdateLockoutDuration) .def("UpdateLockoutDuration", (void(Lua_Expedition::*)(std::string, uint32_t, bool))&Lua_Expedition::UpdateLockoutDuration); diff --git a/zone/lua_expedition.h b/zone/lua_expedition.h index d154f9323..a338e3272 100644 --- a/zone/lua_expedition.h +++ b/zone/lua_expedition.h @@ -90,6 +90,7 @@ public: void SetSafeReturn(uint32_t 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 SetSecondsRemaining(uint32_t seconds_remaining); + void SetSwitchID(int dz_switch_id); void SetZoneInLocation(float x, float y, float z, float heading); void UpdateLockoutDuration(std::string event_name, uint32_t duration); void UpdateLockoutDuration(std::string event_name, uint32_t duration, bool members_only); diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index 948a7077c..16186994d 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -1781,6 +1781,11 @@ Expedition* Perl_Client_CreateExpedition(Client* self, perl::reference table_ref dz.SetZoneInLocation(zonein); } + if (table.exists("switchid")) + { + dz.SetSwitchID(table["switchid"].as()); + } + if (expedition.exists("disable_messages")) { return self->CreateExpedition(dz, expedition["disable_messages"].as()); @@ -1829,6 +1834,11 @@ void Perl_Client_CreateTaskDynamicZone(Client* self, int task_id, perl::referenc dz.SetZoneInLocation(zonein); } + if (table.exists("switchid")) + { + dz.SetSwitchID(table["switchid"].as()); + } + self->CreateTaskDynamicZone(task_id, dz); } diff --git a/zone/perl_expedition.cpp b/zone/perl_expedition.cpp index 1a0b04487..b757aed39 100644 --- a/zone/perl_expedition.cpp +++ b/zone/perl_expedition.cpp @@ -195,6 +195,11 @@ void Perl_Expedition_SetSecondsRemaining(Expedition* self, uint32_t seconds_rema self->GetDynamicZone()->SetSecondsRemaining(seconds_remaining); } +void Perl_Expedition_SetSwitchID(Expedition* self, int dz_switch_id) +{ + self->GetDynamicZone()->SetSwitchID(dz_switch_id, true); +} + void Perl_Expedition_SetZoneInLocation(Expedition* self, float x, float y, float z, float heading) { self->GetDynamicZone()->SetZoneInLocation(x, y, z, heading, true); @@ -250,6 +255,7 @@ void perl_register_expedition() package.add("SetReplayLockoutOnMemberJoin", &Perl_Expedition_SetReplayLockoutOnMemberJoin); package.add("SetSafeReturn", &Perl_Expedition_SetSafeReturn); package.add("SetSecondsRemaining", &Perl_Expedition_SetSecondsRemaining); + package.add("SetSwitchID", &Perl_Expedition_SetSwitchID); package.add("SetZoneInLocation", &Perl_Expedition_SetZoneInLocation); package.add("UpdateLockoutDuration", (void(*)(Expedition*, std::string, uint32_t))&Perl_Expedition_UpdateLockoutDuration); package.add("UpdateLockoutDuration", (void(*)(Expedition*, std::string, uint32_t, bool))&Perl_Expedition_UpdateLockoutDuration); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index a98ae7f10..980d71d23 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -3227,9 +3227,11 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) case ServerOP_DzSetCompass: case ServerOP_DzSetSafeReturn: case ServerOP_DzSetZoneIn: + case ServerOP_DzSetSwitchID: case ServerOP_DzUpdateMemberStatus: case ServerOP_DzLeaderChanged: case ServerOP_DzExpireWarning: + case ServerOP_DzMovePC: { DynamicZone::HandleWorldMessage(pack); break;