Browse Source

Fixed emote visual state ids for classic/DoF client

Fix #154 - emotes will work cross clients since visual state ids can vary
Image 3 years ago
parent
commit
745185ecde

File diff suppressed because it is too large
+ 43 - 0
DB/updates/fixed_emotes_table.sql


+ 114 - 7
EQ2/source/WorldServer/VisualStates.h

@@ -17,6 +17,7 @@
     You should have received a copy of the GNU General Public License
     along with EQ2Emulator.  If not, see <http://www.gnu.org/licenses/>.
 */
+#include "../common/Log.h"
 #include <map>
 
 using namespace std;
@@ -47,7 +48,6 @@ private:
 	int id;
 	string name;
 };
-
 class Emote{
 public:
 	Emote(char* in_name, int in_visual_state, char* in_message, char* in_targeted_message){
@@ -74,6 +74,97 @@ private:
 	string message;
 	string targeted_message;
 };
+class VersionRange {
+public:
+	VersionRange(int32 in_min_version, int32 in_max_version)
+	{
+		min_version = in_min_version;
+		max_version = in_max_version;
+	}
+	int32 GetMinVersion() { return min_version; }
+	int32 GetMaxVersion() { return max_version; }
+private:
+	int32 min_version;
+	int32 max_version;
+};
+
+class EmoteVersionRange {
+public:
+	EmoteVersionRange(char* in_name)
+	{
+		name = string(in_name);
+	}
+
+	~EmoteVersionRange()
+	{
+		map<VersionRange*, Emote*>::iterator itr;
+		for (itr = version_map.begin(); itr != version_map.end(); itr++)
+		{
+			VersionRange* range = itr->first;
+			Emote* emote = itr->second;
+			delete range;
+			delete emote;
+		}
+
+		version_map.clear();
+	}
+
+	void AddVersionRange(int32 min_version, int32 max_version,
+		char* in_name, int in_visual_state, char* in_message, char* in_targeted_message)
+	{
+		map<VersionRange*, Emote*>::iterator itr = FindVersionRange(min_version, max_version);
+		if (itr != version_map.end())
+		{
+			VersionRange* range = itr->first;
+			LogWrite(WORLD__ERROR, 0, "Emotes Table Error: Duplicate emote mapping of %s with range min %u max %u, Existing found with range min %u max %u\n", name.c_str(), min_version, max_version, range->GetMinVersion(), range->GetMaxVersion());
+			return;
+		}
+
+		version_map.insert(make_pair(new VersionRange(min_version, max_version), new Emote(in_name, in_visual_state, in_message, in_targeted_message)));
+	}
+
+	map<VersionRange*, Emote*>::iterator FindVersionRange(int32 min_version, int32 max_version)
+	{
+		map<VersionRange*, Emote*>::iterator itr;
+		for (itr = version_map.begin(); itr != version_map.end(); itr++)
+		{
+			VersionRange* range = itr->first;
+			// if min and max version are both in range
+			if (range->GetMinVersion() <= min_version && max_version <= range->GetMaxVersion())
+				return itr;
+			// if the min version is in range, but max range is 0
+			else if (range->GetMinVersion() <= min_version && range->GetMaxVersion() == 0)
+				return itr;
+			// if min version is 0 and max_version has a cap
+			else if (range->GetMinVersion() == 0 && max_version <= range->GetMaxVersion())
+				return itr;
+		}
+
+		return version_map.end();
+	}
+
+	map<VersionRange*, Emote*>::iterator FindEmoteVersion(int32 version)
+	{
+		map<VersionRange*, Emote*>::iterator itr;
+		for (itr = version_map.begin(); itr != version_map.end(); itr++)
+		{
+			VersionRange* range = itr->first;
+			// if min and max version are both in range
+			if (version >= range->GetMinVersion() && (range->GetMaxVersion() == 0 || version <= range->GetMaxVersion()))
+				return itr;
+		}
+
+		return version_map.end();
+	}
+
+	const char* GetName() { return name.c_str(); }
+	string GetNameString() { return name; }
+
+	map<VersionRange*, Emote*>::iterator GetRangeEnd() { return version_map.end(); }
+private:
+	map<VersionRange*, Emote*> version_map;
+	string name;
+};
 
 class VisualStates
 {
@@ -88,7 +179,7 @@ public:
 	}
 
 	void ClearEmotes(){
-		map<string, Emote*>::iterator map_list;
+		map<string, EmoteVersionRange*>::iterator map_list;
 		for(map_list = emoteMap.begin(); map_list != emoteMap.end(); map_list++ )
 			safe_delete(map_list->second);
 		emoteMap.clear();
@@ -111,17 +202,33 @@ public:
 		return 0;
 	}
 
-	void InsertEmote(Emote* emote){
-		emoteMap[emote->GetNameString()] = emote;
+	void InsertEmoteRange(EmoteVersionRange* emote) {
+		emoteMap[emote->GetName()] = emote;
 	}
 
-	Emote* FindEmote(string var){
-		if(emoteMap.count(var) > 0)
+	EmoteVersionRange* FindEmoteRange(string var) {
+		if (emoteMap.count(var) > 0)
+		{
 			return emoteMap[var];
+		}
+		return 0;
+	}
+
+	Emote* FindEmote(string var, int32 version){
+		if (emoteMap.count(var) > 0)
+		{
+			map<VersionRange*,Emote*>::iterator itr = emoteMap[var]->FindEmoteVersion(version);
+
+			if (itr != emoteMap[var]->GetRangeEnd())
+			{
+				Emote* emote = itr->second;
+				return emote;
+			}
+		}
 		return 0;
 	}
 private:
 	map<string,VisualState*> visualStateMap;
-	map<string,Emote*> emoteMap;
+	map<string,EmoteVersionRange*> emoteMap;
 };
 

+ 9 - 3
EQ2/source/WorldServer/WorldDatabase.cpp

@@ -429,11 +429,17 @@ void WorldDatabase::LoadVisualStates()
 	LogWrite(WORLD__DEBUG, 3, "World", "--Loaded %u visual states", total);
 
 	total = 0;
-	result = query2.RunQuery2(Q_SELECT, "SELECT name, visual_state_id, message, targeted_message FROM emotes");
+	result = query2.RunQuery2(Q_SELECT, "SELECT name, visual_state_id, message, targeted_message, min_version_range, max_version_range FROM emotes");
 	while(result && (row = mysql_fetch_row(result)))
 	{
-		Emote* emote = new Emote(row[0], atoi(row[1]), row[2], row[3]);
-		visual_states.InsertEmote(emote);
+		EmoteVersionRange* range = 0;
+		if ((range = visual_states.FindEmoteRange(string(row[0]))) == NULL)
+		{
+			range = new EmoteVersionRange(row[0]);
+			visual_states.InsertEmoteRange(range);
+		}
+		
+		range->AddVersionRange(atoul(row[4]),atoul(row[5]), row[0], atoi(row[1]), row[2], row[3]);
 		total++;
 		LogWrite(WORLD__DEBUG, 5, "World", "---Loading emote state: '%s' (%i)", row[1], atoi(row[0]));
 	}

+ 26 - 2
EQ2/source/WorldServer/zoneserver.cpp

@@ -5661,20 +5661,44 @@ void ZoneServer::HandleEmote(Client* originator, string name) {
 	}
 
 	Client* client = 0;
-	Emote* emote = visual_states.FindEmote(name);
-	if(!emote){
+	Emote* origEmote = visual_states.FindEmote(name, originator->GetVersion());
+	if(!origEmote){
 		originator->Message(CHANNEL_COLOR_YELLOW, "Unable to find emote '%s'.  If this should be a valid emote be sure to submit a /bug report.", name.c_str());
 		return;
 	}
+	Emote* emote = origEmote;
+
 	PacketStruct* packet = 0;
 	char* emoteResponse = 0;
 	vector<Client*>::iterator client_itr;
 	
+	int32 cur_client_version = originator->GetVersion();
+	map<int32, Emote*> emote_version_range;
 	MClientList.readlock(__FUNCTION__, __LINE__);
 	for (client_itr = clients.begin(); client_itr != clients.end(); client_itr++) {
 		client = *client_itr;
 		if(!client || (client && client->GetPlayer()->IsIgnored(originator->GetPlayer()->GetName())))
 			continue;
+
+		// establish appropriate emote for the version used by the client
+		if (client->GetVersion() != originator->GetVersion())
+		{
+			map<int32, Emote*>::iterator rangeitr = emote_version_range.find(client->GetVersion());
+			if (rangeitr == emote_version_range.end())
+			{
+				Emote* tmp_new_emote = visual_states.FindEmote(name, client->GetVersion());
+				if (tmp_new_emote)
+				{
+					emote_version_range.insert(make_pair(client->GetVersion(), tmp_new_emote));
+					emote = tmp_new_emote;
+				} // else its missing just use the current clients default
+			}
+			else // we have an existing emote already cached
+				emote = rangeitr->second;
+		}
+		else // since the client and originator client match use the original emote
+			emote = origEmote;
+
 		packet = configReader.getStruct("WS_CannedEmote", client->GetVersion());
 		if(packet){
 			packet->setDataByName("spawn_id" , client->GetPlayer()->GetIDWithPlayerSpawn(originator->GetPlayer()));

Some files were not shown because too many files changed in this diff