better mutex handling for spell process, grid now has broken down spawns, KillSpawnByDistance and SetSpawnByDistance is now limited to its grid, future prospect of cross grid support

This commit is contained in:
Emagi 2022-11-05 15:46:43 -04:00
parent 1cb4896596
commit cd17261b83
13 changed files with 232 additions and 64 deletions

View file

@ -198,7 +198,11 @@ void Commands::Command_Bot(Client* client, Seperator* sep) {
continue;
if (member->IsBot() && ((Bot*)member)->GetOwner() == player) {
member->appearance.pos.grid_id = player->appearance.pos.grid_id;
if(member->GetZone() && member->appearance.pos.grid_id != player->appearance.pos.grid_id) {
member->GetZone()->RemoveSpawnFromGrid(member, member->appearance.pos.grid_id);
member->appearance.pos.grid_id = player->appearance.pos.grid_id;
member->GetZone()->AddSpawnToGrid(member, member->appearance.pos.grid_id);
}
member->SetX(player->GetX());
member->SetY(player->GetY());
member->SetZ(player->GetZ());

View file

@ -3350,16 +3350,21 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
if (sep && sep->arg[0] && strlen(sep->arg[0]) > 1) {
Client* new_leader = zone_list.GetClientByCharName(sep->arg[0]);
if (new_leader) {
if (new_leader && new_leader->GetPlayer()->GetGroupMemberInfo() && new_leader->GetPlayer()->GetGroupMemberInfo()->group_id == client->GetPlayer()->GetGroupMemberInfo()->group_id) {
if (client->GetPlayer()->IsGroupMember(new_leader->GetPlayer())) {
world.GetGroupManager()->MakeLeader(client->GetPlayer()->GetGroupMemberInfo()->group_id, new_leader->GetPlayer());
if(world.GetGroupManager()->MakeLeader(client->GetPlayer()->GetGroupMemberInfo()->group_id, new_leader->GetPlayer())) {
world.GetGroupManager()->GroupMessage(client->GetPlayer()->GetGroupMemberInfo()->group_id, "%s is now leader of the group.", new_leader->GetPlayer()->GetName());
}
}
}
else
client->SimpleMessage(CHANNEL_COMMANDS, "Unable to find the given player.");
}
else if (cmdTarget && cmdTarget->IsPlayer())
world.GetGroupManager()->MakeLeader(client->GetPlayer()->GetGroupMemberInfo()->group_id, (Entity*)cmdTarget);
else if (cmdTarget && cmdTarget->IsPlayer() && ((Player*)cmdTarget)->GetGroupMemberInfo() && ((Player*)cmdTarget)->GetGroupMemberInfo()->group_id == client->GetPlayer()->GetGroupMemberInfo()->group_id) {
if(client->GetPlayer()->IsGroupMember((Player*)cmdTarget) && world.GetGroupManager()->MakeLeader(client->GetPlayer()->GetGroupMemberInfo()->group_id, (Entity*)cmdTarget)) {
world.GetGroupManager()->GroupMessage(client->GetPlayer()->GetGroupMemberInfo()->group_id, "%s is now leader of the group.", cmdTarget->GetName());
}
}
else
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Unable to change group leader.");
@ -5491,7 +5496,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
case COMMAND_LOCATION_DELETE : { Command_LocationDelete(client, sep); break; }
case COMMAND_LOCATION_LIST : { Command_LocationList(client, sep); break; }
case COMMAND_LOCATION_REMOVE : { Command_LocationRemove(client, sep); break; }
case COMMAND_GRID : { Command_Grid(client); break; }
case COMMAND_GRID : { Command_Grid(client, sep); break; }
case COMMAND_TRY_ON : { Command_TryOn(client, sep); break; }
case COMMAND_RANDOMIZE : { Command_Randomize(client, sep); break; }
case COMMAND_AFK : { Command_AFK(client, sep); break; }
@ -6114,18 +6119,32 @@ void Commands::Command_StopFollow(Client* client, Seperator* sep)
Dev : Scatman
Example : /grid
*/
void Commands::Command_Grid(Client* client)
void Commands::Command_Grid(Client* client, Seperator* sep)
{
client->Message(CHANNEL_COLOR_YELLOW, "Your Grid ID is %u", client->GetPlayer()->appearance.pos.grid_id);
if (client->GetPlayer()->GetMap() != nullptr) {
if(sep && sep->arg[0][0] && strncasecmp("spawns", sep->arg[0], 6) == 0) {
int32 grid = client->GetPlayer()->GetLocation();
if(sep->IsNumber(1))
grid = atoul(sep->arg[1]);
std::vector<Spawn*> spawns = client->GetPlayer()->GetZone()->GetSpawnsInGrid(grid);
client->Message(CHANNEL_COLOR_RED, "Grid ID %u has %u spawns.", grid, spawns.size());
for(int i=0;i<spawns.size();i++) {
Spawn* spawn = spawns.at(i);
client->Message(CHANNEL_COLOR_YELLOW, "Spawn %s (%u), Loc X/Y/Z: %f/%f/%f.", spawn->GetName(), spawn->GetID(), spawn->GetX(), spawn->GetY(), spawn->GetZ());
}
}
else {
client->Message(CHANNEL_COLOR_YELLOW, "Your Grid ID is %u", client->GetPlayer()->appearance.pos.grid_id);
auto loc = glm::vec3(client->GetPlayer()->GetX(), client->GetPlayer()->GetZ(), client->GetPlayer()->GetY());
uint32 GridID = 0;
uint32 WidgetID = 0;
float new_z = client->GetPlayer()->GetMap()->FindBestZ(loc, nullptr, &GridID, &WidgetID);
float minY = client->GetPlayer()->GetMap()->GetMinY();
float maxY = client->GetPlayer()->GetMap()->GetMaxY();
client->Message(CHANNEL_COLOR_YELLOW, "Grid result is %u, at EQ2 Y coordinate %f. Min/Max Y %f/%f. Widget ID: %u", GridID, new_z, minY, maxY, WidgetID);
int32 grid_spawn_count = client->GetPlayer()->GetZone()->GetSpawnCountInGrid(GridID);
client->Message(CHANNEL_COLOR_YELLOW, "Grid result is %u, at EQ2 Y coordinate %f. Spawns on grid: %u. Min/Max Y %f/%f. Widget ID: %u", GridID, new_z, grid_spawn_count, minY, maxY, WidgetID);
}
}
}

View file

@ -309,7 +309,7 @@ public:
void Command_EntityCommand(Client* client, Seperator* sep, int handler);
void Command_Follow(Client* client, Seperator* sep);
void Command_StopFollow(Client* client, Seperator* sep);
void Command_Grid(Client* client);
void Command_Grid(Client* client, Seperator* sep);
void Command_Guild(Client* client, Seperator* sep);
void Command_CreateGuild(Client* client);
void Command_SetGuildOfficerNote(Client* client, Seperator* sep);

View file

@ -10313,7 +10313,7 @@ int EQ2Emu_lua_SetGridID(lua_State* state) {
return 0;
}
spawn->SetPos(&(spawn->appearance.pos.grid_id), grid);
spawn->SetLocation(grid);
return 0;
}

View file

@ -3415,12 +3415,17 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
LogWrite(PLAYER__DEBUG, 0, "Player", "%s left grid %u and entered grid %u", appearance.name, appearance.pos.grid_id, grid_id);
const char* zone_script = world.GetZoneScript(GetZone()->GetZoneID());
if (zone_script && lua_interface)
{
lua_interface->RunZoneScript(zone_script, "enter_location", GetZone(), this, grid_id);
lua_interface->RunZoneScript(zone_script, "leave_location", GetZone(), this, appearance.pos.grid_id);
if (zone_script && lua_interface) {
lua_interface->RunZoneScript(zone_script, "leave_location", GetZone(), this, GetLocation());
}
GetZone()->RemoveSpawnFromGrid(this, GetLocation());
GetZone()->AddSpawnToGrid(this, grid_id);
if (zone_script && lua_interface) {
lua_interface->RunZoneScript(zone_script, "enter_location", GetZone(), this, grid_id);
}
appearance.pos.grid_id = grid_id;
}
if (activity == UPDATE_ACTIVITY_IN_WATER_ABOVE || activity == UPDATE_ACTIVITY_IN_WATER_BELOW) {

View file

@ -174,7 +174,7 @@ void PlayerGroup::GroupChatMessage(Spawn* from, int32 language, const char* mess
MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
}
void PlayerGroup::MakeLeader(Entity* new_leader) {
bool PlayerGroup::MakeLeader(Entity* new_leader) {
deque<GroupMemberInfo*>::iterator itr;
MGroupMembers.readlock(__FUNCTION__, __LINE__);
for (itr = m_members.begin(); itr != m_members.end(); itr++) {
@ -188,6 +188,8 @@ void PlayerGroup::MakeLeader(Entity* new_leader) {
new_leader->GetGroupMemberInfo()->leader = true;
SendGroupUpdate();
return true;
}
@ -377,6 +379,8 @@ int8 PlayerGroupManager::AcceptInvite(Entity* member) {
// Remove from invite list and add to the group
m_pendingInvites.erase(member->GetName());
GroupMessage(client_leader->GetPlayer()->GetGroupMemberInfo()->group_id, "%s has joined the group.", member->GetName());
AddGroupMember(client_leader->GetPlayer()->GetGroupMemberInfo()->group_id, member);
ret = 0; // success
}
@ -585,11 +589,13 @@ void PlayerGroupManager::GroupChatMessage(int32 group_id, Spawn* from, int32 lan
m_groups[group_id]->GroupChatMessage(from, language, message);
}
void PlayerGroupManager::MakeLeader(int32 group_id, Entity* new_leader) {
bool PlayerGroupManager::MakeLeader(int32 group_id, Entity* new_leader) {
std::shared_lock lock(MGroups);
if (m_groups.count(group_id) > 0)
m_groups[group_id]->MakeLeader(new_leader);
return m_groups[group_id]->MakeLeader(new_leader);
return false;
}
void PlayerGroupManager::UpdateGroupBuffs() {

View file

@ -84,7 +84,7 @@ public:
void SimpleGroupMessage(const char* message);
void GroupChatMessage(Spawn* from, int32 language, const char* message);
void MakeLeader(Entity* new_leader);
bool MakeLeader(Entity* new_leader);
void RemoveClientReference(Client* remove);
void UpdateGroupMemberInfo(Entity* ent, bool groupMembersLocked=false);
@ -175,7 +175,7 @@ public:
void SimpleGroupMessage(int32 group_id, const char* message);
void GroupMessage(int32 group_id, const char* message, ...);
void GroupChatMessage(int32 group_id, Spawn* from, int32 language, const char* message);
void MakeLeader(int32 group_id, Entity* new_leader);
bool MakeLeader(int32 group_id, Entity* new_leader);
void UpdateGroupBuffs();
bool IsInGroup(int32 group_id, Entity* member);

View file

@ -3383,7 +3383,7 @@ bool Spawn::CalculateChange(){
}
if ((!IsFlyingCreature() || IsTransportSpawn()) && newGrid != 0 && newGrid != appearance.pos.grid_id)
SetPos(&(appearance.pos.grid_id), newGrid);
SetLocation(newGrid);
}
return remove_needed;
}
@ -3948,12 +3948,18 @@ void Spawn::FixZ(bool forceUpdate) {
const char* zone_script = world.GetZoneScript(GetZone()->GetZoneID());
if (zone_script && lua_interface)
{
lua_interface->RunZoneScript(zone_script, "enter_location", GetZone(), this, GridID);
lua_interface->RunZoneScript(zone_script, "leave_location", GetZone(), this, appearance.pos.grid_id);
if (zone_script && lua_interface) {
lua_interface->RunZoneScript(zone_script, "leave_location", GetZone(), this, GetLocation());
}
SetPos(&(appearance.pos.grid_id), GridID);
GetZone()->RemoveSpawnFromGrid(this, GetLocation());
GetZone()->AddSpawnToGrid(this, GridID);
if (zone_script && lua_interface) {
lua_interface->RunZoneScript(zone_script, "enter_location", GetZone(), this, GridID);
}
SetPos(&appearance.pos.grid_id, GridID);
}
trigger_widget_id = WidgetID;
}
@ -4492,4 +4498,14 @@ bool Spawn::HasRegionTracked(Region_Node* node, ZBSP_Node* bsp_root, bool in_reg
}
return false;
}
void Spawn::SetLocation(int32 id, bool setUpdateFlags)
{
if(GetZone()) {
GetZone()->RemoveSpawnFromGrid(this, appearance.pos.grid_id);
GetZone()->AddSpawnToGrid(this, id);
}
SetPos(&appearance.pos.grid_id, id, setUpdateFlags);
}

View file

@ -506,9 +506,7 @@ public:
void SetAttackable(int8 new_val, bool setUpdateFlags = true){
SetInfo(&appearance.attackable, new_val, setUpdateFlags);
}
void SetLocation(int32 id, bool setUpdateFlags = true){
SetPos(&appearance.pos.grid_id, id, setUpdateFlags);
}
void SetLocation(int32 id, bool setUpdateFlags = true);
void SetRace(int8 race, bool setUpdateFlags = true){
SetInfo(&appearance.race, race, setUpdateFlags);
}

View file

@ -33,7 +33,6 @@ extern RuleManager rule_manager;
SpellProcess::SpellProcess(){
last_checked_time = 0;
MSpellProcess.SetName("SpellProcess::MSpellProcess");
MRemoveTargetList.SetName("SpellProcess::MRemoveTargetList");
MSoloHO.SetName("SpellProcess::m_soloHO");
MGroupHO.SetName("SpellProcess:m_groupHO");
@ -45,7 +44,7 @@ SpellProcess::~SpellProcess(){
}
void SpellProcess::RemoveAllSpells(){
MSpellProcess.lock();
std::unique_lock lock(MSpellProcess);
ClearSpellScriptTimerList();
MutexList<LuaSpell*>::iterator active_spells_itr = active_spells.begin();
@ -105,15 +104,13 @@ void SpellProcess::RemoveAllSpells(){
MSpellCancelList.writelock(__FUNCTION__, __LINE__);
SpellCancelList.clear();
MSpellCancelList.releasewritelock(__FUNCTION__, __LINE__);
MSpellProcess.unlock();
}
void SpellProcess::Process(){
if(last_checked_time > Timer::GetCurrentTime2())
return;
last_checked_time = Timer::GetCurrentTime2() + 50;
MSpellProcess.lock();
MSpellProcess.lock_shared();
CheckSpellScriptTimers();
if(active_spells.size(true) > 0){
LuaSpell* spell = 0;
@ -279,7 +276,7 @@ void SpellProcess::Process(){
}
MGroupHO.releasewritelock(__FUNCTION__, __LINE__);
MSpellProcess.unlock();
MSpellProcess.unlock_shared();
}
bool SpellProcess::IsReady(Spell* spell, Entity* caster){
if(caster->IsCasting()) {
@ -1946,7 +1943,7 @@ void SpellProcess::Interrupted(Entity* caster, Spawn* interruptor, int16 error_c
void SpellProcess::RemoveSpellTimersFromSpawn(Spawn* spawn, bool remove_all, bool delete_recast, bool call_expire_function, bool lock_spell_process){
if(lock_spell_process)
MSpellProcess.lock();
MSpellProcess.lock_shared();
int32 i = 0;
if(cast_timers.size() > 0){
@ -2012,7 +2009,7 @@ void SpellProcess::RemoveSpellTimersFromSpawn(Spawn* spawn, bool remove_all, boo
}
if(lock_spell_process)
MSpellProcess.unlock();
MSpellProcess.unlock_shared();
}
void SpellProcess::GetSpellTargets(LuaSpell* luaspell)

View file

@ -19,6 +19,9 @@
*/
#ifndef __EQ2_SPELL_PROCESS__
#define __EQ2_SPELL_PROCESS__
#include <mutex>
#include <shared_mutex>
#include "client.h"
#include "Spells.h"
#include "zoneserver.h"
@ -393,7 +396,7 @@ public:
void DeleteActiveSpell(LuaSpell* spell);
static bool AddLuaSpellTarget(LuaSpell* lua_spell, int32 id, bool lock_spell_targets = true);
private:
Mutex MSpellProcess;
mutable std::shared_mutex MSpellProcess;
MutexMap<Entity*,Spell*> spell_que;
MutexList<LuaSpell*> active_spells;
MutexList<CastTimer*> cast_timers;

View file

@ -220,6 +220,16 @@ ZoneServer::~ZoneServer() {
// moved to the bottom as we want spawns deleted first, this used to be above Spawn deletion which is a big no no
safe_delete(spellProcess);
MGridMaps.lock();
std::map<int32, GridMap*>::iterator grids;
for(grids = grid_maps.begin(); grids != grid_maps.end(); grids++) {
GridMap* gm = grids->second;
safe_delete(gm);
}
grid_maps.clear();
MGridMaps.unlock();
LogWrite(ZONE__INFO, 0, "Zone", "Completed zone shutdown of '%s'", zone_name);
--numzones;
UpdateWindowTitle(0);
@ -3191,6 +3201,7 @@ void ZoneServer::AddSpawn(Spawn* spawn) {
AddSpawnProximities(spawn);
AddSpawnToGrid(spawn, spawn->GetLocation());
spawn->SetAddedToWorldTimestamp(Timer::GetCurrentTime2());
}
@ -4124,36 +4135,40 @@ void ZoneServer::CheckSpawnScriptTimers(){
}
void ZoneServer::KillSpawnByDistance(Spawn* spawn, float max_distance, bool include_players, bool send_packet){
if(!spawn)
return;
Spawn* test_spawn = 0;
map<int32, Spawn*>::iterator itr;
MSpawnList.readlock(__FUNCTION__, __LINE__);
for (itr = spawn_list.begin(); itr != spawn_list.end(); itr++) {
test_spawn = itr->second;
std::vector<Spawn*> ret_list = GetSpawnsInGrid(spawn->GetLocation());
std::vector<Spawn*>::iterator itr;
for (itr = ret_list.begin(); itr != ret_list.end(); itr++) {
test_spawn = *itr;
if(test_spawn && test_spawn->IsEntity() && test_spawn != spawn && (!test_spawn->IsPlayer() || include_players)){
if(test_spawn->GetDistance(spawn) < max_distance)
KillSpawn(true, test_spawn, spawn, send_packet);
}
}
MSpawnList.releasereadlock(__FUNCTION__, __LINE__);
}
void ZoneServer::SpawnSetByDistance(Spawn* spawn, float max_distance, string field, string value){
if(!spawn)
return;
Spawn* test_spawn = 0;
int32 type = commands.GetSpawnSetType(field);
if(type == 0xFFFFFFFF)
return;
map<int32, Spawn*>::iterator itr;
MSpawnList.readlock(__FUNCTION__, __LINE__);
for (itr = spawn_list.begin(); itr != spawn_list.end(); itr++) {
test_spawn = itr->second;
std::vector<Spawn*> ret_list = GetSpawnsInGrid(spawn->GetLocation());
std::vector<Spawn*>::iterator itr;
for (itr = ret_list.begin(); itr != ret_list.end(); itr++) {
test_spawn = *itr;
if(test_spawn && test_spawn != spawn && !test_spawn->IsPlayer()){
if(test_spawn->GetDistance(spawn) < max_distance){
commands.SetSpawnCommand(0, test_spawn, type, value.c_str());
}
}
}
MSpawnList.releasereadlock(__FUNCTION__, __LINE__);
}
void ZoneServer::AddSpawnScriptTimer(SpawnScriptTimer* timer){
@ -5086,10 +5101,22 @@ void ZoneServer::SendCastSpellPacket(LuaSpell* spell, Entity* caster){
continue;
packet = configReader.getStruct("WS_HearCastSpell", client->GetVersion());
if(packet){
packet->setDataByName("spawn_id", client->GetPlayer()->GetIDWithPlayerSpawn(caster));
int32 caster_id = client->GetPlayer()->GetIDWithPlayerSpawn(caster);
if(!caster_id)
continue;
packet->setDataByName("spawn_id", caster_id);
packet->setArrayLengthByName("num_targets", spell->targets.size());
for (int32 i = 0; i < spell->targets.size(); i++)
packet->setArrayDataByName("target", client->GetPlayer()->GetIDWithPlayerSpawn(spell->caster->GetZone()->GetSpawnByID(spell->targets[i])), i);
for (int32 i = 0; i < spell->targets.size(); i++) {
int32 target_id = client->GetPlayer()->GetIDWithPlayerSpawn(spell->caster->GetZone()->GetSpawnByID(spell->targets[i]));
if(target_id) {
packet->setArrayDataByName("target", target_id, i);
}
else {
packet->setArrayDataByName("target", 0xFFFFFFFF, i);
}
}
packet->setDataByName("spell_visual", spell->spell->GetSpellData()->spell_visual); //result
packet->setDataByName("cast_time", spell->spell->GetSpellData()->cast_time*.01); //delay
packet->setDataByName("spell_id", spell->spell->GetSpellID());
@ -5115,17 +5142,24 @@ void ZoneServer::SendCastSpellPacket(int32 spell_visual, Spawn* target, Spawn* c
continue;
PacketStruct* packet = configReader.getStruct("WS_HearCastSpell", client->GetVersion());
if (packet) {
int32 target_id = client->GetPlayer()->GetIDWithPlayerSpawn(target);
if(!target_id) // client is not aware of spawn
continue;
if (!caster) {
packet->setDataByName("spawn_id", 0xFFFFFFFF);
packet->setDataByName("invoker_id", 0xFFFFFFFF);
}
else {
int32 caster_id = client->GetPlayer()->GetIDWithPlayerSpawn(caster);
if(!caster_id) // client is not aware of spawn
continue;
packet->setDataByName("spawn_id", caster_id);
packet->setDataByName("invoker_id", caster_id);
}
packet->setArrayLengthByName("num_targets", 1);
packet->setArrayDataByName("target", client->GetPlayer()->GetIDWithPlayerSpawn(target));
packet->setArrayDataByName("target", target_id);
packet->setDataByName("spell_visual", spell_visual);
packet->setDataByName("cast_time", 0);
packet->setDataByName("spell_id", 0);
@ -5156,9 +5190,15 @@ void ZoneServer::SendCastEntityCommandPacket(EntityCommand* entity_command, int3
continue;
PacketStruct* packet = configReader.getStruct("WS_HearCastSpell", client->GetVersion());
if (packet) {
packet->setDataByName("spawn_id", client->GetPlayer()->GetIDWithPlayerSpawn(spawn));
int32 caster_id = client->GetPlayer()->GetIDWithPlayerSpawn(spawn);
int32 target_id = client->GetPlayer()->GetIDWithPlayerSpawn(target);
if(!caster_id || !target_id)
continue;
packet->setDataByName("spawn_id", caster_id);
packet->setArrayLengthByName("num_targets", 1);
packet->setArrayDataByName("target", client->GetPlayer()->GetIDWithPlayerSpawn(target));
packet->setArrayDataByName("target", target_id);
packet->setDataByName("num_targets", 1);
packet->setDataByName("spell_visual", entity_command->spell_visual); //result
packet->setDataByName("cast_time", entity_command->cast_time * 0.01); //delay
@ -6114,6 +6154,8 @@ void ZoneServer::RemoveSpawnSupportFunctions(Spawn* spawn, bool lock_spell_proce
if(!spawn)
return;
RemoveSpawnFromGrid(spawn, spawn->GetLocation());
if(spawn->IsPlayer() && spawn->GetZone())
spawn->GetZone()->RemovePlayerPassenger(((Player*)spawn)->GetCharacterID());
if(spawn->IsEntity())
@ -6957,14 +6999,13 @@ void ZoneServer::RemovePlayerPassenger(int32 char_id) {
vector<Spawn*> ZoneServer::GetAttackableSpawnsByDistance(Spawn* caster, float distance) {
vector<Spawn*> ret;
Spawn* spawn = 0;
map<int32, Spawn*>::iterator itr;
MSpawnList.readlock(__FUNCTION__, __LINE__);
for (itr = spawn_list.begin(); itr != spawn_list.end(); itr++) {
spawn = itr->second;
std::vector<Spawn*> ret_list = GetSpawnsInGrid(caster->GetLocation());
std::vector<Spawn*>::iterator itr;
for (itr = ret_list.begin(); itr != ret_list.end(); itr++) {
spawn = *itr;
if (spawn && spawn->IsNPC() && spawn->appearance.attackable > 0 && spawn != caster && spawn->Alive() && spawn->GetDistance(caster, true) <= distance)
ret.push_back(spawn);
}
MSpawnList.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
@ -8431,4 +8472,66 @@ void ZoneServer::ProcessPendingSpawns() {
pending_spawn_list_add.clear();
MPendingSpawnListAdd.releasewritelock(__FUNCTION__, __LINE__);
MSpawnList.releasewritelock(__FUNCTION__, __LINE__);
}
}
void ZoneServer::AddSpawnToGrid(Spawn* spawn, int32 grid_id) {
MGridMaps.lock_shared();
std::map<int32, GridMap*>::iterator grids = grid_maps.find(grid_id);
if(grids != grid_maps.end()) {
grids->second->MSpawns.lock();
grids->second->spawns.insert(make_pair(spawn->GetID(), spawn));
grids->second->MSpawns.unlock();
}
else {
MGridMaps.unlock_shared();
GridMap* gm = new GridMap;
gm->grid_id = grid_id;
gm->spawns.insert(make_pair(spawn->GetID(), spawn));
MGridMaps.lock();
grid_maps.insert(make_pair(grid_id, gm));
MGridMaps.unlock();
return;
}
MGridMaps.unlock_shared();
}
void ZoneServer::RemoveSpawnFromGrid(Spawn* spawn, int32 grid_id) {
std::shared_lock lock(MGridMaps);
std::map<int32, GridMap*>::iterator grids = grid_maps.find(grid_id);
if(grids != grid_maps.end() && grids->second->spawns.count(spawn->GetID()) > 0) {
grids->second->MSpawns.lock();
grids->second->spawns.erase(spawn->GetID());
grids->second->MSpawns.unlock();
}
}
int32 ZoneServer::GetSpawnCountInGrid(int32 grid_id) {
int32 count = 0;
std::shared_lock lock(MGridMaps);
std::map<int32, GridMap*>::iterator grids = grid_maps.find(grid_id);
if(grids != grid_maps.end()) {
grids->second->MSpawns.lock_shared();
count = grids->second->spawns.size();
grids->second->MSpawns.unlock_shared();
}
return count;
}
std::vector<Spawn*> ZoneServer::GetSpawnsInGrid(int32 grid_id) {
std::vector<Spawn*> ret;
int32 count = 0;
std::shared_lock lock(MGridMaps);
std::map<int32, GridMap*>::iterator grids = grid_maps.find(grid_id);
if(grids != grid_maps.end()) {
grids->second->MSpawns.lock_shared();
typedef map <int32, Spawn*> SpawnMapType;
for( SpawnMapType::iterator it = grids->second->spawns.begin(); it != grids->second->spawns.end(); ++it ) {
ret.push_back( it->second );
}
grids->second->MSpawns.unlock_shared();
}
return ret;
}

View file

@ -20,6 +20,9 @@
#ifndef ZONESERVER_H
#define ZONESERVER_H
#include <mutex>
#include <shared_mutex>
#include "../common/linked_list.h"
#include "../common/timer.h"
#include "../common/queue.h"
@ -153,6 +156,12 @@ struct LocationGrid {
MutexMap<Player*, bool> players;
};
struct GridMap {
int32 grid_id;
std::map<int32, Spawn*> spawns;
mutable std::shared_mutex MSpawns;
};
struct TrackedSpawn {
Spawn* spawn;
float distance;
@ -701,6 +710,10 @@ public:
void SendSubSpawnUpdates(SUBSPAWN_TYPES subtype);
bool HouseItemSpawnExists(int32 item_id);
void ProcessPendingSpawns();
void AddSpawnToGrid(Spawn* spawn, int32 grid_id);
void RemoveSpawnFromGrid(Spawn* spawn, int32 grid_id);
int32 GetSpawnCountInGrid(int32 grid_id);
std::vector<Spawn*> GetSpawnsInGrid(int32 grid_id);
private:
#ifndef WIN32
pthread_t ZoneThread;
@ -816,7 +829,11 @@ private:
Mutex MWidgetTimers;
map<int32, int32> widget_timers; // 1st int32 = spawn id
std::map<int32, GridMap*> grid_maps;
/* Mutexs */
mutable std::shared_mutex MGridMaps;
Mutex m_enemy_faction_list;
Mutex m_npc_faction_list;
Mutex m_reverse_enemy_faction_list;