# Conflicts:
#	EQ2/source/WorldServer/Spawn.cpp
#	server/EQ2World__Debug_x64.exe
#	server/SpawnStructs.xml
This commit is contained in:
LethalEncounter 2020-07-26 00:36:20 -04:00
commit e64b718066
17 changed files with 375 additions and 29 deletions

View file

@ -0,0 +1 @@
insert into commands set handler=521,command='findspawn',required_status=200,subcommand='';

File diff suppressed because one or more lines are too long

View file

@ -4379,6 +4379,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
case SAVE_AA_PROFILE : { Save_AA_Profile(client, sep); break; }
case COMMAND_TARGETITEM : { Command_TargetItem(client, sep); break; }
case COMMAND_FINDSPAWN: { Command_FindSpawn(client, sep); break; }
default:
@ -10218,3 +10219,7 @@ void Commands::Command_TargetItem(Client* client, Seperator* sep) {
}
}
}
void Commands::Command_FindSpawn(Client* client, Seperator* sep) {
client->GetCurrentZone()->FindSpawn(client, (char*)sep->argplus[0]);
}

View file

@ -468,6 +468,8 @@ public:
void Command_DeclineResurrection(Client* client, Seperator* set);
void Command_TargetItem(Client* client, Seperator* set);
void Command_FindSpawn(Client* client, Seperator* set);
// Bot Commands
void Command_Bot(Client* client, Seperator* sep);
void Command_Bot_Create(Client* client, Seperator* sep);
@ -899,6 +901,8 @@ private:
#define COMMAND_RELOAD_RULES 519
#define COMMAND_RELOAD_TRANSPORTERS 520
#define COMMAND_FINDSPAWN 521
#define GET_AA_XML 751
#define ADD_AA 752
#define COMMIT_AA_PROFILE 753

View file

@ -54,6 +54,7 @@ Player::Player(){
spawn_index = 0;
info = 0;
movement_packet = 0;
fully_logged_in = false;
last_movement_activity = 0;
//speed = 0;
packet_num = 0;
@ -578,7 +579,7 @@ void PlayerInfo::SetAccountAge(int16 age){
EQ2Packet* PlayerInfo::serialize(int16 version, int16 modifyPos, int32 modifyValue) {
player->CalculateBonuses();
info_struct->heat = 15;
/* info_struct->heat = 15;
info_struct->heat_base = 13;
info_struct->divine = 14;
info_struct->divine_base = 11;
@ -587,7 +588,7 @@ EQ2Packet* PlayerInfo::serialize(int16 version, int16 modifyPos, int32 modifyVal
info_struct->coin_copper = 1;
info_struct->coin_silver = 2;
info_struct->coin_gold = 3;
info_struct->coin_plat = 4;
info_struct->coin_plat = 4;*/
int8 blah1 = 90;
int8 blah2 = 120;

View file

@ -2391,7 +2391,7 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
temp_activity_status = 1;
temp_activity_status += (IsNPC() || IsObject() || IsGroundSpawn()) ? 1 << 1 : 0;
if (version > 546) {
if (version >= 1188) {
if (IsGroundSpawn() || GetShowHandIcon())
temp_activity_status += ACTIVITY_STATUS_INTERACTABLE_1188;
@ -2429,14 +2429,22 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
temp_activity_status += ACTIVITY_STATUS_INCOMBAT_1188;
// if this is either a boat or lift let the client be manipulated by the object
// doesn't work for DoF client version 546
if (appearance.icon == 28 || appearance.icon == 12)
{
temp_activity_status += ACTIVITY_STATUS_ISTRANSPORT_1188;
}
}
else
{
temp_activity_status = appearance.activity_status;
if(IsNPC())
temp_activity_status = 0xFF;
// this only partially fixes lifts in classic 283 client if you move just as the lift starts to move
if (appearance.icon == 28 || appearance.icon == 12)
packet->setDataByName("is_transport", 1);
if (MeetsSpawnAccessRequirements(spawn))
packet->setDataByName("hand_icon", appearance.display_hand_icon);
else {

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

@ -587,6 +587,13 @@ void MobMovementManager::RotateTo(Entity *who, float to, MobMovementMode mob_mov
{
MobListMutex.readlock();
auto iter = _impl->Entries.find(who);
if (iter == _impl->Entries.end())
{
MobListMutex.releasereadlock();
return; // does not exist in navigation
}
auto &ent = (*iter);
if (true != ent.second.Commands.empty()) {
@ -608,6 +615,13 @@ void MobMovementManager::Teleport(Entity *who, float x, float y, float z, float
{
MobListMutex.readlock();
auto iter = _impl->Entries.find(who);
if (iter == _impl->Entries.end())
{
MobListMutex.releasereadlock();
return; // does not exist in navigation
}
auto &ent = (*iter);
ent.second.Commands.clear();
@ -633,6 +647,13 @@ void MobMovementManager::NavigateTo(Entity *who, float x, float y, float z, MobM
}
MobListMutex.readlock();
auto iter = _impl->Entries.find(who);
if (iter == _impl->Entries.end())
{
MobListMutex.releasereadlock();
return; // does not exist in navigation
}
auto &ent = (*iter);
auto &nav = ent.second.NavTo;
@ -693,6 +714,13 @@ void MobMovementManager::StopNavigation(Entity *who)
{
MobListMutex.readlock();
auto iter = _impl->Entries.find(who);
if (iter == _impl->Entries.end())
{
MobListMutex.releasereadlock();
return; // does not exist in navigation
}
auto &ent = (*iter);
auto &nav = ent.second.NavTo;
@ -728,6 +756,13 @@ void MobMovementManager::DisruptNavigation(Entity* who)
{
MobListMutex.readlock();
auto iter = _impl->Entries.find(who);
if (iter == _impl->Entries.end())
{
MobListMutex.releasereadlock();
return; // does not exist in navigation
}
auto& ent = (*iter);
auto& nav = ent.second.NavTo;
@ -786,6 +821,13 @@ void MobMovementManager::UpdatePath(Entity *who, float x, float y, float z, MobM
if (!who->GetZone()->zonemap /*|| !zone->HasWaterMap()*/) {
MobListMutex.readlock();
auto iter = _impl->Entries.find(who);
if (iter == _impl->Entries.end())
{
MobListMutex.releasereadlock();
return; // does not exist in navigation
}
auto &ent = (*iter);
PushMoveTo(ent.second, x, y, z, mob_movement_mode);
@ -833,6 +875,13 @@ void MobMovementManager::UpdatePathGround(Entity *who, float x, float y, float z
MobListMutex.readlock();
auto eiter = _impl->Entries.find(who);
if (eiter == _impl->Entries.end())
{
MobListMutex.releasereadlock();
return; // does not exist in navigation
}
auto &ent = (*eiter);
if (route.size() == 0) {
@ -960,6 +1009,13 @@ void MobMovementManager::UpdatePathUnderwater(Entity *who, float x, float y, flo
{
MobListMutex.readlock();
auto eiter = _impl->Entries.find(who);
if (eiter == _impl->Entries.end())
{
MobListMutex.releasereadlock();
return; // does not exist in navigation
}
auto &ent = (*eiter);
if (/*zone->watermap->InLiquid(who->GetPosition()) && zone->watermap->InLiquid(glm::vec3(x, y, z)) &&*/
who->GetZone()->zonemap->CheckLoS(glm::vec3(who->GetX(),who->GetZ(),who->GetY()), glm::vec3(x, y, z))) {
@ -1081,6 +1137,13 @@ void MobMovementManager::UpdatePathBoat(Entity *who, float x, float y, float z,
{
MobListMutex.readlock();
auto eiter = _impl->Entries.find(who);
if (eiter == _impl->Entries.end())
{
MobListMutex.releasereadlock();
return; // does not exist in navigation
}
auto &ent = (*eiter);
PushSwimTo(ent.second, x, y, z, mode);
@ -1188,6 +1251,13 @@ void MobMovementManager::HandleStuckBehavior(Entity *who, float x, float y, floa
}
auto eiter = _impl->Entries.find(who);
if (eiter == _impl->Entries.end())
{
MobListMutex.releasereadlock();
return; // does not exist in navigation
}
auto &ent = (*eiter);
switch (sb) {

View file

@ -973,12 +973,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
case OP_SysClient: {
LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_SysClient", opcode, opcode);
LogWrite(CCLIENT__DEBUG, 0, "Client", "Client '%s' (%u) is ready for spawn updates.", GetPlayer()->GetName(), GetPlayer()->GetCharacterID());
GetPlayer()->SetFullyLoggedIn(true);
if (!ready_for_updates)
database.loadCharacterProperties(this);
ready_for_updates = true;
SetReadyForUpdates();
break;
}
case OP_MapRequest: {
@ -1533,8 +1528,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
EQ2_16BitString str = packet->getType_EQ2_16BitString_ByName("signal");
if (str.size > 0) {
if (strcmp(str.data.c_str(), "sys_client_avatar_ready") == 0) {
GetPlayer()->SetFullyLoggedIn(true);
ready_for_updates = true;
SetReadyForUpdates();
GetPlayer()->SendSpawnChanges(true);
}
const char* zone_script = world.GetZoneScript(player->GetZone()->GetZoneID());
@ -7541,6 +7535,15 @@ void Client::SearchStore(int32 page) {
}
void Client::SetReadyForUpdates() {
GetPlayer()->SetFullyLoggedIn(true);
if (!ready_for_updates)
database.loadCharacterProperties(this);
ready_for_updates = true;
}
void Client::SetReadyForSpawns(bool val) {
ready_for_spawns = val;
if (GetPlayer()->GetActivityStatus() > 0) {

View file

@ -146,6 +146,7 @@ public:
bool IsReadyForSpawns(){ return ready_for_spawns; }
bool IsReadyForUpdates() { return ready_for_updates; }
bool IsZoning(){ return client_zoning; }
void SetReadyForUpdates();
void SetReadyForSpawns(bool val);
void QueuePacket(EQ2Packet* app, bool attemptedCombine=false);
void SendLoginInfo();

View file

@ -25,6 +25,7 @@ using namespace std;
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <regex>
#include "Commands/Commands.h"
#include "Zone/pathfinder_interface.h"
@ -5661,20 +5662,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()));
@ -5816,6 +5841,63 @@ bool ZoneServer::SendRadiusSpawnInfo(Client* client, float radius) {
return ret;
}
void ZoneServer::FindSpawn(Client* client, char* regSearchStr)
{
if (!regSearchStr || strlen(regSearchStr) < 1)
{
client->SimpleMessage(CHANNEL_COLOR_RED, "Bad ZoneServer::FindSpawn(Client*, char* regSearchStr) attempt, regSearchStr is NULL or empty.");
return;
}
string resString = string(regSearchStr);
try
{
std::regex pre_re_check("^[a-zA-Z0-9_ ]+$");
bool output = std::regex_match(resString, pre_re_check);
if (output)
{
string newStr(".*");
newStr.append(regSearchStr);
newStr.append(".*");
resString = newStr;
}
}
catch (...)
{
client->SimpleMessage(CHANNEL_COLOR_RED, "Try/Catch ZoneServer::FindSpawn(Client*, char* regSearchStr) failure.");
return;
}
client->Message(CHANNEL_COLOR_WHITE, "RegEx Search Spawn List: %s", regSearchStr);
client->Message(CHANNEL_COLOR_WHITE, "Database ID | Spawn Name | X , Y , Z");
client->Message(CHANNEL_COLOR_WHITE, "========================");
map<int32, Spawn*>::iterator itr;
MSpawnList.readlock(__FUNCTION__, __LINE__);
int32 spawnsFound = 0;
std::regex re(resString, std::regex_constants::icase);
for (itr = spawn_list.begin(); itr != spawn_list.end(); itr++) {
Spawn* spawn = itr->second;
if (!spawn || !spawn->GetName())
continue;
bool output = false;
try {
output = std::regex_match(string(spawn->GetName()), re);
}
catch (...)
{
continue;
}
if (output)
{
client->Message(CHANNEL_COLOR_WHITE, "%i | %s | %f , %f , %f", spawn->GetDatabaseID(), spawn->GetName(), spawn->GetX(), spawn->GetY(), spawn->GetZ());
spawnsFound++;
}
}
client->Message(CHANNEL_COLOR_WHITE, "========================", spawnsFound);
client->Message(CHANNEL_COLOR_WHITE, "%u Results Found.", spawnsFound);
MSpawnList.releasereadlock(__FUNCTION__, __LINE__);
}
void ZoneServer::AddPlayerTracking(Player* player) {
if (player && !player->GetIsTracking() && players_tracking.count(player->GetDatabaseID()) == 0) {

View file

@ -345,8 +345,9 @@ public:
void CheckTransporters(Client* client);
void WritePlayerStatistics();
bool SendRadiusSpawnInfo(Client* client, float radius);
void FindSpawn(Client* client, char* regSearchStr);
volatile bool spawnthread_active;
volatile bool combatthread_active;

View file

@ -38,9 +38,9 @@
#endif
#if defined(LOGIN)
#define CURRENT_VERSION "0.8.1-cancer2"
#define CURRENT_VERSION "0.8.1-leo1"
#elif defined(WORLD)
#define CURRENT_VERSION "0.8.1-cancer2"
#define CURRENT_VERSION "0.8.1-leo1"
#else
#define CURRENT_VERSION "0.7.3-dev"
#endif

Binary file not shown.

Binary file not shown.

View file

@ -373,7 +373,7 @@
<Data ElementName="no_arrow_color_or_healthbar" Type="int8" Size="1" /> <!-- 37 -->
<Data ElementName="hand_icon" Type="int8" Size="1" /> <!-- 38 127 -->
<Data ElementName="hide_health" Type="int8" Size="1" /> <!-- 39 -->
<Data ElementName="unknown15" Type="int8" Size="1" /> <!-- 40 -->
<Data ElementName="is_transport" Type="int8" Size="1" /> <!-- 40 -->
<Data ElementName="house_icon" Type="int8" Size="1" /> <!-- 41 -->
<Data ElementName="in_combat" Type="int8" Size="1" /> <!-- 42 -->
<Data ElementName="afk" Type="int8" Size="1" /> <!-- 43 -->
@ -462,9 +462,9 @@
<Data ElementName="unknown10" Type="int8" Size="1" /> <!-- 306 -->
<Data ElementName="no_arrow_color_or_highlight" Type="int8" Size="1" /> <!-- 307 -->
<Data ElementName="no_arrow_color_or_healthbar" Type="int8" Size="1" /> <!-- 308 -->
<Data ElementName="hand_icon" Type="int8" Size="1" /> <!-- 309 127 -->
<Data ElementName="hand_icon" Type="int8" Size="1" /> <!-- 309 -->
<Data ElementName="hide_health" Type="int8" Size="1" /> <!-- 310 -->
<Data ElementName="unknown11" Type="int8" Size="1" /> <!-- 311 -->
<Data ElementName="is_transport" Type="int8" Size="1" /> <!-- 311 -->
<Data ElementName="house_icon" Type="int8" Size="1" /> <!-- 312 -->
<Data ElementName="in_combat" Type="int8" Size="1" /> <!-- 313 -->
<Data ElementName="afk" Type="int8" Size="1" /> <!-- 314 -->