1
0

Added tracking of zone duplicate id (when its a public zone) to the characters table. We will now properly persist to the respective zone when a public zone becomes instanced.

This commit is contained in:
Emagi 2024-12-23 17:43:58 -05:00
parent 42173ceef2
commit 314fc8396c
8 changed files with 187 additions and 56 deletions

View File

@ -12081,9 +12081,12 @@ void Commands::Command_MoveCharacter(Client* client, Seperator* sep) {
{
char* name = sep->arg[0];
char* zoneName = sep->arg[1];
int32 zone_duplicating_id = 0;
if(sep->arg[2][0])
zone_duplicating_id = atoul(sep->arg[2]);
char query[256];
snprintf(query, 256, "UPDATE characters c, zones z set c.x = z.safe_x, c.y = z.safe_y, c.z = z.safe_z, c.heading = z.safe_heading, c.current_zone_id = z.id where c.name = '%s' and z.name='%s'", name, zoneName);
snprintf(query, 256, "UPDATE characters c, zones z set c.x = z.safe_x, c.y = z.safe_y, c.z = z.safe_z, c.heading = z.safe_heading, c.current_zone_id = z.id, c.zone_duplicating_id = %u where c.name = '%s' and z.name='%s'", zone_duplicating_id, name, zoneName);
if (database.RunQuery(query, strnlen(query, 256)))
{
client->Message(CHANNEL_COLOR_YELLOW, "Ran query:%s", query);

View File

@ -170,7 +170,7 @@ void PeerManager::setZonePeerDataSelf(ZoneChangeDetails* opt_details, std::strin
}
}
std::string PeerManager::getZonePeerId(const std::string& inc_zone_name, int32 inc_zone_id, int32 inc_instance_id, ZoneChangeDetails* opt_details, bool only_always_loaded) {
std::string PeerManager::getZonePeerId(const std::string& inc_zone_name, int32 inc_zone_id, int32 inc_instance_id, ZoneChangeDetails* opt_details, bool only_always_loaded, int32 matchDuplicatedId) {
bool matchFullZone = false;
std::string fullZoneId = "";
for (auto& [peerId, peer] : peers) {
@ -201,12 +201,16 @@ std::string PeerManager::getZonePeerId(const std::string& inc_zone_name, int32 i
int32 default_reenter_time = zone.second.get<int32>("default_reenter_time");
int8 instance_type = zone.second.get<int8>("instance_type");
bool always_loaded = zone.second.get<bool>("always_loaded");
int32 duplicate_id = zone.second.get<int32>("duplicated_id");
if (only_always_loaded && !always_loaded)
continue;
if (!shutting_down) {
bool match = false;
if(matchDuplicatedId > 0 && duplicate_id != matchDuplicatedId)
continue;
if (instance_zone && inc_instance_id > 0 && instance_id == inc_instance_id) {
match = true;
}
@ -244,7 +248,7 @@ std::string PeerManager::getZonePeerId(const std::string& inc_zone_name, int32 i
return fullZoneId;
}
int32 PeerManager::getZoneHighestDuplicateId(const std::string& inc_zone_name, int32 inc_zone_id) {
int32 PeerManager::getZoneHighestDuplicateId(const std::string& inc_zone_name, int32 inc_zone_id, bool increment_new_value) {
int32 highestID = 0;
bool matched_zone = false;
for (auto& [peerId, peer] : peers) {
@ -281,7 +285,7 @@ int32 PeerManager::getZoneHighestDuplicateId(const std::string& inc_zone_name, i
}
}
if(matched_zone) {
if(matched_zone && increment_new_value) {
highestID++;
}

View File

@ -181,8 +181,8 @@ public:
void SendPeersChannelMessage(int32 group_id, std::string fromName, std::string message, int16 channel, int32 language_id = 0);
void SendPeersGuildChannelMessage(int32 guild_id, std::string fromName, std::string message, int16 channel, int32 language_id = 0);
void sendZonePeerList(Client* client);
std::string getZonePeerId(const std::string& inc_zone_name, int32 inc_zone_id, int32 inc_instance_id, ZoneChangeDetails* opt_details = nullptr, bool only_always_loaded = false);
int32 getZoneHighestDuplicateId(const std::string& inc_zone_name, int32 inc_zone_id);
std::string getZonePeerId(const std::string& inc_zone_name, int32 inc_zone_id, int32 inc_instance_id, ZoneChangeDetails* opt_details = nullptr, bool only_always_loaded = false, int32 matchDuplicatedId = 0);
int32 getZoneHighestDuplicateId(const std::string& inc_zone_name, int32 inc_zone_id, bool increment_new_value = true);
void setZonePeerData(ZoneChangeDetails* opt_details);
void setPrimary(const std::string& id);
bool hasPrimary();

View File

@ -1608,11 +1608,11 @@ void ZoneList::ReloadSpawns() {
}
int32 ZoneList::GetHighestDuplicateID(const std::string& inc_zone_name, int32 inc_zone_id)
int32 ZoneList::GetHighestDuplicateID(const std::string& inc_zone_name, int32 inc_zone_id, bool increment_new_value)
{
list<ZoneServer*>::iterator zone_iter;
ZoneServer* tmp = 0;
int32 highest_id = peer_manager.getZoneHighestDuplicateId(inc_zone_name, inc_zone_id);
int32 highest_id = peer_manager.getZoneHighestDuplicateId(inc_zone_name, inc_zone_id, increment_new_value);
MZoneList.readlock(__FUNCTION__, __LINE__);
bool match = false;
bool matched_peer = (highest_id>0);
@ -1635,12 +1635,47 @@ int32 ZoneList::GetHighestDuplicateID(const std::string& inc_zone_name, int32 in
MZoneList.releasereadlock(__FUNCTION__, __LINE__);
if(match && !matched_peer)
if(match && !matched_peer && increment_new_value)
highest_id++;
return highest_id;
}
bool ZoneList::GetDuplicateZoneDetails(ZoneChangeDetails* zone_details, const std::string& inc_zone_name, int32 inc_zone_id, int32 matchDuplicateId)
{
list<ZoneServer*>::iterator zone_iter;
ZoneServer* tmp = 0;
std::string peerId = peer_manager.getZonePeerId(inc_zone_name, inc_zone_id, 0, zone_details, false, matchDuplicateId);
if(peerId.size() > 0)
return true;
MZoneList.readlock(__FUNCTION__, __LINE__);
bool match = false;
for(zone_iter=zlist.begin(); zone_iter!=zlist.end(); zone_iter++)
{
tmp = *zone_iter;
if(tmp->IsInstanceZone())
continue;
if(((inc_zone_id > 0 && tmp->GetZoneID() == inc_zone_id) || (inc_zone_name.length() > 0 && strncasecmp(tmp->GetZoneName(), inc_zone_name.c_str(), inc_zone_name.length())==0))){
if(tmp->DuplicatedID() == matchDuplicateId) {
peer_manager.setZonePeerDataSelf(zone_details, std::string(tmp->GetZoneFile()), std::string(tmp->GetZoneName()), tmp->GetZoneID(),
tmp->GetInstanceID(), tmp->GetSafeX(), tmp->GetSafeY(), tmp->GetSafeZ(), tmp->GetSafeHeading(),
tmp->GetZoneLockState(), tmp->GetMinimumStatus(), tmp->GetMinimumLevel(), tmp->GetMaximumLevel(),
tmp->GetMinimumVersion(), tmp->GetDefaultLockoutTime(), tmp->GetDefaultReenterTime(),
tmp->GetInstanceType(), tmp->NumPlayers(), tmp->IsCityZone(), tmp);
match = true;
break;
}
}
}
MZoneList.releasereadlock(__FUNCTION__, __LINE__);
return match;
}
bool World::ReportBug(string data, char* player_name, int32 account_id, const char* spawn_name, int32 spawn_id, int32 zone_id){
//loginserver
vector<string> list;

View File

@ -512,7 +512,8 @@ class ZoneList {
void ReloadMail();
void ReloadSpawns();
int32 GetHighestDuplicateID(const std::string& inc_zone_name, int32 inc_zone_id);
int32 GetHighestDuplicateID(const std::string& inc_zone_name, int32 inc_zone_id, bool increment_new_value = true);
bool GetDuplicateZoneDetails(ZoneChangeDetails* zone_details, const std::string& inc_zone_name, int32 inc_zone_id, int32 matchDuplicateId);
void WatchdogHeartbeat();

View File

@ -1780,7 +1780,7 @@ bool WorldDatabase::loadCharacter(const char* ch_name, int32 account_id, Client*
MYSQL_ROW row, row4;
int32 id = 0;
query.escaped_name = getEscapeString(ch_name);
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, current_zone_id, x, y, z, heading, admin_status, race, model_type, class, deity, level, gender, tradeskill_class, tradeskill_level, wing_type, hair_type, chest_type, legs_type, soga_wing_type, soga_hair_type, soga_chest_type, soga_legs_type, 0xFFFFFFFF - crc32(name), facial_hair_type, soga_facial_hair_type, instance_id, group_id, last_saved, DATEDIFF(curdate(), created_date) as accage, alignment, first_world_login FROM characters where name='%s' and account_id=%i AND deleted = 0", query.escaped_name, account_id);
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, current_zone_id, x, y, z, heading, admin_status, race, model_type, class, deity, level, gender, tradeskill_class, tradeskill_level, wing_type, hair_type, chest_type, legs_type, soga_wing_type, soga_hair_type, soga_chest_type, soga_legs_type, 0xFFFFFFFF - crc32(name), facial_hair_type, soga_facial_hair_type, instance_id, group_id, last_saved, DATEDIFF(curdate(), created_date) as accage, alignment, first_world_login, zone_duplicating_id FROM characters where name='%s' and account_id=%i AND deleted = 0", query.escaped_name, account_id);
// no character found
if ( result == NULL ) {
LogWrite(PLAYER__ERROR, 0, "Player", "Error loading character for '%s'", ch_name);
@ -1840,12 +1840,13 @@ SOGA chars looked ok in LoginServer screen tho... odd.
if ( LoadCharacterInstances(client) )
client->UpdateCharacterInstances();
int32 zone_duplicate_id = atoul(row[32]);
InstanceData* data = client->GetPlayer()->GetCharacterInstances()->FindInstanceByZoneID(zoneid);
// housing doesn't have a data pointer here is why the data check was removed.. hmm
if (instanceid > 0)
client->SetCurrentZoneByInstanceID(instanceid, zoneid);
else
client->SetCurrentZone(zoneid);
client->SetCurrentZone(zoneid, zone_duplicate_id);
int32 lastsavedtime = atoi(row[28]);
client->SetLastSavedTimeStamp(lastsavedtime);
@ -4378,7 +4379,7 @@ void WorldDatabase::Save(Client* client){
else if(client->GetCurrentZone())
zone_id = client->GetCurrentZone()->GetZoneID();
query.AddQueryAsync(client->GetCharacterID(), this, Q_UPDATE, "update characters set current_zone_id=%u, x=%f, y=%f, z=%f, heading=%f, level=%i,instance_id=%i,last_saved=%i, `class`=%i, `tradeskill_level`=%i, `tradeskill_class`=%i, `group_id`=%u, deity = %u, alignment = %u where id = %u", zone_id, player->GetX(), player->GetY(), player->GetZ(), player->GetHeading(), player->GetLevel(), instance_id, client->GetLastSavedTimeStamp(), client->GetPlayer()->GetAdventureClass(), client->GetPlayer()->GetTSLevel(), client->GetPlayer()->GetTradeskillClass(), client->GetPlayer()->GetGroupMemberInfo() ? client->GetPlayer()->GetGroupMemberInfo()->group_id : client->GetRejoinGroupID(), client->GetPlayer()->GetDeity(), client->GetPlayer()->GetInfoStruct()->get_alignment(), client->GetCharacterID());
query.AddQueryAsync(client->GetCharacterID(), this, Q_UPDATE, "update characters set current_zone_id=%u, x=%f, y=%f, z=%f, heading=%f, level=%i,instance_id=%i,last_saved=%i, `class`=%i, `tradeskill_level`=%i, `tradeskill_class`=%i, `group_id`=%u, deity = %u, alignment = %u, zone_duplicating_id = %u where id = %u", zone_id, player->GetX(), player->GetY(), player->GetZ(), player->GetHeading(), player->GetLevel(), instance_id, client->GetLastSavedTimeStamp(), client->GetPlayer()->GetAdventureClass(), client->GetPlayer()->GetTSLevel(), client->GetPlayer()->GetTradeskillClass(), client->GetPlayer()->GetGroupMemberInfo() ? client->GetPlayer()->GetGroupMemberInfo()->group_id : client->GetRejoinGroupID(), client->GetPlayer()->GetDeity(), client->GetPlayer()->GetInfoStruct()->get_alignment(), client->GetDuplicatingZoneID(), client->GetCharacterID());
query.AddQueryAsync(client->GetCharacterID(), this, Q_UPDATE, "update character_details set hp=%u, power=%u, str=%i, sta=%i, agi=%i, wis=%i, intel=%i, heat=%i, cold=%i, magic=%i, mental=%i, divine=%i, disease=%i, poison=%i, coin_copper=%u, coin_silver=%u, coin_gold=%u, coin_plat=%u, max_hp = %u, max_power=%u, xp = %u, xp_needed = %u, xp_debt = %f, xp_vitality = %f, tradeskill_xp = %u, tradeskill_xp_needed = %u, tradeskill_xp_vitality = %f, bank_copper = %u, bank_silver = %u, bank_gold = %u, bank_plat = %u, status_points = %u, bind_zone_id=%u, bind_x = %f, bind_y = %f, bind_z = %f, bind_heading = %f, house_zone_id=%u, combat_voice = %i, emote_voice = %i, biography='%s', flags=%u, flags2=%u, last_name='%s', assigned_aa = %i, unassigned_aa = %i, tradeskill_aa = %i, unassigned_tradeskill_aa = %i, prestige_aa = %i, unassigned_prestige_aa = %i, tradeskill_prestige_aa = %i, unassigned_tradeskill_prestige_aa = %i, pet_name = '%s' where char_id = %u",
player->GetHP(), player->GetPower(), player->GetStrBase(), player->GetStaBase(), player->GetAgiBase(), player->GetWisBase(), player->GetIntBase(), player->GetHeatResistanceBase(), player->GetColdResistanceBase(), player->GetMagicResistanceBase(),
player->GetMentalResistanceBase(), player->GetDivineResistanceBase(), player->GetDiseaseResistanceBase(), player->GetPoisonResistanceBase(), player->GetCoinsCopper(), player->GetCoinsSilver(), player->GetCoinsGold(), player->GetCoinsPlat(), player->GetTotalHPBase(), player->GetTotalPowerBase(), player->GetXP(), player->GetNeededXP(), player->GetXPDebt(), player->GetXPVitality(), player->GetTSXP(), player->GetNeededTSXP(), player->GetTSXPVitality(), player->GetBankCoinsCopper(),

View File

@ -166,6 +166,7 @@ Client::Client(EQStream* ieqs) : underworld_cooldown_timer(5000), pos_update(125
zoning_x = 0;
zoning_y = 0;
zoning_z = 0;
duplicate_zoning_id = 0;
zoning_instance_id = 0;
player_pos_changed = false;
player_pos_timer = Timer::GetCurrentTime2() + 1000;
@ -958,9 +959,8 @@ void Client::SendZoneInfo() {
QueuePacket(fog_packet->serialize());
safe_delete(fog_packet);
}
zone->SendFlightPathsPackets(this);
}
zone->SendFlightPathsPackets(this);
}
/*
uchar blah[] ={0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x01,0x00,0x00,0x00,0x00
@ -2753,33 +2753,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
case OP_ReadyForTakeOffMsg:
{
LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_ReadyForTakeOffMsg", opcode, opcode);
int32 index = GetCurrentZone()->GetFlightPathIndex(GetPendingFlightPath());
if (GetPendingFlightPath() > 0) {
if (index != -1) {
PacketStruct* packet = configReader.getStruct("WS_ClearForTakeOff", GetVersion());
if (packet) {
packet->setDataByName("spawn_id", GetPlayer()->GetIDWithPlayerSpawn(GetPlayer()));
packet->setDataByName("path_id", index);
packet->setDataByName("speed", GetCurrentZone()->GetFlightPathSpeed(GetPendingFlightPath()));
QueuePacket(packet->serialize());
safe_delete(packet);
on_auto_mount = true;
}
}
else {
LogWrite(CCLIENT__ERROR, 0, "Client", "OP_ReadyForTakeOffMsg recieved but unable to get an index for path (%u) in zone (%u)", GetPendingFlightPath(), GetCurrentZone()->GetZoneID());
Message(CHANNEL_ERROR, "Unable to get index for path (%u) in zone (%u)", GetPendingFlightPath(), GetCurrentZone()->GetZoneID());
EndAutoMount();
}
SetPendingFlightPath(0);
}
else
LogWrite(CCLIENT__ERROR, 0, "Client", "OP_ReadyForTakeOffMsg recieved but there is no pending flight path...");
AttemptStartAutoMount();
break;
}
@ -4133,15 +4107,25 @@ void Client::SetCurrentZone(ZoneServer* zone) {
if (player) {
player->SetZone(zone, GetVersion());
}
if(zone)
duplicate_zoning_id = zone->DuplicatedID();
}
void Client::SetCurrentZone(int32 id) {
void Client::SetCurrentZone(int32 id, int32 duplicate_zone_id) {
if (current_zone) {
//current_zone->GetCombat()->RemoveHate(player);
current_zone->RemoveSpawn(player, false, true, true, true, true);
}
duplicate_zoning_id = 0;
bool foundDupeZone = false;
ZoneChangeDetails zone_details;
if (zone_list.GetZone(&zone_details, id, "", true, false, true, false)) {
if(duplicate_zone_id) {
if(foundDupeZone = zone_list.GetDuplicateZoneDetails(&zone_details, "", id, duplicate_zone_id))
duplicate_zoning_id = duplicate_zone_id;
}
if (foundDupeZone || zone_list.GetZone(&zone_details, id, "", true, false, true, false)) {
SetCurrentZone((ZoneServer*)zone_details.zonePtr);
}
}
@ -4151,6 +4135,7 @@ void Client::SetCurrentZoneByInstanceID(int32 id, int32 zoneid) {
//current_zone->GetCombat()->RemoveHate(player);
current_zone->RemoveSpawn(player, false, true, true, true, true);
}
duplicate_zoning_id = 0;
ZoneChangeDetails zone_details;
int32 minLevel = 0, maxLevel = 0, avgLevel = 0, firstLevel = 0;
world.GetGroupManager()->EstablishRaidLevelRange(this, &minLevel, &maxLevel, &avgLevel, &firstLevel);
@ -4766,7 +4751,7 @@ bool Client::TryZoneInstance(int32 zoneID, bool zone_coords_valid) {
instance_zone->GetSafeZ(), instance_zone->GetSafeHeading(), instance_zone->GetZoneLockState(),
instance_zone->GetMinimumStatus(), instance_zone->GetMinimumLevel(), instance_zone->GetMaximumLevel(),
instance_zone->GetMinimumVersion(), instance_zone->GetDefaultLockoutTime(), instance_zone->GetDefaultReenterTime(),
instance_zone->GetInstanceType(), instance_zone->NumPlayers(), instance_zone);
instance_zone->GetInstanceType(), instance_zone->NumPlayers(), instance_zone->IsCityZone(), instance_zone);
}
}
else {
@ -10009,6 +9994,7 @@ void Client::ProcessTeleport(Spawn* spawn, vector<TransportDestination*>* destin
if (packet) {
packet->setDataByName("spawn_id", GetPlayer()->GetIDWithPlayerSpawn(spawn));
int32 additional_locations = 0;
// Put all the destinations the player can go in a new vector
vector<TransportDestination*> destinations;
for (int32 i = 0; i < transport_list.size(); i++) {
@ -10033,27 +10019,48 @@ void Client::ProcessTeleport(Spawn* spawn, vector<TransportDestination*>* destin
packet->setDataByName("current_map_y", destination->map_y);
}
else {
int32 additional_zones = zone_list.GetHighestDuplicateID("", destination->destination_zone_id, false);
additional_locations += additional_zones;
destinations.push_back(destination);
}
}
// Use the new vector to create the packet
destination = 0;
packet->setArrayLengthByName("num_destinations", destinations.size());
packet->setArrayLengthByName("num_destinations", additional_locations+destinations.size());
int32 offset = 0;
int32 unique_ids = 3000000; // db has hard cap of 2 million
for (int32 i = 0; i < destinations.size(); i++) {
destination = destinations.at(i);
packet->setArrayDataByName("unique_id", destination->unique_id, i);
packet->setArrayDataByName("display_name", destination->display_name.c_str(), i);
packet->setArrayDataByName("zone_name", destination->display_name.c_str(), i);
packet->setArrayDataByName("zone_file_name", destination->display_name.c_str(), i);
packet->setArrayDataByName("cost", destination->cost, i);
packet->setArrayDataByName("unique_id", destination->unique_id, i+offset);
packet->setArrayDataByName("display_name", destination->display_name.c_str(), i+offset);
packet->setArrayDataByName("zone_name", destination->display_name.c_str(), i+offset);
packet->setArrayDataByName("zone_file_name", destination->display_name.c_str(), i+offset);
packet->setArrayDataByName("cost", destination->cost, i+offset);
if (has_map) {
packet->setArrayDataByName("map_x", destination->map_x, i);
packet->setArrayDataByName("map_y", destination->map_y, i);
packet->setArrayDataByName("map_x", destination->map_x, i+offset);
packet->setArrayDataByName("map_y", destination->map_y, i+offset);
}
int32 additional_zones = zone_list.GetHighestDuplicateID("", destination->destination_zone_id, false);
for (int32 a = 0; a < additional_zones; a++) {
int32 field_pos = a+1;
packet->setArrayDataByName("unique_id", unique_ids++, i+offset+field_pos);
std::string name = destination->display_name + " " + std::to_string(field_pos);
packet->setArrayDataByName("display_name", name.c_str(), i+offset+field_pos);
packet->setArrayDataByName("zone_name", name.c_str(), i+offset+field_pos);
packet->setArrayDataByName("zone_file_name", destination->display_name.c_str(), i+offset+field_pos);
packet->setArrayDataByName("cost", destination->cost, i+offset+field_pos);
if (has_map) {
packet->setArrayDataByName("map_x", destination->map_x, i+offset+field_pos);
packet->setArrayDataByName("map_y", destination->map_y, i+offset+field_pos);
}
}
offset += additional_zones;
}
if (has_map)
@ -10069,6 +10076,7 @@ void Client::ProcessTeleport(Spawn* spawn, vector<TransportDestination*>* destin
}
void Client::ProcessTeleportLocation(EQApplicationPacket* app) {
int32 duplicateId = 0;
PacketStruct* packet = configReader.getStruct("WS_TeleportDestination", GetVersion());
if (packet) {
if (packet->LoadPacketData(app->pBuffer, app->size)) {
@ -10078,11 +10086,18 @@ void Client::ProcessTeleportLocation(EQApplicationPacket* app) {
int32 cost = packet->getType_int32_ByName("cost");
vector<TransportDestination*> destinations;
TransportDestination* destination = 0;
duplicateId = extractZoneNumericalSuffix(zone_name);
if(duplicateId > 0) {
size_t lastSpacePos = zone_name.find_last_of(' ');
if (lastSpacePos != std::string::npos) {
zone_name = zone_name.substr(0, lastSpacePos);
}
}
if (this->GetTemporaryTransportID() || (spawn && spawn == transport_spawn && spawn->GetTransporterID()))
GetCurrentZone()->GetTransporters(&destinations, this, this->GetTemporaryTransportID() ? this->GetTemporaryTransportID() : spawn->GetTransporterID());
vector<TransportDestination*>::iterator itr;
for (itr = destinations.begin(); itr != destinations.end(); itr++) {
if ((*itr)->unique_id == unique_id && (*itr)->display_name == zone_name && (*itr)->cost == cost) {
if (((*itr)->unique_id == unique_id || unique_id >= 3000000) && (*itr)->display_name == zone_name && (*itr)->cost == cost) {
destination = *itr;
break;
}
@ -10115,7 +10130,14 @@ void Client::ProcessTeleportLocation(EQApplicationPacket* app) {
if (!TryZoneInstance(destination->destination_zone_id, false)) {
LogWrite(INSTANCE__DEBUG, 0, "Instance", "Attempting to zone normally");
ZoneChangeDetails zone_details;
if (zone_list.GetZone(&zone_details, destination->destination_zone_id)) {
bool foundDupeZone = false;
duplicate_zoning_id = 0;
if(duplicateId > 0) {
if(foundDupeZone = zone_list.GetDuplicateZoneDetails(&zone_details, "", destination->destination_zone_id, duplicateId))
duplicate_zoning_id = duplicateId;
}
if (foundDupeZone || zone_list.GetZone(&zone_details, destination->destination_zone_id)) {
Zone(&zone_details, (ZoneServer*)zone_details.zonePtr, false);
}
}
@ -11587,6 +11609,34 @@ void Client::SavePlayerImages() {
incoming_paperdoll.current_size_bytes = 0;
}
void Client::AttemptStartAutoMount() {
int32 index = GetCurrentZone()->GetFlightPathIndex(GetPendingFlightPath());
if (GetPendingFlightPath() > 0) {
if (index != -1) {
PacketStruct* packet = configReader.getStruct("WS_ClearForTakeOff", GetVersion());
if (packet) {
packet->setDataByName("spawn_id", GetPlayer()->GetIDWithPlayerSpawn(GetPlayer()));
packet->setDataByName("path_id", index);
packet->setDataByName("speed", GetCurrentZone()->GetFlightPathSpeed(GetPendingFlightPath()));
QueuePacket(packet->serialize());
safe_delete(packet);
on_auto_mount = true;
}
}
else {
LogWrite(CCLIENT__ERROR, 0, "Client", "OP_ReadyForTakeOffMsg recieved but unable to get an index for path (%u) in zone (%u)", GetPendingFlightPath(), GetCurrentZone()->GetZoneID());
Message(CHANNEL_ERROR, "Unable to get index for path (%u) in zone (%u)", GetPendingFlightPath(), GetCurrentZone()->GetZoneID());
EndAutoMount();
}
SetPendingFlightPath(0);
}
else
LogWrite(CCLIENT__ERROR, 0, "Client", "OP_ReadyForTakeOffMsg recieved but there is no pending flight path...");
}
void Client::EndAutoMount() {
PacketStruct* packet = configReader.getStruct("WS_ServerControlFlags", GetVersion());
if (packet) {
@ -12208,6 +12258,20 @@ void Client::SendFlightAutoMount(int32 path_id, int16 mount_id, int8 mount_red_c
if (mount_id)
((Entity*)GetPlayer())->SetMount(mount_id, mount_red_color, mount_green_color, mount_blue_color);
if(GetVersion() <= 561) {
PacketStruct* packet = configReader.getStruct("WS_CreateBoatTransportMsg", GetVersion());
if (!packet) {
LogWrite(CCLIENT__ERROR, 0, "Client", "WS_CreateBoatTransportMsg missing for version %u", GetVersion());
return;
}
int8 index = (int8)GetCurrentZone()->GetFlightPathIndex(GetPendingFlightPath());
packet->setDataByName("path_id", index);
// packet->PrintPacket();
QueuePacket(packet->serialize());
safe_delete(packet);
AttemptStartAutoMount();
}
}
void Client::SendShowBook(Spawn* sender, string title, int8 language, int8 num_pages, ...)

View File

@ -30,6 +30,8 @@
#include <thread>
#include <chrono>
#include <condition_variable>
#include <regex>
#include <optional>
#include "../common/EQStream.h"
#include "../common/timer.h"
@ -314,12 +316,14 @@ public:
int32 GetCurrentZoneID();
void SetCurrentZoneByInstanceID(int32 id, int32 zoneid);
//void SetCurrentZoneByInstanceID(instanceid, zoneid);
void SetCurrentZone(int32 id);
void SetCurrentZone(int32 id, int32 zone_duplicate_id = 0);
void SetCurrentZone(ZoneServer* zone);
void SetZoningDestination(ZoneServer* zone) {
zoning_destination = zone;
}
ZoneServer* GetZoningDestination() { return zoning_destination; }
int32 GetDuplicatingZoneID() { return duplicate_zoning_id; }
Player* GetPlayer() { return player; }
EQStream* getConnection() { return eqs; }
void setConnection(EQStream* ieqs) { eqs = ieqs; }
@ -508,6 +512,24 @@ public:
void SetPendingFlightPath(int32 val) { pending_flight_path = val; }
int32 GetPendingFlightPath() { return pending_flight_path; }
void AttemptStartAutoMount();
int32 extractZoneNumericalSuffix(const std::string& input) {
try {
std::regex pattern(R"(.*\s(\d+)$)"); // Matches a space followed by digits at the end
std::smatch match;
if (std::regex_match(input, match, pattern)) {
return std::stoul(match[1].str()); // Extract and convert the numerical part
}
} catch (const std::regex_error& e) {
std::cerr << "Regex error: " << e.what() << "\n";
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << "\n";
}
return 0; // Return nullopt if no match is found or an exception occurs
}
void EndAutoMount();
bool GetOnAutoMount() { return on_auto_mount; }
@ -764,6 +786,7 @@ private:
int32 zoning_id;
int32 zoning_instance_id;
ZoneServer* zoning_destination;
int32 duplicate_zoning_id; // when a public zone is instanced for too many players this its number
float zoning_x;
float zoning_y;
float zoning_z;