Fixed emote visual state ids for classic/DoF client

Fix  - emotes will work cross clients since visual state ids can vary
This commit is contained in:
Image 2020-07-25 08:24:05 -04:00
parent e8bf4be00f
commit 745185ecde
4 changed files with 206 additions and 12 deletions

File diff suppressed because one or more lines are too long

View file

@ -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;
};

View file

@ -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]));
}

View file

@ -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()));