mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-14 03:11:28 +00:00
[Zone] Implement zone player count sharding (#4536)
* [Zone] Implement zone player count sharding * Update client.cpp * Update database_instances.cpp * You must request a shard change from the zone you are currently in. * // zone sharding * You cannot request a shard change while in combat. * Query adjustment * Use safe coords * Changes * Fixes to instance query * Push * Push * Final push * Update client.cpp * Update eq_packet_structs.h * Remove pick menu * Comment * Update character_data_repository.h * Update zoning.cpp --------- Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
This commit is contained in:
parent
15684567cf
commit
c82f1b9afc
@ -5791,6 +5791,18 @@ ALTER TABLE `trader`
|
|||||||
.match = "float",
|
.match = "float",
|
||||||
.sql = R"(
|
.sql = R"(
|
||||||
ALTER TABLE `npc_types` MODIFY COLUMN `walkspeed` float NOT NULL DEFAULT 0;
|
ALTER TABLE `npc_types` MODIFY COLUMN `walkspeed` float NOT NULL DEFAULT 0;
|
||||||
|
)",
|
||||||
|
.content_schema_update = true
|
||||||
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9288,
|
||||||
|
.description = "2024_11_10_zone_player_partitioning.sql",
|
||||||
|
.check = "SHOW CREATE TABLE `zone`",
|
||||||
|
.condition = "missing",
|
||||||
|
.match = "shard_at_player_count",
|
||||||
|
.sql = R"(
|
||||||
|
ALTER TABLE `zone`
|
||||||
|
ADD COLUMN `shard_at_player_count` int(11) NULL DEFAULT 0 AFTER `seconds_before_idle`;
|
||||||
)",
|
)",
|
||||||
.content_schema_update = true
|
.content_schema_update = true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -114,7 +114,9 @@ bool Database::CheckInstanceExpired(uint16 instance_id)
|
|||||||
timeval tv{};
|
timeval tv{};
|
||||||
gettimeofday(&tv, nullptr);
|
gettimeofday(&tv, nullptr);
|
||||||
|
|
||||||
return (i.start_time + i.duration) <= tv.tv_sec;
|
// Use uint64_t for the addition to prevent overflow
|
||||||
|
uint64_t expiration_time = static_cast<uint64_t>(i.start_time) + static_cast<uint64_t>(i.duration);
|
||||||
|
return expiration_time <= tv.tv_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
|
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
|
||||||
@ -469,15 +471,13 @@ void Database::AssignRaidToInstance(uint32 raid_id, uint32 instance_id)
|
|||||||
|
|
||||||
void Database::DeleteInstance(uint16 instance_id)
|
void Database::DeleteInstance(uint16 instance_id)
|
||||||
{
|
{
|
||||||
|
// I'm not sure why this isn't in here but we should add it in a later change and make sure it's tested
|
||||||
|
// InstanceListRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id));
|
||||||
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id));
|
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id));
|
||||||
|
|
||||||
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
||||||
|
|
||||||
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
||||||
|
|
||||||
DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id);
|
DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id);
|
||||||
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
|
||||||
|
|
||||||
CharacterCorpsesRepository::BuryInstance(*this, instance_id);
|
CharacterCorpsesRepository::BuryInstance(*this, instance_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -400,6 +400,8 @@ N(OP_PetitionSearchText),
|
|||||||
N(OP_PetitionUnCheckout),
|
N(OP_PetitionUnCheckout),
|
||||||
N(OP_PetitionUpdate),
|
N(OP_PetitionUpdate),
|
||||||
N(OP_PickPocket),
|
N(OP_PickPocket),
|
||||||
|
N(OP_PickZone),
|
||||||
|
N(OP_PickZoneWindow),
|
||||||
N(OP_PlayerProfile),
|
N(OP_PlayerProfile),
|
||||||
N(OP_PlayerStateAdd),
|
N(OP_PlayerStateAdd),
|
||||||
N(OP_PlayerStateRemove),
|
N(OP_PlayerStateRemove),
|
||||||
|
|||||||
@ -6440,6 +6440,26 @@ struct BuylineItemDetails_Struct {
|
|||||||
uint32 item_quantity;
|
uint32 item_quantity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PickZoneEntry_Struct {
|
||||||
|
int16 zone_id;
|
||||||
|
int16 unknown;
|
||||||
|
int32 player_count;
|
||||||
|
int32 instance_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PickZoneWindow_Struct {
|
||||||
|
char padding000[64];
|
||||||
|
int64 session_id;
|
||||||
|
int8 option_count;
|
||||||
|
char padding073[23];
|
||||||
|
PickZoneEntry_Struct entries[10];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PickZone_Struct {
|
||||||
|
int64 session_id;
|
||||||
|
int32 selection_id;
|
||||||
|
};
|
||||||
|
|
||||||
// Restore structure packing to default
|
// Restore structure packing to default
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
|
|||||||
@ -250,6 +250,7 @@ IN(OP_TraderBuy, TraderBuy_Struct);
|
|||||||
IN(OP_Trader, Trader_ShowItems_Struct);
|
IN(OP_Trader, Trader_ShowItems_Struct);
|
||||||
IN(OP_GMFind, GMSummon_Struct);
|
IN(OP_GMFind, GMSummon_Struct);
|
||||||
IN(OP_PickPocket, PickPocket_Struct);
|
IN(OP_PickPocket, PickPocket_Struct);
|
||||||
|
IN(OP_PickZone, PickZone_Struct);
|
||||||
IN(OP_Bind_Wound, BindWound_Struct);
|
IN(OP_Bind_Wound, BindWound_Struct);
|
||||||
INr(OP_TrackTarget);
|
INr(OP_TrackTarget);
|
||||||
INr(OP_Track);
|
INr(OP_Track);
|
||||||
|
|||||||
@ -117,6 +117,7 @@ public:
|
|||||||
int32_t min_lava_damage;
|
int32_t min_lava_damage;
|
||||||
uint8_t idle_when_empty;
|
uint8_t idle_when_empty;
|
||||||
uint32_t seconds_before_idle;
|
uint32_t seconds_before_idle;
|
||||||
|
int32_t shard_at_player_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
@ -225,6 +226,7 @@ public:
|
|||||||
"min_lava_damage",
|
"min_lava_damage",
|
||||||
"idle_when_empty",
|
"idle_when_empty",
|
||||||
"seconds_before_idle",
|
"seconds_before_idle",
|
||||||
|
"shard_at_player_count",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,6 +331,7 @@ public:
|
|||||||
"min_lava_damage",
|
"min_lava_damage",
|
||||||
"idle_when_empty",
|
"idle_when_empty",
|
||||||
"seconds_before_idle",
|
"seconds_before_idle",
|
||||||
|
"shard_at_player_count",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,6 +470,7 @@ public:
|
|||||||
e.min_lava_damage = 10;
|
e.min_lava_damage = 10;
|
||||||
e.idle_when_empty = 1;
|
e.idle_when_empty = 1;
|
||||||
e.seconds_before_idle = 60;
|
e.seconds_before_idle = 60;
|
||||||
|
e.shard_at_player_count = 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@ -601,6 +605,7 @@ public:
|
|||||||
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
|
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
|
||||||
e.idle_when_empty = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 1;
|
e.idle_when_empty = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 1;
|
||||||
e.seconds_before_idle = row[97] ? static_cast<uint32_t>(strtoul(row[97], nullptr, 10)) : 60;
|
e.seconds_before_idle = row[97] ? static_cast<uint32_t>(strtoul(row[97], nullptr, 10)) : 60;
|
||||||
|
e.shard_at_player_count = row[98] ? static_cast<int32_t>(atoi(row[98])) : 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@ -731,6 +736,7 @@ public:
|
|||||||
v.push_back(columns[95] + " = " + std::to_string(e.min_lava_damage));
|
v.push_back(columns[95] + " = " + std::to_string(e.min_lava_damage));
|
||||||
v.push_back(columns[96] + " = " + std::to_string(e.idle_when_empty));
|
v.push_back(columns[96] + " = " + std::to_string(e.idle_when_empty));
|
||||||
v.push_back(columns[97] + " = " + std::to_string(e.seconds_before_idle));
|
v.push_back(columns[97] + " = " + std::to_string(e.seconds_before_idle));
|
||||||
|
v.push_back(columns[98] + " = " + std::to_string(e.shard_at_player_count));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -850,6 +856,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.min_lava_damage));
|
v.push_back(std::to_string(e.min_lava_damage));
|
||||||
v.push_back(std::to_string(e.idle_when_empty));
|
v.push_back(std::to_string(e.idle_when_empty));
|
||||||
v.push_back(std::to_string(e.seconds_before_idle));
|
v.push_back(std::to_string(e.seconds_before_idle));
|
||||||
|
v.push_back(std::to_string(e.shard_at_player_count));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -977,6 +984,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.min_lava_damage));
|
v.push_back(std::to_string(e.min_lava_damage));
|
||||||
v.push_back(std::to_string(e.idle_when_empty));
|
v.push_back(std::to_string(e.idle_when_empty));
|
||||||
v.push_back(std::to_string(e.seconds_before_idle));
|
v.push_back(std::to_string(e.seconds_before_idle));
|
||||||
|
v.push_back(std::to_string(e.shard_at_player_count));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
@ -1108,6 +1116,7 @@ public:
|
|||||||
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
|
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
|
||||||
e.idle_when_empty = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 1;
|
e.idle_when_empty = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 1;
|
||||||
e.seconds_before_idle = row[97] ? static_cast<uint32_t>(strtoul(row[97], nullptr, 10)) : 60;
|
e.seconds_before_idle = row[97] ? static_cast<uint32_t>(strtoul(row[97], nullptr, 10)) : 60;
|
||||||
|
e.shard_at_player_count = row[98] ? static_cast<int32_t>(atoi(row[98])) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@ -1230,6 +1239,7 @@ public:
|
|||||||
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
|
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
|
||||||
e.idle_when_empty = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 1;
|
e.idle_when_empty = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 1;
|
||||||
e.seconds_before_idle = row[97] ? static_cast<uint32_t>(strtoul(row[97], nullptr, 10)) : 60;
|
e.seconds_before_idle = row[97] ? static_cast<uint32_t>(strtoul(row[97], nullptr, 10)) : 60;
|
||||||
|
e.shard_at_player_count = row[98] ? static_cast<int32_t>(atoi(row[98])) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@ -1402,6 +1412,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.min_lava_damage));
|
v.push_back(std::to_string(e.min_lava_damage));
|
||||||
v.push_back(std::to_string(e.idle_when_empty));
|
v.push_back(std::to_string(e.idle_when_empty));
|
||||||
v.push_back(std::to_string(e.seconds_before_idle));
|
v.push_back(std::to_string(e.seconds_before_idle));
|
||||||
|
v.push_back(std::to_string(e.shard_at_player_count));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -1522,6 +1533,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.min_lava_damage));
|
v.push_back(std::to_string(e.min_lava_damage));
|
||||||
v.push_back(std::to_string(e.idle_when_empty));
|
v.push_back(std::to_string(e.idle_when_empty));
|
||||||
v.push_back(std::to_string(e.seconds_before_idle));
|
v.push_back(std::to_string(e.seconds_before_idle));
|
||||||
|
v.push_back(std::to_string(e.shard_at_player_count));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,6 +80,93 @@ public:
|
|||||||
|
|
||||||
return l.empty() ? CharacterDataRepository::NewEntity() : l.front();
|
return l.empty() ? CharacterDataRepository::NewEntity() : l.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct InstancePlayerCount {
|
||||||
|
int32_t instance_id;
|
||||||
|
uint32_t zone_id;
|
||||||
|
uint32_t player_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<InstancePlayerCount> GetInstanceZonePlayerCounts(Database& db, int zone_id) {
|
||||||
|
std::vector<InstancePlayerCount> zone_player_counts;
|
||||||
|
|
||||||
|
uint64_t shard_instance_duration = 3155760000;
|
||||||
|
|
||||||
|
auto query = fmt::format(SQL(
|
||||||
|
SELECT
|
||||||
|
zone_id,
|
||||||
|
0 AS instance_id,
|
||||||
|
COUNT(id) AS player_count
|
||||||
|
FROM
|
||||||
|
character_data
|
||||||
|
WHERE
|
||||||
|
zone_instance = 0
|
||||||
|
AND zone_id = {}
|
||||||
|
AND last_login >= UNIX_TIMESTAMP(NOW()) - 600
|
||||||
|
GROUP BY
|
||||||
|
zone_id
|
||||||
|
ORDER BY
|
||||||
|
zone_id, player_count DESC
|
||||||
|
), zone_id);
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(query);
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
InstancePlayerCount e{};
|
||||||
|
e.zone_id = std::stoi(row[0]);
|
||||||
|
e.instance_id = 0;
|
||||||
|
e.player_count = std::stoi(row[2]);
|
||||||
|
zone_player_counts.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zone_player_counts.empty()) {
|
||||||
|
InstancePlayerCount e{};
|
||||||
|
e.zone_id = zone_id;
|
||||||
|
e.instance_id = 0;
|
||||||
|
e.player_count = 0;
|
||||||
|
zone_player_counts.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// duration 3155760000 is for shards explicitly
|
||||||
|
query = fmt::format(
|
||||||
|
SQL(
|
||||||
|
SELECT
|
||||||
|
i.id AS instance_id,
|
||||||
|
i.zone AS zone_id,
|
||||||
|
COUNT(c.id) AS player_count
|
||||||
|
FROM
|
||||||
|
instance_list i
|
||||||
|
LEFT JOIN
|
||||||
|
character_data c
|
||||||
|
ON
|
||||||
|
i.zone = c.zone_id
|
||||||
|
AND i.id = c.zone_instance
|
||||||
|
AND c.last_login >= UNIX_TIMESTAMP(NOW()) - 600
|
||||||
|
AND (i.start_time + i.duration >= UNIX_TIMESTAMP(NOW()) OR i.never_expires = 0)
|
||||||
|
AND i.duration = {}
|
||||||
|
WHERE
|
||||||
|
i.zone IS NOT NULL AND i.zone = {}
|
||||||
|
GROUP BY
|
||||||
|
i.id, i.zone, i.version
|
||||||
|
ORDER BY
|
||||||
|
i.id ASC;
|
||||||
|
), shard_instance_duration, zone_id
|
||||||
|
);
|
||||||
|
|
||||||
|
results = db.QueryDatabase(query);
|
||||||
|
if (!results.Success() || results.RowCount() == 0) {
|
||||||
|
return zone_player_counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
InstancePlayerCount e{};
|
||||||
|
e.instance_id = std::stoi(row[0]);
|
||||||
|
e.zone_id = std::stoi(row[1]);
|
||||||
|
e.player_count = std::stoi(row[2]);
|
||||||
|
zone_player_counts.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return zone_player_counts;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //EQEMU_CHARACTER_DATA_REPOSITORY_H
|
#endif //EQEMU_CHARACTER_DATA_REPOSITORY_H
|
||||||
|
|||||||
@ -372,6 +372,7 @@ RULE_INT(Zone, FishingChance, 399, "Chance of fishing from zone table vs global
|
|||||||
RULE_BOOL(Zone, AllowCrossZoneSpellsOnBots, false, "Set to true to allow cross zone spells (cast/remove) to affect bots")
|
RULE_BOOL(Zone, AllowCrossZoneSpellsOnBots, false, "Set to true to allow cross zone spells (cast/remove) to affect bots")
|
||||||
RULE_BOOL(Zone, AllowCrossZoneSpellsOnMercs, false, "Set to true to allow cross zone spells (cast/remove) to affect mercenaries")
|
RULE_BOOL(Zone, AllowCrossZoneSpellsOnMercs, false, "Set to true to allow cross zone spells (cast/remove) to affect mercenaries")
|
||||||
RULE_BOOL(Zone, AllowCrossZoneSpellsOnPets, false, "Set to true to allow cross zone spells (cast/remove) to affect pets")
|
RULE_BOOL(Zone, AllowCrossZoneSpellsOnPets, false, "Set to true to allow cross zone spells (cast/remove) to affect pets")
|
||||||
|
RULE_BOOL(Zone, ZoneShardQuestMenuOnly, false, "Set to true if you only want quests to show the zone shard menu")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Map)
|
RULE_CATEGORY(Map)
|
||||||
|
|||||||
@ -42,7 +42,7 @@
|
|||||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CURRENT_BINARY_DATABASE_VERSION 9287
|
#define CURRENT_BINARY_DATABASE_VERSION 9288
|
||||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
|
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -728,3 +728,6 @@ OP_InitialHPUpdate=0x0000
|
|||||||
#aura related
|
#aura related
|
||||||
OP_UpdateAura=0x1456
|
OP_UpdateAura=0x1456
|
||||||
OP_RemoveTrap=0x71da
|
OP_RemoveTrap=0x71da
|
||||||
|
|
||||||
|
OP_PickZoneWindow=0x72d8
|
||||||
|
OP_PickZone=0xaaba
|
||||||
|
|||||||
@ -13037,19 +13037,19 @@ void Client::ClientToNpcAggroProcess()
|
|||||||
const std::vector<int16>& Client::GetInventorySlots()
|
const std::vector<int16>& Client::GetInventorySlots()
|
||||||
{
|
{
|
||||||
static const std::vector<std::pair<int16, int16>> slots = {
|
static const std::vector<std::pair<int16, int16>> slots = {
|
||||||
{ EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END },
|
{EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END},
|
||||||
{ EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END },
|
{EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END},
|
||||||
{ EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END },
|
{EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END},
|
||||||
{ EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END },
|
{EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END},
|
||||||
{ EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END },
|
{EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END},
|
||||||
{ EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END },
|
{EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END},
|
||||||
{ EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END },
|
{EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END},
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<int16> slot_ids;
|
static std::vector<int16> slot_ids;
|
||||||
|
|
||||||
if (slot_ids.empty()) {
|
if (slot_ids.empty()) {
|
||||||
for (const auto& [begin, end] : slots) {
|
for (const auto &[begin, end]: slots) {
|
||||||
for (int16 slot_id = begin; slot_id <= end; ++slot_id) {
|
for (int16 slot_id = begin; slot_id <= end; ++slot_id) {
|
||||||
slot_ids.emplace_back(slot_id);
|
slot_ids.emplace_back(slot_id);
|
||||||
}
|
}
|
||||||
@ -13058,3 +13058,51 @@ const std::vector<int16>& Client::GetInventorySlots()
|
|||||||
|
|
||||||
return slot_ids;
|
return slot_ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::ShowZoneShardMenu()
|
||||||
|
{
|
||||||
|
auto z = GetZone(GetZoneID());
|
||||||
|
if (z && !z->shard_at_player_count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto results = CharacterDataRepository::GetInstanceZonePlayerCounts(database, GetZoneID());
|
||||||
|
LogZoning("Zone sharding results count [{}]", results.size());
|
||||||
|
|
||||||
|
if (results.empty()) {
|
||||||
|
Message(Chat::White, "No zone shards found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!results.empty()) {
|
||||||
|
Message(Chat::White, "Available Zone Shards:");
|
||||||
|
}
|
||||||
|
|
||||||
|
int number = 1;
|
||||||
|
for (auto &e: results) {
|
||||||
|
std::string teleport_link = Saylink::Silent(
|
||||||
|
fmt::format("#zoneshard {} {}", e.zone_id, (e.instance_id == 0 ? -1 : e.instance_id)),
|
||||||
|
"Teleport"
|
||||||
|
);
|
||||||
|
|
||||||
|
std::string yours;
|
||||||
|
if (e.zone_id == GetZoneID() && e.instance_id == GetInstanceID()) {
|
||||||
|
teleport_link = "Teleport";
|
||||||
|
yours = " (Yours)";
|
||||||
|
}
|
||||||
|
|
||||||
|
Message(
|
||||||
|
Chat::White, fmt::format(
|
||||||
|
" --> [{}] #{} {} ({}) [{}/{}] players {}",
|
||||||
|
teleport_link,
|
||||||
|
number,
|
||||||
|
z->long_name,
|
||||||
|
e.instance_id,
|
||||||
|
e.player_count,
|
||||||
|
z->shard_at_player_count,
|
||||||
|
yours
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
number++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2236,6 +2236,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
const std::string &GetMailKeyFull() const;
|
const std::string &GetMailKeyFull() const;
|
||||||
const std::string &GetMailKey() const;
|
const std::string &GetMailKey() const;
|
||||||
|
void ShowZoneShardMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -339,6 +339,7 @@ void MapOpcodes()
|
|||||||
ConnectedOpcodes[OP_PlayerStateAdd] = &Client::Handle_OP_PlayerStateAdd;
|
ConnectedOpcodes[OP_PlayerStateAdd] = &Client::Handle_OP_PlayerStateAdd;
|
||||||
ConnectedOpcodes[OP_PlayerStateRemove] = &Client::Handle_OP_PlayerStateRemove;
|
ConnectedOpcodes[OP_PlayerStateRemove] = &Client::Handle_OP_PlayerStateRemove;
|
||||||
ConnectedOpcodes[OP_PickPocket] = &Client::Handle_OP_PickPocket;
|
ConnectedOpcodes[OP_PickPocket] = &Client::Handle_OP_PickPocket;
|
||||||
|
ConnectedOpcodes[OP_PickZone] = &Client::Handle_OP_PickZone;
|
||||||
ConnectedOpcodes[OP_PopupResponse] = &Client::Handle_OP_PopupResponse;
|
ConnectedOpcodes[OP_PopupResponse] = &Client::Handle_OP_PopupResponse;
|
||||||
ConnectedOpcodes[OP_PotionBelt] = &Client::Handle_OP_PotionBelt;
|
ConnectedOpcodes[OP_PotionBelt] = &Client::Handle_OP_PotionBelt;
|
||||||
ConnectedOpcodes[OP_PurchaseLeadershipAA] = &Client::Handle_OP_PurchaseLeadershipAA;
|
ConnectedOpcodes[OP_PurchaseLeadershipAA] = &Client::Handle_OP_PurchaseLeadershipAA;
|
||||||
@ -941,6 +942,11 @@ void Client::CompleteConnect()
|
|||||||
ShowDevToolsMenu();
|
ShowDevToolsMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto z = GetZone(GetZoneID(), GetInstanceVersion());
|
||||||
|
if (z && z->shard_at_player_count > 0 && !RuleB(Zone, ZoneShardQuestMenuOnly)) {
|
||||||
|
ShowZoneShardMenu();
|
||||||
|
}
|
||||||
|
|
||||||
// shared tasks memberlist
|
// shared tasks memberlist
|
||||||
if (RuleB(TaskSystem, EnableTaskSystem) && GetTaskState()->HasActiveSharedTask()) {
|
if (RuleB(TaskSystem, EnableTaskSystem) && GetTaskState()->HasActiveSharedTask()) {
|
||||||
|
|
||||||
@ -11839,6 +11845,17 @@ void Client::Handle_OP_PickPocket(const EQApplicationPacket *app)
|
|||||||
SendPickPocketResponse(victim, 0, PickPocketFailed);
|
SendPickPocketResponse(victim, 0, PickPocketFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::Handle_OP_PickZone(const EQApplicationPacket *app)
|
||||||
|
{
|
||||||
|
if (app->size != sizeof(PickZone_Struct)) {
|
||||||
|
LogDebug("Size mismatch in OP_PickZone expected [{}] got [{}]", sizeof(PickZone_Struct), app->size);
|
||||||
|
DumpPacket(app);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle
|
||||||
|
}
|
||||||
|
|
||||||
void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app)
|
void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@ -242,6 +242,7 @@
|
|||||||
void Handle_OP_PlayerStateAdd(const EQApplicationPacket *app);
|
void Handle_OP_PlayerStateAdd(const EQApplicationPacket *app);
|
||||||
void Handle_OP_PlayerStateRemove(const EQApplicationPacket *app);
|
void Handle_OP_PlayerStateRemove(const EQApplicationPacket *app);
|
||||||
void Handle_OP_PickPocket(const EQApplicationPacket *app);
|
void Handle_OP_PickPocket(const EQApplicationPacket *app);
|
||||||
|
void Handle_OP_PickZone(const EQApplicationPacket *app);
|
||||||
void Handle_OP_PopupResponse(const EQApplicationPacket *app);
|
void Handle_OP_PopupResponse(const EQApplicationPacket *app);
|
||||||
void Handle_OP_PotionBelt(const EQApplicationPacket *app);
|
void Handle_OP_PotionBelt(const EQApplicationPacket *app);
|
||||||
void Handle_OP_PurchaseLeadershipAA(const EQApplicationPacket *app);
|
void Handle_OP_PurchaseLeadershipAA(const EQApplicationPacket *app);
|
||||||
|
|||||||
@ -243,6 +243,7 @@ int command_init(void)
|
|||||||
command_add("zone", "[Zone ID|Zone Short Name] [X] [Y] [Z] - Teleport to specified Zone by ID or Short Name (coordinates are optional)", AccountStatus::Guide, command_zone) ||
|
command_add("zone", "[Zone ID|Zone Short Name] [X] [Y] [Z] - Teleport to specified Zone by ID or Short Name (coordinates are optional)", AccountStatus::Guide, command_zone) ||
|
||||||
command_add("zonebootup", "[ZoneServerID] [shortname] - Make a zone server boot a specific zone", AccountStatus::GMLeadAdmin, command_zonebootup) ||
|
command_add("zonebootup", "[ZoneServerID] [shortname] - Make a zone server boot a specific zone", AccountStatus::GMLeadAdmin, command_zonebootup) ||
|
||||||
command_add("zoneinstance", "[Instance ID] [X] [Y] [Z] - Teleport to specified Instance by ID (coordinates are optional)", AccountStatus::Guide, command_zone_instance) ||
|
command_add("zoneinstance", "[Instance ID] [X] [Y] [Z] - Teleport to specified Instance by ID (coordinates are optional)", AccountStatus::Guide, command_zone_instance) ||
|
||||||
|
command_add("zoneshard", "[zone] [instance_id] - Teleport explicitly to a zone shard", AccountStatus::Player, command_zone_shard) ||
|
||||||
command_add("zoneshutdown", "[shortname] - Shut down a zone server", AccountStatus::GMLeadAdmin, command_zoneshutdown) ||
|
command_add("zoneshutdown", "[shortname] - Shut down a zone server", AccountStatus::GMLeadAdmin, command_zoneshutdown) ||
|
||||||
command_add("zsave", " Saves zheader to the database", AccountStatus::QuestTroupe, command_zsave)
|
command_add("zsave", " Saves zheader to the database", AccountStatus::QuestTroupe, command_zsave)
|
||||||
) {
|
) {
|
||||||
@ -936,4 +937,5 @@ void command_bot(Client *c, const Seperator *sep)
|
|||||||
#include "gm_commands/zonebootup.cpp"
|
#include "gm_commands/zonebootup.cpp"
|
||||||
#include "gm_commands/zoneshutdown.cpp"
|
#include "gm_commands/zoneshutdown.cpp"
|
||||||
#include "gm_commands/zone_instance.cpp"
|
#include "gm_commands/zone_instance.cpp"
|
||||||
|
#include "gm_commands/zone_shard.cpp"
|
||||||
#include "gm_commands/zsave.cpp"
|
#include "gm_commands/zsave.cpp"
|
||||||
|
|||||||
@ -195,6 +195,7 @@ void command_wpadd(Client *c, const Seperator *sep);
|
|||||||
void command_worldwide(Client *c, const Seperator *sep);
|
void command_worldwide(Client *c, const Seperator *sep);
|
||||||
void command_zone(Client *c, const Seperator *sep);
|
void command_zone(Client *c, const Seperator *sep);
|
||||||
void command_zone_instance(Client *c, const Seperator *sep);
|
void command_zone_instance(Client *c, const Seperator *sep);
|
||||||
|
void command_zone_shard(Client *c, const Seperator *sep);
|
||||||
void command_zonebootup(Client *c, const Seperator *sep);
|
void command_zonebootup(Client *c, const Seperator *sep);
|
||||||
void command_zoneshutdown(Client *c, const Seperator *sep);
|
void command_zoneshutdown(Client *c, const Seperator *sep);
|
||||||
void command_zopp(Client *c, const Seperator *sep);
|
void command_zopp(Client *c, const Seperator *sep);
|
||||||
|
|||||||
137
zone/gm_commands/zone_shard.cpp
Normal file
137
zone/gm_commands/zone_shard.cpp
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#include "../client.h"
|
||||||
|
|
||||||
|
void command_zone_shard(Client *c, const Seperator *sep)
|
||||||
|
{
|
||||||
|
int arguments = sep->argnum;
|
||||||
|
if (!arguments || !sep->IsNumber(1)) {
|
||||||
|
if (!RuleB(Zone, ZoneShardQuestMenuOnly)) {
|
||||||
|
c->ShowZoneShardMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->GetAggroCount() > 0) {
|
||||||
|
c->Message(Chat::White, "You cannot request a shard change while in combat.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string zone_input = sep->arg[1];
|
||||||
|
uint32 zone_id = 0;
|
||||||
|
|
||||||
|
// if input is id
|
||||||
|
if (Strings::IsNumber(zone_input)) {
|
||||||
|
zone_id = Strings::ToInt(zone_input);
|
||||||
|
|
||||||
|
// validate
|
||||||
|
if (zone_id != 0 && !GetZone(zone_id)) {
|
||||||
|
c->Message(Chat::White, fmt::format("Could not find zone by id [{}]", zone_id).c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// validate
|
||||||
|
if (!zone_store.GetZone(zone_input)) {
|
||||||
|
c->Message(Chat::White, fmt::format("Could not find zone by short_name [{}]", zone_input).c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate we got id
|
||||||
|
zone_id = ZoneID(zone_input);
|
||||||
|
if (zone_id == 0) {
|
||||||
|
c->Message(Chat::White, fmt::format("Could not find zone id by short_name [{}]", zone_input).c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto z = GetZone(zone_id);
|
||||||
|
if (z && z->shard_at_player_count == 0) {
|
||||||
|
c->Message(Chat::White, "Zone does not have sharding enabled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto instance_id = sep->arg[2] ? Strings::ToBigInt(sep->arg[2]) : 0;
|
||||||
|
if (instance_id < -1) {
|
||||||
|
c->Message(Chat::White, "You must enter a valid Instance ID.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zone_id == c->GetZoneID() && c->GetInstanceID() == instance_id) {
|
||||||
|
c->Message(Chat::White, "You are already in this shard.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zone_id != c->GetZoneID()) {
|
||||||
|
c->Message(Chat::White, "You must request a shard change from the zone you are currently in.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto results = CharacterDataRepository::GetInstanceZonePlayerCounts(database, c->GetZoneID());
|
||||||
|
if (results.size() <= 1) {
|
||||||
|
c->Message(Chat::White, "No shards found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance_id > 0) {
|
||||||
|
if (!database.CheckInstanceExists(instance_id)) {
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"Instance ID {} does not exist.",
|
||||||
|
instance_id
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto instance_zone_id = database.GetInstanceZoneID(instance_id);
|
||||||
|
if (!instance_zone_id) {
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"Instance ID {} not found or zone is set to null.",
|
||||||
|
instance_id
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance_zone_id != zone_id) {
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"Instance Zone ID {} does not match zone ID {}.",
|
||||||
|
instance_id,
|
||||||
|
zone_id
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!database.CheckInstanceByCharID(instance_id, c->CharacterID())) {
|
||||||
|
database.AddClientToInstance(instance_id, c->CharacterID());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!database.VerifyInstanceAlive(instance_id, c->CharacterID())) {
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"Instance ID {} expired.",
|
||||||
|
instance_id
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c->MovePC(
|
||||||
|
zone_id,
|
||||||
|
instance_id,
|
||||||
|
c->GetX(),
|
||||||
|
c->GetY(),
|
||||||
|
c->GetZ(),
|
||||||
|
c->GetHeading(),
|
||||||
|
0,
|
||||||
|
ZoneSolicited
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -3436,13 +3436,14 @@ void Lua_Client::AreaTaunt(float range, int bonus_hate)
|
|||||||
entity_list.AETaunt(self, range, bonus_hate);
|
entity_list.AETaunt(self, range, bonus_hate);
|
||||||
}
|
}
|
||||||
|
|
||||||
luabind::object Lua_Client::GetInventorySlots(lua_State* L) {
|
luabind::object Lua_Client::GetInventorySlots(lua_State* L)
|
||||||
|
{
|
||||||
auto lua_table = luabind::newtable(L);
|
auto lua_table = luabind::newtable(L);
|
||||||
|
|
||||||
if (d_) {
|
if (d_) {
|
||||||
auto self = reinterpret_cast<NativeType*>(d_);
|
auto self = reinterpret_cast<NativeType *>(d_);
|
||||||
int index = 1;
|
int index = 1;
|
||||||
for (const int16& slot_id : self->GetInventorySlots()) {
|
for (const int16 &slot_id: self->GetInventorySlots()) {
|
||||||
lua_table[index] = slot_id;
|
lua_table[index] = slot_id;
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@ -3451,6 +3452,12 @@ luabind::object Lua_Client::GetInventorySlots(lua_State* L) {
|
|||||||
return lua_table;
|
return lua_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Lua_Client::ShowZoneShardMenu()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->ShowZoneShardMenu();
|
||||||
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_client() {
|
luabind::scope lua_register_client() {
|
||||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||||
.def(luabind::constructor<>())
|
.def(luabind::constructor<>())
|
||||||
@ -3970,6 +3977,7 @@ luabind::scope lua_register_client() {
|
|||||||
.def("SetTint", (void(Lua_Client::*)(int,uint32))&Lua_Client::SetTint)
|
.def("SetTint", (void(Lua_Client::*)(int,uint32))&Lua_Client::SetTint)
|
||||||
.def("SetTitleSuffix", (void(Lua_Client::*)(const char *))&Lua_Client::SetTitleSuffix)
|
.def("SetTitleSuffix", (void(Lua_Client::*)(const char *))&Lua_Client::SetTitleSuffix)
|
||||||
.def("SetZoneFlag", (void(Lua_Client::*)(uint32))&Lua_Client::SetZoneFlag)
|
.def("SetZoneFlag", (void(Lua_Client::*)(uint32))&Lua_Client::SetZoneFlag)
|
||||||
|
.def("ShowZoneShardMenu", (void(Lua_Client::*)(void))&Lua_Client::ShowZoneShardMenu)
|
||||||
.def("Signal", (void(Lua_Client::*)(int))&Lua_Client::Signal)
|
.def("Signal", (void(Lua_Client::*)(int))&Lua_Client::Signal)
|
||||||
.def("Sit", (void(Lua_Client::*)(void))&Lua_Client::Sit)
|
.def("Sit", (void(Lua_Client::*)(void))&Lua_Client::Sit)
|
||||||
.def("Stand", (void(Lua_Client::*)(void))&Lua_Client::Stand)
|
.def("Stand", (void(Lua_Client::*)(void))&Lua_Client::Stand)
|
||||||
|
|||||||
@ -587,6 +587,7 @@ public:
|
|||||||
void DialogueWindow(std::string markdown);
|
void DialogueWindow(std::string markdown);
|
||||||
|
|
||||||
bool ReloadDataBuckets();
|
bool ReloadDataBuckets();
|
||||||
|
void ShowZoneShardMenu();
|
||||||
|
|
||||||
Lua_Expedition CreateExpedition(luabind::object expedition_info);
|
Lua_Expedition CreateExpedition(luabind::object expedition_info);
|
||||||
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players);
|
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players);
|
||||||
|
|||||||
@ -915,7 +915,8 @@ luabind::scope lua_register_packet_opcodes() {
|
|||||||
luabind::value("Marquee", static_cast<int>(OP_Marquee)),
|
luabind::value("Marquee", static_cast<int>(OP_Marquee)),
|
||||||
luabind::value("ClientTimeStamp", static_cast<int>(OP_ClientTimeStamp)),
|
luabind::value("ClientTimeStamp", static_cast<int>(OP_ClientTimeStamp)),
|
||||||
luabind::value("GuildPromote", static_cast<int>(OP_GuildPromote)),
|
luabind::value("GuildPromote", static_cast<int>(OP_GuildPromote)),
|
||||||
luabind::value("Fling", static_cast<int>(OP_Fling))
|
luabind::value("Fling", static_cast<int>(OP_Fling)),
|
||||||
|
luabind::value("PickZoneWindow", static_cast<int>(OP_PickZoneWindow))
|
||||||
)];
|
)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1756,6 +1756,11 @@ int Perl_Client_GetClientMaxLevel(Client* self)
|
|||||||
return self->GetClientMaxLevel();
|
return self->GetClientMaxLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Perl_Client_ShowZoneShardMenu(Client* self) // @categories Script Utility
|
||||||
|
{
|
||||||
|
self->ShowZoneShardMenu();
|
||||||
|
}
|
||||||
|
|
||||||
DynamicZoneLocation GetDynamicZoneLocationFromHash(perl::hash table)
|
DynamicZoneLocation GetDynamicZoneLocationFromHash(perl::hash table)
|
||||||
{
|
{
|
||||||
// dynamic zone helper method, defaults invalid/missing keys to 0
|
// dynamic zone helper method, defaults invalid/missing keys to 0
|
||||||
@ -3742,6 +3747,7 @@ void perl_register_client()
|
|||||||
package.add("SetTitleSuffix", (void(*)(Client*, std::string))&Perl_Client_SetTitleSuffix);
|
package.add("SetTitleSuffix", (void(*)(Client*, std::string))&Perl_Client_SetTitleSuffix);
|
||||||
package.add("SetTitleSuffix", (void(*)(Client*, std::string, bool))&Perl_Client_SetTitleSuffix);
|
package.add("SetTitleSuffix", (void(*)(Client*, std::string, bool))&Perl_Client_SetTitleSuffix);
|
||||||
package.add("SetZoneFlag", &Perl_Client_SetZoneFlag);
|
package.add("SetZoneFlag", &Perl_Client_SetZoneFlag);
|
||||||
|
package.add("ShowZoneShardMenu", &Perl_Client_ShowZoneShardMenu);
|
||||||
package.add("Signal", &Perl_Client_Signal);
|
package.add("Signal", &Perl_Client_Signal);
|
||||||
package.add("SignalClient", &Perl_Client_SignalClient);
|
package.add("SignalClient", &Perl_Client_SignalClient);
|
||||||
package.add("SilentMessage", &Perl_Client_SilentMessage);
|
package.add("SilentMessage", &Perl_Client_SilentMessage);
|
||||||
|
|||||||
@ -778,6 +778,66 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// zone sharding
|
||||||
|
if (zoneID == zd->zoneidnumber &&
|
||||||
|
instance_id == 0 &&
|
||||||
|
zd->shard_at_player_count > 0) {
|
||||||
|
|
||||||
|
bool found_shard = false;
|
||||||
|
auto results = CharacterDataRepository::GetInstanceZonePlayerCounts(database, zoneID);
|
||||||
|
|
||||||
|
LogZoning("Zone sharding results count [{}]", results.size());
|
||||||
|
|
||||||
|
uint64_t shard_instance_duration = 3155760000;
|
||||||
|
|
||||||
|
for (auto &e: results) {
|
||||||
|
LogZoning(
|
||||||
|
"Zone sharding results [{}] ({}) instance_id [{}] player_count [{}]",
|
||||||
|
ZoneName(e.zone_id) ? ZoneName(e.zone_id) : "Unknown",
|
||||||
|
e.zone_id,
|
||||||
|
e.instance_id,
|
||||||
|
e.player_count
|
||||||
|
);
|
||||||
|
|
||||||
|
if (e.player_count < zd->shard_at_player_count) {
|
||||||
|
instance_id = e.instance_id;
|
||||||
|
|
||||||
|
database.AddClientToInstance(instance_id, CharacterID());
|
||||||
|
|
||||||
|
LogZoning(
|
||||||
|
"Client [{}] attempting zone to sharded zone > instance_id [{}] zone [{}] ({})",
|
||||||
|
GetCleanName(),
|
||||||
|
instance_id,
|
||||||
|
ZoneName(zoneID) ? ZoneName(zoneID) : "Unknown",
|
||||||
|
zoneID
|
||||||
|
);
|
||||||
|
|
||||||
|
found_shard = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_shard) {
|
||||||
|
uint16 new_instance_id = 0;
|
||||||
|
database.GetUnusedInstanceID(new_instance_id);
|
||||||
|
database.CreateInstance(new_instance_id, zoneID, zd->version, shard_instance_duration);
|
||||||
|
database.AddClientToInstance(new_instance_id, CharacterID());
|
||||||
|
instance_id = new_instance_id;
|
||||||
|
LogZoning(
|
||||||
|
"Client [{}] creating new sharded zone > instance_id [{}] zone [{}] ({})",
|
||||||
|
GetCleanName(),
|
||||||
|
new_instance_id,
|
||||||
|
ZoneName(zoneID) ? ZoneName(zoneID) : "Unknown",
|
||||||
|
zoneID
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// passed from zone shard request to normal zone
|
||||||
|
if (instance_id == -1) {
|
||||||
|
instance_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
LogInfo(
|
LogInfo(
|
||||||
"Client [{}] zone_id [{}] instance_id [{}] x [{}] y [{}] z [{}] heading [{}] ignorerestrictions [{}] zone_mode [{}]",
|
"Client [{}] zone_id [{}] instance_id [{}] x [{}] y [{}] z [{}] heading [{}] ignorerestrictions [{}] zone_mode [{}]",
|
||||||
GetCleanName(),
|
GetCleanName(),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user