Browse Source

Map memory cache disabled by default, enable with R_World, MemoryCacheZoneMaps set to 1. Changed Spawns no longer a MutexList, was terribly inefficient, in debug 50% cpu performance improvement on moving spawns

Emagi 1 year ago
parent
commit
005244259b

+ 3 - 1
EQ2/source/WorldServer/Commands/Commands.cpp

@@ -6142,8 +6142,10 @@ void Commands::Command_Grid(Client* client, Seperator* sep)
 			float new_z = client->GetPlayer()->GetMap()->FindBestZ(loc, nullptr, &GridID, &WidgetID);
 			float minY = client->GetPlayer()->GetMap()->GetMinY();
 			float maxY = client->GetPlayer()->GetMap()->GetMaxY();
+			float minZ = client->GetPlayer()->GetMap()->GetMinZ();
+			float maxZ = client->GetPlayer()->GetMap()->GetMaxZ();
 			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);
+			client->Message(CHANNEL_COLOR_YELLOW, "Grid result is %u, at EQ2 Y coordinate %f.  Spawns on grid: %u.  Min/Max Y %f/%f Z %f/%f.  Widget ID: %u", GridID, new_z, grid_spawn_count, minY, maxY, minZ, maxZ, WidgetID);
 		}
 	}
 }

+ 1 - 0
EQ2/source/WorldServer/Rules/Rules.cpp

@@ -304,6 +304,7 @@ void RuleManager::Init()
 																	// 4 - send to 'new' starting zones, won't support old clients
 																	// 5+ - send to new and old starting zones as needed
 	RULE_INIT(R_World, EnforceRacialAlignment, "1");
+	RULE_INIT(R_World, MemoryCacheZoneMaps, "0");					// 0 disables caching the zone maps in memory, too many individual/unique zones entered may cause a lot of memory build up
 	//INSERT INTO `ruleset_details`(`id`, `ruleset_id`, `rule_category`, `rule_type`, `rule_value`, `description`) VALUES (NULL, '1', 'R_World', '', '', '')
 
 	/* ZONE */

+ 1 - 0
EQ2/source/WorldServer/Rules/Rules.h

@@ -157,6 +157,7 @@ enum RuleType {
 	StartingZoneLanguages,
 	StartingZoneRuleFlag,
 	EnforceRacialAlignment,
+	MemoryCacheZoneMaps,
 
 	/* ZONE */
 	MinZoneLevelOverrideStatus,

+ 26 - 0
EQ2/source/WorldServer/World.cpp

@@ -539,9 +539,15 @@ void ZoneList::Add(ZoneServer* zone) {
 	MZoneList.releasewritelock(__FUNCTION__, __LINE__);
 }
 void ZoneList::Remove(ZoneServer* zone) {
+	const char* zoneName = zone->GetZoneName();
 	MZoneList.writelock(__FUNCTION__, __LINE__);
 	zlist.remove(zone);
 	MZoneList.releasewritelock(__FUNCTION__, __LINE__);
+	
+	ZoneServer* alternativeZone = Get(zoneName, false, false);
+	if(!alternativeZone && !rule_manager.GetGlobalRule(R_World, MemoryCacheZoneMaps)->GetBool()) {
+		world.RemoveMaps(std::string(zoneName));
+	}
 }
 ZoneServer* ZoneList::Get(const char* zone_name, bool loadZone, bool skip_existing_zones) {
 	list<ZoneServer*>::iterator zone_iter;
@@ -2597,6 +2603,26 @@ void World::LoadMaps(std::string zoneFile)
 	MWorldMaps.releasewritelock();
 }
 
+void World::RemoveMaps(std::string zoneFile)
+{
+	string zoneToLower(zoneFile);
+	boost::algorithm::to_lower(zoneToLower);
+
+	MWorldMaps.writelock();
+	std::map<std::string, MapRange*>::iterator itr;
+	itr = maps.find(zoneToLower);
+	if (itr != maps.end())
+	{
+		MapRange* range = itr->second;
+		maps.erase(itr);
+		MWorldMaps.releasewritelock();
+		safe_delete(range);
+	}
+	else {
+		MWorldMaps.releasewritelock();
+	}
+}
+
 Map* World::GetMap(std::string zoneFile, int32 client_version)
 {
 	string zoneToLower(zoneFile);

+ 1 - 0
EQ2/source/WorldServer/World.h

@@ -649,6 +649,7 @@ public:
 	RegionMap* GetRegionMap(std::string zoneFile, int32 client_version);
 	
 	void LoadMaps(std::string zoneFile);
+	void RemoveMaps(std::string zoneFile);
 	Map* GetMap(std::string zoneFile, int32 client_version);
 	
 	void SendTimeUpdate();

+ 38 - 12
EQ2/source/WorldServer/zoneserver.cpp

@@ -175,6 +175,7 @@ ZoneServer::ZoneServer(const char* name, bool incoming_client) {
 	lifetime_client_count = 0;
 }
 
+typedef map <int32, bool> ChangedSpawnMapType;
 ZoneServer::~ZoneServer() {
 	zoneShuttingDown = true;  //ensure other threads shut down too
 	//allow other threads to properly shut down
@@ -186,7 +187,11 @@ ZoneServer::~ZoneServer() {
 			LogWrite(ZONE__DEBUG, 7, "Zone", "Zone shutdown waiting on initial spawn thread");
 		Sleep(10);
 	}
-	changed_spawns.clear(true);
+	
+	MChangedSpawns.lock();
+	changed_spawns.clear();
+	MChangedSpawns.unlock();
+	
 	transport_spawns.clear();
 	safe_delete(tradeskillMgr);
 	MMasterZoneLock->lock();
@@ -1919,13 +1924,31 @@ Spawn* ZoneServer::FindSpawn(Player* searcher, const char* name){
 void ZoneServer::AddChangedSpawn(Spawn* spawn) {
 	if (!spawn || (spawn->IsPlayer() && !spawn->info_changed && !spawn->vis_changed) || (spawn->IsPlayer() && ((Player*)spawn)->IsFullyLoggedIn() == false))
 		return;
-	if (changed_spawns.count(spawn->GetID()) == 0)
-		changed_spawns.Add(spawn->GetID());
+	
+    MChangedSpawns.lock_shared();
+	ChangedSpawnMapType::iterator it = changed_spawns.find(spawn->GetID());
+	if (it != changed_spawns.end()) {
+		it->second = true;
+		MChangedSpawns.unlock_shared();
+	}
+	else {
+		MChangedSpawns.unlock_shared();
+		MChangedSpawns.lock();
+		changed_spawns.insert(make_pair(spawn->GetID(),true));
+		MChangedSpawns.unlock();
+	}
 }
 
 void ZoneServer::RemoveChangedSpawn(Spawn* spawn){
-	if (spawn)
-		changed_spawns.Remove(spawn->GetID());
+	if(!spawn)
+		return;
+	
+    MChangedSpawns.lock();
+	ChangedSpawnMapType::iterator it = changed_spawns.find(spawn->GetID());
+	if (it != changed_spawns.end()) {
+		it->second = false;
+	}
+	MChangedSpawns.unlock();
 }
 
 void ZoneServer::AddDrowningVictim(Player* player){
@@ -1980,25 +2003,28 @@ void ZoneServer::ProcessDrowning(){
 }
 
 void ZoneServer::SendSpawnChanges(){
+    std::shared_lock lock(MChangedSpawns);
 	if (changed_spawns.size() < 1)
 		return;
 
 	set<Spawn*> spawns_to_send;
 	Spawn* spawn = 0;
 
-	MSpawnList.readlock(__FUNCTION__, __LINE__);
-	MutexList<int32>::iterator spawn_iter = changed_spawns.begin();
 	int count = 0;
-	while(spawn_iter.Next()){		
-		spawn = GetSpawnByID(spawn_iter->value);
+	
+	MSpawnList.readlock(__FUNCTION__, __LINE__);
+	
+	for( ChangedSpawnMapType::iterator it = changed_spawns.begin(); it != changed_spawns.end(); ++it ) {
+		if(!it->second)
+			continue;
+		
+		spawn = GetSpawnByID(it->first);
 		if(spawn){
 			spawns_to_send.insert(spawn);
 			count++;
 		}
-		if (!spawn)
-			changed_spawns.Remove(spawn_iter->value);
 	}
-
+	
 	vector<Client*>::iterator client_itr;
 	Client* client = 0;
 	

+ 2 - 1
EQ2/source/WorldServer/zoneserver.h

@@ -794,7 +794,7 @@ private:
 	void DismissAllPets();																						// never used outside zone server
 	
 	/* Mutex Lists */
-	MutexList<int32> changed_spawns;										// int32 = spawn id
+	std::map<int32, bool> changed_spawns;										// int32 = spawn id
 	vector<Client*> clients;
 	MutexList<Client*> connected_clients;									// probably remove this list so we are not maintaining 2 client lists
 	MutexList<int32> damaged_spawns;										// int32 = spawn id
@@ -833,6 +833,7 @@ private:
 	
 	/* Mutexs */
 	mutable std::shared_mutex MGridMaps;
+	mutable std::shared_mutex MChangedSpawns;
 	
 	Mutex	m_enemy_faction_list;
 	Mutex	m_npc_faction_list;