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:
parent
42173ceef2
commit
314fc8396c
@ -12081,9 +12081,12 @@ void Commands::Command_MoveCharacter(Client* client, Seperator* sep) {
|
|||||||
{
|
{
|
||||||
char* name = sep->arg[0];
|
char* name = sep->arg[0];
|
||||||
char* zoneName = sep->arg[1];
|
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];
|
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)))
|
if (database.RunQuery(query, strnlen(query, 256)))
|
||||||
{
|
{
|
||||||
client->Message(CHANNEL_COLOR_YELLOW, "Ran query:%s", query);
|
client->Message(CHANNEL_COLOR_YELLOW, "Ran query:%s", query);
|
||||||
|
@ -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;
|
bool matchFullZone = false;
|
||||||
std::string fullZoneId = "";
|
std::string fullZoneId = "";
|
||||||
for (auto& [peerId, peer] : peers) {
|
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");
|
int32 default_reenter_time = zone.second.get<int32>("default_reenter_time");
|
||||||
int8 instance_type = zone.second.get<int8>("instance_type");
|
int8 instance_type = zone.second.get<int8>("instance_type");
|
||||||
bool always_loaded = zone.second.get<bool>("always_loaded");
|
bool always_loaded = zone.second.get<bool>("always_loaded");
|
||||||
|
int32 duplicate_id = zone.second.get<int32>("duplicated_id");
|
||||||
|
|
||||||
if (only_always_loaded && !always_loaded)
|
if (only_always_loaded && !always_loaded)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!shutting_down) {
|
if (!shutting_down) {
|
||||||
bool match = false;
|
bool match = false;
|
||||||
|
if(matchDuplicatedId > 0 && duplicate_id != matchDuplicatedId)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (instance_zone && inc_instance_id > 0 && instance_id == inc_instance_id) {
|
if (instance_zone && inc_instance_id > 0 && instance_id == inc_instance_id) {
|
||||||
match = true;
|
match = true;
|
||||||
}
|
}
|
||||||
@ -244,7 +248,7 @@ std::string PeerManager::getZonePeerId(const std::string& inc_zone_name, int32 i
|
|||||||
return fullZoneId;
|
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;
|
int32 highestID = 0;
|
||||||
bool matched_zone = false;
|
bool matched_zone = false;
|
||||||
for (auto& [peerId, peer] : peers) {
|
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++;
|
highestID++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,8 +181,8 @@ public:
|
|||||||
void SendPeersChannelMessage(int32 group_id, std::string fromName, std::string message, int16 channel, int32 language_id = 0);
|
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 SendPeersGuildChannelMessage(int32 guild_id, std::string fromName, std::string message, int16 channel, int32 language_id = 0);
|
||||||
void sendZonePeerList(Client* client);
|
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);
|
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);
|
int32 getZoneHighestDuplicateId(const std::string& inc_zone_name, int32 inc_zone_id, bool increment_new_value = true);
|
||||||
void setZonePeerData(ZoneChangeDetails* opt_details);
|
void setZonePeerData(ZoneChangeDetails* opt_details);
|
||||||
void setPrimary(const std::string& id);
|
void setPrimary(const std::string& id);
|
||||||
bool hasPrimary();
|
bool hasPrimary();
|
||||||
|
@ -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;
|
list<ZoneServer*>::iterator zone_iter;
|
||||||
ZoneServer* tmp = 0;
|
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__);
|
MZoneList.readlock(__FUNCTION__, __LINE__);
|
||||||
bool match = false;
|
bool match = false;
|
||||||
bool matched_peer = (highest_id>0);
|
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__);
|
MZoneList.releasereadlock(__FUNCTION__, __LINE__);
|
||||||
|
|
||||||
if(match && !matched_peer)
|
if(match && !matched_peer && increment_new_value)
|
||||||
highest_id++;
|
highest_id++;
|
||||||
|
|
||||||
return 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){
|
bool World::ReportBug(string data, char* player_name, int32 account_id, const char* spawn_name, int32 spawn_id, int32 zone_id){
|
||||||
//loginserver
|
//loginserver
|
||||||
vector<string> list;
|
vector<string> list;
|
||||||
|
@ -512,7 +512,8 @@ class ZoneList {
|
|||||||
void ReloadMail();
|
void ReloadMail();
|
||||||
void ReloadSpawns();
|
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();
|
void WatchdogHeartbeat();
|
||||||
|
|
||||||
|
@ -1780,7 +1780,7 @@ bool WorldDatabase::loadCharacter(const char* ch_name, int32 account_id, Client*
|
|||||||
MYSQL_ROW row, row4;
|
MYSQL_ROW row, row4;
|
||||||
int32 id = 0;
|
int32 id = 0;
|
||||||
query.escaped_name = getEscapeString(ch_name);
|
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
|
// no character found
|
||||||
if ( result == NULL ) {
|
if ( result == NULL ) {
|
||||||
LogWrite(PLAYER__ERROR, 0, "Player", "Error loading character for '%s'", ch_name);
|
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) )
|
if ( LoadCharacterInstances(client) )
|
||||||
client->UpdateCharacterInstances();
|
client->UpdateCharacterInstances();
|
||||||
|
|
||||||
|
int32 zone_duplicate_id = atoul(row[32]);
|
||||||
InstanceData* data = client->GetPlayer()->GetCharacterInstances()->FindInstanceByZoneID(zoneid);
|
InstanceData* data = client->GetPlayer()->GetCharacterInstances()->FindInstanceByZoneID(zoneid);
|
||||||
// housing doesn't have a data pointer here is why the data check was removed.. hmm
|
// housing doesn't have a data pointer here is why the data check was removed.. hmm
|
||||||
if (instanceid > 0)
|
if (instanceid > 0)
|
||||||
client->SetCurrentZoneByInstanceID(instanceid, zoneid);
|
client->SetCurrentZoneByInstanceID(instanceid, zoneid);
|
||||||
else
|
else
|
||||||
client->SetCurrentZone(zoneid);
|
client->SetCurrentZone(zoneid, zone_duplicate_id);
|
||||||
|
|
||||||
int32 lastsavedtime = atoi(row[28]);
|
int32 lastsavedtime = atoi(row[28]);
|
||||||
client->SetLastSavedTimeStamp(lastsavedtime);
|
client->SetLastSavedTimeStamp(lastsavedtime);
|
||||||
@ -4378,7 +4379,7 @@ void WorldDatabase::Save(Client* client){
|
|||||||
else if(client->GetCurrentZone())
|
else if(client->GetCurrentZone())
|
||||||
zone_id = client->GetCurrentZone()->GetZoneID();
|
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",
|
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->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(),
|
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(),
|
||||||
|
@ -166,6 +166,7 @@ Client::Client(EQStream* ieqs) : underworld_cooldown_timer(5000), pos_update(125
|
|||||||
zoning_x = 0;
|
zoning_x = 0;
|
||||||
zoning_y = 0;
|
zoning_y = 0;
|
||||||
zoning_z = 0;
|
zoning_z = 0;
|
||||||
|
duplicate_zoning_id = 0;
|
||||||
zoning_instance_id = 0;
|
zoning_instance_id = 0;
|
||||||
player_pos_changed = false;
|
player_pos_changed = false;
|
||||||
player_pos_timer = Timer::GetCurrentTime2() + 1000;
|
player_pos_timer = Timer::GetCurrentTime2() + 1000;
|
||||||
@ -958,9 +959,8 @@ void Client::SendZoneInfo() {
|
|||||||
QueuePacket(fog_packet->serialize());
|
QueuePacket(fog_packet->serialize());
|
||||||
safe_delete(fog_packet);
|
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
|
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:
|
case OP_ReadyForTakeOffMsg:
|
||||||
{
|
{
|
||||||
LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_ReadyForTakeOffMsg", opcode, opcode);
|
LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_ReadyForTakeOffMsg", opcode, opcode);
|
||||||
|
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...");
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4133,15 +4107,25 @@ void Client::SetCurrentZone(ZoneServer* zone) {
|
|||||||
if (player) {
|
if (player) {
|
||||||
player->SetZone(zone, GetVersion());
|
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) {
|
if (current_zone) {
|
||||||
//current_zone->GetCombat()->RemoveHate(player);
|
//current_zone->GetCombat()->RemoveHate(player);
|
||||||
current_zone->RemoveSpawn(player, false, true, true, true, true);
|
current_zone->RemoveSpawn(player, false, true, true, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
duplicate_zoning_id = 0;
|
||||||
|
bool foundDupeZone = false;
|
||||||
ZoneChangeDetails zone_details;
|
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);
|
SetCurrentZone((ZoneServer*)zone_details.zonePtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4151,6 +4135,7 @@ void Client::SetCurrentZoneByInstanceID(int32 id, int32 zoneid) {
|
|||||||
//current_zone->GetCombat()->RemoveHate(player);
|
//current_zone->GetCombat()->RemoveHate(player);
|
||||||
current_zone->RemoveSpawn(player, false, true, true, true, true);
|
current_zone->RemoveSpawn(player, false, true, true, true, true);
|
||||||
}
|
}
|
||||||
|
duplicate_zoning_id = 0;
|
||||||
ZoneChangeDetails zone_details;
|
ZoneChangeDetails zone_details;
|
||||||
int32 minLevel = 0, maxLevel = 0, avgLevel = 0, firstLevel = 0;
|
int32 minLevel = 0, maxLevel = 0, avgLevel = 0, firstLevel = 0;
|
||||||
world.GetGroupManager()->EstablishRaidLevelRange(this, &minLevel, &maxLevel, &avgLevel, &firstLevel);
|
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->GetSafeZ(), instance_zone->GetSafeHeading(), instance_zone->GetZoneLockState(),
|
||||||
instance_zone->GetMinimumStatus(), instance_zone->GetMinimumLevel(), instance_zone->GetMaximumLevel(),
|
instance_zone->GetMinimumStatus(), instance_zone->GetMinimumLevel(), instance_zone->GetMaximumLevel(),
|
||||||
instance_zone->GetMinimumVersion(), instance_zone->GetDefaultLockoutTime(), instance_zone->GetDefaultReenterTime(),
|
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 {
|
else {
|
||||||
@ -10009,6 +9994,7 @@ void Client::ProcessTeleport(Spawn* spawn, vector<TransportDestination*>* destin
|
|||||||
if (packet) {
|
if (packet) {
|
||||||
packet->setDataByName("spawn_id", GetPlayer()->GetIDWithPlayerSpawn(spawn));
|
packet->setDataByName("spawn_id", GetPlayer()->GetIDWithPlayerSpawn(spawn));
|
||||||
|
|
||||||
|
int32 additional_locations = 0;
|
||||||
// Put all the destinations the player can go in a new vector
|
// Put all the destinations the player can go in a new vector
|
||||||
vector<TransportDestination*> destinations;
|
vector<TransportDestination*> destinations;
|
||||||
for (int32 i = 0; i < transport_list.size(); i++) {
|
for (int32 i = 0; i < transport_list.size(); i++) {
|
||||||
@ -10033,26 +10019,47 @@ void Client::ProcessTeleport(Spawn* spawn, vector<TransportDestination*>* destin
|
|||||||
packet->setDataByName("current_map_y", destination->map_y);
|
packet->setDataByName("current_map_y", destination->map_y);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
int32 additional_zones = zone_list.GetHighestDuplicateID("", destination->destination_zone_id, false);
|
||||||
|
additional_locations += additional_zones;
|
||||||
destinations.push_back(destination);
|
destinations.push_back(destination);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the new vector to create the packet
|
// Use the new vector to create the packet
|
||||||
destination = 0;
|
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++) {
|
for (int32 i = 0; i < destinations.size(); i++) {
|
||||||
destination = destinations.at(i);
|
destination = destinations.at(i);
|
||||||
|
|
||||||
packet->setArrayDataByName("unique_id", destination->unique_id, i);
|
packet->setArrayDataByName("unique_id", destination->unique_id, i+offset);
|
||||||
packet->setArrayDataByName("display_name", destination->display_name.c_str(), i);
|
packet->setArrayDataByName("display_name", destination->display_name.c_str(), i+offset);
|
||||||
packet->setArrayDataByName("zone_name", destination->display_name.c_str(), i);
|
packet->setArrayDataByName("zone_name", destination->display_name.c_str(), i+offset);
|
||||||
packet->setArrayDataByName("zone_file_name", destination->display_name.c_str(), i);
|
packet->setArrayDataByName("zone_file_name", destination->display_name.c_str(), i+offset);
|
||||||
packet->setArrayDataByName("cost", destination->cost, i);
|
packet->setArrayDataByName("cost", destination->cost, i+offset);
|
||||||
|
|
||||||
if (has_map) {
|
if (has_map) {
|
||||||
packet->setArrayDataByName("map_x", destination->map_x, i);
|
packet->setArrayDataByName("map_x", destination->map_x, i+offset);
|
||||||
packet->setArrayDataByName("map_y", destination->map_y, i);
|
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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10069,6 +10076,7 @@ void Client::ProcessTeleport(Spawn* spawn, vector<TransportDestination*>* destin
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::ProcessTeleportLocation(EQApplicationPacket* app) {
|
void Client::ProcessTeleportLocation(EQApplicationPacket* app) {
|
||||||
|
int32 duplicateId = 0;
|
||||||
PacketStruct* packet = configReader.getStruct("WS_TeleportDestination", GetVersion());
|
PacketStruct* packet = configReader.getStruct("WS_TeleportDestination", GetVersion());
|
||||||
if (packet) {
|
if (packet) {
|
||||||
if (packet->LoadPacketData(app->pBuffer, app->size)) {
|
if (packet->LoadPacketData(app->pBuffer, app->size)) {
|
||||||
@ -10078,11 +10086,18 @@ void Client::ProcessTeleportLocation(EQApplicationPacket* app) {
|
|||||||
int32 cost = packet->getType_int32_ByName("cost");
|
int32 cost = packet->getType_int32_ByName("cost");
|
||||||
vector<TransportDestination*> destinations;
|
vector<TransportDestination*> destinations;
|
||||||
TransportDestination* destination = 0;
|
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()))
|
if (this->GetTemporaryTransportID() || (spawn && spawn == transport_spawn && spawn->GetTransporterID()))
|
||||||
GetCurrentZone()->GetTransporters(&destinations, this, this->GetTemporaryTransportID() ? this->GetTemporaryTransportID() : spawn->GetTransporterID());
|
GetCurrentZone()->GetTransporters(&destinations, this, this->GetTemporaryTransportID() ? this->GetTemporaryTransportID() : spawn->GetTransporterID());
|
||||||
vector<TransportDestination*>::iterator itr;
|
vector<TransportDestination*>::iterator itr;
|
||||||
for (itr = destinations.begin(); itr != destinations.end(); 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;
|
destination = *itr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -10115,7 +10130,14 @@ void Client::ProcessTeleportLocation(EQApplicationPacket* app) {
|
|||||||
if (!TryZoneInstance(destination->destination_zone_id, false)) {
|
if (!TryZoneInstance(destination->destination_zone_id, false)) {
|
||||||
LogWrite(INSTANCE__DEBUG, 0, "Instance", "Attempting to zone normally");
|
LogWrite(INSTANCE__DEBUG, 0, "Instance", "Attempting to zone normally");
|
||||||
ZoneChangeDetails zone_details;
|
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);
|
Zone(&zone_details, (ZoneServer*)zone_details.zonePtr, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11587,6 +11609,34 @@ void Client::SavePlayerImages() {
|
|||||||
incoming_paperdoll.current_size_bytes = 0;
|
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() {
|
void Client::EndAutoMount() {
|
||||||
PacketStruct* packet = configReader.getStruct("WS_ServerControlFlags", GetVersion());
|
PacketStruct* packet = configReader.getStruct("WS_ServerControlFlags", GetVersion());
|
||||||
if (packet) {
|
if (packet) {
|
||||||
@ -12208,6 +12258,20 @@ void Client::SendFlightAutoMount(int32 path_id, int16 mount_id, int8 mount_red_c
|
|||||||
|
|
||||||
if (mount_id)
|
if (mount_id)
|
||||||
((Entity*)GetPlayer())->SetMount(mount_id, mount_red_color, mount_green_color, mount_blue_color);
|
((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, ...)
|
void Client::SendShowBook(Spawn* sender, string title, int8 language, int8 num_pages, ...)
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
#include <regex>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "../common/EQStream.h"
|
#include "../common/EQStream.h"
|
||||||
#include "../common/timer.h"
|
#include "../common/timer.h"
|
||||||
@ -314,12 +316,14 @@ public:
|
|||||||
int32 GetCurrentZoneID();
|
int32 GetCurrentZoneID();
|
||||||
void SetCurrentZoneByInstanceID(int32 id, int32 zoneid);
|
void SetCurrentZoneByInstanceID(int32 id, int32 zoneid);
|
||||||
//void SetCurrentZoneByInstanceID(instanceid, zoneid);
|
//void SetCurrentZoneByInstanceID(instanceid, zoneid);
|
||||||
void SetCurrentZone(int32 id);
|
void SetCurrentZone(int32 id, int32 zone_duplicate_id = 0);
|
||||||
void SetCurrentZone(ZoneServer* zone);
|
void SetCurrentZone(ZoneServer* zone);
|
||||||
void SetZoningDestination(ZoneServer* zone) {
|
void SetZoningDestination(ZoneServer* zone) {
|
||||||
zoning_destination = zone;
|
zoning_destination = zone;
|
||||||
}
|
}
|
||||||
ZoneServer* GetZoningDestination() { return zoning_destination; }
|
ZoneServer* GetZoningDestination() { return zoning_destination; }
|
||||||
|
int32 GetDuplicatingZoneID() { return duplicate_zoning_id; }
|
||||||
|
|
||||||
Player* GetPlayer() { return player; }
|
Player* GetPlayer() { return player; }
|
||||||
EQStream* getConnection() { return eqs; }
|
EQStream* getConnection() { return eqs; }
|
||||||
void setConnection(EQStream* ieqs) { eqs = ieqs; }
|
void setConnection(EQStream* ieqs) { eqs = ieqs; }
|
||||||
@ -508,7 +512,25 @@ public:
|
|||||||
|
|
||||||
void SetPendingFlightPath(int32 val) { pending_flight_path = val; }
|
void SetPendingFlightPath(int32 val) { pending_flight_path = val; }
|
||||||
int32 GetPendingFlightPath() { return pending_flight_path; }
|
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();
|
void EndAutoMount();
|
||||||
bool GetOnAutoMount() { return on_auto_mount; }
|
bool GetOnAutoMount() { return on_auto_mount; }
|
||||||
|
|
||||||
@ -764,6 +786,7 @@ private:
|
|||||||
int32 zoning_id;
|
int32 zoning_id;
|
||||||
int32 zoning_instance_id;
|
int32 zoning_instance_id;
|
||||||
ZoneServer* zoning_destination;
|
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_x;
|
||||||
float zoning_y;
|
float zoning_y;
|
||||||
float zoning_z;
|
float zoning_z;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user