Merge branch 'master' of https://github.com/EQEmu/Server into kick_events

This commit is contained in:
Akkadius 2019-08-10 02:38:48 -05:00
commit 69bad593cd
20 changed files with 794 additions and 396 deletions

View File

@ -326,14 +326,10 @@ IF(ZLIB_FOUND)
SET(SERVER_LIBS ${SERVER_LIBS} ${ZLIB_LIBRARY}) SET(SERVER_LIBS ${SERVER_LIBS} ${ZLIB_LIBRARY})
ENDIF() ENDIF()
ELSE() ELSE()
# NOTE: This processing chain is broken. MESSAGE(STATUS "Could NOT find ZLIB - using ZLIBSTATIC package.")
# Path "${CMAKE_CURRENT_BINARY_DIR}/libs/zlibng" is added to ${SERVER_LIBS}..but, the current CMake process does not SET(EQEMU_BUILD_ZLIB ON)
# generate the "${CMAKE_CURRENT_SOURCE_DIR}/build/lib/zlibng" and create the required "zconf.h" file. A path to
# a valid ZLIB package is required to trigger this process. "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng/zconf.h" is not
# valid due to the extension name change to "../zlibng/zconf.h.in" during the ZLIB project creation process.
INCLUDE_DIRECTORIES(BEFORE SYSTEM "${CMAKE_CURRENT_BINARY_DIR}/libs/zlibng" "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng") INCLUDE_DIRECTORIES(BEFORE SYSTEM "${CMAKE_CURRENT_BINARY_DIR}/libs/zlibng" "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng")
SET(SERVER_LIBS ${SERVER_LIBS} "zlibstatic") SET(SERVER_LIBS ${SERVER_LIBS} "zlibstatic")
MESSAGE(STATUS "Could NOT find ZLIB - using ZLIBSTATIC package.")
ENDIF() ENDIF()
IF(WIN32) IF(WIN32)

View File

@ -70,3 +70,9 @@ forum, although pull requests will be much quicker and easier on all parties.
* GPL Perl - GPL / ActiveState (under the assumption that this is a free project) * GPL Perl - GPL / ActiveState (under the assumption that this is a free project)
* CPPUnit - GLP StringUtilities - Apache * CPPUnit - GLP StringUtilities - Apache
* LUA - MIT * LUA - MIT
## Contributors
<a href="https://github.com/EQEmu/server/graphs/contributors">
<img src="https://contributors-img.firebaseapp.com/image?repo=EQEmu/server" />
</a>

View File

@ -1,5 +1,8 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50) EQEMu Changelog (Started on Sept 24, 2003 15:50)
------------------------------------------------------- -------------------------------------------------------
== 8/6/2019 ==
Akkadius: Optimizations to movement updates to eliminate ghosting possibilities in larger zones
== 7/22/2019 == == 7/22/2019 ==
Uleat: Added script 'vcxproj_dependencies.py' - a script to help determine conflicting project dependencies (alpha-stage) Uleat: Added script 'vcxproj_dependencies.py' - a script to help determine conflicting project dependencies (alpha-stage)

View File

@ -77,6 +77,10 @@ namespace EQEmu
} // namespace invtype } // namespace invtype
namespace DevTools {
const int32 GM_ACCOUNT_STATUS_LEVEL = 150;
}
namespace popupresponse { namespace popupresponse {
const int32 SERVER_INTERNAL_USE_BASE = 2000000000; const int32 SERVER_INTERNAL_USE_BASE = 2000000000;
const int32 MOB_INFO_DISMISS = 2000000001; const int32 MOB_INFO_DISMISS = 2000000001;

View File

@ -1116,7 +1116,10 @@ namespace SoF
} }
OUT(deity); OUT(deity);
OUT(intoxication); OUT(intoxication);
OUT_array(spellSlotRefresh, spells::SPELL_GEM_COUNT); OUT_array(spellSlotRefresh, spells::SPELL_GEM_COUNT);
eq->spellSlotRefresh[9] = 0; // 10th slot is not valid in this release
OUT(abilitySlotRefresh); OUT(abilitySlotRefresh);
OUT(points); // Relocation Test OUT(points); // Relocation Test
// OUT(unknown0166[4]); // OUT(unknown0166[4]);
@ -1177,7 +1180,10 @@ namespace SoF
} }
// OUT(unknown4184[128]); // OUT(unknown4184[128]);
OUT_array(mem_spells, spells::SPELL_GEM_COUNT); OUT_array(mem_spells, spells::SPELL_GEM_COUNT);
eq->mem_spells[9] = 0xFFFFFFFFU; // 10th slot is not valid in this release
// OUT(unknown04396[32]); // OUT(unknown04396[32]);
OUT(platinum); OUT(platinum);
OUT(gold); OUT(gold);

View File

@ -328,7 +328,11 @@ namespace SoF
const int SPELL_ID_MAX = 15999; const int SPELL_ID_MAX = 15999;
const int SPELLBOOK_SIZE = 480; const int SPELLBOOK_SIZE = 480;
// Be careful not to confuse these two..SoF disc release has a special requirement...
// - The number of available spell gems HAS NOT increased from 9 at this point
// - The profile allocation HAS increased to 10 at this point
const int SPELL_GEM_COUNT = static_cast<uint32>(CastingSlot::MaxGems); const int SPELL_GEM_COUNT = static_cast<uint32>(CastingSlot::MaxGems);
const int SPELL_GEM_PROFILE_SIZE = 10; // special case declaration
const int LONG_BUFFS = 25; const int LONG_BUFFS = 25;
const int SHORT_BUFFS = 15; const int SHORT_BUFFS = 15;

View File

@ -885,7 +885,7 @@ struct PlayerProfile_Struct //23576 Octets
/*00060*/ BindStruct binds[5]; // Bind points (primary is first) /*00060*/ BindStruct binds[5]; // Bind points (primary is first)
/*00160*/ uint32 deity; // deity /*00160*/ uint32 deity; // deity
/*00164*/ uint32 intoxication; // Alcohol level (in ticks till sober?) /*00164*/ uint32 intoxication; // Alcohol level (in ticks till sober?)
/*00168*/ uint32 spellSlotRefresh[spells::SPELL_GEM_COUNT]; // Refresh time (millis) - 4 Octets Each /*00168*/ uint32 spellSlotRefresh[spells::SPELL_GEM_PROFILE_SIZE]; // Refresh time (millis) - 4 Octets Each
/*00208*/ uint32 abilitySlotRefresh; /*00208*/ uint32 abilitySlotRefresh;
/*00212*/ uint8 haircolor; // Player hair color /*00212*/ uint8 haircolor; // Player hair color
/*00213*/ uint8 beardcolor; // Player beard color /*00213*/ uint8 beardcolor; // Player beard color
@ -912,7 +912,7 @@ struct PlayerProfile_Struct //23576 Octets
/*04173*/ uint8 unknown02264[147]; // was [139] /*04173*/ uint8 unknown02264[147]; // was [139]
/*04312*/ uint32 spell_book[spells::SPELLBOOK_SIZE]; // List of the Spells in spellbook 480 = 60 pages /*04312*/ uint32 spell_book[spells::SPELLBOOK_SIZE]; // List of the Spells in spellbook 480 = 60 pages
/*06232*/ uint8 unknown4184[128]; // was [136] /*06232*/ uint8 unknown4184[128]; // was [136]
/*06396*/ uint32 mem_spells[spells::SPELL_GEM_COUNT]; // List of spells memorized /*06396*/ uint32 mem_spells[spells::SPELL_GEM_PROFILE_SIZE]; // List of spells memorized
/*06436*/ uint8 unknown04396[28]; //#### uint8 unknown04396[32]; in Titanium ####[28] /*06436*/ uint8 unknown04396[28]; //#### uint8 unknown04396[32]; in Titanium ####[28]
/*06464*/ uint32 platinum; // Platinum Pieces on player /*06464*/ uint32 platinum; // Platinum Pieces on player
/*06468*/ uint32 gold; // Gold Pieces on player /*06468*/ uint32 gold; // Gold Pieces on player
@ -3768,7 +3768,7 @@ struct AnnoyingZoneUnknown_Struct {
}; };
struct LoadSpellSet_Struct { struct LoadSpellSet_Struct {
uint32 spell[spells::SPELL_GEM_COUNT]; uint32 spell[spells::SPELL_GEM_PROFILE_SIZE];
uint32 unknown; uint32 unknown;
}; };

View File

@ -379,6 +379,7 @@ void Database::LogMerchantTransaction(QSMerchantLogTransaction_Struct* QS, uint3
} }
// this function does not delete the ServerPacket, so it must be handled at call site
void Database::GeneralQueryReceive(ServerPacket *pack) { void Database::GeneralQueryReceive(ServerPacket *pack) {
/* /*
These are general queries passed from anywhere in zone instead of packing structures and breaking them down again and again These are general queries passed from anywhere in zone instead of packing structures and breaking them down again and again
@ -393,7 +394,6 @@ void Database::GeneralQueryReceive(ServerPacket *pack) {
Log(Logs::Detail, Logs::QS_Server, "%s", query.c_str()); Log(Logs::Detail, Logs::QS_Server, "%s", query.c_str());
} }
safe_delete(pack);
safe_delete_array(queryBuffer); safe_delete_array(queryBuffer);
} }

View File

@ -1587,22 +1587,24 @@ sub add_login_server_firewall_rules {
print "If firewall rules don't add you must run this script (eqemu_server.pl) as administrator\n"; print "If firewall rules don't add you must run this script (eqemu_server.pl) as administrator\n";
print "\n"; print "\n";
print "[Install] Instructions \n"; print "[Install] Instructions \n";
print "[Install] In order to connect your server to the loginserver you must point your eqemu_config.xml to your local server similar to the following:\n"; print "[Install] In order to connect your server to the loginserver you must point your eqemu_config.json to your local server similar to the following:\n";
print " print "
<loginserver1> \"loginserver1\" : {
<host>login.eqemulator.net</host> \"account\" : \"\",
<port>5998</port> \"host\" : \"login.eqemulator.net\",
<account></account> \"password\" : \"\",
<password></password> \"port\" : \"5998\",
</loginserver1> \"legacy\": \"1\"
<loginserver2> },
<host>127.0.0.1</host> \"loginserver2\" : {
<port>5998</port> \"account\" : \"\",
<account></account> \"host\" : \"192.168.197.129\",
<password></password> \"password\" : \"\",
</loginserver2> \"port\" : \"5998\"
},
\"localaddress\" : \"192.168.197.129\",
"; ";
print "[Install] When done, make sure your EverQuest client points to your loginserver's IP (In this case it would be 127.0.0.1) in the eqhosts.txt file\n"; print "[Install] When done, make sure your EverQuest client points to your loginserver's IP (In this case it would be 192.168.197.129) in the eqhosts.txt file\n";
} }
} }

View File

@ -136,6 +136,7 @@ Client::Client(EQStreamInterface* ieqs)
forget_timer(0), forget_timer(0),
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000), autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckInterval) * 1000), client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckInterval) * 1000),
client_zone_wide_full_position_update_timer(5 * 60 * 1000),
tribute_timer(Tribute_duration), tribute_timer(Tribute_duration),
proximity_timer(ClientProximity_interval), proximity_timer(ClientProximity_interval),
TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000), TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000),
@ -9121,3 +9122,16 @@ bool Client::GotoPlayer(std::string player_name)
return false; return false;
} }
glm::vec4 &Client::GetLastPositionBeforeBulkUpdate()
{
return last_position_before_bulk_update;
}
/**
* @param in_last_position_before_bulk_update
*/
void Client::SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update)
{
Client::last_position_before_bulk_update = in_last_position_before_bulk_update;
}

View File

@ -1309,6 +1309,9 @@ public:
uint32 trapid; //ID of trap player has triggered. This is cleared when the player leaves the trap's radius, or it despawns. uint32 trapid; //ID of trap player has triggered. This is cleared when the player leaves the trap's radius, or it despawns.
void SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update);
glm::vec4 &GetLastPositionBeforeBulkUpdate();
protected: protected:
friend class Mob; friend class Mob;
void CalcItemBonuses(StatBonuses* newbon); void CalcItemBonuses(StatBonuses* newbon);
@ -1517,6 +1520,7 @@ private:
Timer forget_timer; // our 2 min everybody forgets you timer Timer forget_timer; // our 2 min everybody forgets you timer
Timer autosave_timer; Timer autosave_timer;
Timer client_scan_npc_aggro_timer; Timer client_scan_npc_aggro_timer;
Timer client_zone_wide_full_position_update_timer;
Timer tribute_timer; Timer tribute_timer;
Timer proximity_timer; Timer proximity_timer;
@ -1539,6 +1543,7 @@ private:
Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */ Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
glm::vec3 m_Proximity; glm::vec3 m_Proximity;
glm::vec4 last_position_before_bulk_update;
void BulkSendInventoryItems(); void BulkSendInventoryItems();

View File

@ -60,6 +60,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "water_map.h" #include "water_map.h"
#include "worldserver.h" #include "worldserver.h"
#include "zone.h" #include "zone.h"
#include "mob_movement_manager.h"
#ifdef BOTS #ifdef BOTS
#include "bot.h" #include "bot.h"
@ -805,6 +806,8 @@ void Client::CompleteConnect()
parse->EventPlayer(EVENT_ENTER_ZONE, this, "", 0); parse->EventPlayer(EVENT_ENTER_ZONE, this, "", 0);
SetLastPositionBeforeBulkUpdate(GetPosition());
/* This sub event is for if a player logs in for the first time since entering world. */ /* This sub event is for if a player logs in for the first time since entering world. */
if (firstlogon == 1) { if (firstlogon == 1) {
parse->EventPlayer(EVENT_CONNECT, this, "", 0); parse->EventPlayer(EVENT_CONNECT, this, "", 0);
@ -1679,7 +1682,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
/** /**
* DevTools Load Settings * DevTools Load Settings
*/ */
if (Admin() >= 200) { if (Admin() >= EQEmu::DevTools::GM_ACCOUNT_STATUS_LEVEL) {
std::string dev_tools_window_key = StringFormat("%i-dev-tools-window-disabled", AccountID()); std::string dev_tools_window_key = StringFormat("%i-dev-tools-window-disabled", AccountID());
if (DataBucket::GetData(dev_tools_window_key) == "true") { if (DataBucket::GetData(dev_tools_window_key) == "true") {
dev_tools_window_enabled = false; dev_tools_window_enabled = false;
@ -4464,16 +4467,16 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
/* Handle client aggro scanning timers NPCs */ /* Handle client aggro scanning timers NPCs */
is_client_moving = (ppu->y_pos == m_Position.y && ppu->x_pos == m_Position.x) ? false : true; is_client_moving = (ppu->y_pos == m_Position.y && ppu->x_pos == m_Position.x) ? false : true;
if (is_client_moving) { if (is_client_moving) {
Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is moving - scan timer is: %u", Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is moving - scan timer is: %u",
client_scan_npc_aggro_timer.GetDuration()); client_scan_npc_aggro_timer.GetDuration());
if (client_scan_npc_aggro_timer.GetDuration() > 1000) { if (client_scan_npc_aggro_timer.GetDuration() > 1000) {
client_scan_npc_aggro_timer.Disable(); client_scan_npc_aggro_timer.Disable();
client_scan_npc_aggro_timer.Start(500); client_scan_npc_aggro_timer.Start(500);
} }
} else { }
else {
Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is NOT moving - scan timer is: %u", Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is NOT moving - scan timer is: %u",
client_scan_npc_aggro_timer.GetDuration()); client_scan_npc_aggro_timer.GetDuration());
if (client_scan_npc_aggro_timer.GetDuration() < 1000) { if (client_scan_npc_aggro_timer.GetDuration() < 1000) {
@ -4481,7 +4484,51 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
client_scan_npc_aggro_timer.Start(3000); client_scan_npc_aggro_timer.Start(3000);
} }
} }
/**
* 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
*/
float distance_moved = DistanceNoZ(GetLastPositionBeforeBulkUpdate(), GetPosition());
bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetNpcPositionUpdateDistance();
bool is_ready_to_update = (
client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update
);
if (is_client_moving && is_ready_to_update) {
Log(Logs::Detail, Logs::Normal, "[%s] Client Zone Wide Position Update NPCs", GetCleanName());
auto &mob_movement_manager = MobMovementManager::Get();
auto &mob_list = entity_list.GetMobList();
for (auto &it : mob_list) {
Mob *entity = it.second;
if (!entity->IsNPC()) {
continue;
}
int animation_speed = 0;
if (entity->IsMoving()) {
if (entity->IsRunning()) {
animation_speed = (entity->IsFeared() ? entity->GetFearSpeed() : entity->GetRunspeed());
}
else {
animation_speed = entity->GetWalkspeed();
}
}
mob_movement_manager.SendCommandToClients(entity, 0.0, 0.0, 0.0, 0.0, animation_speed, ClientRangeAny, this);
}
SetLastPositionBeforeBulkUpdate(GetPosition());
}
float new_heading = EQ12toFloat(ppu->heading); float new_heading = EQ12toFloat(ppu->heading);
int32 new_animation = ppu->animation; int32 new_animation = ppu->animation;

View File

@ -592,8 +592,8 @@ bool Client::Process() {
// only if client is not feigned // only if client is not feigned
if (zone->CanDoCombat() && ret && !GetFeigned() && client_scan_npc_aggro_timer.Check()) { if (zone->CanDoCombat() && ret && !GetFeigned() && client_scan_npc_aggro_timer.Check()) {
int npc_scan_count = 0; int npc_scan_count = 0;
for (auto it = close_mobs.begin(); it != close_mobs.end(); ++it) { for (auto & close_mob : close_mobs) {
Mob *mob = it->first; Mob *mob = close_mob.first;
if (!mob) if (!mob)
continue; continue;
@ -604,6 +604,7 @@ bool Client::Process() {
if (mob->CheckWillAggro(this) && !mob->CheckAggro(this)) { if (mob->CheckWillAggro(this) && !mob->CheckAggro(this)) {
mob->AddToHateList(this, 25); mob->AddToHateList(this, 25);
} }
npc_scan_count++; npc_scan_count++;
} }
Log(Logs::General, Logs::Aggro, "Checking Reverse Aggro (client->npc) scanned_npcs (%i)", npc_scan_count); Log(Logs::General, Logs::Aggro, "Checking Reverse Aggro (client->npc) scanned_npcs (%i)", npc_scan_count);

View File

@ -4490,7 +4490,7 @@ void command_gmzone(Client *c, const Seperator *sep)
identifier = sep->arg[3]; identifier = sep->arg[3];
} }
std::string bucket_key = StringFormat("%s-%s-instance", zone_short_name, identifier.c_str()); std::string bucket_key = StringFormat("%s-%s-%u-instance", zone_short_name, identifier.c_str(), zone_version);
std::string existing_zone_instance = DataBucket::GetData(bucket_key); std::string existing_zone_instance = DataBucket::GetData(bucket_key);
if (existing_zone_instance.length() > 0) { if (existing_zone_instance.length() > 0) {

View File

@ -1128,7 +1128,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
UpdateActiveLight(); UpdateActiveLight();
ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive]; ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive];
ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0; if (IsNPC() && race == ERUDITE)
ns->spawn.showhelm = 1;
else
ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0;
ns->spawn.invis = (invisible || hidden) ? 1 : 0; // TODO: load this before spawning players ns->spawn.invis = (invisible || hidden) ? 1 : 0; // TODO: load this before spawning players
ns->spawn.NPC = IsClient() ? 0 : 1; ns->spawn.NPC = IsClient() ? 0 : 1;

File diff suppressed because it is too large Load Diff

View File

@ -41,18 +41,29 @@ class MobMovementManager
public: public:
~MobMovementManager(); ~MobMovementManager();
void Process(); void Process();
void AddMob(Mob *m); void AddMob(Mob *mob);
void RemoveMob(Mob *m); void RemoveMob(Mob *mob);
void AddClient(Client *c); void AddClient(Client *client);
void RemoveClient(Client *c); void RemoveClient(Client *client);
void RotateTo(Mob *who, float to, MobMovementMode mode = MovementRunning); void RotateTo(Mob *who, float to, MobMovementMode mob_movement_mode = MovementRunning);
void Teleport(Mob *who, float x, float y, float z, float heading); void Teleport(Mob *who, float x, float y, float z, float heading);
void NavigateTo(Mob *who, float x, float y, float z, MobMovementMode mode = MovementRunning); void NavigateTo(Mob *who, float x, float y, float z, MobMovementMode mode = MovementRunning);
void StopNavigation(Mob *who); void StopNavigation(Mob *who);
void SendCommandToClients(Mob *m, float dx, float dy, float dz, float dh, int anim, ClientRange range);
void SendCommandToClients(
Mob *mob,
float delta_x,
float delta_y,
float delta_z,
float delta_heading,
int anim,
ClientRange range,
Client* single_client = nullptr
);
float FixHeading(float in); float FixHeading(float in);
void DumpStats(Client *to); void DumpStats(Client *client);
void ClearStats(); void ClearStats();
static MobMovementManager &Get() { static MobMovementManager &Get() {
@ -65,18 +76,18 @@ private:
MobMovementManager(const MobMovementManager&); MobMovementManager(const MobMovementManager&);
MobMovementManager& operator=(const MobMovementManager&); MobMovementManager& operator=(const MobMovementManager&);
void FillCommandStruct(PlayerPositionUpdateServer_Struct *spu, Mob *m, float dx, float dy, float dz, float dh, int anim); void FillCommandStruct(PlayerPositionUpdateServer_Struct *position_update, Mob *mob, float delta_x, float delta_y, float delta_z, float delta_heading, int anim);
void UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mode); void UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode);
void UpdatePathGround(Mob *who, float x, float y, float z, MobMovementMode mode); void UpdatePathGround(Mob *who, float x, float y, float z, MobMovementMode mode);
void UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode mode); void UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode movement_mode);
void UpdatePathBoat(Mob *who, float x, float y, float z, MobMovementMode mode); void UpdatePathBoat(Mob *who, float x, float y, float z, MobMovementMode mode);
void PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading); void PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading);
void PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode); void PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode);
void PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode); void PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode);
void PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mode); void PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mob_movement_mode);
void PushStopMoving(MobMovementEntry &ent); void PushStopMoving(MobMovementEntry &mob_movement_entry);
void PushEvadeCombat(MobMovementEntry &ent); void PushEvadeCombat(MobMovementEntry &mob_movement_entry);
void HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mode); void HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode);
struct Implementation; struct Implementation;
std::unique_ptr<Implementation> _impl; std::unique_ptr<Implementation> _impl;

View File

@ -298,7 +298,8 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
if(IsClient()) { if(IsClient()) {
char temp[64]; char temp[64];
sprintf(temp, "%d", spell_id); sprintf(temp, "%d", spell_id);
parse->EventPlayer(EVENT_CAST_BEGIN, CastToClient(), temp, 0); if (parse->EventPlayer(EVENT_CAST_BEGIN, CastToClient(), temp, 0) != 0)
return false;
} else if(IsNPC()) { } else if(IsNPC()) {
char temp[64]; char temp[64];
sprintf(temp, "%d", spell_id); sprintf(temp, "%d", spell_id);

View File

@ -55,6 +55,7 @@
#include "zone_config.h" #include "zone_config.h"
#include "mob_movement_manager.h" #include "mob_movement_manager.h"
#include "npc_scale_manager.h" #include "npc_scale_manager.h"
#include "../common/data_verification.h"
#include <time.h> #include <time.h>
#include <ctime> #include <ctime>
@ -864,6 +865,8 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
m_last_ucss_update = 0; m_last_ucss_update = 0;
mMovementManager = &MobMovementManager::Get(); mMovementManager = &MobMovementManager::Get();
SetNpcPositionUpdateDistance(0);
} }
Zone::~Zone() { Zone::~Zone() {
@ -1194,9 +1197,9 @@ uint32 Zone::CountAuth() {
bool Zone::Process() { bool Zone::Process() {
spawn_conditions.Process(); spawn_conditions.Process();
if(spawn2_timer.Check()) { if (spawn2_timer.Check()) {
LinkedListIterator<Spawn2*> iterator(spawn2_list); LinkedListIterator<Spawn2 *> iterator(spawn2_list);
EQEmu::InventoryProfile::CleanDirty(); EQEmu::InventoryProfile::CleanDirty();
@ -1212,10 +1215,15 @@ bool Zone::Process() {
} }
} }
if(adv_data && !did_adventure_actions) if (adv_data && !did_adventure_actions) {
DoAdventureActions(); DoAdventureActions();
}
if (GetNpcPositionUpdateDistance() == 0) {
CalculateNpcUpdateDistanceSpread();
}
} }
if(initgrids_timer.Check()) { if(initgrids_timer.Check()) {
//delayed grid loading stuff. //delayed grid loading stuff.
initgrids_timer.Disable(); initgrids_timer.Disable();
@ -2365,3 +2373,59 @@ void Zone::SetUCSServerAvailable(bool ucss_available, uint32 update_timestamp) {
if (m_last_ucss_update < update_timestamp) if (m_last_ucss_update < 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(abs(max_x - min_x));
int y_spread = int(abs(max_y - min_y));
int combined_spread = int(abs((x_spread + y_spread) / 2));
int update_distance = EQEmu::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
);
}

View File

@ -126,6 +126,9 @@ public:
bool Process(); bool Process();
bool SaveZoneCFG(); bool SaveZoneCFG();
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);
@ -219,6 +222,7 @@ public:
void ChangeWeather(); void ChangeWeather();
void ClearBlockedSpells(); void ClearBlockedSpells();
void ClearNPCTypeCache(int id); void ClearNPCTypeCache(int id);
void CalculateNpcUpdateDistanceSpread();
void DelAggroMob() { aggroedmobs--; } void DelAggroMob() { aggroedmobs--; }
void DeleteQGlobal(std::string name, uint32 npcID, uint32 charID, uint32 zoneID); void DeleteQGlobal(std::string name, uint32 npcID, uint32 charID, uint32 zoneID);
void Despawn(uint32 spawngroupID); void Despawn(uint32 spawngroupID);
@ -290,7 +294,7 @@ public:
*/ */
find_replace(message, std::string("%"), std::string(".")); find_replace(message, std::string("%"), std::string("."));
if (message.find("\n") != std::string::npos) { if (message.find('\n') != std::string::npos) {
auto message_split = SplitString(message, '\n'); auto message_split = SplitString(message, '\n');
entity_list.MessageStatus( entity_list.MessageStatus(
0, 0,
@ -345,6 +349,7 @@ private:
glm::vec4 m_Graveyard; glm::vec4 m_Graveyard;
int default_ruleset; int default_ruleset;
int totalBS; int totalBS;
int npc_position_update_distance;
int32 aggroedmobs; int32 aggroedmobs;
uint8 zone_type; uint8 zone_type;
uint16 instanceversion; uint16 instanceversion;