mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-19 13:28:25 +00:00
Merge branch 'master' into bot-rewrite
This commit is contained in:
@@ -7549,40 +7549,6 @@ void EntityList::ShowSpawnWindow(Client* client, int Distance, bool NamedOnly) {
|
||||
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 include_pets, Raid* raid) {
|
||||
|
||||
uint8 need_healed = 0;
|
||||
|
||||
+214
-32
@@ -67,6 +67,7 @@ extern volatile bool RunLoops;
|
||||
#include "../common/repositories/character_spells_repository.h"
|
||||
#include "../common/repositories/character_disciplines_repository.h"
|
||||
#include "../common/repositories/character_data_repository.h"
|
||||
#include "../common/repositories/character_pet_name_repository.h"
|
||||
#include "../common/repositories/discovered_items_repository.h"
|
||||
#include "../common/repositories/inventory_repository.h"
|
||||
#include "../common/repositories/keyring_repository.h"
|
||||
@@ -159,7 +160,7 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
||||
endupkeep_timer(1000),
|
||||
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
|
||||
m_client_npc_aggro_scan_timer(RuleI(Aggro, ClientAggroCheckIdleInterval)),
|
||||
m_client_zone_wide_full_position_update_timer(5 * 60 * 1000),
|
||||
m_client_bulk_npc_pos_update_timer(60 * 1000),
|
||||
tribute_timer(Tribute_duration),
|
||||
proximity_timer(ClientProximity_interval),
|
||||
TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000),
|
||||
@@ -405,6 +406,7 @@ Client::~Client() {
|
||||
|
||||
mMovementManager->RemoveClient(this);
|
||||
|
||||
DataBucket::DeleteCachedBuckets(DataBucketLoadType::Account, AccountID());
|
||||
DataBucket::DeleteCachedBuckets(DataBucketLoadType::Client, CharacterID());
|
||||
|
||||
if (RuleB(Bots, Enabled)) {
|
||||
@@ -1832,7 +1834,7 @@ void Client::FriendsWho(char *FriendsString) {
|
||||
Message(0, "Error: World server disconnected");
|
||||
else {
|
||||
auto pack =
|
||||
new ServerPacket(ServerOP_FriendsWho, sizeof(ServerFriendsWho_Struct) + strlen(FriendsString));
|
||||
new ServerPacket(ServerOP_FriendsWho, sizeof(ServerFriendsWho_Struct) + strlen(FriendsString));
|
||||
ServerFriendsWho_Struct* FriendsWho = (ServerFriendsWho_Struct*) pack->pBuffer;
|
||||
FriendsWho->FromID = GetID();
|
||||
strcpy(FriendsWho->FromName, GetName());
|
||||
@@ -2213,7 +2215,7 @@ void Client::Stand() {
|
||||
}
|
||||
|
||||
void Client::Sit() {
|
||||
SetAppearance(eaSitting, false);
|
||||
SetAppearance(eaSitting, false);
|
||||
}
|
||||
|
||||
void Client::ChangeLastName(std::string last_name) {
|
||||
@@ -4396,6 +4398,83 @@ void Client::KeyRingList()
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::IsPetNameChangeAllowed() {
|
||||
DataBucketKey k = GetScopedBucketKeys();
|
||||
k.key = "PetNameChangesAllowed";
|
||||
|
||||
auto b = DataBucket::GetData(k);
|
||||
if (!b.value.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Client::InvokeChangePetName(bool immediate) {
|
||||
if (!IsPetNameChangeAllowed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet_op = immediate ? OP_InvokeChangePetNameImmediate : OP_InvokeChangePetName;
|
||||
|
||||
auto outapp = new EQApplicationPacket(packet_op, 0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::GrantPetNameChange() {
|
||||
DataBucketKey k = GetScopedBucketKeys();
|
||||
k.key = "PetNameChangesAllowed";
|
||||
k.value = "true";
|
||||
DataBucket::SetData(k);
|
||||
|
||||
InvokeChangePetName(true);
|
||||
}
|
||||
|
||||
void Client::ClearPetNameChange() {
|
||||
DataBucketKey k = GetScopedBucketKeys();
|
||||
k.key = "PetNameChangesAllowed";
|
||||
|
||||
DataBucket::DeleteData(k);
|
||||
}
|
||||
|
||||
bool Client::ChangePetName(std::string new_name)
|
||||
{
|
||||
if (new_name.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsPetNameChangeAllowed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pet = GetPet();
|
||||
if (!pet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pet->GetName() == new_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!database.CheckNameFilter(new_name) || database.IsNameUsed(new_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CharacterPetNameRepository::ReplaceOne(
|
||||
database,
|
||||
CharacterPetNameRepository::CharacterPetName{
|
||||
.character_id = static_cast<int32_t>(CharacterID()),
|
||||
.name = new_name
|
||||
}
|
||||
);
|
||||
|
||||
pet->TempName(new_name.c_str());
|
||||
|
||||
ClearPetNameChange();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Client::IsDiscovered(uint32 item_id) {
|
||||
const auto& l = DiscoveredItemsRepository::GetWhere(
|
||||
database,
|
||||
@@ -5632,13 +5711,13 @@ bool Client::TryReward(uint32 claim_id)
|
||||
|
||||
if (amt == 1) {
|
||||
query = StringFormat("DELETE FROM account_rewards "
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
} else {
|
||||
query = StringFormat("UPDATE account_rewards SET amount = (amount-1) "
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
@@ -8371,7 +8450,7 @@ int Client::GetQuiverHaste(int delay)
|
||||
for (int r = EQ::invslot::GENERAL_BEGIN; r <= EQ::invslot::GENERAL_END; r++) {
|
||||
pi = GetInv().GetItem(r);
|
||||
if (pi && pi->IsClassBag() && pi->GetItem()->BagType == EQ::item::BagTypeQuiver &&
|
||||
pi->GetItem()->BagWR > 0)
|
||||
pi->GetItem()->BagWR > 0)
|
||||
break;
|
||||
if (r == EQ::invslot::GENERAL_END)
|
||||
// we will get here if we don't find a valid quiver
|
||||
@@ -9845,7 +9924,7 @@ const ExpeditionLockoutTimer* Client::GetExpeditionLockout(
|
||||
for (const auto& expedition_lockout : m_expedition_lockouts)
|
||||
{
|
||||
if ((include_expired || !expedition_lockout.IsExpired()) &&
|
||||
expedition_lockout.IsSameLockout(expedition_name, event_name))
|
||||
expedition_lockout.IsSameLockout(expedition_name, event_name))
|
||||
{
|
||||
return &expedition_lockout;
|
||||
}
|
||||
@@ -9860,7 +9939,7 @@ std::vector<ExpeditionLockoutTimer> Client::GetExpeditionLockouts(
|
||||
for (const auto& lockout : m_expedition_lockouts)
|
||||
{
|
||||
if ((include_expired || !lockout.IsExpired()) &&
|
||||
lockout.GetExpeditionName() == expedition_name)
|
||||
lockout.GetExpeditionName() == expedition_name)
|
||||
{
|
||||
lockouts.emplace_back(lockout);
|
||||
}
|
||||
@@ -12944,50 +13023,77 @@ 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::CheckSendBulkNpcPositions()
|
||||
{
|
||||
float distance_moved = DistanceNoZ(m_last_position_before_bulk_update, GetPosition());
|
||||
bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetNpcPositionUpdateDistance();
|
||||
float update_range = RuleI(Range, MobCloseScanDistance);
|
||||
bool moved_far_enough_before_bulk_update = distance_moved >= update_range;
|
||||
bool is_ready_to_update = (
|
||||
m_client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update
|
||||
m_client_bulk_npc_pos_update_timer.Check() || moved_far_enough_before_bulk_update
|
||||
);
|
||||
|
||||
if (IsMoving() && is_ready_to_update) {
|
||||
LogDebug("[[{}]] Client Zone Wide Position Update NPCs", GetCleanName());
|
||||
|
||||
int updated_count = 0;
|
||||
int skipped_count = 0;
|
||||
if (is_ready_to_update) {
|
||||
auto &mob_movement_manager = MobMovementManager::Get();
|
||||
auto &mob_list = entity_list.GetMobList();
|
||||
|
||||
for (auto &it : mob_list) {
|
||||
Mob *entity = it.second;
|
||||
if (!entity->IsNPC()) {
|
||||
for (auto &e: entity_list.GetMobList()) {
|
||||
Mob *mob = e.second;
|
||||
if (!mob->IsNPC()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int animation_speed = 0;
|
||||
if (entity->IsMoving()) {
|
||||
if (entity->IsRunning()) {
|
||||
animation_speed = (entity->IsFeared() ? entity->GetFearSpeed() : entity->GetRunspeed());
|
||||
if (mob->IsMoving()) {
|
||||
if (mob->IsRunning()) {
|
||||
animation_speed = (mob->IsFeared() ? mob->GetFearSpeed() : mob->GetRunspeed());
|
||||
}
|
||||
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 (m_last_seen_mob_position.contains(mob->GetID())) {
|
||||
if (m_last_seen_mob_position[mob->GetID()] == mob->GetPosition()) {
|
||||
LogPositionUpdateDetail(
|
||||
"Mob [{}] has already been sent to client [{}] at this position, skipping",
|
||||
mob->GetCleanName(),
|
||||
GetCleanName()
|
||||
);
|
||||
skipped_count++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
mob_movement_manager.SendCommandToClients(
|
||||
mob,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
animation_speed,
|
||||
ClientRangeAny,
|
||||
this
|
||||
);
|
||||
|
||||
updated_count++;
|
||||
}
|
||||
|
||||
LogPositionUpdate(
|
||||
"[{}] Sent [{}] bulk updated NPC positions, skipped [{}] distance_moved [{}] update_range [{}]",
|
||||
GetCleanName(),
|
||||
updated_count,
|
||||
skipped_count,
|
||||
distance_moved,
|
||||
update_range
|
||||
);
|
||||
|
||||
m_last_position_before_bulk_update = GetPosition();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const uint16 scan_npc_aggro_timer_idle = RuleI(Aggro, ClientAggroCheckIdleInterval);
|
||||
const uint16 scan_npc_aggro_timer_moving = RuleI(Aggro, ClientAggroCheckMovingInterval);
|
||||
|
||||
@@ -13278,3 +13384,79 @@ void Client::SetAAEXPPercentage(uint8 percentage)
|
||||
SendAlternateAdvancementStats();
|
||||
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->GetClientUpdateRange());
|
||||
|
||||
Group *g = GetGroup();
|
||||
if (g) {
|
||||
for (auto &m: g->members) {
|
||||
if (m && m->IsClient() && m != this) {
|
||||
m->CastToClient()->QueuePacket(&outapp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Client::GetAccountBucket(std::string bucket_name)
|
||||
{
|
||||
DataBucketKey k = {};
|
||||
k.account_id = AccountID();
|
||||
k.key = bucket_name;
|
||||
|
||||
return DataBucket::GetData(k).value;
|
||||
}
|
||||
|
||||
void Client::SetAccountBucket(std::string bucket_name, std::string bucket_value, std::string expiration)
|
||||
{
|
||||
DataBucketKey k = {};
|
||||
k.account_id = AccountID();
|
||||
k.key = bucket_name;
|
||||
k.expires = expiration;
|
||||
k.value = bucket_value;
|
||||
|
||||
DataBucket::SetData(k);
|
||||
}
|
||||
|
||||
void Client::DeleteAccountBucket(std::string bucket_name)
|
||||
{
|
||||
DataBucketKey k = {};
|
||||
k.account_id = AccountID();
|
||||
k.key = bucket_name;
|
||||
|
||||
DataBucket::DeleteData(k);
|
||||
}
|
||||
|
||||
std::string Client::GetAccountBucketExpires(std::string bucket_name)
|
||||
{
|
||||
DataBucketKey k = {};
|
||||
k.account_id = AccountID();
|
||||
k.key = bucket_name;
|
||||
|
||||
return DataBucket::GetDataExpires(k);
|
||||
}
|
||||
|
||||
std::string Client::GetAccountBucketRemaining(std::string bucket_name)
|
||||
{
|
||||
DataBucketKey k = {};
|
||||
k.account_id = AccountID();
|
||||
k.key = bucket_name;
|
||||
|
||||
return DataBucket::GetDataRemaining(k);
|
||||
}
|
||||
|
||||
+16
-2
@@ -320,6 +320,11 @@ public:
|
||||
void KeyRingAdd(uint32 item_id);
|
||||
bool KeyRingCheck(uint32 item_id);
|
||||
void KeyRingList();
|
||||
bool IsPetNameChangeAllowed();
|
||||
void GrantPetNameChange();
|
||||
void ClearPetNameChange();
|
||||
void InvokeChangePetName(bool immediate = true);
|
||||
bool ChangePetName(std::string new_name);
|
||||
bool IsClient() const override { return true; }
|
||||
bool IsOfClientBot() const override { return true; }
|
||||
bool IsOfClientBotMerc() const override { return true; }
|
||||
@@ -1848,6 +1853,13 @@ public:
|
||||
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);
|
||||
|
||||
// Account buckets
|
||||
std::string GetAccountBucket(std::string bucket_name);
|
||||
void SetAccountBucket(std::string bucket_name, std::string bucket_value, std::string expiration = "");
|
||||
void DeleteAccountBucket(std::string bucket_name);
|
||||
std::string GetAccountBucketExpires(std::string bucket_name);
|
||||
std::string GetAccountBucketRemaining(std::string bucket_name);
|
||||
|
||||
protected:
|
||||
friend class Mob;
|
||||
void CalcEdibleBonuses(StatBonuses* newbon);
|
||||
@@ -2107,12 +2119,13 @@ private:
|
||||
Timer m_client_npc_aggro_scan_timer;
|
||||
void CheckClientToNpcAggroTimer();
|
||||
void ClientToNpcAggroProcess();
|
||||
void BroadcastPositionUpdate();
|
||||
|
||||
// bulk position updates
|
||||
glm::vec4 m_last_position_before_bulk_update;
|
||||
Timer m_client_zone_wide_full_position_update_timer;
|
||||
Timer m_client_bulk_npc_pos_update_timer;
|
||||
Timer m_position_update_timer;
|
||||
void CheckSendBulkClientPositionUpdate();
|
||||
void CheckSendBulkNpcPositions();
|
||||
|
||||
void BulkSendInventoryItems();
|
||||
|
||||
@@ -2300,6 +2313,7 @@ public:
|
||||
const std::string &GetMailKeyFull() const;
|
||||
const std::string &GetMailKey() const;
|
||||
void ShowZoneShardMenu();
|
||||
void Handle_OP_ChangePetName(const EQApplicationPacket *app);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+38
-1
@@ -66,6 +66,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/repositories/character_corpses_repository.h"
|
||||
#include "../common/repositories/guild_tributes_repository.h"
|
||||
#include "../common/repositories/buyer_buy_lines_repository.h"
|
||||
#include "../common/repositories/character_pet_name_repository.h"
|
||||
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "../common/repositories/character_stats_record_repository.h"
|
||||
@@ -160,6 +161,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_CancelTrade] = &Client::Handle_OP_CancelTrade;
|
||||
ConnectedOpcodes[OP_CastSpell] = &Client::Handle_OP_CastSpell;
|
||||
ConnectedOpcodes[OP_ChannelMessage] = &Client::Handle_OP_ChannelMessage;
|
||||
ConnectedOpcodes[OP_ChangePetName] = &Client::Handle_OP_ChangePetName;
|
||||
ConnectedOpcodes[OP_ClearBlockedBuffs] = &Client::Handle_OP_ClearBlockedBuffs;
|
||||
ConnectedOpcodes[OP_ClearNPCMarks] = &Client::Handle_OP_ClearNPCMarks;
|
||||
ConnectedOpcodes[OP_ClearSurname] = &Client::Handle_OP_ClearSurname;
|
||||
@@ -824,6 +826,10 @@ void Client::CompleteConnect()
|
||||
CharacterID()
|
||||
)
|
||||
);
|
||||
|
||||
if (IsPetNameChangeAllowed()) {
|
||||
InvokeChangePetName(false);
|
||||
}
|
||||
}
|
||||
|
||||
if(ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants)) {
|
||||
@@ -975,6 +981,16 @@ void Client::CompleteConnect()
|
||||
RecordStats();
|
||||
AutoGrantAAPoints();
|
||||
|
||||
// set initial position for mob tracking
|
||||
m_last_seen_mob_position.reserve(entity_list.GetMobList().size());
|
||||
for (auto& mob : entity_list.GetMobList()) {
|
||||
if (!mob.second->IsNPC()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_last_seen_mob_position[mob.second->GetID()] = mob.second->GetPosition();
|
||||
}
|
||||
|
||||
// enforce some rules..
|
||||
if (!CanEnterZone()) {
|
||||
LogInfo("Kicking character [{}] from zone, not allowed here (missing requirements)", GetCleanName());
|
||||
@@ -4573,6 +4589,27 @@ void Client::Handle_OP_ChannelMessage(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_ChangePetName(const EQApplicationPacket *app) {
|
||||
if (app->size != sizeof(ChangePetName_Struct)) {
|
||||
LogError("Got OP_ChangePetName of incorrect size. Expected [{}], got [{}].", sizeof(ChangePetName_Struct), app->size);
|
||||
return;
|
||||
}
|
||||
|
||||
auto p = (ChangePetName_Struct *) app->pBuffer;
|
||||
if (!IsPetNameChangeAllowed()) {
|
||||
p->response_code = ChangePetNameResponse::NotEligible;
|
||||
QueuePacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
p->response_code = ChangePetNameResponse::Denied;
|
||||
if (ChangePetName(p->new_pet_name)) {
|
||||
p->response_code = ChangePetNameResponse::Accepted;
|
||||
}
|
||||
|
||||
QueuePacket(app);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_ClearBlockedBuffs(const EQApplicationPacket *app)
|
||||
{
|
||||
if (!RuleB(Spells, EnableBlockedBuffs))
|
||||
@@ -4971,7 +5008,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
CheckScanCloseMobsMovingTimer();
|
||||
}
|
||||
|
||||
CheckSendBulkClientPositionUpdate();
|
||||
CheckSendBulkNpcPositions();
|
||||
|
||||
int32 new_animation = ppu->animation;
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ bool Client::Process() {
|
||||
|
||||
/* I haven't naturally updated my position in 10 seconds, updating manually */
|
||||
if (!IsMoving() && m_position_update_timer.Check()) {
|
||||
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||
BroadcastPositionUpdate();
|
||||
}
|
||||
|
||||
if (mana_timer.Check())
|
||||
|
||||
+37
-12
@@ -16,6 +16,7 @@ void DataBucket::SetData(const std::string &bucket_key, const std::string &bucke
|
||||
.key = bucket_key,
|
||||
.value = bucket_value,
|
||||
.expires = expires_time,
|
||||
.account_id = 0,
|
||||
.character_id = 0,
|
||||
.npc_id = 0,
|
||||
.bot_id = 0
|
||||
@@ -37,6 +38,9 @@ void DataBucket::SetData(const DataBucketKey &k)
|
||||
if (k.character_id > 0) {
|
||||
b.character_id = k.character_id;
|
||||
}
|
||||
else if (k.account_id > 0) {
|
||||
b.account_id = k.account_id;
|
||||
}
|
||||
else if (k.npc_id > 0) {
|
||||
b.npc_id = k.npc_id;
|
||||
}
|
||||
@@ -95,9 +99,10 @@ std::string DataBucket::GetData(const std::string &bucket_key)
|
||||
DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, bool ignore_misses_cache)
|
||||
{
|
||||
LogDataBuckets(
|
||||
"Getting bucket key [{}] bot_id [{}] character_id [{}] npc_id [{}]",
|
||||
"Getting bucket key [{}] bot_id [{}] account_id [{}] character_id [{}] npc_id [{}]",
|
||||
k.key,
|
||||
k.bot_id,
|
||||
k.account_id,
|
||||
k.character_id,
|
||||
k.npc_id
|
||||
);
|
||||
@@ -151,6 +156,7 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, b
|
||||
.key_ = k.key,
|
||||
.value = "",
|
||||
.expires = 0,
|
||||
.account_id = k.account_id,
|
||||
.character_id = k.character_id,
|
||||
.npc_id = k.npc_id,
|
||||
.bot_id = k.bot_id
|
||||
@@ -158,8 +164,9 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, b
|
||||
);
|
||||
|
||||
LogDataBuckets(
|
||||
"Key [{}] not found in database, adding to cache as a miss character_id [{}] npc_id [{}] bot_id [{}] cache size before [{}] after [{}]",
|
||||
"Key [{}] not found in database, adding to cache as a miss account_id [{}] character_id [{}] npc_id [{}] bot_id [{}] cache size before [{}] after [{}]",
|
||||
k.key,
|
||||
k.account_id,
|
||||
k.character_id,
|
||||
k.npc_id,
|
||||
k.bot_id,
|
||||
@@ -216,8 +223,6 @@ bool DataBucket::DeleteData(const std::string &bucket_key)
|
||||
// GetDataBuckets bulk loads all data buckets for a mob
|
||||
bool DataBucket::GetDataBuckets(Mob *mob)
|
||||
{
|
||||
DataBucketLoadType::Type t{};
|
||||
|
||||
const uint32 id = mob->GetMobTypeIdentifier();
|
||||
|
||||
if (!id) {
|
||||
@@ -225,14 +230,13 @@ bool DataBucket::GetDataBuckets(Mob *mob)
|
||||
}
|
||||
|
||||
if (mob->IsBot()) {
|
||||
t = DataBucketLoadType::Bot;
|
||||
BulkLoadEntitiesToCache(DataBucketLoadType::Bot, {id});
|
||||
}
|
||||
else if (mob->IsClient()) {
|
||||
t = DataBucketLoadType::Client;
|
||||
BulkLoadEntitiesToCache(DataBucketLoadType::Account, {id});
|
||||
BulkLoadEntitiesToCache(DataBucketLoadType::Client, {id});
|
||||
}
|
||||
|
||||
BulkLoadEntitiesToCache(t, {id});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -254,9 +258,10 @@ bool DataBucket::DeleteData(const DataBucketKey &k)
|
||||
);
|
||||
|
||||
LogDataBuckets(
|
||||
"Deleting bucket key [{}] bot_id [{}] character_id [{}] npc_id [{}] cache size before [{}] after [{}]",
|
||||
"Deleting bucket key [{}] bot_id [{}] account_id [{}] character_id [{}] npc_id [{}] cache size before [{}] after [{}]",
|
||||
k.key,
|
||||
k.bot_id,
|
||||
k.account_id,
|
||||
k.character_id,
|
||||
k.npc_id,
|
||||
size_before,
|
||||
@@ -277,9 +282,10 @@ bool DataBucket::DeleteData(const DataBucketKey &k)
|
||||
std::string DataBucket::GetDataExpires(const DataBucketKey &k)
|
||||
{
|
||||
LogDataBuckets(
|
||||
"Getting bucket expiration key [{}] bot_id [{}] character_id [{}] npc_id [{}]",
|
||||
"Getting bucket expiration key [{}] bot_id [{}] account_id [{}] character_id [{}] npc_id [{}]",
|
||||
k.key,
|
||||
k.bot_id,
|
||||
k.account_id,
|
||||
k.character_id,
|
||||
k.npc_id
|
||||
);
|
||||
@@ -295,9 +301,10 @@ std::string DataBucket::GetDataExpires(const DataBucketKey &k)
|
||||
std::string DataBucket::GetDataRemaining(const DataBucketKey &k)
|
||||
{
|
||||
LogDataBuckets(
|
||||
"Getting bucket remaining key [{}] bot_id [{}] character_id [{}] npc_id [{}]",
|
||||
"Getting bucket remaining key [{}] bot_id [{}] account_id [{}] character_id [{}] npc_id [{}]",
|
||||
k.key,
|
||||
k.bot_id,
|
||||
k.account_id,
|
||||
k.character_id,
|
||||
k.npc_id
|
||||
);
|
||||
@@ -320,6 +327,13 @@ std::string DataBucket::GetScopedDbFilters(const DataBucketKey &k)
|
||||
query.emplace_back("character_id = 0");
|
||||
}
|
||||
|
||||
if (k.account_id > 0) {
|
||||
query.emplace_back(fmt::format("account_id = {}", k.account_id));
|
||||
}
|
||||
else {
|
||||
query.emplace_back("account_id = 0");
|
||||
}
|
||||
|
||||
if (k.npc_id > 0) {
|
||||
query.emplace_back(fmt::format("npc_id = {}", k.npc_id));
|
||||
}
|
||||
@@ -346,6 +360,7 @@ bool DataBucket::CheckBucketMatch(const DataBucketsRepository::DataBuckets &dbe,
|
||||
return (
|
||||
dbe.key_ == k.key &&
|
||||
dbe.bot_id == k.bot_id &&
|
||||
dbe.account_id == k.account_id &&
|
||||
dbe.character_id == k.character_id &&
|
||||
dbe.npc_id == k.npc_id
|
||||
);
|
||||
@@ -364,6 +379,9 @@ void DataBucket::BulkLoadEntitiesToCache(DataBucketLoadType::Type t, std::vector
|
||||
if (t == DataBucketLoadType::Bot) {
|
||||
has_cache = e.bot_id == ids[0];
|
||||
}
|
||||
else if (t == DataBucketLoadType::Account) {
|
||||
has_cache = e.account_id == ids[0];
|
||||
}
|
||||
else if (t == DataBucketLoadType::Client) {
|
||||
has_cache = e.character_id == ids[0];
|
||||
}
|
||||
@@ -384,6 +402,9 @@ void DataBucket::BulkLoadEntitiesToCache(DataBucketLoadType::Type t, std::vector
|
||||
case DataBucketLoadType::Client:
|
||||
column = "character_id";
|
||||
break;
|
||||
case DataBucketLoadType::Account:
|
||||
column = "account_id";
|
||||
break;
|
||||
default:
|
||||
LogError("Incorrect LoadType [{}]", static_cast<int>(t));
|
||||
break;
|
||||
@@ -442,6 +463,7 @@ void DataBucket::DeleteCachedBuckets(DataBucketLoadType::Type type, uint32 id)
|
||||
[&](DataBucketsRepository::DataBuckets &e) {
|
||||
return (
|
||||
(type == DataBucketLoadType::Bot && e.bot_id == id) ||
|
||||
(type == DataBucketLoadType::Account && e.account_id == id) ||
|
||||
(type == DataBucketLoadType::Client && e.character_id == id)
|
||||
);
|
||||
}
|
||||
@@ -481,6 +503,7 @@ void DataBucket::DeleteFromMissesCache(DataBucketsRepository::DataBuckets e)
|
||||
g_data_bucket_cache.end(),
|
||||
[&](DataBucketsRepository::DataBuckets &ce) {
|
||||
return ce.id == 0 && ce.key_ == e.key_ &&
|
||||
ce.account_id == e.account_id &&
|
||||
ce.character_id == e.character_id &&
|
||||
ce.npc_id == e.npc_id &&
|
||||
ce.bot_id == e.bot_id;
|
||||
@@ -516,6 +539,8 @@ void DataBucket::DeleteFromCache(uint64 id, DataBucketLoadType::Type type)
|
||||
return e.bot_id == id;
|
||||
case DataBucketLoadType::Client:
|
||||
return e.character_id == id;
|
||||
case DataBucketLoadType::Account:
|
||||
return e.account_id == id;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -539,7 +564,7 @@ void DataBucket::DeleteFromCache(uint64 id, DataBucketLoadType::Type type)
|
||||
// npcs (ids) can be in multiple zones so we can't cache locally to the zone
|
||||
bool DataBucket::CanCache(const DataBucketKey &key)
|
||||
{
|
||||
if (key.character_id > 0 || key.bot_id > 0) {
|
||||
if (key.character_id > 0 || key.account_id > 0 || key.bot_id > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -12,20 +12,23 @@ struct DataBucketKey {
|
||||
std::string key;
|
||||
std::string value;
|
||||
std::string expires;
|
||||
int64_t character_id;
|
||||
int64_t npc_id;
|
||||
int64_t bot_id;
|
||||
int64_t account_id = 0;
|
||||
int64_t character_id = 0;
|
||||
int64_t npc_id = 0;
|
||||
int64_t bot_id = 0;
|
||||
};
|
||||
|
||||
namespace DataBucketLoadType {
|
||||
enum Type : uint8 {
|
||||
Bot,
|
||||
Account,
|
||||
Client,
|
||||
MaxType
|
||||
};
|
||||
|
||||
static const std::string Name[Type::MaxType] = {
|
||||
"Bot",
|
||||
"Account",
|
||||
"Client",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5653,16 +5653,6 @@ int Perl__GetZoneNPCMaximumAggroDistance(uint32 zone_id, int version)
|
||||
return zone_store.GetZoneNPCMaximumAggroDistance(zone_id, version);
|
||||
}
|
||||
|
||||
uint32 Perl__GetZoneMaximumMovementUpdateRange(uint32 zone_id)
|
||||
{
|
||||
return zone_store.GetZoneMaximumMovementUpdateRange(zone_id);
|
||||
}
|
||||
|
||||
uint32 Perl__GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version)
|
||||
{
|
||||
return zone_store.GetZoneMaximumMovementUpdateRange(zone_id, version);
|
||||
}
|
||||
|
||||
int8 Perl__GetZoneMinimumExpansion(uint32 zone_id)
|
||||
{
|
||||
return zone_store.GetZoneMinimumExpansion(zone_id);
|
||||
@@ -6112,8 +6102,6 @@ void perl_register_quest()
|
||||
package.add("GetZoneMaximumExpansion", (int8(*)(uint32, int))&Perl__GetZoneMaximumExpansion);
|
||||
package.add("GetZoneMaximumLevel", (uint8(*)(uint32))&Perl__GetZoneMaximumLevel);
|
||||
package.add("GetZoneMaximumLevel", (uint8(*)(uint32, int))&Perl__GetZoneMaximumLevel);
|
||||
package.add("GetZoneMaximumMovementUpdateRange", (uint32(*)(uint32))&Perl__GetZoneMaximumMovementUpdateRange);
|
||||
package.add("GetZoneMaximumMovementUpdateRange", (uint32(*)(uint32, int))&Perl__GetZoneMaximumMovementUpdateRange);
|
||||
package.add("GetZoneMaximumPlayers", (int(*)(uint32))&Perl__GetZoneMaximumPlayers);
|
||||
package.add("GetZoneMaximumPlayers", (int(*)(uint32, int))&Perl__GetZoneMaximumPlayers);
|
||||
package.add("GetZoneMinimumClip", (float(*)(uint32))&Perl__GetZoneMinimumClip);
|
||||
|
||||
+13
-18
@@ -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(
|
||||
Mob *sender,
|
||||
const EQApplicationPacket *app,
|
||||
@@ -1742,7 +1733,7 @@ void EntityList::QueueCloseClients(
|
||||
}
|
||||
|
||||
if (distance <= 0) {
|
||||
distance = 600;
|
||||
distance = zone->GetClientUpdateRange();
|
||||
}
|
||||
|
||||
float distance_squared = distance * distance;
|
||||
@@ -2871,6 +2862,8 @@ bool EntityList::RemoveMobFromCloseLists(Mob *mob)
|
||||
);
|
||||
|
||||
it->second->m_close_mobs.erase(entity_id);
|
||||
it->second->m_last_seen_mob_position.erase(entity_id);
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
@@ -2924,6 +2917,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
|
||||
// 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)
|
||||
|
||||
BenchTimer g_scan_bench_timer;
|
||||
|
||||
void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
||||
{
|
||||
if (!scanning_mob) {
|
||||
@@ -2934,7 +2930,9 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
||||
return;
|
||||
}
|
||||
|
||||
float scan_range = RuleI(Range, MobCloseScanDistance) * RuleI(Range, MobCloseScanDistance);
|
||||
g_scan_bench_timer.reset();
|
||||
|
||||
float scan_range = RuleI(Range, MobCloseScanDistance);
|
||||
|
||||
// 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.
|
||||
@@ -2951,7 +2949,7 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
||||
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) {
|
||||
// add mob to scanning_mob's close list and vice versa
|
||||
// check if the mob is already in the close mobs list before inserting
|
||||
@@ -2963,10 +2961,11 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
||||
}
|
||||
|
||||
LogAIScanClose(
|
||||
"[{}] Scanning close list > list_size [{}] moving [{}]",
|
||||
"[{}] Scanning close list > list_size [{}] moving [{}] elapsed [{}] us",
|
||||
scanning_mob->GetCleanName(),
|
||||
scanning_mob->m_close_mobs.size(),
|
||||
scanning_mob->IsMoving() ? "true" : "false"
|
||||
scanning_mob->IsMoving() ? "true" : "false",
|
||||
g_scan_bench_timer.elapsedMicroseconds()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5752,10 +5751,6 @@ void EntityList::ReloadMerchants() {
|
||||
* then we return the full list
|
||||
*
|
||||
* See comments @EntityList::ScanCloseMobs for system explanation
|
||||
*
|
||||
* @param mob
|
||||
* @param distance
|
||||
* @return
|
||||
*/
|
||||
std::unordered_map<uint16, Mob *> &EntityList::GetCloseMobList(Mob *mob, float distance)
|
||||
{
|
||||
|
||||
@@ -630,8 +630,6 @@ private:
|
||||
|
||||
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);
|
||||
private:
|
||||
std::unordered_map<uint16, Bot*> bot_list;
|
||||
|
||||
@@ -9,6 +9,19 @@ void command_loc(Client *c, const Seperator *sep)
|
||||
|
||||
auto target_position = target->GetPosition();
|
||||
|
||||
// check los benchmark
|
||||
BenchTimer timer;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
zone->zonemap->CheckLoS(c->GetPosition(), target_position);
|
||||
}
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"CheckLoS benchmark took [{}]",
|
||||
timer.elapsed()
|
||||
).c_str()
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
|
||||
@@ -3458,12 +3458,54 @@ void Lua_Client::ShowZoneShardMenu()
|
||||
self->ShowZoneShardMenu();
|
||||
}
|
||||
|
||||
void Lua_Client::GrantPetNameChange()
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->GrantPetNameChange();
|
||||
}
|
||||
|
||||
void Lua_Client::SetAAEXPPercentage(uint8 percentage)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetAAEXPPercentage(percentage);
|
||||
}
|
||||
|
||||
void Lua_Client::SetAccountBucket(std::string bucket_name, std::string bucket_value)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetAccountBucket(bucket_name, bucket_value);
|
||||
}
|
||||
|
||||
void Lua_Client::SetAccountBucket(std::string bucket_name, std::string bucket_value, std::string expiration)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetAccountBucket(bucket_name, bucket_value, expiration);
|
||||
}
|
||||
|
||||
void Lua_Client::DeleteAccountBucket(std::string bucket_name)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->DeleteAccountBucket(bucket_name);
|
||||
}
|
||||
|
||||
std::string Lua_Client::GetAccountBucket(std::string bucket_name)
|
||||
{
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetAccountBucket(bucket_name);
|
||||
}
|
||||
|
||||
std::string Lua_Client::GetAccountBucketExpires(std::string bucket_name)
|
||||
{
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetAccountBucketExpires(bucket_name);
|
||||
}
|
||||
|
||||
std::string Lua_Client::GetAccountBucketRemaining(std::string bucket_name)
|
||||
{
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetAccountBucketRemaining(bucket_name);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_client() {
|
||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||
.def(luabind::constructor<>())
|
||||
@@ -3532,6 +3574,7 @@ luabind::scope lua_register_client() {
|
||||
.def("CanHaveSkill", (bool(Lua_Client::*)(int))&Lua_Client::CanHaveSkill)
|
||||
.def("CashReward", &Lua_Client::CashReward)
|
||||
.def("ChangeLastName", (void(Lua_Client::*)(std::string))&Lua_Client::ChangeLastName)
|
||||
.def("GrantPetNameChange", &Lua_Client::GrantPetNameChange)
|
||||
.def("CharacterID", (uint32(Lua_Client::*)(void))&Lua_Client::CharacterID)
|
||||
.def("CheckIncreaseSkill", (void(Lua_Client::*)(int,Lua_Mob))&Lua_Client::CheckIncreaseSkill)
|
||||
.def("CheckIncreaseSkill", (void(Lua_Client::*)(int,Lua_Mob,int))&Lua_Client::CheckIncreaseSkill)
|
||||
@@ -3552,6 +3595,7 @@ luabind::scope lua_register_client() {
|
||||
.def("CreateTaskDynamicZone", &Lua_Client::CreateTaskDynamicZone)
|
||||
.def("DecreaseByID", (bool(Lua_Client::*)(uint32,int))&Lua_Client::DecreaseByID)
|
||||
.def("DescribeSpecialAbilities", (void(Lua_Client::*)(Lua_NPC))&Lua_Client::DescribeSpecialAbilities)
|
||||
.def("DeleteAccountBucket", (void(Lua_Client::*)(std::string))&Lua_Client::DeleteAccountBucket)
|
||||
.def("DeleteBucket", (void(Lua_Client::*)(std::string))&Lua_Client::DeleteBucket)
|
||||
.def("DeleteItemInInventory", (void(Lua_Client::*)(int,int))&Lua_Client::DeleteItemInInventory)
|
||||
.def("DeleteItemInInventory", (void(Lua_Client::*)(int,int,bool))&Lua_Client::DeleteItemInInventory)
|
||||
@@ -3630,6 +3674,9 @@ luabind::scope lua_register_client() {
|
||||
.def("GetBotRequiredLevel", (int(Lua_Client::*)(uint8))&Lua_Client::GetBotRequiredLevel)
|
||||
.def("GetBotSpawnLimit", (int(Lua_Client::*)(void))&Lua_Client::GetBotSpawnLimit)
|
||||
.def("GetBotSpawnLimit", (int(Lua_Client::*)(uint8))&Lua_Client::GetBotSpawnLimit)
|
||||
.def("GetAccountBucket", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetAccountBucket)
|
||||
.def("GetAccountBucketExpires", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetAccountBucketExpires)
|
||||
.def("GetAccountBucketRemaining", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetAccountBucketRemaining)
|
||||
.def("GetBucket", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetBucket)
|
||||
.def("GetBucketExpires", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetBucketExpires)
|
||||
.def("GetBucketRemaining", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetBucketRemaining)
|
||||
@@ -3922,6 +3969,8 @@ luabind::scope lua_register_client() {
|
||||
.def("SetBotRequiredLevel", (void(Lua_Client::*)(int,uint8))&Lua_Client::SetBotRequiredLevel)
|
||||
.def("SetBotSpawnLimit", (void(Lua_Client::*)(int))&Lua_Client::SetBotSpawnLimit)
|
||||
.def("SetBotSpawnLimit", (void(Lua_Client::*)(int,uint8))&Lua_Client::SetBotSpawnLimit)
|
||||
.def("SetAccountBucket", (void(Lua_Client::*)(std::string,std::string))&Lua_Client::SetAccountBucket)
|
||||
.def("SetAccountBucket", (void(Lua_Client::*)(std::string,std::string,std::string))&Lua_Client::SetAccountBucket)
|
||||
.def("SetBucket", (void(Lua_Client::*)(std::string,std::string))&Lua_Client::SetBucket)
|
||||
.def("SetBucket", (void(Lua_Client::*)(std::string,std::string,std::string))&Lua_Client::SetBucket)
|
||||
.def("SetClientMaxLevel", (void(Lua_Client::*)(int))&Lua_Client::SetClientMaxLevel)
|
||||
|
||||
@@ -512,6 +512,14 @@ public:
|
||||
luabind::object GetInventorySlots(lua_State* L);
|
||||
void SetAAEXPPercentage(uint8 percentage);
|
||||
|
||||
// account data buckets
|
||||
void SetAccountBucket(std::string bucket_name, std::string bucket_value);
|
||||
void SetAccountBucket(std::string bucket_name, std::string bucket_value, std::string expiration = "");
|
||||
void DeleteAccountBucket(std::string bucket_name);
|
||||
std::string GetAccountBucket(std::string bucket_name);
|
||||
std::string GetAccountBucketExpires(std::string bucket_name);
|
||||
std::string GetAccountBucketRemaining(std::string bucket_name);
|
||||
|
||||
void ApplySpell(int spell_id);
|
||||
void ApplySpell(int spell_id, int duration);
|
||||
void ApplySpell(int spell_id, int duration, int level);
|
||||
@@ -589,6 +597,7 @@ public:
|
||||
|
||||
bool ReloadDataBuckets();
|
||||
void ShowZoneShardMenu();
|
||||
void GrantPetNameChange();
|
||||
|
||||
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);
|
||||
|
||||
@@ -4668,16 +4668,6 @@ int lua_get_zone_npc_maximum_aggro_distance(uint32 zone_id, int version)
|
||||
return zone_store.GetZoneNPCMaximumAggroDistance(zone_id, version);
|
||||
}
|
||||
|
||||
uint32 lua_get_zone_maximum_movement_update_range(uint32 zone_id)
|
||||
{
|
||||
return zone_store.GetZoneMaximumMovementUpdateRange(zone_id);
|
||||
}
|
||||
|
||||
uint32 lua_get_zone_maximum_movement_update_range(uint32 zone_id, int version)
|
||||
{
|
||||
return zone_store.GetZoneMaximumMovementUpdateRange(zone_id, version);
|
||||
}
|
||||
|
||||
int8 lua_get_zone_minimum_expansion(uint32 zone_id)
|
||||
{
|
||||
return zone_store.GetZoneMinimumExpansion(zone_id);
|
||||
@@ -6287,8 +6277,6 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("get_zone_fast_regen_endurance", (int(*)(uint32,int))&lua_get_zone_fast_regen_endurance),
|
||||
luabind::def("get_zone_npc_maximum_aggro_distance", (int(*)(uint32))&lua_get_zone_npc_maximum_aggro_distance),
|
||||
luabind::def("get_zone_npc_maximum_aggro_distance", (int(*)(uint32,int))&lua_get_zone_npc_maximum_aggro_distance),
|
||||
luabind::def("get_zone_npc_maximum_movement_update_range", (uint32(*)(uint32))&lua_get_zone_maximum_movement_update_range),
|
||||
luabind::def("get_zone_npc_maximum_movement_update_range", (uint32(*)(uint32,int))&lua_get_zone_maximum_movement_update_range),
|
||||
luabind::def("get_zone_minimum_expansion", (int8(*)(uint32))&lua_get_zone_minimum_expansion),
|
||||
luabind::def("get_zone_minimum_expansion", (int8(*)(uint32,int))&lua_get_zone_minimum_expansion),
|
||||
luabind::def("get_zone_maximum_expansion", (int8(*)(uint32))&lua_get_zone_maximum_expansion),
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "raycast_mesh.h"
|
||||
#include "zone.h"
|
||||
#include "../common/file.h"
|
||||
#include "../common/memory/ksm.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
@@ -953,6 +954,7 @@ bool Map::LoadV2(FILE *f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Map::RotateVertex(glm::vec3 &v, float rx, float ry, float rz) {
|
||||
glm::vec3 nv = v;
|
||||
|
||||
|
||||
+4
-3
@@ -129,6 +129,7 @@ Mob::Mob(
|
||||
position_update_melee_push_timer(500),
|
||||
hate_list_cleanup_timer(6000),
|
||||
m_scan_close_mobs_timer(6000),
|
||||
m_see_close_mobs_timer(1000),
|
||||
m_mob_check_moving_timer(1000),
|
||||
bot_attack_flag_timer(10000)
|
||||
{
|
||||
@@ -8621,15 +8622,15 @@ std::unordered_map<uint16, Mob*>& Mob::GetCloseMobList(float distance)
|
||||
void Mob::ClearDataBucketCache()
|
||||
{
|
||||
if (IsOfClientBot()) {
|
||||
uint64 id = 0;
|
||||
uint64 id = 0;
|
||||
DataBucketLoadType::Type t{};
|
||||
if (IsBot()) {
|
||||
id = CastToBot()->GetBotID();
|
||||
t = DataBucketLoadType::Bot;
|
||||
t = DataBucketLoadType::Bot;
|
||||
}
|
||||
else if (IsClient()) {
|
||||
id = CastToClient()->CharacterID();
|
||||
t = DataBucketLoadType::Client;
|
||||
t = DataBucketLoadType::Client;
|
||||
}
|
||||
|
||||
DataBucket::DeleteFromCache(id, t);
|
||||
|
||||
+5
-3
@@ -223,9 +223,11 @@ public:
|
||||
|
||||
void DisplayInfo(Mob *mob);
|
||||
|
||||
std::unordered_map<uint16, Mob *> m_close_mobs;
|
||||
Timer m_scan_close_mobs_timer;
|
||||
Timer m_mob_check_moving_timer;
|
||||
std::unordered_map<uint16, Mob *> m_close_mobs;
|
||||
std::unordered_map<int, glm::vec4> m_last_seen_mob_position;
|
||||
Timer m_scan_close_mobs_timer;
|
||||
Timer m_see_close_mobs_timer;
|
||||
Timer m_mob_check_moving_timer;
|
||||
|
||||
// Bot attack flag
|
||||
Timer bot_attack_flag_timer;
|
||||
|
||||
@@ -851,12 +851,24 @@ void MobMovementManager::SendCommandToClients(
|
||||
_impl->Stats.TotalSentPosition++;
|
||||
}
|
||||
|
||||
if (c->m_last_seen_mob_position.contains(mob->GetID())) {
|
||||
if (c->m_last_seen_mob_position[mob->GetID()] == mob->GetPosition() && anim == 0) {
|
||||
LogPositionUpdate(
|
||||
"Mob [{}] has already been sent to client [{}] at this position, skipping",
|
||||
mob->GetCleanName(),
|
||||
c->GetCleanName()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
c->QueuePacket(&outapp, false);
|
||||
c->m_last_seen_mob_position[mob->GetID()] = mob->GetPosition();
|
||||
}
|
||||
}
|
||||
else {
|
||||
float short_range = RuleR(Pathing, ShortMovementUpdateRange);
|
||||
float long_range = zone->GetNpcPositionUpdateDistance();
|
||||
float long_range = RuleI(Range, MobCloseScanDistance);
|
||||
|
||||
for (auto &c : _impl->Clients) {
|
||||
if (single_client && c != single_client) {
|
||||
@@ -901,7 +913,19 @@ void MobMovementManager::SendCommandToClients(
|
||||
_impl->Stats.TotalSentPosition++;
|
||||
}
|
||||
|
||||
if (c->m_last_seen_mob_position.contains(mob->GetID())) {
|
||||
if (c->m_last_seen_mob_position[mob->GetID()] == mob->GetPosition() && anim == 0) {
|
||||
LogPositionUpdate(
|
||||
"Mob [{}] has already been sent to client [{}] at this position, skipping",
|
||||
mob->GetCleanName(),
|
||||
c->GetCleanName()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
c->QueuePacket(&outapp, false);
|
||||
c->m_last_seen_mob_position[mob->GetID()] = mob->GetPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -997,8 +997,8 @@ NPC * NPC::SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4
|
||||
|
||||
npc_type->current_hp = 4000000;
|
||||
npc_type->max_hp = 4000000;
|
||||
npc_type->race = 2254;
|
||||
npc_type->gender = 2;
|
||||
npc_type->race = 127;
|
||||
npc_type->gender = 0;
|
||||
npc_type->class_ = 9;
|
||||
npc_type->deity = 1;
|
||||
npc_type->level = 200;
|
||||
|
||||
@@ -3229,11 +3229,46 @@ perl::array Perl_Client_GetInventorySlots(Client* self)
|
||||
return result;
|
||||
}
|
||||
|
||||
void Perl_Client_GrantPetNameChange(Client* self)
|
||||
{
|
||||
self->GrantPetNameChange();
|
||||
}
|
||||
|
||||
void Perl_Client_SetAAEXPPercentage(Client* self, uint8 percentage)
|
||||
{
|
||||
self->SetAAEXPPercentage(percentage);
|
||||
}
|
||||
|
||||
void Perl_Client_SetAccountBucket(Client* self, std::string bucket_name, std::string bucket_value)
|
||||
{
|
||||
self->SetAccountBucket(bucket_name, bucket_value);
|
||||
}
|
||||
|
||||
void Perl_Client_SetAccountBucket(Client* self, std::string bucket_name, std::string bucket_value, std::string expiration = "")
|
||||
{
|
||||
self->SetAccountBucket(bucket_name, bucket_value, expiration);
|
||||
}
|
||||
|
||||
void Perl_Client_DeleteAccountBucket(Client* self, std::string bucket_name)
|
||||
{
|
||||
self->DeleteAccountBucket(bucket_name);
|
||||
}
|
||||
|
||||
std::string Perl_Client_GetAccountBucket(Client* self, std::string bucket_name)
|
||||
{
|
||||
return self->GetAccountBucket(bucket_name);
|
||||
}
|
||||
|
||||
std::string Perl_Client_GetAccountBucketExpires(Client* self, std::string bucket_name)
|
||||
{
|
||||
return self->GetAccountBucketExpires(bucket_name);
|
||||
}
|
||||
|
||||
std::string Perl_Client_GetAccountBucketRemaining(Client* self, std::string bucket_name)
|
||||
{
|
||||
return self->GetAccountBucketRemaining(bucket_name);
|
||||
}
|
||||
|
||||
void perl_register_client()
|
||||
{
|
||||
perl::interpreter perl(PERL_GET_THX);
|
||||
@@ -3305,6 +3340,7 @@ void perl_register_client()
|
||||
package.add("CanHaveSkill", &Perl_Client_CanHaveSkill);
|
||||
package.add("CashReward", &Perl_Client_CashReward);
|
||||
package.add("ChangeLastName", &Perl_Client_ChangeLastName);
|
||||
package.add("GrantPetNameChange", &Perl_Client_GrantPetNameChange);
|
||||
package.add("CharacterID", &Perl_Client_CharacterID);
|
||||
package.add("CheckIncreaseSkill", (bool(*)(Client*, int))&Perl_Client_CheckIncreaseSkill);
|
||||
package.add("CheckIncreaseSkill", (bool(*)(Client*, int, int))&Perl_Client_CheckIncreaseSkill);
|
||||
@@ -3325,6 +3361,7 @@ void perl_register_client()
|
||||
package.add("CreateTaskDynamicZone", &Perl_Client_CreateTaskDynamicZone);
|
||||
package.add("DecreaseByID", &Perl_Client_DecreaseByID);
|
||||
package.add("DescribeSpecialAbilities", &Perl_Client_DescribeSpecialAbilities);
|
||||
package.add("DeleteAccountBucket", &Perl_Client_DeleteAccountBucket);
|
||||
package.add("DeleteItemInInventory", (void(*)(Client*, int16))&Perl_Client_DeleteItemInInventory);
|
||||
package.add("DeleteItemInInventory", (void(*)(Client*, int16, int16))&Perl_Client_DeleteItemInInventory);
|
||||
package.add("DeleteItemInInventory", (void(*)(Client*, int16, int16, bool))&Perl_Client_DeleteItemInInventory);
|
||||
@@ -3362,6 +3399,9 @@ void perl_register_client()
|
||||
package.add("GetAAPoints", &Perl_Client_GetAAPoints);
|
||||
package.add("GetAFK", &Perl_Client_GetAFK);
|
||||
package.add("GetAccountAge", &Perl_Client_GetAccountAge);
|
||||
package.add("GetAccountBucket", &Perl_Client_GetAccountBucket);
|
||||
package.add("GetAccountBucketExpires", &Perl_Client_GetAccountBucketExpires);
|
||||
package.add("GetGetAccountBucketRemaining", &Perl_Client_GetAccountBucketRemaining);
|
||||
package.add("GetAccountFlag", &Perl_Client_GetAccountFlag);
|
||||
package.add("GetAccountFlags", &Perl_Client_GetAccountFlags);
|
||||
package.add("GetAggroCount", &Perl_Client_GetAggroCount);
|
||||
@@ -3668,6 +3708,8 @@ void perl_register_client()
|
||||
package.add("SetAATitle", (void(*)(Client*, std::string, bool))&Perl_Client_SetAATitle);
|
||||
package.add("SetAFK", &Perl_Client_SetAFK);
|
||||
package.add("SetAccountFlag", &Perl_Client_SetAccountFlag);
|
||||
package.add("SetAccountBucket", (void(*)(Client*, std::string, std::string))&Perl_Client_SetAccountBucket);
|
||||
package.add("SetAccountBucket", (void(*)(Client*, std::string, std::string, std::string))&Perl_Client_SetAccountBucket);
|
||||
package.add("SetAlternateCurrencyValue", &Perl_Client_SetAlternateCurrencyValue);
|
||||
package.add("SetAnon", &Perl_Client_SetAnon);
|
||||
package.add("SetAutoLoginCharacterName", (bool(*)(Client*))&Perl_Client_SetAutoLoginCharacterName);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "../common/repositories/pets_repository.h"
|
||||
#include "../common/repositories/pets_beastlord_data_repository.h"
|
||||
#include "../common/repositories/character_pet_name_repository.h"
|
||||
|
||||
#include "entity.h"
|
||||
#include "client.h"
|
||||
@@ -164,6 +165,12 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
// 4 - Keep DB name
|
||||
// 5 - `s ward
|
||||
|
||||
if (IsClient() && !petname) {
|
||||
const auto vanity_name = CharacterPetNameRepository::FindOne(database, CastToClient()->CharacterID());
|
||||
if (!vanity_name.name.empty()) {
|
||||
petname = vanity_name.name.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
if (petname != nullptr) {
|
||||
// Name was provided, use it.
|
||||
|
||||
+87
-30
@@ -1,4 +1,6 @@
|
||||
#include "raycast_mesh.h"
|
||||
#include "../common/memory/ksm.hpp"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
@@ -9,7 +11,7 @@
|
||||
// This code snippet allows you to create an axis aligned bounding volume tree for a triangle mesh so that you can do
|
||||
// high-speed raycasting.
|
||||
//
|
||||
// There are much better implementations of this available on the internet. In particular I recommend that you use
|
||||
// There are much better implementations of this available on the internet. In particular I recommend that you use
|
||||
// OPCODE written by Pierre Terdiman.
|
||||
// @see: http://www.codercorner.com/Opcode.htm
|
||||
//
|
||||
@@ -17,7 +19,7 @@
|
||||
//
|
||||
// I am providing this code snippet for the use case where you *only* want to do quick and dirty optimized raycasting.
|
||||
// I have not done performance testing between this version and OPCODE; so I don't know how much slower it is. However,
|
||||
// anytime you switch to using a spatial data structure for raycasting, you increase your performance by orders and orders
|
||||
// anytime you switch to using a spatial data structure for raycasting, you increase your performance by orders and orders
|
||||
// of magnitude; so this implementation should work fine for simple tools and utilities.
|
||||
//
|
||||
// It also serves as a nice sample for people who are trying to learn the algorithm of how to implement AABB trees.
|
||||
@@ -32,14 +34,14 @@
|
||||
//
|
||||
// The official source can be found at: http://code.google.com/p/raycastmesh/
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
#pragma warning(disable:4100)
|
||||
|
||||
namespace RAYCAST_MESH
|
||||
{
|
||||
|
||||
typedef std::vector< RmUint32 > TriVector;
|
||||
typedef std::vector<RmUint32, PageAlignedAllocator<RmUint32>> TriVector;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
@@ -365,7 +367,7 @@ public:
|
||||
{
|
||||
RmUint32 ret = 0;
|
||||
|
||||
if ( p[0] < mMin[0] )
|
||||
if ( p[0] < mMin[0] )
|
||||
{
|
||||
ret|=CC_MINX;
|
||||
}
|
||||
@@ -374,7 +376,7 @@ public:
|
||||
ret|=CC_MAXX;
|
||||
}
|
||||
|
||||
if ( p[1] < mMin[1] )
|
||||
if ( p[1] < mMin[1] )
|
||||
{
|
||||
ret|=CC_MINY;
|
||||
}
|
||||
@@ -383,7 +385,7 @@ public:
|
||||
ret|=CC_MAXY;
|
||||
}
|
||||
|
||||
if ( p[2] < mMin[2] )
|
||||
if ( p[2] < mMin[2] )
|
||||
{
|
||||
ret|=CC_MINZ;
|
||||
}
|
||||
@@ -514,7 +516,7 @@ public:
|
||||
// the width of the longest axis is less than the minimum axis size then...
|
||||
// we create the leaf node and copy the triangles into the leaf node triangle array.
|
||||
if ( count < minLeafSize || depth >= maxDepth || laxis < minAxisSize )
|
||||
{
|
||||
{
|
||||
// Copy the triangle indices into the leaf triangles array
|
||||
mLeafTriangleIndex = leafTriangles.size(); // assign the array start location for these leaf triangles.
|
||||
leafTriangles.push_back(count);
|
||||
@@ -542,7 +544,7 @@ public:
|
||||
// and another array that includes all triangles which intersect the 'right' half of the bounding volume node.
|
||||
for (auto i = triangles.begin(); i != triangles.end(); ++i) {
|
||||
|
||||
RmUint32 tri = (*i);
|
||||
RmUint32 tri = (*i);
|
||||
|
||||
{
|
||||
RmUint32 i1 = indices[tri*3+0];
|
||||
@@ -590,7 +592,7 @@ public:
|
||||
{
|
||||
leftBounds.clamp(b1); // we have to clamp the bounding volume so it stays inside the parent volume.
|
||||
mLeft = callback->getNode(); // get a new AABB node
|
||||
new ( mLeft ) NodeAABB(leftBounds); // initialize it to default constructor values.
|
||||
new ( mLeft ) NodeAABB(leftBounds); // initialize it to default constructor values.
|
||||
// Then recursively split this node.
|
||||
mLeft->split(leftTriangles,vcount,vertices,tcount,indices,depth+1,maxDepth,minLeafSize,minAxisSize,callback,leafTriangles);
|
||||
}
|
||||
@@ -662,7 +664,7 @@ public:
|
||||
RmReal nd = nearestDistance;
|
||||
if ( !intersectLineSegmentAABB(mBounds.mMin,mBounds.mMax,from,dir,nd,sect) )
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
if ( mLeafTriangleIndex != TRI_EOF )
|
||||
{
|
||||
@@ -754,28 +756,60 @@ public:
|
||||
{
|
||||
mMaxNodeCount+=pow2Table[i];
|
||||
}
|
||||
mNodes = new NodeAABB[mMaxNodeCount];
|
||||
// Allocate page-aligned memory
|
||||
mNodes = static_cast<NodeAABB*>(KSM::AllocatePageAligned(sizeof(NodeAABB) * mMaxNodeCount));
|
||||
if (!mNodes) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
mNodeCount = 0;
|
||||
KSM::CheckPageAlignment(mNodes);
|
||||
|
||||
mVertices = static_cast<RmReal*>(KSM::AllocatePageAligned(sizeof(RmReal) * 3 * vcount));
|
||||
if (!mVertices) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
std::memcpy(mVertices, vertices, sizeof(RmReal) * 3 * vcount);
|
||||
mVcount = vcount;
|
||||
mVertices = (RmReal *)::malloc(sizeof(RmReal)*3*vcount);
|
||||
memcpy(mVertices,vertices,sizeof(RmReal)*3*vcount);
|
||||
|
||||
mIndices = static_cast<RmUint32*>(KSM::AllocatePageAligned(sizeof(RmUint32) * 3 * tcount));
|
||||
if (!mIndices) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
std::memcpy(mIndices, indices, sizeof(RmUint32) * 3 * tcount);
|
||||
mTcount = tcount;
|
||||
mIndices = (RmUint32 *)::malloc(sizeof(RmUint32)*tcount*3);
|
||||
memcpy(mIndices,indices,sizeof(RmUint32)*tcount*3);
|
||||
mRaycastTriangles = (RmUint32 *)::malloc(tcount*sizeof(RmUint32));
|
||||
memset(mRaycastTriangles,0,tcount*sizeof(RmUint32));
|
||||
|
||||
mRaycastTriangles = static_cast<RmUint32*>(KSM::AllocatePageAligned(sizeof(RmUint32) * tcount));
|
||||
if (!mRaycastTriangles) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
std::memset(mRaycastTriangles, 0, sizeof(RmUint32) * tcount);
|
||||
|
||||
mFaceNormals = static_cast<RmReal*>(KSM::AllocatePageAligned(sizeof(RmReal) * 3 * tcount));
|
||||
if (!mFaceNormals) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
std::memset(mFaceNormals, 0, sizeof(RmReal) * 3 * tcount);
|
||||
|
||||
// Mark memory as mergeable for KSM
|
||||
KSM::MarkMemoryForKSM(mVertices, sizeof(RmReal) * 3 * vcount);
|
||||
KSM::MarkMemoryForKSM(mIndices, sizeof(RmUint32) * 3 * tcount);
|
||||
KSM::MarkMemoryForKSM(mRaycastTriangles, sizeof(RmUint32) * tcount);
|
||||
KSM::MarkMemoryForKSM(mFaceNormals, sizeof(RmReal) * 3 * tcount);
|
||||
|
||||
mRoot = getNode();
|
||||
mFaceNormals = NULL;
|
||||
new ( mRoot ) NodeAABB(mVcount,mVertices,mTcount,mIndices,maxDepth,minLeafSize,minAxisSize,this,mLeafTriangles);
|
||||
|
||||
KSM::MarkMemoryForKSM(mLeafTriangles.data(), mLeafTriangles.size() * sizeof(RmUint32));
|
||||
}
|
||||
|
||||
~MyRaycastMesh(void)
|
||||
{
|
||||
delete []mNodes;
|
||||
::free(mVertices);
|
||||
::free(mIndices);
|
||||
::free(mFaceNormals);
|
||||
::free(mRaycastTriangles);
|
||||
if (mNodes) { free(mNodes); }
|
||||
if (mVertices) { free(mVertices); }
|
||||
if (mIndices) { free(mIndices); }
|
||||
if (mRaycastTriangles) { free(mRaycastTriangles); }
|
||||
if (mFaceNormals) { free(mFaceNormals); }
|
||||
}
|
||||
|
||||
virtual bool raycast(const RmReal *from,const RmReal *to,RmReal *hitLocation,RmReal *hitNormal,RmReal *hitDistance)
|
||||
@@ -812,7 +846,7 @@ public:
|
||||
return mRoot->mBounds.mMax;
|
||||
}
|
||||
|
||||
virtual NodeAABB * getNode(void)
|
||||
virtual NodeAABB * getNode(void)
|
||||
{
|
||||
assert( mNodeCount < mMaxNodeCount );
|
||||
NodeAABB *ret = &mNodes[mNodeCount];
|
||||
@@ -820,7 +854,7 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual void getFaceNormal(RmUint32 tri,RmReal *faceNormal)
|
||||
virtual void getFaceNormal(RmUint32 tri,RmReal *faceNormal)
|
||||
{
|
||||
if ( mFaceNormals == NULL )
|
||||
{
|
||||
@@ -938,6 +972,29 @@ RaycastMesh * createRaycastMesh(RmUint32 vcount, // The number of vertices in t
|
||||
)
|
||||
{
|
||||
auto m = new MyRaycastMesh(vcount, vertices, tcount, indices, maxDepth, minLeafSize, minAxisSize);
|
||||
|
||||
// Calculate memory usage
|
||||
size_t vertex_size = vcount * sizeof(RmReal) * 3; // Each vertex has 3 floats
|
||||
size_t index_size = tcount * 3 * sizeof(RmUint32); // Each triangle has 3 indices
|
||||
size_t bvh_node_size = m->mNodeCount * sizeof(NodeAABB); // BVH Node memory usage
|
||||
size_t bvh_leaf_size = m->mLeafTriangles.size() * sizeof(RmUint32); // BVH leaf triangles
|
||||
|
||||
size_t bvh_size = bvh_node_size + bvh_leaf_size; // Total BVH size
|
||||
size_t total_size = vertex_size + index_size + bvh_size;
|
||||
|
||||
KSM::CheckPageAlignment(m->mNodes);
|
||||
KSM::CheckPageAlignment(m->mVertices);
|
||||
|
||||
LogInfo(
|
||||
"Map Raycast Memory Usage | Vertices [{:.2f}] MB Indices [{:.2f}] MB BVH Nodes [{:.2f}] MB BVH Leaves [{:.2f}] MB BVH Total [{:.2f}] MB",
|
||||
vertex_size / (1024.0 * 1024.0),
|
||||
index_size / (1024.0 * 1024.0),
|
||||
bvh_node_size / (1024.0 * 1024.0),
|
||||
bvh_leaf_size / (1024.0 * 1024.0),
|
||||
bvh_size / (1024.0 * 1024.0)
|
||||
);
|
||||
LogInfo("Total Raycast Memory [{:.2f}] MB", total_size / (1024.0 * 1024.0));
|
||||
|
||||
return static_cast< RaycastMesh * >(m);
|
||||
}
|
||||
|
||||
@@ -984,12 +1041,12 @@ MyRaycastMesh::MyRaycastMesh(std::vector<char>& rm_buffer)
|
||||
return;
|
||||
|
||||
char* buf = rm_buffer.data();
|
||||
|
||||
|
||||
chunk_size = sizeof(RmUint32);
|
||||
memcpy(&mVcount, buf, chunk_size);
|
||||
buf += chunk_size;
|
||||
bytes_read += chunk_size;
|
||||
|
||||
|
||||
chunk_size = (sizeof(RmReal) * (3 * mVcount));
|
||||
mVertices = (RmReal *)::malloc(chunk_size);
|
||||
memcpy(mVertices, buf, chunk_size);
|
||||
@@ -1037,7 +1094,7 @@ MyRaycastMesh::MyRaycastMesh(std::vector<char>& rm_buffer)
|
||||
buf += chunk_size;
|
||||
bytes_read += chunk_size;
|
||||
}
|
||||
|
||||
|
||||
chunk_size = sizeof(RmUint32);
|
||||
memcpy(&mNodeCount, buf, chunk_size);
|
||||
buf += chunk_size;
|
||||
@@ -1071,7 +1128,7 @@ MyRaycastMesh::MyRaycastMesh(std::vector<char>& rm_buffer)
|
||||
mNodes[index].mLeft = &mNodes[lNodeIndex];
|
||||
buf += chunk_size;
|
||||
bytes_read += chunk_size;
|
||||
|
||||
|
||||
RmUint32 rNodeIndex;
|
||||
chunk_size = sizeof(RmUint32);
|
||||
memcpy(&rNodeIndex, buf, chunk_size);
|
||||
@@ -1106,7 +1163,7 @@ MyRaycastMesh::MyRaycastMesh(std::vector<char>& rm_buffer)
|
||||
void MyRaycastMesh::serialize(std::vector<char>& rm_buffer)
|
||||
{
|
||||
rm_buffer.clear();
|
||||
|
||||
|
||||
size_t rm_buffer_size_ = 0;
|
||||
|
||||
rm_buffer_size_ += sizeof(RmUint32); // mVcount
|
||||
|
||||
+4
-2
@@ -7513,15 +7513,17 @@ void Mob::SetHP(int64 hp)
|
||||
|
||||
void Mob::DrawDebugCoordinateNode(std::string node_name, const glm::vec4 vec)
|
||||
{
|
||||
NPC *node = nullptr;
|
||||
NPC *node = nullptr;
|
||||
|
||||
for (const auto &n: entity_list.GetNPCList()) {
|
||||
if (n.second->GetCleanName() == node_name) {
|
||||
if (n.second->GetEntityVariable("node_parent_id") == std::to_string(GetID())) {
|
||||
node = n.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!node) {
|
||||
node = NPC::SpawnNodeNPC(node_name, "", GetPosition());
|
||||
node->SetEntityVariable("node_parent_id", std::to_string(GetID()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-72
@@ -1091,7 +1091,6 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
|
||||
|
||||
mMovementManager = &MobMovementManager::Get();
|
||||
|
||||
SetNpcPositionUpdateDistance(0);
|
||||
SetQuestHotReloadQueued(false);
|
||||
}
|
||||
|
||||
@@ -1374,17 +1373,17 @@ bool Zone::LoadZoneCFG(const char* filename, uint16 instance_version)
|
||||
newzone_data.suspend_buffs = z->suspendbuffs;
|
||||
|
||||
// local attributes
|
||||
can_bind = z->canbind != 0;
|
||||
is_city = z->canbind == 2;
|
||||
can_combat = z->cancombat != 0;
|
||||
can_levitate = z->canlevitate != 0;
|
||||
can_castoutdoor = z->castoutdoor != 0;
|
||||
is_hotzone = z->hotzone != 0;
|
||||
max_movement_update_range = z->max_movement_update_range;
|
||||
default_ruleset = z->ruleset;
|
||||
allow_mercs = true;
|
||||
m_graveyard_id = z->graveyard_id;
|
||||
m_max_clients = z->maxclients;
|
||||
can_bind = z->canbind != 0;
|
||||
is_city = z->canbind == 2;
|
||||
can_combat = z->cancombat != 0;
|
||||
can_levitate = z->canlevitate != 0;
|
||||
can_castoutdoor = z->castoutdoor != 0;
|
||||
is_hotzone = z->hotzone != 0;
|
||||
m_client_update_range = z->client_update_range;
|
||||
default_ruleset = z->ruleset;
|
||||
allow_mercs = true;
|
||||
m_graveyard_id = z->graveyard_id;
|
||||
m_max_clients = z->maxclients;
|
||||
|
||||
SetIdleWhenEmpty(z->idle_when_empty);
|
||||
SetSecondsBeforeIdle(z->seconds_before_idle);
|
||||
@@ -1538,10 +1537,6 @@ bool Zone::Process() {
|
||||
if (adv_data && !did_adventure_actions) {
|
||||
DoAdventureActions();
|
||||
}
|
||||
|
||||
if (GetNpcPositionUpdateDistance() == 0) {
|
||||
CalculateNpcUpdateDistanceSpread();
|
||||
}
|
||||
}
|
||||
|
||||
if (hot_reload_timer.Check() && IsQuestHotReloadQueued()) {
|
||||
@@ -2735,62 +2730,6 @@ void Zone::SetUCSServerAvailable(bool ucss_available, uint32 update_timestamp) {
|
||||
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
|
||||
{
|
||||
return quest_hot_reload_queued;
|
||||
|
||||
+2
-5
@@ -156,9 +156,6 @@ public:
|
||||
bool SaveZoneCFG();
|
||||
bool DoesAlternateCurrencyExist(uint32 currency_id);
|
||||
|
||||
int GetNpcPositionUpdateDistance() const;
|
||||
void SetNpcPositionUpdateDistance(int in_npc_position_update_distance);
|
||||
|
||||
char *adv_data;
|
||||
|
||||
const char *GetSpellBlockedMessage(uint32 spell_id, const glm::vec3 &location);
|
||||
@@ -417,7 +414,7 @@ public:
|
||||
SendDiscordMessage(webhook_id, message_prefix + Discord::FormatDiscordMessage(log_category, message));
|
||||
};
|
||||
|
||||
double GetMaxMovementUpdateRange() const { return max_movement_update_range; }
|
||||
double GetClientUpdateRange() const { return m_client_update_range; }
|
||||
|
||||
void SetIsHotzone(bool is_hotzone);
|
||||
|
||||
@@ -469,7 +466,7 @@ private:
|
||||
bool staticzone;
|
||||
bool zone_has_current_time;
|
||||
bool quest_hot_reload_queued;
|
||||
double max_movement_update_range;
|
||||
double m_client_update_range;
|
||||
char *long_name;
|
||||
char *map_name;
|
||||
char *short_name;
|
||||
|
||||
Reference in New Issue
Block a user