mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-31 17:26:30 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 78b0c86442 | |||
| ce3d3153d8 | |||
| 92cc457067 | |||
| 9780623fea | |||
| d89bcf4f6c | |||
| 34b3a3fc88 | |||
| 8f54abec61 | |||
| ed4d72c54b | |||
| 2d8ef8d286 | |||
| 6424e6a3f3 | |||
| 8606ccffc9 | |||
| 2bf02a5be5 | |||
| abc507d173 | |||
| c18cba4faf | |||
| 010ba01ee7 |
@@ -457,10 +457,11 @@ enum ServerLockType : int {
|
|||||||
Unlock
|
Unlock
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Invisibility : uint8 {
|
enum Invisibility : uint16 {
|
||||||
Visible,
|
Visible,
|
||||||
Invisible,
|
Invisible,
|
||||||
Special = 255
|
Special = 255,
|
||||||
|
GMInvis = 3001
|
||||||
};
|
};
|
||||||
|
|
||||||
enum AugmentActions : int {
|
enum AugmentActions : int {
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ namespace Logs {
|
|||||||
Corpses,
|
Corpses,
|
||||||
XTargets,
|
XTargets,
|
||||||
EvolveItem,
|
EvolveItem,
|
||||||
|
Visibility,
|
||||||
MaxCategoryID /* Don't Remove this */
|
MaxCategoryID /* Don't Remove this */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -244,7 +245,8 @@ namespace Logs {
|
|||||||
"EqTime",
|
"EqTime",
|
||||||
"Corpses",
|
"Corpses",
|
||||||
"XTargets",
|
"XTargets",
|
||||||
"EvolveItem"
|
"EvolveItem",
|
||||||
|
"Visibility"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -854,6 +854,16 @@
|
|||||||
OutF(LogSys, Logs::Detail, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
OutF(LogSys, Logs::Detail, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define LogVisibility(message, ...) do {\
|
||||||
|
if (LogSys.IsLogEnabled(Logs::General, Logs::Visibility))\
|
||||||
|
OutF(LogSys, Logs::General, Logs::Visibility, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LogVisibilityDetail(message, ...) do {\
|
||||||
|
if (LogSys.IsLogEnabled(Logs::Detail, Logs::Visibility))\
|
||||||
|
OutF(LogSys, Logs::Detail, Logs::Visibility, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define Log(debug_level, log_category, message, ...) do {\
|
#define Log(debug_level, log_category, message, ...) do {\
|
||||||
if (LogSys.IsLogEnabled(debug_level, log_category))\
|
if (LogSys.IsLogEnabled(debug_level, log_category))\
|
||||||
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
|
|||||||
@@ -373,6 +373,8 @@ RULE_BOOL(Zone, AllowCrossZoneSpellsOnBots, false, "Set to true to allow cross z
|
|||||||
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_BOOL(Zone, ZoneShardQuestMenuOnly, false, "Set to true if you only want quests to show the zone shard menu")
|
||||||
|
RULE_BOOL(Zone, AkkadiusTempPerformanceFeatureFlag, true, "Enable or disable the Akkadius Temp Performance Feature Flag")
|
||||||
|
RULE_BOOL(Zone, EnableEntityClipping, true, "Enable or disable visual entity clipping server side")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Map)
|
RULE_CATEGORY(Map)
|
||||||
|
|||||||
@@ -86,6 +86,9 @@ struct BenchTimer
|
|||||||
void reset() { start_time = clock::now(); }
|
void reset() { start_time = clock::now(); }
|
||||||
// this is seconds
|
// this is seconds
|
||||||
double elapsed() { return std::chrono::duration<double> (clock::now() - start_time).count(); }
|
double elapsed() { return std::chrono::duration<double> (clock::now() - start_time).count(); }
|
||||||
|
std::chrono::milliseconds::rep elapsedMilliseconds() { return std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() - start_time).count(); }
|
||||||
|
std::chrono::microseconds::rep elapsedMicroseconds() { return std::chrono::duration_cast<std::chrono::microseconds>(clock::now() - start_time).count(); }
|
||||||
|
std::chrono::nanoseconds::rep elapsedNanoseconds() { return std::chrono::duration_cast<std::chrono::nanoseconds>(clock::now() - start_time).count(); }
|
||||||
private:
|
private:
|
||||||
std::chrono::time_point<std::chrono::high_resolution_clock> start_time;
|
std::chrono::time_point<std::chrono::high_resolution_clock> start_time;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -679,7 +679,7 @@ int ZoneStore::GetZoneNPCMaximumAggroDistance(uint32 zone_id, int version)
|
|||||||
uint32 ZoneStore::GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version)
|
uint32 ZoneStore::GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version)
|
||||||
{
|
{
|
||||||
const auto& z = GetZoneVersionWithFallback(zone_id, version);
|
const auto& z = GetZoneVersionWithFallback(zone_id, version);
|
||||||
return z ? z->max_movement_update_range : DEFAULT_ZONE_MAX_MOVEMENT_UPDATE_RANGE;
|
return z ? z->npc_update_range : DEFAULT_ZONE_MAX_MOVEMENT_UPDATE_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int8 ZoneStore::GetZoneMinimumExpansion(uint32 zone_id, int version)
|
int8 ZoneStore::GetZoneMinimumExpansion(uint32 zone_id, int version)
|
||||||
|
|||||||
@@ -7390,39 +7390,6 @@ void EntityList::ShowSpawnWindow(Client* client, int Distance, bool NamedOnly) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param close_mobs
|
|
||||||
* @param scanning_mob
|
|
||||||
*/
|
|
||||||
void EntityList::ScanCloseClientMobs(std::unordered_map<uint16, Mob*>& close_mobs, Mob* scanning_mob)
|
|
||||||
{
|
|
||||||
float scan_range = RuleI(Range, MobCloseScanDistance) * RuleI(Range, MobCloseScanDistance);
|
|
||||||
|
|
||||||
close_mobs.clear();
|
|
||||||
|
|
||||||
for (auto& e : mob_list) {
|
|
||||||
auto mob = e.second;
|
|
||||||
|
|
||||||
if (!mob->IsClient()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mob->GetID() <= 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float distance = DistanceSquared(scanning_mob->GetPosition(), mob->GetPosition());
|
|
||||||
if (distance <= scan_range) {
|
|
||||||
close_mobs.insert(std::pair<uint16, Mob*>(mob->GetID(), mob));
|
|
||||||
}
|
|
||||||
else if (mob->GetAggroRange() >= scan_range) {
|
|
||||||
close_mobs.insert(std::pair<uint16, Mob*>(mob->GetID(), mob));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LogAIScanCloseDetail("Close Client Mob List Size [{}] for mob [{}]", close_mobs.size(), scanning_mob->GetCleanName());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 Bot::GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets, Raid* raid) {
|
uint8 Bot::GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets, Raid* raid) {
|
||||||
|
|
||||||
uint8 need_healed = 0;
|
uint8 need_healed = 0;
|
||||||
|
|||||||
+72
-17
@@ -12939,17 +12939,10 @@ void Client::SendTopLevelInventory()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// On a normal basis we limit mob movement updates based on distance
|
|
||||||
// This ensures we send a periodic full zone update to a client that has started moving after 5 or so minutes
|
|
||||||
//
|
|
||||||
// For very large zones we will also force a full update based on distance
|
|
||||||
//
|
|
||||||
// We ignore a small distance around us so that we don't interrupt already pathing deltas as those npcs will appear
|
|
||||||
// to full stop when they are actually still pathing
|
|
||||||
void Client::CheckSendBulkClientPositionUpdate()
|
void Client::CheckSendBulkClientPositionUpdate()
|
||||||
{
|
{
|
||||||
float distance_moved = DistanceNoZ(m_last_position_before_bulk_update, GetPosition());
|
float distance_moved = DistanceNoZ(m_last_position_before_bulk_update, GetPosition());
|
||||||
bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetNpcPositionUpdateDistance();
|
bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetMaxNpcUpdateRange();
|
||||||
bool is_ready_to_update = (
|
bool is_ready_to_update = (
|
||||||
m_client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update
|
m_client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update
|
||||||
);
|
);
|
||||||
@@ -12958,31 +12951,54 @@ void Client::CheckSendBulkClientPositionUpdate()
|
|||||||
LogDebug("[[{}]] Client Zone Wide Position Update NPCs", GetCleanName());
|
LogDebug("[[{}]] Client Zone Wide Position Update NPCs", GetCleanName());
|
||||||
|
|
||||||
auto &mob_movement_manager = MobMovementManager::Get();
|
auto &mob_movement_manager = MobMovementManager::Get();
|
||||||
auto &mob_list = entity_list.GetMobList();
|
|
||||||
|
|
||||||
for (auto &it : mob_list) {
|
for (auto &e: entity_list.GetMobList()) {
|
||||||
Mob *entity = it.second;
|
Mob *mob = e.second;
|
||||||
if (!entity->IsNPC()) {
|
if (!mob->IsNPC()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int animation_speed = 0;
|
int animation_speed = 0;
|
||||||
if (entity->IsMoving()) {
|
if (mob->IsMoving()) {
|
||||||
if (entity->IsRunning()) {
|
if (mob->IsRunning()) {
|
||||||
animation_speed = (entity->IsFeared() ? entity->GetFearSpeed() : entity->GetRunspeed());
|
animation_speed = (mob->IsFeared() ? mob->GetFearSpeed() : mob->GetRunspeed());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
animation_speed = entity->GetWalkspeed();
|
animation_speed = mob->GetWalkspeed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mob_movement_manager.SendCommandToClients(entity, 0.0, 0.0, 0.0, 0.0, animation_speed, ClientRangeAny, this);
|
// if we have seen this mob before, and it hasn't moved, skip it
|
||||||
|
if (RuleB(Zone, AkkadiusTempPerformanceFeatureFlag)) {
|
||||||
|
if (m_last_seen_mob_position.contains(mob->GetID())) {
|
||||||
|
if (m_last_seen_mob_position[mob->GetID()] == mob->GetPosition()) {
|
||||||
|
LogVisibilityDetail(
|
||||||
|
"Mob [{}] has already been sent to client [{}] at this position, skipping",
|
||||||
|
mob->GetCleanName(),
|
||||||
|
GetCleanName()
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mob_movement_manager.SendCommandToClients(
|
||||||
|
mob,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
animation_speed,
|
||||||
|
ClientRangeAny,
|
||||||
|
this
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_last_position_before_bulk_update = GetPosition();
|
m_last_position_before_bulk_update = GetPosition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const uint16 scan_npc_aggro_timer_idle = RuleI(Aggro, ClientAggroCheckIdleInterval);
|
const uint16 scan_npc_aggro_timer_idle = RuleI(Aggro, ClientAggroCheckIdleInterval);
|
||||||
const uint16 scan_npc_aggro_timer_moving = RuleI(Aggro, ClientAggroCheckMovingInterval);
|
const uint16 scan_npc_aggro_timer_moving = RuleI(Aggro, ClientAggroCheckMovingInterval);
|
||||||
|
|
||||||
@@ -13123,3 +13139,42 @@ void Client::SetAAEXPPercentage(uint8 percentage)
|
|||||||
SendAlternateAdvancementStats();
|
SendAlternateAdvancementStats();
|
||||||
SendAlternateAdvancementTable();
|
SendAlternateAdvancementTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::BroadcastPositionUpdate()
|
||||||
|
{
|
||||||
|
EQApplicationPacket outapp(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||||
|
PlayerPositionUpdateServer_Struct *spu = (PlayerPositionUpdateServer_Struct *) outapp.pBuffer;
|
||||||
|
|
||||||
|
memset(spu, 0x00, sizeof(PlayerPositionUpdateServer_Struct));
|
||||||
|
spu->spawn_id = GetID();
|
||||||
|
spu->x_pos = FloatToEQ19(GetX());
|
||||||
|
spu->y_pos = FloatToEQ19(GetY());
|
||||||
|
spu->z_pos = FloatToEQ19(GetZ());
|
||||||
|
spu->heading = FloatToEQ12(GetHeading());
|
||||||
|
spu->delta_x = FloatToEQ13(0);
|
||||||
|
spu->delta_y = FloatToEQ13(0);
|
||||||
|
spu->delta_z = FloatToEQ13(0);
|
||||||
|
spu->delta_heading = FloatToEQ10(0);
|
||||||
|
spu->animation = 0;
|
||||||
|
|
||||||
|
entity_list.QueueCloseClients(this, &outapp, true, zone->GetMaxClientUpdateRange());
|
||||||
|
|
||||||
|
Group *g = GetGroup();
|
||||||
|
if (g) {
|
||||||
|
for (auto & m : g->members) {
|
||||||
|
if (m && m->IsClient() && m != this) {
|
||||||
|
m->CastToClient()->QueuePacket(&outapp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::SetVisibility(Mob* mob, bool visible) {
|
||||||
|
mob->SendAppearancePacket(
|
||||||
|
AppearanceType::Invisibility,
|
||||||
|
visible ? m_invisibility_state : Invisibility::GMInvis, // reset back to original visibility state when visible
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
this
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1828,6 +1828,7 @@ public:
|
|||||||
void DoEvolveTransferXP(const EQApplicationPacket* app);
|
void DoEvolveTransferXP(const EQApplicationPacket* app);
|
||||||
void SendEvolveXPTransferWindow();
|
void SendEvolveXPTransferWindow();
|
||||||
void SendEvolveTransferResults(const EQ::ItemInstance &inst_from, const EQ::ItemInstance &inst_to, const EQ::ItemInstance &inst_from_new, const EQ::ItemInstance &inst_to_new, const uint32 compatibility, const uint32 max_transfer_level);
|
void SendEvolveTransferResults(const EQ::ItemInstance &inst_from, const EQ::ItemInstance &inst_to, const EQ::ItemInstance &inst_from_new, const EQ::ItemInstance &inst_to_new, const uint32 compatibility, const uint32 max_transfer_level);
|
||||||
|
void SetVisibility(Mob* mob, bool visible);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Mob;
|
friend class Mob;
|
||||||
@@ -2087,6 +2088,7 @@ private:
|
|||||||
Timer m_client_npc_aggro_scan_timer;
|
Timer m_client_npc_aggro_scan_timer;
|
||||||
void CheckClientToNpcAggroTimer();
|
void CheckClientToNpcAggroTimer();
|
||||||
void ClientToNpcAggroProcess();
|
void ClientToNpcAggroProcess();
|
||||||
|
void BroadcastPositionUpdate();
|
||||||
|
|
||||||
// bulk position updates
|
// bulk position updates
|
||||||
glm::vec4 m_last_position_before_bulk_update;
|
glm::vec4 m_last_position_before_bulk_update;
|
||||||
|
|||||||
@@ -971,6 +971,10 @@ void Client::CompleteConnect()
|
|||||||
RecordStats();
|
RecordStats();
|
||||||
AutoGrantAAPoints();
|
AutoGrantAAPoints();
|
||||||
|
|
||||||
|
if (RuleB(Zone, AkkadiusTempPerformanceFeatureFlag)) {
|
||||||
|
m_last_seen_mob_position.reserve(entity_list.GetMobList().size());
|
||||||
|
}
|
||||||
|
|
||||||
// enforce some rules..
|
// enforce some rules..
|
||||||
if (!CanEnterZone()) {
|
if (!CanEnterZone()) {
|
||||||
LogInfo("Kicking character [{}] from zone, not allowed here (missing requirements)", GetCleanName());
|
LogInfo("Kicking character [{}] from zone, not allowed here (missing requirements)", GetCleanName());
|
||||||
@@ -4956,6 +4960,21 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
|||||||
CheckScanCloseMobsMovingTimer();
|
CheckScanCloseMobsMovingTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RuleB(Zone, EnableEntityClipping)) {
|
||||||
|
if (moving) {
|
||||||
|
if (m_see_close_mobs_timer.GetRemainingTime() > 1000) {
|
||||||
|
m_see_close_mobs_timer.Disable();
|
||||||
|
m_see_close_mobs_timer.Start(1000);
|
||||||
|
m_see_close_mobs_timer.Trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_see_close_mobs_timer.GetDuration() == 1000) {
|
||||||
|
m_see_close_mobs_timer.Disable();
|
||||||
|
m_see_close_mobs_timer.Start(60000);
|
||||||
|
m_see_close_mobs_timer.Trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CheckSendBulkClientPositionUpdate();
|
CheckSendBulkClientPositionUpdate();
|
||||||
|
|
||||||
int32 new_animation = ppu->animation;
|
int32 new_animation = ppu->animation;
|
||||||
|
|||||||
@@ -122,8 +122,12 @@ bool Client::Process() {
|
|||||||
|
|
||||||
/* I haven't naturally updated my position in 10 seconds, updating manually */
|
/* I haven't naturally updated my position in 10 seconds, updating manually */
|
||||||
if (!IsMoving() && m_position_update_timer.Check()) {
|
if (!IsMoving() && m_position_update_timer.Check()) {
|
||||||
|
if (RuleB(Zone, AkkadiusTempPerformanceFeatureFlag)) {
|
||||||
|
CastToClient()->BroadcastPositionUpdate();
|
||||||
|
} else {
|
||||||
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mana_timer.Check())
|
if (mana_timer.Check())
|
||||||
CheckManaEndUpdate();
|
CheckManaEndUpdate();
|
||||||
@@ -285,6 +289,10 @@ bool Client::Process() {
|
|||||||
entity_list.ScanCloseMobs(this);
|
entity_list.ScanCloseMobs(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RuleB(Zone, EnableEntityClipping) && m_see_close_mobs_timer.Check() && RuleB(Zone, AkkadiusTempPerformanceFeatureFlag)) {
|
||||||
|
entity_list.UpdateVisibility(this);
|
||||||
|
}
|
||||||
|
|
||||||
if (RuleB(Inventory, LazyLoadBank)) {
|
if (RuleB(Inventory, LazyLoadBank)) {
|
||||||
// poll once a second to see if we are close to a banker and we haven't loaded the bank yet
|
// poll once a second to see if we are close to a banker and we haven't loaded the bank yet
|
||||||
if (!m_lazy_load_bank && lazy_load_bank_check_timer.Check()) {
|
if (!m_lazy_load_bank && lazy_load_bank_check_timer.Check()) {
|
||||||
|
|||||||
+1
-1
@@ -1122,7 +1122,7 @@ void EntityList::AESpell(
|
|||||||
|
|
||||||
LogAoeCast(
|
LogAoeCast(
|
||||||
"Close scan distance [{}] cast distance [{}]",
|
"Close scan distance [{}] cast distance [{}]",
|
||||||
RuleI(Range, MobCloseScanDistance),
|
zone->GetMaxNpcUpdateRange(),
|
||||||
distance
|
distance
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
+68
-19
@@ -1717,15 +1717,6 @@ void EntityList::QueueClientsByXTarget(Mob *sender, const EQApplicationPacket *a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param sender
|
|
||||||
* @param app
|
|
||||||
* @param ignore_sender
|
|
||||||
* @param distance
|
|
||||||
* @param skipped_mob
|
|
||||||
* @param is_ack_required
|
|
||||||
* @param filter
|
|
||||||
*/
|
|
||||||
void EntityList::QueueCloseClients(
|
void EntityList::QueueCloseClients(
|
||||||
Mob *sender,
|
Mob *sender,
|
||||||
const EQApplicationPacket *app,
|
const EQApplicationPacket *app,
|
||||||
@@ -1742,7 +1733,7 @@ void EntityList::QueueCloseClients(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (distance <= 0) {
|
if (distance <= 0) {
|
||||||
distance = 600;
|
distance = zone->GetMaxClientUpdateRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
float distance_squared = distance * distance;
|
float distance_squared = distance * distance;
|
||||||
@@ -2878,6 +2869,9 @@ bool EntityList::RemoveMobFromCloseLists(Mob *mob)
|
|||||||
);
|
);
|
||||||
|
|
||||||
it->second->m_close_mobs.erase(entity_id);
|
it->second->m_close_mobs.erase(entity_id);
|
||||||
|
it->second->m_can_see_mob.erase(entity_id);
|
||||||
|
it->second->m_last_seen_mob_position.erase(entity_id);
|
||||||
|
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2931,6 +2925,9 @@ void EntityList::RemoveAuraFromMobs(Mob *aura)
|
|||||||
// All of the above makes a tremendous impact on the bottom line of cpu cycle performance because we run an order of magnitude
|
// All of the above makes a tremendous impact on the bottom line of cpu cycle performance because we run an order of magnitude
|
||||||
// less checks by focusing our hot path logic down to a very small subset of relevant entities instead of looping an entire
|
// less checks by focusing our hot path logic down to a very small subset of relevant entities instead of looping an entire
|
||||||
// entity list (zone wide)
|
// entity list (zone wide)
|
||||||
|
|
||||||
|
BenchTimer g_scan_bench_timer;
|
||||||
|
|
||||||
void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
||||||
{
|
{
|
||||||
if (!scanning_mob) {
|
if (!scanning_mob) {
|
||||||
@@ -2941,7 +2938,9 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float scan_range = RuleI(Range, MobCloseScanDistance) * RuleI(Range, MobCloseScanDistance);
|
g_scan_bench_timer.reset();
|
||||||
|
|
||||||
|
float scan_range = std::max(zone->GetMaxNpcUpdateRange(), zone->GetMaxClientUpdateRange());
|
||||||
|
|
||||||
// Reserve memory in m_close_mobs to avoid frequent re-allocations if not already reserved.
|
// Reserve memory in m_close_mobs to avoid frequent re-allocations if not already reserved.
|
||||||
// Assuming mob_list.size() as an upper bound for reservation.
|
// Assuming mob_list.size() as an upper bound for reservation.
|
||||||
@@ -2957,7 +2956,7 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float distance = DistanceSquared(scanning_mob->GetPosition(), mob->GetPosition());
|
float distance = Distance(scanning_mob->GetPosition(), mob->GetPosition());
|
||||||
if (distance <= scan_range || mob->GetAggroRange() >= scan_range) {
|
if (distance <= scan_range || mob->GetAggroRange() >= scan_range) {
|
||||||
// add mob to scanning_mob's close list and vice versa
|
// add mob to scanning_mob's close list and vice versa
|
||||||
// check if the mob is already in the close mobs list before inserting
|
// check if the mob is already in the close mobs list before inserting
|
||||||
@@ -2969,10 +2968,64 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
|||||||
}
|
}
|
||||||
|
|
||||||
LogAIScanClose(
|
LogAIScanClose(
|
||||||
"[{}] Scanning close list > list_size [{}] moving [{}]",
|
"[{}] Scanning close list > list_size [{}] moving [{}] elapsed [{}] us",
|
||||||
scanning_mob->GetCleanName(),
|
scanning_mob->GetCleanName(),
|
||||||
scanning_mob->m_close_mobs.size(),
|
scanning_mob->m_close_mobs.size(),
|
||||||
scanning_mob->IsMoving() ? "true" : "false"
|
scanning_mob->IsMoving() ? "true" : "false",
|
||||||
|
g_scan_bench_timer.elapsedMicroseconds()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BenchTimer g_vis_bench_timer;
|
||||||
|
#define STATE_HIDDEN (-1)
|
||||||
|
#define STATE_VISIBLE 1
|
||||||
|
|
||||||
|
void EntityList::UpdateVisibility(Mob *scanning_mob) {
|
||||||
|
if (!scanning_mob) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_vis_bench_timer.reset();
|
||||||
|
|
||||||
|
// Ensure sufficient capacity in the visibility map
|
||||||
|
if (scanning_mob->m_can_see_mob.bucket_count() < scanning_mob->m_close_mobs.size()) {
|
||||||
|
scanning_mob->m_can_see_mob.reserve(scanning_mob->m_close_mobs.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through all mobs in the zone
|
||||||
|
for (auto &e: mob_list) {
|
||||||
|
auto mob = e.second;
|
||||||
|
if (!mob || mob == scanning_mob) { continue; }
|
||||||
|
|
||||||
|
// Update scanning_mob's visibility of mob
|
||||||
|
auto it_scanning_visible = scanning_mob->m_can_see_mob.find(mob->GetID());
|
||||||
|
int8_t scanning_visibility = (it_scanning_visible != scanning_mob->m_can_see_mob.end())
|
||||||
|
? it_scanning_visible->second : 0;
|
||||||
|
|
||||||
|
if (scanning_mob->CalculateDistance(mob) <= mob->GetUpdateRange()) {
|
||||||
|
if (scanning_visibility != STATE_VISIBLE) { // Become visible
|
||||||
|
if (scanning_mob->IsClient()) {
|
||||||
|
scanning_mob->CastToClient()->SetVisibility(mob, true);
|
||||||
|
}
|
||||||
|
scanning_mob->m_can_see_mob[mob->GetID()] = STATE_VISIBLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (scanning_visibility != STATE_HIDDEN) { // Become invisible
|
||||||
|
if (scanning_mob->IsClient()) {
|
||||||
|
scanning_mob->CastToClient()->SetVisibility(mob, false);
|
||||||
|
}
|
||||||
|
scanning_mob->m_can_see_mob[mob->GetID()] = STATE_HIDDEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogVisibility(
|
||||||
|
"[{}] Visibility > list_size [{}] moving [{}] elapsed [{}] us",
|
||||||
|
scanning_mob->GetCleanName(),
|
||||||
|
scanning_mob->m_can_see_mob.size(),
|
||||||
|
scanning_mob->IsMoving() ? "true" : "false",
|
||||||
|
g_vis_bench_timer.elapsedMicroseconds()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5759,14 +5812,10 @@ void EntityList::ReloadMerchants() {
|
|||||||
* then we return the full list
|
* then we return the full list
|
||||||
*
|
*
|
||||||
* See comments @EntityList::ScanCloseMobs for system explanation
|
* See comments @EntityList::ScanCloseMobs for system explanation
|
||||||
*
|
|
||||||
* @param mob
|
|
||||||
* @param distance
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
std::unordered_map<uint16, Mob *> &EntityList::GetCloseMobList(Mob *mob, float distance)
|
std::unordered_map<uint16, Mob *> &EntityList::GetCloseMobList(Mob *mob, float distance)
|
||||||
{
|
{
|
||||||
if (distance <= RuleI(Range, MobCloseScanDistance)) {
|
if (distance <= zone->GetMaxNpcUpdateRange()) {
|
||||||
return mob->m_close_mobs;
|
return mob->m_close_mobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -570,6 +570,8 @@ public:
|
|||||||
void RefreshClientXTargets(Client *c);
|
void RefreshClientXTargets(Client *c);
|
||||||
void SendAlternateAdvancementStats();
|
void SendAlternateAdvancementStats();
|
||||||
void ScanCloseMobs(Mob *scanning_mob);
|
void ScanCloseMobs(Mob *scanning_mob);
|
||||||
|
void UpdateVisibility(Mob *scanning_mob);
|
||||||
|
void UpdateKnownPositions(Mob *scanning_mob);
|
||||||
|
|
||||||
void GetTrapInfo(Client* c);
|
void GetTrapInfo(Client* c);
|
||||||
bool IsTrapGroupSpawned(uint32 trap_id, uint8 group);
|
bool IsTrapGroupSpawned(uint32 trap_id, uint8 group);
|
||||||
@@ -631,8 +633,6 @@ private:
|
|||||||
bool Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint32 iSpellTypes); // TODO: Evaluate this closesly in hopes to eliminate
|
bool Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint32 iSpellTypes); // TODO: Evaluate this closesly in hopes to eliminate
|
||||||
void ShowSpawnWindow(Client* client, int Distance, bool NamedOnly); // TODO: Implement ShowSpawnWindow in the bot class but it needs entity list stuff
|
void ShowSpawnWindow(Client* client, int Distance, bool NamedOnly); // TODO: Implement ShowSpawnWindow in the bot class but it needs entity list stuff
|
||||||
|
|
||||||
void ScanCloseClientMobs(std::unordered_map<uint16, Mob*>& close_mobs, Mob* scanning_mob);
|
|
||||||
|
|
||||||
void GetBotList(std::list<Bot*> &b_list);
|
void GetBotList(std::list<Bot*> &b_list);
|
||||||
private:
|
private:
|
||||||
std::list<Bot*> bot_list;
|
std::list<Bot*> bot_list;
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ Mob::Mob(
|
|||||||
position_update_melee_push_timer(500),
|
position_update_melee_push_timer(500),
|
||||||
hate_list_cleanup_timer(6000),
|
hate_list_cleanup_timer(6000),
|
||||||
m_scan_close_mobs_timer(6000),
|
m_scan_close_mobs_timer(6000),
|
||||||
|
m_see_close_mobs_timer(1000),
|
||||||
m_mob_check_moving_timer(1000),
|
m_mob_check_moving_timer(1000),
|
||||||
bot_attack_flag_timer(10000)
|
bot_attack_flag_timer(10000)
|
||||||
{
|
{
|
||||||
@@ -4126,6 +4127,10 @@ void Mob::SendAppearancePacket(
|
|||||||
auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||||
auto* a = (SpawnAppearance_Struct*)outapp->pBuffer;
|
auto* a = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||||
|
|
||||||
|
if (type == AppearanceType::Invisibility && value != Invisibility::GMInvis) {
|
||||||
|
m_invisibility_state = value;
|
||||||
|
}
|
||||||
|
|
||||||
a->spawn_id = GetID();
|
a->spawn_id = GetID();
|
||||||
a->type = type;
|
a->type = type;
|
||||||
a->parameter = value;
|
a->parameter = value;
|
||||||
@@ -8626,3 +8631,7 @@ void Mob::ClearDataBucketCache()
|
|||||||
DataBucket::DeleteFromCache(id, t);
|
DataBucket::DeleteFromCache(id, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Mob::GetUpdateRange() {
|
||||||
|
return IsClient() ? zone->GetMaxClientUpdateRange() : zone->GetMaxNpcUpdateRange();
|
||||||
|
}
|
||||||
|
|||||||
@@ -202,7 +202,10 @@ public:
|
|||||||
void DisplayInfo(Mob *mob);
|
void DisplayInfo(Mob *mob);
|
||||||
|
|
||||||
std::unordered_map<uint16, Mob *> m_close_mobs;
|
std::unordered_map<uint16, Mob *> m_close_mobs;
|
||||||
|
std::unordered_map<int, int8> m_can_see_mob;
|
||||||
|
std::unordered_map<int, glm::vec4> m_last_seen_mob_position;
|
||||||
Timer m_scan_close_mobs_timer;
|
Timer m_scan_close_mobs_timer;
|
||||||
|
Timer m_see_close_mobs_timer;
|
||||||
Timer m_mob_check_moving_timer;
|
Timer m_mob_check_moving_timer;
|
||||||
|
|
||||||
// Bot attack flag
|
// Bot attack flag
|
||||||
@@ -1490,6 +1493,7 @@ public:
|
|||||||
|
|
||||||
std::unordered_map<uint16, Mob *> &GetCloseMobList(float distance = 0.0f);
|
std::unordered_map<uint16, Mob *> &GetCloseMobList(float distance = 0.0f);
|
||||||
void CheckScanCloseMobsMovingTimer();
|
void CheckScanCloseMobsMovingTimer();
|
||||||
|
float GetUpdateRange();
|
||||||
|
|
||||||
void ClearDataBucketCache();
|
void ClearDataBucketCache();
|
||||||
|
|
||||||
@@ -1907,6 +1911,8 @@ protected:
|
|||||||
|
|
||||||
MobMovementManager *mMovementManager;
|
MobMovementManager *mMovementManager;
|
||||||
|
|
||||||
|
bool m_invisibility_state = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Mob* target;
|
Mob* target;
|
||||||
EQ::InventoryProfile m_inv;
|
EQ::InventoryProfile m_inv;
|
||||||
|
|||||||
@@ -852,11 +852,14 @@ void MobMovementManager::SendCommandToClients(
|
|||||||
}
|
}
|
||||||
|
|
||||||
c->QueuePacket(&outapp, false);
|
c->QueuePacket(&outapp, false);
|
||||||
|
if (RuleB(Zone, AkkadiusTempPerformanceFeatureFlag)) {
|
||||||
|
c->m_last_seen_mob_position[mob->GetID()] = mob->GetPosition();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
float short_range = RuleR(Pathing, ShortMovementUpdateRange);
|
float short_range = RuleR(Pathing, ShortMovementUpdateRange);
|
||||||
float long_range = zone->GetNpcPositionUpdateDistance();
|
float long_range = zone->GetMaxNpcUpdateRange();
|
||||||
|
|
||||||
for (auto &c : _impl->Clients) {
|
for (auto &c : _impl->Clients) {
|
||||||
if (single_client && c != single_client) {
|
if (single_client && c != single_client) {
|
||||||
@@ -902,6 +905,9 @@ void MobMovementManager::SendCommandToClients(
|
|||||||
}
|
}
|
||||||
|
|
||||||
c->QueuePacket(&outapp, false);
|
c->QueuePacket(&outapp, false);
|
||||||
|
if (RuleB(Zone, AkkadiusTempPerformanceFeatureFlag)) {
|
||||||
|
c->m_last_seen_mob_position[mob->GetID()] = mob->GetPosition();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-62
@@ -1091,7 +1091,6 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
|
|||||||
|
|
||||||
mMovementManager = &MobMovementManager::Get();
|
mMovementManager = &MobMovementManager::Get();
|
||||||
|
|
||||||
SetNpcPositionUpdateDistance(0);
|
|
||||||
SetQuestHotReloadQueued(false);
|
SetQuestHotReloadQueued(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1380,7 +1379,8 @@ bool Zone::LoadZoneCFG(const char* filename, uint16 instance_version)
|
|||||||
can_levitate = z->canlevitate != 0;
|
can_levitate = z->canlevitate != 0;
|
||||||
can_castoutdoor = z->castoutdoor != 0;
|
can_castoutdoor = z->castoutdoor != 0;
|
||||||
is_hotzone = z->hotzone != 0;
|
is_hotzone = z->hotzone != 0;
|
||||||
max_movement_update_range = z->max_movement_update_range;
|
m_npc_update_range = z->npc_update_range;
|
||||||
|
m_client_update_range = z->client_update_range;
|
||||||
default_ruleset = z->ruleset;
|
default_ruleset = z->ruleset;
|
||||||
allow_mercs = true;
|
allow_mercs = true;
|
||||||
m_graveyard_id = z->graveyard_id;
|
m_graveyard_id = z->graveyard_id;
|
||||||
@@ -1538,10 +1538,6 @@ bool Zone::Process() {
|
|||||||
if (adv_data && !did_adventure_actions) {
|
if (adv_data && !did_adventure_actions) {
|
||||||
DoAdventureActions();
|
DoAdventureActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetNpcPositionUpdateDistance() == 0) {
|
|
||||||
CalculateNpcUpdateDistanceSpread();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hot_reload_timer.Check() && IsQuestHotReloadQueued()) {
|
if (hot_reload_timer.Check() && IsQuestHotReloadQueued()) {
|
||||||
@@ -2735,62 +2731,6 @@ void Zone::SetUCSServerAvailable(bool ucss_available, uint32 update_timestamp) {
|
|||||||
m_ucss_available = ucss_available;
|
m_ucss_available = ucss_available;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Zone::GetNpcPositionUpdateDistance() const
|
|
||||||
{
|
|
||||||
return npc_position_update_distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Zone::SetNpcPositionUpdateDistance(int in_npc_position_update_distance)
|
|
||||||
{
|
|
||||||
Zone::npc_position_update_distance = in_npc_position_update_distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Zone::CalculateNpcUpdateDistanceSpread()
|
|
||||||
{
|
|
||||||
float max_x = 0;
|
|
||||||
float max_y = 0;
|
|
||||||
float min_x = 0;
|
|
||||||
float min_y = 0;
|
|
||||||
|
|
||||||
auto &mob_list = entity_list.GetMobList();
|
|
||||||
|
|
||||||
for (auto &it : mob_list) {
|
|
||||||
Mob *entity = it.second;
|
|
||||||
if (!entity->IsNPC()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity->GetX() <= min_x) {
|
|
||||||
min_x = entity->GetX();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity->GetY() <= min_y) {
|
|
||||||
min_y = entity->GetY();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity->GetX() >= max_x) {
|
|
||||||
max_x = entity->GetX();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity->GetY() >= max_y) {
|
|
||||||
max_y = entity->GetY();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int x_spread = int(std::abs(max_x - min_x));
|
|
||||||
int y_spread = int(std::abs(max_y - min_y));
|
|
||||||
int combined_spread = int(std::abs((x_spread + y_spread) / 2));
|
|
||||||
int update_distance = EQ::ClampLower(int(combined_spread / 4), int(zone->GetMaxMovementUpdateRange()));
|
|
||||||
|
|
||||||
SetNpcPositionUpdateDistance(update_distance);
|
|
||||||
|
|
||||||
Log(Logs::General, Logs::Debug,
|
|
||||||
"NPC update spread distance set to [%i] combined_spread [%i]",
|
|
||||||
update_distance,
|
|
||||||
combined_spread
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Zone::IsQuestHotReloadQueued() const
|
bool Zone::IsQuestHotReloadQueued() const
|
||||||
{
|
{
|
||||||
return quest_hot_reload_queued;
|
return quest_hot_reload_queued;
|
||||||
|
|||||||
+4
-5
@@ -156,9 +156,6 @@ public:
|
|||||||
bool SaveZoneCFG();
|
bool SaveZoneCFG();
|
||||||
bool DoesAlternateCurrencyExist(uint32 currency_id);
|
bool DoesAlternateCurrencyExist(uint32 currency_id);
|
||||||
|
|
||||||
int GetNpcPositionUpdateDistance() const;
|
|
||||||
void SetNpcPositionUpdateDistance(int in_npc_position_update_distance);
|
|
||||||
|
|
||||||
char *adv_data;
|
char *adv_data;
|
||||||
|
|
||||||
const char *GetSpellBlockedMessage(uint32 spell_id, const glm::vec3 &location);
|
const char *GetSpellBlockedMessage(uint32 spell_id, const glm::vec3 &location);
|
||||||
@@ -417,7 +414,8 @@ public:
|
|||||||
SendDiscordMessage(webhook_id, message_prefix + Discord::FormatDiscordMessage(log_category, message));
|
SendDiscordMessage(webhook_id, message_prefix + Discord::FormatDiscordMessage(log_category, message));
|
||||||
};
|
};
|
||||||
|
|
||||||
double GetMaxMovementUpdateRange() const { return max_movement_update_range; }
|
double GetMaxNpcUpdateRange() const { return m_npc_update_range; }
|
||||||
|
double GetMaxClientUpdateRange() const { return m_client_update_range; }
|
||||||
|
|
||||||
void SetIsHotzone(bool is_hotzone);
|
void SetIsHotzone(bool is_hotzone);
|
||||||
|
|
||||||
@@ -469,7 +467,8 @@ private:
|
|||||||
bool staticzone;
|
bool staticzone;
|
||||||
bool zone_has_current_time;
|
bool zone_has_current_time;
|
||||||
bool quest_hot_reload_queued;
|
bool quest_hot_reload_queued;
|
||||||
double max_movement_update_range;
|
double m_npc_update_range;
|
||||||
|
double m_client_update_range;
|
||||||
char *long_name;
|
char *long_name;
|
||||||
char *map_name;
|
char *map_name;
|
||||||
char *short_name;
|
char *short_name;
|
||||||
|
|||||||
Reference in New Issue
Block a user