[Dynamic Zones] Implement dz switch id (#2343)

This adds the `dz_switch_id` field to doors and dynamic_zones. It will
allow for compasses to be automatically added to dz entrances and will
support moving clients to the dz on use without needing to script it.
These can be imported for switches/doors from live packet dumps.

Also removes compass packet encoders (same struct in all clients)
This commit is contained in:
hg
2022-07-30 22:00:11 -04:00
committed by GitHub
parent 1351f147f4
commit 676467cbdc
42 changed files with 349 additions and 235 deletions
+58 -2
View File
@@ -10103,12 +10103,23 @@ void Client::SendDzCompassUpdate()
// client may be associated with multiple dynamic zone compasses in this zone
std::vector<DynamicZoneCompassEntry_Struct> 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<Doors*> 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<uint32_t>(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<uint32_t>(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<DynamicZone*> 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<EQApplicationPacket> Client::CreateDzSwitchListPacket(
const std::vector<DynamicZone*>& client_dzs)
{
+3 -2
View File
@@ -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<DynamicZone*> GetDynamicZones(uint32_t zone_id = 0, int zone_version = -1);
std::unique_ptr<EQApplicationPacket> CreateDzSwitchListPacket(const std::vector<DynamicZone*>& dzs);
std::unique_ptr<EQApplicationPacket> CreateCompassPacket(const std::vector<DynamicZoneCompassEntry_Struct>& entries);
+10 -1
View File
@@ -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();
+2
View File
@@ -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
+50
View File
@@ -363,6 +363,16 @@ void DynamicZone::HandleWorldMessage(ServerPacket* pack)
}
break;
}
case ServerOP_DzSetSwitchID:
{
auto buf = reinterpret_cast<ServerDzSwitchID_Struct*>(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<ServerDzMovePC_Struct*>(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<ServerDzMovePC_Struct*>(pack.pBuffer);
buf->dz_id = GetID();
buf->sender_zone_id = static_cast<uint16_t>(zone->GetZoneID());
buf->sender_instance_id = static_cast<uint16_t>(zone->GetInstanceID());
buf->character_id = client->CharacterID();
worldserver.SendPacket(&pack);
}
}
+2
View File
@@ -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<void(Client* client, bool removed, bool silent)> 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:
+10
View File
@@ -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<int>(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<int>(dz_table["switchid"]));
}
self->CreateTaskDynamicZone(task_id, dz);
}
+7
View File
@@ -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);
+1
View File
@@ -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);
+10
View File
@@ -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<int>());
}
if (expedition.exists("disable_messages"))
{
return self->CreateExpedition(dz, expedition["disable_messages"].as<bool>());
@@ -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<int>());
}
self->CreateTaskDynamicZone(task_id, dz);
}
+6
View File
@@ -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);
+2
View File
@@ -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;