Browse Source

Fixed some limitations/bugs with starting skills/spells implementation

- multimap needs to be used for various key matches
- fixed class matching
- Put a short tic wait for the async queries to hit the DB.  Eventual solution here really would be that all character loading (char sheet/spells/etc) should be done async.
image 3 years ago
parent
commit
51b314ac87

+ 27 - 16
EQ2/source/WorldServer/World.cpp

@@ -2146,9 +2146,10 @@ void World::SyncCharacterAbilities(Client* client)
 
 	bool reloadSpells = false;
 
-	map<int8, map<int8, StartingSkill>*>::iterator skill_itr = starting_skills.begin();
-	map<int8, map<int8, StartingSpell>*>::iterator spell_itr = starting_spells.begin();
+	multimap<int8, multimap<int8, StartingSkill>*>::iterator skill_itr = starting_skills.begin();
+	multimap<int8, multimap<int8, StartingSpell>*>::iterator spell_itr = starting_spells.begin();
 	bool isComplete = false;
+	int8 wait_iterations = 0; // wait 5 iterations and give up if db takes too long
 	do
 	{
 		bool isProcessing = false;
@@ -2158,12 +2159,12 @@ void World::SyncCharacterAbilities(Client* client)
 
 			if ((skill_itr->first & baseRace) == baseRace)
 			{
-				map<int8, StartingSkill>::iterator child_itr;
+				multimap<int8, StartingSkill>::iterator child_itr;
 				for (child_itr = skill_itr->second->begin(); child_itr != skill_itr->second->end(); child_itr++)
 				{
-					if ((skill_itr->first & baseClass) == baseClass ||
-						(skill_itr->first & secondaryClass) == secondaryClass ||
-						(skill_itr->first & actualClass) == actualClass)
+					if ((child_itr->first & baseClass) == baseClass ||
+						(child_itr->first & secondaryClass) == secondaryClass ||
+						(child_itr->first & actualClass) == actualClass)
 					{
 						if (!client->GetPlayer()->skill_list.HasSkill(child_itr->second.skill_id))
 						{
@@ -2186,18 +2187,19 @@ void World::SyncCharacterAbilities(Client* client)
 
 			if ((spell_itr->first & baseRace) == baseRace)
 			{
-				map<int8, StartingSpell>::iterator child_itr;
+				multimap<int8, StartingSpell>::iterator child_itr;
 				for (child_itr = spell_itr->second->begin(); child_itr != spell_itr->second->end(); child_itr++)
 				{
-					if ((spell_itr->first & baseClass) == baseClass ||
-						(spell_itr->first & secondaryClass) == secondaryClass ||
-						(spell_itr->first & actualClass) == actualClass)
+					if ((child_itr->first & baseClass) == baseClass ||
+						(child_itr->first & secondaryClass) == secondaryClass ||
+						(child_itr->first & actualClass) == actualClass)
 					{
 						if (!client->GetPlayer()->HasSpell(child_itr->second.spell_id, child_itr->second.tier, true))
 						{
 							Query query;
 							LogWrite(PLAYER__DEBUG, 0, "Player", "Adding spell %i for race: %i, class: %i for char_id: %u", child_itr->second.spell_id, baseRace, baseClass, client->GetCharacterID());
-							query.AddQueryAsync(client->GetCharacterID(), &database, Q_INSERT, "INSERT IGNORE INTO character_spells (char_id, spell_id, tier, knowledge_slot) VALUES (%u, %u, %u, %u)",
+							// knowledge_slot is a signed int in the DB
+							query.AddQueryAsync(client->GetCharacterID(), &database, Q_INSERT, "INSERT IGNORE INTO character_spells (char_id, spell_id, tier, knowledge_slot) VALUES (%u, %u, %u, %i)",
 								client->GetCharacterID(), child_itr->second.spell_id, child_itr->second.tier, child_itr->second.knowledge_slot);
 
 							// reload spells, we don't know the spellbook or timer info
@@ -2209,8 +2211,17 @@ void World::SyncCharacterAbilities(Client* client)
 			spell_itr++;
 		}
 
+		// poor mans async kill just in case, we don't want a client stuck here, they can get the spells on next zone
 		if (!isProcessing)
-			isComplete = true;
+		{
+			bool isDBActive = database.IsActiveQuery(client->GetCharacterID());
+			if (isDBActive && wait_iterations < 5)
+			{
+				wait_iterations++;
+			}
+			else
+				isComplete = true;
+		}
 
 	} while (!isComplete);
 
@@ -2233,21 +2244,21 @@ void World::PurgeStartingLists()
 {
 	MStartingLists.writelock();
 
-	map<int8, map<int8, StartingSkill>*>::iterator skill_itr;
+	multimap<int8, multimap<int8, StartingSkill>*>::iterator skill_itr;
 
 	for (skill_itr = starting_skills.begin(); skill_itr != starting_skills.end(); skill_itr++)
 	{
-		map<int8, StartingSkill>* tmpMap = skill_itr->second;
+		multimap<int8, StartingSkill>* tmpMap = skill_itr->second;
 		safe_delete(tmpMap);
 	}
 	starting_skills.clear();
 
 
-	map<int8, map<int8, StartingSpell>*>::iterator spell_itr;
+	multimap<int8, multimap<int8, StartingSpell>*>::iterator spell_itr;
 
 	for (spell_itr = starting_spells.begin(); spell_itr != starting_spells.end(); spell_itr++)
 	{
-		map<int8, StartingSpell>* tmpMap = spell_itr->second;
+		multimap<int8, StartingSpell>* tmpMap = spell_itr->second;
 		safe_delete(tmpMap);
 	}
 	starting_spells.clear();

+ 2 - 2
EQ2/source/WorldServer/World.h

@@ -608,8 +608,8 @@ public:
 
 	void LoadStartingLists();
 	void PurgeStartingLists();
-	map<int8, map<int8, StartingSkill>*> starting_skills;
-	map<int8, map<int8, StartingSpell>*> starting_spells;
+	multimap<int8, multimap<int8, StartingSkill>*> starting_skills;
+	multimap<int8, multimap<int8, StartingSpell>*> starting_spells;
 	Mutex MStartingLists;
 private:
 	//void RemovePlayerFromGroup(PlayerGroup* group, GroupMemberInfo* info, bool erase = true);

+ 6 - 4
EQ2/source/WorldServer/WorldDatabase.cpp

@@ -6893,13 +6893,14 @@ void WorldDatabase::LoadStartingSkills(World* world)
 
 				if (!world->starting_skills.count(skill.header.race_id))
 				{
-					map<int8, StartingSkill>* skills = new map<int8, StartingSkill>();
+					multimap<int8, StartingSkill>* skills = new multimap<int8, StartingSkill>();
 					skills->insert(make_pair(skill.header.class_id, skill));
 					world->starting_skills.insert(make_pair(skill.header.race_id, skills));
 				}
 				else
 				{
-					world->starting_skills[skill.header.race_id]->insert(make_pair(skill.header.class_id, skill));
+					multimap<int8, multimap<int8, StartingSkill>*>::const_iterator skills = world->starting_skills.find(skill.header.race_id);
+					skills->second->insert(make_pair(skill.header.class_id, skill));
 				}
 				total++;
 			}
@@ -6938,13 +6939,14 @@ void WorldDatabase::LoadStartingSpells(World* world)
 
 				if (!world->starting_spells.count(spell.header.race_id))
 				{
-					map<int8, StartingSpell>* spells = new map<int8, StartingSpell>();
+					multimap<int8, StartingSpell>* spells = new multimap<int8, StartingSpell>();
 					spells->insert(make_pair(spell.header.class_id, spell));
 					world->starting_spells.insert(make_pair(spell.header.race_id, spells));
 				}
 				else
 				{
-					world->starting_spells[spell.header.race_id]->insert(make_pair(spell.header.class_id, spell));
+					multimap<int8, multimap<int8, StartingSpell>*>::iterator spells = world->starting_spells.find(spell.header.race_id);
+					spells->second->insert(make_pair(spell.header.class_id, spell));
 				}
 				total++;
 			}