mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-30 03:25:44 +00:00
Compare commits
9 Commits
v23.7.0
...
akkadius/iwyu
| Author | SHA1 | Date | |
|---|---|---|---|
| faa6819f80 | |||
| 4cc1d99322 | |||
| a0ff9d67a1 | |||
| befee1c729 | |||
| 3d70063a68 | |||
| 4e28bcf85e | |||
| 687d10960a | |||
| 567d46c3d6 | |||
| 53cc2de459 |
@@ -177,6 +177,21 @@ void EQEmuConfig::parse_config()
|
||||
SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString();
|
||||
LogDir = _root["server"]["directories"].get("logs", "logs/").asString();
|
||||
|
||||
auto load_paths = [&](const std::string& key, std::vector<std::string>& target) {
|
||||
const auto& paths = _root["server"]["directories"][key];
|
||||
if (paths.isArray()) {
|
||||
for (const auto& dir : paths) {
|
||||
if (dir.isString()) {
|
||||
target.push_back(dir.asString());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
load_paths("quest_paths", m_quest_directories);
|
||||
load_paths("plugin_paths", m_plugin_directories);
|
||||
load_paths("lua_module_paths", m_lua_module_directories);
|
||||
|
||||
/**
|
||||
* Logs
|
||||
*/
|
||||
|
||||
@@ -120,6 +120,22 @@ class EQEmuConfig
|
||||
const std::string &GetUCSHost() const;
|
||||
uint16 GetUCSPort() const;
|
||||
|
||||
std::vector<std::string> GetQuestDirectories() const
|
||||
{
|
||||
return m_quest_directories;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetPluginsDirectories() const
|
||||
{
|
||||
return m_plugin_directories;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetLuaModuleDirectories() const
|
||||
{
|
||||
return m_lua_module_directories;
|
||||
}
|
||||
|
||||
|
||||
// uint16 DynamicCount;
|
||||
|
||||
// map<string,uint16> StaticZones;
|
||||
@@ -133,6 +149,11 @@ class EQEmuConfig
|
||||
Json::Value _root;
|
||||
static std::string ConfigFile;
|
||||
|
||||
std::vector<std::string> m_quest_directories = {};
|
||||
std::vector<std::string> m_plugin_directories = {};
|
||||
std::vector<std::string> m_lua_module_directories = {};
|
||||
|
||||
protected:
|
||||
void parse_config();
|
||||
|
||||
EQEmuConfig()
|
||||
|
||||
@@ -15,9 +15,9 @@ const uint32 PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL = 60 * 60 * 1000; // 1
|
||||
// general initialization routine
|
||||
void PlayerEventLogs::Init()
|
||||
{
|
||||
|
||||
m_process_batch_events_timer.SetTimer(RuleI(Logging, BatchPlayerEventProcessIntervalSeconds) * 1000);
|
||||
m_process_retention_truncation_timer.SetTimer(PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL);
|
||||
m_database_ping_timer.SetTimer(10 * 1000); // 10 seconds
|
||||
|
||||
ValidateDatabaseConnection();
|
||||
|
||||
@@ -916,6 +916,10 @@ std::string PlayerEventLogs::GetDiscordPayloadFromEvent(const PlayerEvent::Playe
|
||||
// general process function, used in world or QS depending on rule Logging:PlayerEventsQSProcess
|
||||
void PlayerEventLogs::Process()
|
||||
{
|
||||
if (m_database_ping_timer.Check()) {
|
||||
m_database->ping();
|
||||
}
|
||||
|
||||
if (m_process_batch_events_timer.Check() ||
|
||||
m_record_batch_queue.size() >= RuleI(Logging, BatchPlayerEventProcessChunkSize)) {
|
||||
ProcessBatchQueue();
|
||||
|
||||
@@ -113,6 +113,7 @@ private:
|
||||
std::map<PlayerEvent::EventType, EtlSettings> m_etl_settings{};
|
||||
|
||||
// timers
|
||||
Timer m_database_ping_timer; // database ping timer
|
||||
Timer m_process_batch_events_timer; // events processing timer
|
||||
Timer m_process_retention_truncation_timer; // timer for truncating events based on retention settings
|
||||
|
||||
|
||||
+43
-22
@@ -48,10 +48,23 @@ void PathManager::LoadPaths()
|
||||
return dir;
|
||||
};
|
||||
|
||||
auto load_many_paths_fallback = [&](const std::vector<std::string>& dirs, const std::string& fallback, std::vector<std::string>& target) {
|
||||
target.clear();
|
||||
if (!dirs.empty()) {
|
||||
for (const auto& path : dirs) {
|
||||
target.push_back(resolve_path(path));
|
||||
}
|
||||
} else {
|
||||
target.push_back(resolve_path(fallback));
|
||||
}
|
||||
};
|
||||
|
||||
load_many_paths_fallback(c->GetQuestDirectories(), c->QuestDir, m_quests_paths);
|
||||
load_many_paths_fallback(c->GetPluginsDirectories(), c->PluginDir, m_plugin_paths);
|
||||
load_many_paths_fallback(c->GetLuaModuleDirectories(), c->LuaModuleDir, m_lua_module_paths);
|
||||
|
||||
// resolve all paths
|
||||
m_maps_path = resolve_path(c->MapDir, {"maps", "Maps"});
|
||||
m_quests_path = resolve_path(c->QuestDir);
|
||||
m_plugins_path = resolve_path(c->PluginDir);
|
||||
m_lua_modules_path = resolve_path(c->LuaModuleDir);
|
||||
m_lua_mods_path = resolve_path("mods");
|
||||
m_patch_path = resolve_path(c->PatchDir);
|
||||
m_opcode_path = resolve_path(c->OpcodeDir);
|
||||
@@ -62,13 +75,10 @@ void PathManager::LoadPaths()
|
||||
std::vector<std::pair<std::string, std::string>> paths = {
|
||||
{"server", m_server_path},
|
||||
{"logs", m_log_path},
|
||||
{"lua mods", m_lua_mods_path},
|
||||
{"lua_modules", m_lua_modules_path},
|
||||
{"maps", m_maps_path},
|
||||
{"lua mods", m_lua_mods_path},
|
||||
{"patches", m_patch_path},
|
||||
{"opcode", m_opcode_path},
|
||||
{"plugins", m_plugins_path},
|
||||
{"quests", m_quests_path},
|
||||
{"shared_memory", m_shared_memory_path}
|
||||
};
|
||||
|
||||
@@ -83,6 +93,17 @@ void PathManager::LoadPaths()
|
||||
LogInfo("{:>{}} > [{:<{}}]", name, name_width, in_path, path_width);
|
||||
}
|
||||
}
|
||||
|
||||
auto log_paths = [&](const std::string& label, const std::vector<std::string>& paths) {
|
||||
if (!paths.empty()) {
|
||||
LogInfo("{:>{}} > [{:<{}}]", label, name_width - 1, Strings::Join(paths, ";"), path_width);
|
||||
}
|
||||
};
|
||||
|
||||
log_paths("quests", m_quests_paths);
|
||||
log_paths("plugins", m_plugin_paths);
|
||||
log_paths("lua_modules", m_lua_module_paths);
|
||||
|
||||
LogInfo("{}", Strings::Repeat("-", break_length));
|
||||
}
|
||||
|
||||
@@ -96,21 +117,26 @@ const std::string &PathManager::GetMapsPath() const
|
||||
return m_maps_path;
|
||||
}
|
||||
|
||||
const std::string &PathManager::GetQuestsPath() const
|
||||
{
|
||||
return m_quests_path;
|
||||
}
|
||||
|
||||
const std::string &PathManager::GetPluginsPath() const
|
||||
{
|
||||
return m_plugins_path;
|
||||
}
|
||||
|
||||
const std::string &PathManager::GetSharedMemoryPath() const
|
||||
{
|
||||
return m_shared_memory_path;
|
||||
}
|
||||
|
||||
std::vector<std::string> PathManager::GetQuestPaths() const
|
||||
{
|
||||
return m_quests_paths;
|
||||
}
|
||||
|
||||
std::vector<std::string> PathManager::GetPluginPaths() const
|
||||
{
|
||||
return m_plugin_paths;
|
||||
}
|
||||
|
||||
std::vector<std::string> PathManager::GetLuaModulePaths() const
|
||||
{
|
||||
return m_lua_module_paths;
|
||||
}
|
||||
|
||||
const std::string &PathManager::GetLogPath() const
|
||||
{
|
||||
return m_log_path;
|
||||
@@ -126,11 +152,6 @@ const std::string &PathManager::GetOpcodePath() const
|
||||
return m_opcode_path;
|
||||
}
|
||||
|
||||
const std::string &PathManager::GetLuaModulesPath() const
|
||||
{
|
||||
return m_lua_modules_path;
|
||||
}
|
||||
|
||||
const std::string &PathManager::GetLuaModsPath() const
|
||||
{
|
||||
return m_lua_mods_path;
|
||||
|
||||
+18
-12
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class PathManager {
|
||||
public:
|
||||
@@ -14,22 +15,27 @@ public:
|
||||
[[nodiscard]] const std::string &GetMapsPath() const;
|
||||
[[nodiscard]] const std::string &GetPatchPath() const;
|
||||
[[nodiscard]] const std::string &GetOpcodePath() const;
|
||||
[[nodiscard]] const std::string &GetPluginsPath() const;
|
||||
[[nodiscard]] const std::string &GetQuestsPath() const;
|
||||
[[nodiscard]] const std::string &GetServerPath() const;
|
||||
[[nodiscard]] const std::string &GetSharedMemoryPath() const;
|
||||
[[nodiscard]] std::vector<std::string> GetQuestPaths() const;
|
||||
[[nodiscard]] std::vector<std::string> GetPluginPaths() const;
|
||||
[[nodiscard]] std::vector<std::string> GetLuaModulePaths() const;
|
||||
|
||||
private:
|
||||
std::string m_log_path;
|
||||
std::string m_lua_mods_path;
|
||||
std::string m_lua_modules_path;
|
||||
std::string m_maps_path;
|
||||
std::string m_patch_path;
|
||||
std::string m_opcode_path;
|
||||
std::string m_plugins_path;
|
||||
std::string m_quests_path;
|
||||
std::string m_server_path;
|
||||
std::string m_shared_memory_path;
|
||||
std::string m_log_path;
|
||||
std::string m_lua_mods_path;
|
||||
std::string m_maps_path;
|
||||
std::string m_patch_path;
|
||||
std::string m_opcode_path;
|
||||
std::string m_quests_path;
|
||||
std::vector<std::string> m_quests_paths;
|
||||
std::vector<std::string> m_plugin_paths;
|
||||
std::vector<std::string> m_lua_module_paths;
|
||||
|
||||
|
||||
private:
|
||||
std::string m_server_path;
|
||||
std::string m_shared_memory_path;
|
||||
};
|
||||
|
||||
extern PathManager path;
|
||||
|
||||
@@ -233,6 +233,12 @@ RULE_BOOL(Character, SneakAlwaysSucceedOver100, false, "When sneak skill is over
|
||||
RULE_INT(Character, BandolierSwapDelay, 0, "Bandolier swap delay in milliseconds, default is 0")
|
||||
RULE_BOOL(Character, EnableHackedFastCampForGM, false, "Enables hacked fast camp for GM clients, if the GM doesn't have a hacked client they'll camp like normal")
|
||||
RULE_BOOL(Character, AlwaysAllowNameChange, false, "Enable this option to allow /changename to work without enabling a name change via scripts.")
|
||||
RULE_BOOL(Character, EnableAutoAFK, true, "Enable or disable the auto AFK feature, cuts down on packet spam")
|
||||
RULE_BOOL(Character, AutoIdleFilterPackets, true, "Enable or disable filtering packets when auto AFK is enabled, heavily cuts down on packet spam in zones with lots of players")
|
||||
RULE_INT(Character, SecondsBeforeIdleCombatZone, 600, "Seconds before a player is considered idle in combat zones (600 = 10 minutes)")
|
||||
RULE_INT(Character, SecondsBeforeIdleNonCombatZone, 60, "Seconds before a player is considered idle in non-combat zones (60 = 1 minute)")
|
||||
RULE_INT(Character, SecondsBeforeAFKCombatZone, 1800, "Seconds before a player is considered AFK in combat zones (1800 = 30 minutes)")
|
||||
RULE_INT(Character, SecondsBeforeAFKNonCombatZone, 600, "Seconds before a player is considered AFK in non-combat zones (600 = 10 minutes)")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
|
||||
@@ -48,7 +48,7 @@ enum class SharedTaskRequestGroupType {
|
||||
struct ServerSharedTaskRequest_Struct {
|
||||
uint32 requested_character_id;
|
||||
uint32 requested_task_id;
|
||||
uint32 requested_npc_type_id; // original task logic passthrough
|
||||
uint32 requested_npc_entity_id; // original task logic passthrough
|
||||
uint32 accept_time;
|
||||
};
|
||||
|
||||
|
||||
+1
-1
Submodule submodules/libuv updated: 0c1fa696aa...8fb9cb9194
+15
-3
@@ -95,9 +95,22 @@ void ConsoleApi(
|
||||
BenchTimer timer;
|
||||
timer.reset();
|
||||
|
||||
EQEmuApiWorldDataService::get(response, args);
|
||||
std::string method = args.empty() ? "" : args[0];
|
||||
|
||||
std::string method = args[0];
|
||||
if (method.empty()) {
|
||||
root["execution_time"] = std::to_string(timer.elapsed());
|
||||
root["method"] = method;
|
||||
root["data"] = response;
|
||||
root["error"] = "No method specified";
|
||||
|
||||
std::stringstream payload;
|
||||
payload << root;
|
||||
connection->SendLine(payload.str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Safe to call now that args[0] is known to exist
|
||||
EQEmuApiWorldDataService::get(response, args);
|
||||
|
||||
root["execution_time"] = std::to_string(timer.elapsed());
|
||||
root["method"] = method;
|
||||
@@ -105,7 +118,6 @@ void ConsoleApi(
|
||||
|
||||
std::stringstream payload;
|
||||
payload << root;
|
||||
|
||||
connection->SendLine(payload.str());
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,10 @@ void callGetZoneList(Json::Value &response)
|
||||
for (auto &zone: zoneserver_list.getZoneServerList()) {
|
||||
Json::Value row;
|
||||
|
||||
if (!zone) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!zone->IsConnected()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
+8
-12
@@ -182,7 +182,8 @@ int main(int argc, char **argv)
|
||||
EQTimeTimer.Start(600000);
|
||||
Timer parcel_prune_timer(86400000);
|
||||
parcel_prune_timer.Start(86400000);
|
||||
|
||||
Timer player_event_log_process(1000);
|
||||
player_event_log_process.Start(1000);
|
||||
|
||||
// global loads
|
||||
LogInfo("Loading launcher list");
|
||||
@@ -385,15 +386,6 @@ int main(int argc, char **argv)
|
||||
player_event_logs.Init();
|
||||
}
|
||||
|
||||
auto event_log_processor = std::jthread([](const std::stop_token& stoken) {
|
||||
while (!stoken.stop_requested()) {
|
||||
if (!RuleB(Logging, PlayerEventsQSProcess)) {
|
||||
player_event_logs.Process();
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
}
|
||||
});
|
||||
|
||||
auto loop_fn = [&](EQ::Timer* t) {
|
||||
Timer::SetCurrentTime();
|
||||
|
||||
@@ -487,6 +479,12 @@ int main(int argc, char **argv)
|
||||
shared_task_manager.Process();
|
||||
dynamic_zone_manager.Process();
|
||||
|
||||
if (!RuleB(Logging, PlayerEventsQSProcess)) {
|
||||
if (player_event_log_process.Check()) {
|
||||
player_event_logs.Process();
|
||||
}
|
||||
}
|
||||
|
||||
if (InterserverTimer.Check()) {
|
||||
InterserverTimer.Start();
|
||||
database.ping();
|
||||
@@ -506,8 +504,6 @@ int main(int argc, char **argv)
|
||||
|
||||
EQ::EventLoop::Get().Run();
|
||||
|
||||
event_log_processor.request_stop();
|
||||
|
||||
LogInfo("World main loop completed");
|
||||
LogInfo("Shutting down zone connections (if any)");
|
||||
zoneserver_list.KillAll();
|
||||
|
||||
@@ -677,10 +677,10 @@ void SharedTaskManager::SendAcceptNewSharedTaskPacket(
|
||||
);
|
||||
|
||||
auto d = reinterpret_cast<ServerSharedTaskRequest_Struct *>(p->pBuffer);
|
||||
d->requested_character_id = character_id;
|
||||
d->requested_task_id = task_id;
|
||||
d->requested_npc_type_id = npc_context_id;
|
||||
d->accept_time = accept_time;
|
||||
d->requested_character_id = character_id;
|
||||
d->requested_task_id = task_id;
|
||||
d->requested_npc_entity_id = npc_context_id;
|
||||
d->accept_time = accept_time;
|
||||
|
||||
// get requested character zone server
|
||||
ClientListEntry *cle = client_list.FindCLEByCharacterID(character_id);
|
||||
|
||||
@@ -24,16 +24,16 @@ void SharedTaskWorldMessaging::HandleZoneMessage(ServerPacket *pack)
|
||||
case ServerOP_SharedTaskRequest: {
|
||||
auto *r = (ServerSharedTaskRequest_Struct *) pack->pBuffer;
|
||||
LogTasksDetail(
|
||||
"[ServerOP_SharedTaskRequest] Received request from character [{}] task_id [{}] npc_type_id [{}]",
|
||||
"[ServerOP_SharedTaskRequest] Received request from character [{}] task_id [{}] npc_entity_id [{}]",
|
||||
r->requested_character_id,
|
||||
r->requested_task_id,
|
||||
r->requested_npc_type_id
|
||||
r->requested_npc_entity_id
|
||||
);
|
||||
|
||||
shared_task_manager.AttemptSharedTaskCreation(
|
||||
r->requested_task_id,
|
||||
r->requested_character_id,
|
||||
r->requested_npc_type_id
|
||||
r->requested_npc_entity_id
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
Aura::Aura(NPCType *type_data, Mob *owner, AuraRecord &record)
|
||||
: NPC(type_data, 0, owner->GetPosition(), GravityBehavior::Flying), spell_id(record.spell_id),
|
||||
distance(record.distance),
|
||||
remove_timer(record.duration), movement_timer(100), process_timer(1000), aura_id(-1)
|
||||
remove_timer(record.duration), movement_timer(1000), process_timer(1000), aura_id(-1)
|
||||
{
|
||||
GiveNPCTypeData(type_data); // we will delete this later on
|
||||
m_owner = owner->GetID();
|
||||
|
||||
@@ -2,9 +2,10 @@ extern Zone *zone;
|
||||
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <cereal/types/map.hpp>
|
||||
#include "../../common/repositories/npc_types_repository.h"
|
||||
#include "../../corpse.h"
|
||||
#include "../../../common/repositories/npc_types_repository.h"
|
||||
#include "../../../common/repositories/respawn_times_repository.h"
|
||||
#include "../../../common/repositories/zone_state_spawns_repository.h"
|
||||
|
||||
inline void ClearState()
|
||||
{
|
||||
|
||||
+52
-16
@@ -226,8 +226,8 @@ Client::Client() : Mob(
|
||||
last_reported_endurance_percent = 0;
|
||||
last_reported_mana_percent = 0;
|
||||
gm_hide_me = false;
|
||||
AFK = false;
|
||||
LFG = false;
|
||||
m_is_afk = false;
|
||||
LFG = false;
|
||||
LFGFromLevel = 0;
|
||||
LFGToLevel = 0;
|
||||
LFGMatchFilter = false;
|
||||
@@ -536,8 +536,8 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
||||
last_reported_endurance_percent = 0;
|
||||
last_reported_mana_percent = 0;
|
||||
gm_hide_me = false;
|
||||
AFK = false;
|
||||
LFG = false;
|
||||
m_is_afk = false;
|
||||
LFG = false;
|
||||
LFGFromLevel = 0;
|
||||
LFGToLevel = 0;
|
||||
LFGMatchFilter = false;
|
||||
@@ -1175,6 +1175,10 @@ void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req, CLIENT_CO
|
||||
return;
|
||||
}
|
||||
|
||||
if (RuleB(Character, AutoIdleFilterPackets) && m_is_idle && IsFilteredAFKPacket(app)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (client_state != CLIENT_CONNECTED && required_state == CLIENT_CONNECTED) {
|
||||
AddPacket(app, ack_req);
|
||||
return;
|
||||
@@ -2528,7 +2532,7 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
Mob::FillSpawnStruct(ns, ForWho);
|
||||
|
||||
// Populate client-specific spawn information
|
||||
ns->spawn.afk = AFK;
|
||||
ns->spawn.afk = m_is_afk;
|
||||
ns->spawn.lfg = LFG; // afk and lfg are cleared on zoning on live
|
||||
ns->spawn.anon = m_pp.anon;
|
||||
ns->spawn.gm = GetGM() ? 1 : 0;
|
||||
@@ -10839,15 +10843,37 @@ void Client::SetAnon(uint8 anon_flag) {
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::SetAFK(uint8 afk_flag) {
|
||||
AFK = afk_flag;
|
||||
auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||
SpawnAppearance_Struct* spawn_appearance = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||
spawn_appearance->spawn_id = GetID();
|
||||
spawn_appearance->type = AppearanceType::AFK;
|
||||
spawn_appearance->parameter = afk_flag;
|
||||
entity_list.QueueClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
void Client::SetAFK(uint8 afk_flag)
|
||||
{
|
||||
if (!afk_flag) {
|
||||
ResetAFKTimer();
|
||||
}
|
||||
|
||||
bool changed_afk_state = (m_is_afk && !afk_flag) || (!m_is_afk && afk_flag);
|
||||
|
||||
if (!changed_afk_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set messaging based on the state
|
||||
std::string you_are = "You are no longer AFK.";
|
||||
if (!m_is_afk && afk_flag) {
|
||||
you_are = "You are now AFK.";
|
||||
}
|
||||
|
||||
// set the state
|
||||
m_is_afk = afk_flag;
|
||||
|
||||
// inform of state change
|
||||
Message(Chat::Yellow, you_are.c_str());
|
||||
|
||||
// send the spawn appearance packet to all clients
|
||||
static EQApplicationPacket p(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||
auto *s = (SpawnAppearance_Struct *) p.pBuffer;
|
||||
s->spawn_id = GetID();
|
||||
s->type = AppearanceType::AFK;
|
||||
s->parameter = afk_flag;
|
||||
entity_list.QueueClients(this, &p);
|
||||
}
|
||||
|
||||
void Client::SendToInstance(std::string instance_type, std::string zone_short_name, uint32 instance_version, float x, float y, float z, float heading, std::string instance_identifier, uint32 duration) {
|
||||
@@ -12713,7 +12739,7 @@ void Client::SendTopLevelInventory()
|
||||
}
|
||||
}
|
||||
|
||||
void Client::CheckSendBulkNpcPositions()
|
||||
void Client::CheckSendBulkNpcPositions(bool force)
|
||||
{
|
||||
float distance_moved = DistanceNoZ(m_last_position_before_bulk_update, GetPosition());
|
||||
float update_range = RuleI(Range, MobCloseScanDistance);
|
||||
@@ -12724,7 +12750,7 @@ void Client::CheckSendBulkNpcPositions()
|
||||
|
||||
int updated_count = 0;
|
||||
int skipped_count = 0;
|
||||
if (is_ready_to_update) {
|
||||
if (is_ready_to_update || force) {
|
||||
auto &mob_movement_manager = MobMovementManager::Get();
|
||||
|
||||
for (auto &e: entity_list.GetMobList()) {
|
||||
@@ -12770,6 +12796,16 @@ void Client::CheckSendBulkNpcPositions()
|
||||
updated_count++;
|
||||
}
|
||||
|
||||
if (force) {
|
||||
static EQApplicationPacket p(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
auto *s = (PlayerPositionUpdateServer_Struct *) p.pBuffer;
|
||||
for (auto &e: entity_list.GetCorpseList()) {
|
||||
Corpse *c = e.second;
|
||||
MakeSpawnUpdate(s);
|
||||
QueuePacket(&p, false);
|
||||
}
|
||||
}
|
||||
|
||||
LogPositionUpdate(
|
||||
"[{}] Sent [{}] bulk updated NPC positions, skipped [{}] distance_moved [{}] update_range [{}]",
|
||||
GetCleanName(),
|
||||
|
||||
+22
-3
@@ -501,9 +501,19 @@ public:
|
||||
void Kick(const std::string &reason);
|
||||
void WorldKick();
|
||||
inline uint8 GetAnon() const { return m_pp.anon; }
|
||||
inline uint8 GetAFK() const { return AFK; }
|
||||
inline uint8 GetAFK() const { return m_is_afk; }
|
||||
void SetAnon(uint8 anon_flag);
|
||||
inline Client* ResetAFKTimer() {
|
||||
if (!RuleB(Character, EnableAutoAFK)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
m_afk_reset = true;
|
||||
m_last_moved = std::chrono::steady_clock::now();
|
||||
return this;
|
||||
};
|
||||
void SetAFK(uint8 afk_flag);
|
||||
inline bool IsIdle() { return m_is_idle; }
|
||||
inline PlayerProfile_Struct& GetPP() { return m_pp; }
|
||||
inline ExtendedProfile_Struct& GetEPP() { return m_epp; }
|
||||
inline EQ::InventoryProfile& GetInv() { return m_inv; }
|
||||
@@ -2062,7 +2072,8 @@ private:
|
||||
uint8 LFGToLevel;
|
||||
bool LFGMatchFilter;
|
||||
char LFGComments[64];
|
||||
bool AFK;
|
||||
bool m_is_afk = false;
|
||||
bool m_is_manual_afk = false;
|
||||
bool auto_attack;
|
||||
bool auto_fire;
|
||||
bool runmode;
|
||||
@@ -2216,7 +2227,12 @@ private:
|
||||
glm::vec4 m_last_position_before_bulk_update;
|
||||
Timer m_client_bulk_npc_pos_update_timer;
|
||||
Timer m_position_update_timer;
|
||||
void CheckSendBulkNpcPositions();
|
||||
void CheckSendBulkNpcPositions(bool force = false);
|
||||
|
||||
// afk
|
||||
bool m_is_idle = false;
|
||||
bool m_afk_reset = false; // used to trigger next-tic afk reset
|
||||
std::chrono::steady_clock::time_point m_last_moved = std::chrono::steady_clock::now();
|
||||
|
||||
void BulkSendInventoryItems();
|
||||
|
||||
@@ -2410,6 +2426,9 @@ public:
|
||||
const std::string &GetMailKey() const;
|
||||
void ShowZoneShardMenu();
|
||||
void Handle_OP_ChangePetName(const EQApplicationPacket *app);
|
||||
bool IsFilteredAFKPacket(const EQApplicationPacket *p);
|
||||
void CheckAutoIdleAFK(PlayerPositionUpdateClient_Struct *p);
|
||||
void SyncWorldPositionsToClient(bool ignore_idle = false);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+189
-1
@@ -4383,6 +4383,14 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
||||
|
||||
m_TargetRing = glm::vec3(castspell->x_pos, castspell->y_pos, castspell->z_pos);
|
||||
|
||||
if (castspell->spell_id && IsValidSpell(castspell->spell_id)) {
|
||||
bool is_non_combat_zone = !zone->CanDoCombat() || zone->BuffTimersSuspended();
|
||||
bool is_excluded_reset = is_non_combat_zone && IsBardSong(castspell->spell_id);
|
||||
if (!is_excluded_reset) {
|
||||
ResetAFKTimer();
|
||||
}
|
||||
}
|
||||
|
||||
LogSpells("OP CastSpell: slot [{}] spell [{}] target [{}] inv [{}]", castspell->slot, castspell->spell_id, castspell->target_id, (unsigned long)castspell->inventoryslot);
|
||||
CastingSlot slot = static_cast<CastingSlot>(castspell->slot);
|
||||
|
||||
@@ -4566,6 +4574,12 @@ void Client::Handle_OP_ChannelMessage(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
// reject automatic AFK messages from resetting /afk
|
||||
std::string message = cm->message;
|
||||
if (!Strings::Contains(message, "Sorry, I am A.F.K.")) {
|
||||
ResetAFKTimer();
|
||||
}
|
||||
|
||||
if (IsAIControlled() && !GetGM()) {
|
||||
Message(Chat::Red, "You try to speak but can't move your mouth!");
|
||||
return;
|
||||
@@ -4992,6 +5006,10 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
|
||||
SetMoving(!(cy == m_Position.y && cx == m_Position.x));
|
||||
|
||||
if (RuleB(Character, EnableAutoAFK)) {
|
||||
CheckAutoIdleAFK(ppu);
|
||||
}
|
||||
|
||||
CheckClientToNpcAggroTimer();
|
||||
|
||||
if (m_mob_check_moving_timer.Check()) {
|
||||
@@ -10792,6 +10810,8 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
ResetAFKTimer();
|
||||
|
||||
BenchTimer bench;
|
||||
|
||||
MoveItem_Struct* mi = (MoveItem_Struct*) app->pBuffer;
|
||||
@@ -14732,7 +14752,9 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
}
|
||||
else if (sa->type == AppearanceType::AFK) {
|
||||
if (afk_toggle_timer.Check()) {
|
||||
AFK = (sa->parameter == 1);
|
||||
m_is_afk = (sa->parameter == 1);
|
||||
m_is_manual_afk = (sa->parameter == 1);
|
||||
ResetAFKTimer();
|
||||
entity_list.QueueClients(this, app, true);
|
||||
}
|
||||
}
|
||||
@@ -15551,6 +15573,14 @@ void Client::Handle_OP_TradeRequest(const EQApplicationPacket *app)
|
||||
|
||||
// Pass trade request on to recipient
|
||||
if (tradee && tradee->IsClient()) {
|
||||
// if we are idling we need to sync client positions otherwise clients will not be aware of each other
|
||||
if (m_is_idle) {
|
||||
SyncWorldPositionsToClient(true);
|
||||
}
|
||||
if (tradee->CastToClient()->IsIdle()) {
|
||||
tradee->CastToClient()->SyncWorldPositionsToClient(true);
|
||||
}
|
||||
|
||||
tradee->CastToClient()->QueuePacket(app);
|
||||
}
|
||||
else if (tradee && (tradee->IsNPC() || tradee->IsBot())) {
|
||||
@@ -15580,6 +15610,14 @@ void Client::Handle_OP_TradeRequestAck(const EQApplicationPacket *app)
|
||||
Mob* tradee = entity_list.GetMob(msg->to_mob_id);
|
||||
|
||||
if (tradee && tradee->IsClient()) {
|
||||
// if we are idling we need to sync client positions otherwise clients will not be aware of each other
|
||||
if (m_is_idle) {
|
||||
SyncWorldPositionsToClient(true);
|
||||
}
|
||||
if (tradee->CastToClient()->IsIdle()) {
|
||||
tradee->CastToClient()->SyncWorldPositionsToClient(true);
|
||||
}
|
||||
|
||||
trade->Start(msg->to_mob_id);
|
||||
tradee->CastToClient()->QueuePacket(app);
|
||||
}
|
||||
@@ -17166,3 +17204,153 @@ void Client::Handle_OP_EvolveItem(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::IsFilteredAFKPacket(const EQApplicationPacket *p)
|
||||
{
|
||||
if (p->GetOpcode() == OP_ClientUpdate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Client::CheckAutoIdleAFK(PlayerPositionUpdateClient_Struct *p)
|
||||
{
|
||||
if (!RuleB(Character, EnableAutoAFK)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_non_combat_zone = !zone->CanDoCombat() || zone->BuffTimersSuspended();
|
||||
|
||||
int seconds_before_afk =
|
||||
is_non_combat_zone ?
|
||||
RuleI(Character, SecondsBeforeAFKNonCombatZone) :
|
||||
RuleI(Character, SecondsBeforeAFKCombatZone);
|
||||
|
||||
int seconds_before_idle =
|
||||
is_non_combat_zone ?
|
||||
RuleI(Character, SecondsBeforeIdleNonCombatZone) :
|
||||
RuleI(Character, SecondsBeforeIdleCombatZone);
|
||||
|
||||
// seconds_before_idle can't be greater than seconds_before_afk
|
||||
if (seconds_before_idle > seconds_before_afk) {
|
||||
seconds_before_idle = seconds_before_afk;
|
||||
}
|
||||
|
||||
bool has_moved =
|
||||
m_Position.x != p->x_pos ||
|
||||
m_Position.y != p->y_pos ||
|
||||
m_Position.z != p->z_pos ||
|
||||
m_Position.w != EQ12toFloat(p->heading);
|
||||
|
||||
bool triggered_reset = m_afk_reset;
|
||||
bool was_idle = m_is_idle;
|
||||
bool is_idle_or_afk = m_is_idle || m_is_afk;
|
||||
|
||||
if (!has_moved && (!m_is_idle || !m_is_afk)) {
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
auto since_last_moved = now - m_last_moved;
|
||||
|
||||
if (!m_is_manual_afk && !m_is_afk && since_last_moved > std::chrono::seconds(seconds_before_afk)) {
|
||||
bool is_client_excluded_from_afk = (IsBuyer() || IsTrader() || GetGM());
|
||||
if (is_client_excluded_from_afk) {
|
||||
return;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"Client [{}] has been AFK for [{}] seconds",
|
||||
GetCleanName(),
|
||||
std::chrono::duration_cast<std::chrono::seconds>(since_last_moved).count()
|
||||
);
|
||||
SetAFK(true);
|
||||
return;
|
||||
}
|
||||
else if (!m_is_idle && since_last_moved > std::chrono::seconds(seconds_before_idle)) {
|
||||
bool is_client_excluded_from_idle = GetGM() && !is_non_combat_zone;
|
||||
if (is_client_excluded_from_idle) {
|
||||
return;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"Client [{}] has been idle for [{}] seconds",
|
||||
GetCleanName(),
|
||||
std::chrono::duration_cast<std::chrono::seconds>(since_last_moved).count()
|
||||
);
|
||||
m_is_idle = true;
|
||||
Message(Chat::Yellow, "You are now idle. Updates will be sent to you less frequently.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if we triggered a reset, but didn't move, we are still idling but not AFK
|
||||
if (triggered_reset && was_idle) {
|
||||
m_is_idle = true;
|
||||
}
|
||||
|
||||
// if we moved or triggered reset through other actions, we are no longer AFK.
|
||||
// we could trigger resetting AFK status through actions like message, cast, attack etc but still by idle until we move
|
||||
if (!m_is_manual_afk && (has_moved || triggered_reset) && m_is_afk) {
|
||||
LogInfo("AFK [{}] is no longer idle, syncing positions", GetCleanName());
|
||||
SetAFK(false);
|
||||
ResetAFKTimer();
|
||||
}
|
||||
|
||||
// we could be not AFK and idle at the same time
|
||||
if (has_moved && m_is_idle) {
|
||||
LogInfo("Idle [{}] is no longer idle, syncing positions", GetCleanName());
|
||||
m_is_idle = false;
|
||||
Message(Chat::Yellow, "You are no longer idle.");
|
||||
SyncWorldPositionsToClient();
|
||||
ResetAFKTimer();
|
||||
}
|
||||
|
||||
m_afk_reset = false;
|
||||
}
|
||||
|
||||
void Client::SyncWorldPositionsToClient(bool ignore_idle)
|
||||
{
|
||||
// if we are idle currently, we need to force updates (which bypasses idle status) and reset idle status
|
||||
bool reset_idle = false;
|
||||
if (ignore_idle && m_is_idle) {
|
||||
m_is_idle = false;
|
||||
reset_idle = true;
|
||||
}
|
||||
|
||||
LogInfo("Syncing positions for client [{}]", GetCleanName());
|
||||
CheckSendBulkNpcPositions(true);
|
||||
|
||||
static EQApplicationPacket cu(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
|
||||
for (auto &e: entity_list.GetClientList()) {
|
||||
auto c = e.second;
|
||||
|
||||
// skip if not in range
|
||||
if (Distance(c->GetPosition(), GetPosition()) > RuleI(Range, ClientPositionUpdates)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip self
|
||||
if (c == this) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *spu = (PlayerPositionUpdateServer_Struct *) cu.pBuffer;
|
||||
|
||||
memset(spu, 0x00, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
spu->spawn_id = c->GetID();
|
||||
spu->x_pos = FloatToEQ19(c->GetX());
|
||||
spu->y_pos = FloatToEQ19(c->GetY());
|
||||
spu->z_pos = FloatToEQ19(c->GetZ());
|
||||
spu->heading = FloatToEQ12(c->GetHeading());
|
||||
spu->delta_x = FloatToEQ13(0);
|
||||
spu->delta_y = FloatToEQ13(0);
|
||||
spu->delta_z = FloatToEQ13(0);
|
||||
spu->delta_heading = FloatToEQ10(0);
|
||||
spu->animation = 0;
|
||||
QueuePacket(&cu);
|
||||
}
|
||||
|
||||
if (ignore_idle && reset_idle) {
|
||||
m_is_idle = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,6 +536,10 @@ bool Client::Process() {
|
||||
DoEnduranceRegen();
|
||||
BuffProcess();
|
||||
|
||||
if (auto_attack) {
|
||||
ResetAFKTimer();
|
||||
}
|
||||
|
||||
if (tribute_timer.Check()) {
|
||||
ToggleTribute(true); //re-activate the tribute.
|
||||
}
|
||||
|
||||
+3
-1
@@ -852,11 +852,13 @@ void Doors::CreateDatabaseEntry()
|
||||
const auto& l = DoorsRepository::GetWhere(
|
||||
content_db,
|
||||
fmt::format(
|
||||
"zone = '{}' AND doorid = {}",
|
||||
"zone = '{}' AND (version = {} OR version = -1) AND doorid = {}",
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion(),
|
||||
GetDoorID()
|
||||
)
|
||||
);
|
||||
|
||||
if (!l.empty()) {
|
||||
auto e = l[0];
|
||||
|
||||
|
||||
+22
-19
@@ -137,25 +137,28 @@ void Embperl::DoInit()
|
||||
catch (std::string& e) {
|
||||
LogQuests("Warning [{}]: [{}]", Config->PluginPlFile, e);
|
||||
}
|
||||
try {
|
||||
//should probably read the directory in c, instead, so that
|
||||
//I can echo filenames as I do it, but c'mon... I'm lazy and this 1 line reads in all the plugins
|
||||
const std::string& perl_command = (
|
||||
"if(opendir(D,'" +
|
||||
path.GetPluginsPath() +
|
||||
"')) { "
|
||||
" my @d = readdir(D);"
|
||||
" closedir(D);"
|
||||
" foreach(@d){ "
|
||||
" main::eval_file('plugin','" +
|
||||
path.GetPluginsPath() +
|
||||
"/'.$_)if/\\.pl$/;"
|
||||
" }"
|
||||
"}");
|
||||
eval_pv(perl_command.c_str(), FALSE);
|
||||
}
|
||||
catch (std::string& e) {
|
||||
LogQuests("Warning [{}]", e);
|
||||
|
||||
for (auto & dir : path.GetPluginPaths()) {
|
||||
try {
|
||||
//should probably read the directory in c, instead, so that
|
||||
//I can echo filenames as I do it, but c'mon... I'm lazy and this 1 line reads in all the plugins
|
||||
const std::string& perl_command = (
|
||||
"if(opendir(D,'" +
|
||||
dir +
|
||||
"')) { "
|
||||
" my @d = readdir(D);"
|
||||
" closedir(D);"
|
||||
" foreach(@d){ "
|
||||
" main::eval_file('plugin','" +
|
||||
dir +
|
||||
"/'.$_)if/\\.pl$/;"
|
||||
" }"
|
||||
"}");
|
||||
eval_pv(perl_command.c_str(), FALSE);
|
||||
}
|
||||
catch (std::string& e) {
|
||||
LogQuests("Warning [{}]", e);
|
||||
}
|
||||
}
|
||||
#endif //EMBPERL_PLUGIN
|
||||
}
|
||||
|
||||
+45
-36
@@ -1067,13 +1067,16 @@ void LuaParser::ReloadQuests() {
|
||||
|
||||
lua_getglobal(L, "package");
|
||||
lua_getfield(L, -1, "path");
|
||||
std::string module_path = lua_tostring(L,-1);
|
||||
module_path += ";" + path.GetLuaModulesPath() + "/?.lua;" + path.GetLuaModulesPath() + "/?/init.lua";
|
||||
// luarock paths using lua_modules as tree
|
||||
// to path it adds foo/share/lua/5.1/?.lua and foo/share/lua/5.1/?/init.lua
|
||||
module_path += ";" + path.GetLuaModulesPath() + "/share/lua/" + lua_version + "/?.lua";
|
||||
module_path += ";" + path.GetLuaModulesPath() + "/share/lua/" + lua_version + "/?/init.lua";
|
||||
std::string module_path = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
for (const auto& dir : path.GetLuaModulePaths()) {
|
||||
module_path += fmt::format(";{}/?.lua", dir);
|
||||
module_path += fmt::format(";{}/?/init.lua", dir);
|
||||
module_path += fmt::format(";{}/share/lua/{}/?.lua", dir, lua_version);
|
||||
module_path += fmt::format(";{}/share/lua/{}/?/init.lua", dir, lua_version);
|
||||
}
|
||||
|
||||
lua_pushstring(L, module_path.c_str());
|
||||
lua_setfield(L, -2, "path");
|
||||
lua_pop(L, 1);
|
||||
@@ -1081,11 +1084,13 @@ void LuaParser::ReloadQuests() {
|
||||
lua_getglobal(L, "package");
|
||||
lua_getfield(L, -1, "cpath");
|
||||
module_path = lua_tostring(L, -1);
|
||||
module_path += ";" + path.GetLuaModulesPath() + "/?" + libext;
|
||||
// luarock paths using lua_modules as tree
|
||||
// luarocks adds foo/lib/lua/5.1/?.so for cpath
|
||||
module_path += ";" + path.GetLuaModulesPath() + "/lib/lua/" + lua_version + "/?" + libext;
|
||||
lua_pop(L, 1);
|
||||
|
||||
for (const auto& dir : path.GetLuaModulePaths()) {
|
||||
module_path += fmt::format(";{}/?{}", dir, libext);
|
||||
module_path += fmt::format(";{}/lib/lua/{}/?{}", dir, lua_version, libext);
|
||||
}
|
||||
|
||||
lua_pushstring(L, module_path.c_str());
|
||||
lua_setfield(L, -2, "cpath");
|
||||
lua_pop(L, 1);
|
||||
@@ -1093,40 +1098,31 @@ void LuaParser::ReloadQuests() {
|
||||
MapFunctions(L);
|
||||
|
||||
// load init
|
||||
std::string filename = fmt::format("{}/{}/script_init.lua", path.GetQuestsPath(), QUEST_GLOBAL_DIRECTORY);
|
||||
for (auto& dir : path.GetQuestPaths()) {
|
||||
std::string filename = fmt::format("{}/{}/script_init.lua", dir, QUEST_GLOBAL_DIRECTORY);
|
||||
|
||||
FILE *f = fopen(filename.c_str(), "r");
|
||||
if(f) {
|
||||
fclose(f);
|
||||
|
||||
if(luaL_dofile(L, filename.c_str())) {
|
||||
std::string error = lua_tostring(L, -1);
|
||||
AddError(error);
|
||||
}
|
||||
}
|
||||
|
||||
//zone init - always loads after global
|
||||
if(zone) {
|
||||
std::string zone_script = fmt::format(
|
||||
"{}/{}/script_init_v{}.lua",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
|
||||
f = fopen(zone_script.c_str(), "r");
|
||||
if(f) {
|
||||
FILE* f = fopen(filename.c_str(), "r");
|
||||
if (f) {
|
||||
fclose(f);
|
||||
|
||||
if(luaL_dofile(L, zone_script.c_str())) {
|
||||
if (luaL_dofile(L, filename.c_str())) {
|
||||
std::string error = lua_tostring(L, -1);
|
||||
AddError(error);
|
||||
}
|
||||
}
|
||||
else {
|
||||
zone_script = fmt::format("{}/{}/script_init.lua", path.GetQuestsPath(), zone->GetShortName());
|
||||
}
|
||||
|
||||
f = fopen(zone_script.c_str(), "r");
|
||||
//zone init - always loads after global
|
||||
if (zone) {
|
||||
for (auto& dir : path.GetQuestPaths()) {
|
||||
std::string zone_script = fmt::format(
|
||||
"{}/{}/script_init_v{}.lua",
|
||||
dir,
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
|
||||
FILE* f = fopen(zone_script.c_str(), "r");
|
||||
if (f) {
|
||||
fclose(f);
|
||||
|
||||
@@ -1135,6 +1131,19 @@ void LuaParser::ReloadQuests() {
|
||||
AddError(error);
|
||||
}
|
||||
}
|
||||
else {
|
||||
zone_script = fmt::format("{}/{}/script_init.lua", dir, zone->GetShortName());
|
||||
|
||||
f = fopen(zone_script.c_str(), "r");
|
||||
if (f) {
|
||||
fclose(f);
|
||||
|
||||
if (luaL_dofile(L, zone_script.c_str())) {
|
||||
std::string error = lua_tostring(L, -1);
|
||||
AddError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -2646,7 +2646,7 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
" AFK: {} LFG: {} Anon: {} PVP: {} GM: {} Fly Mode: {} ({}) GM Speed: {} Hide Me: {} Invulnerability: {} LD: {} Client Version: {} Tells Off: {}",
|
||||
CastToClient()->AFK ? "Yes" : "No",
|
||||
CastToClient()->m_is_afk ? "Yes" : "No",
|
||||
CastToClient()->LFG ? "Yes" : "No",
|
||||
CastToClient()->GetAnon() ? "Yes" : "No",
|
||||
CastToClient()->GetPVP() ? "Yes" : "No",
|
||||
|
||||
@@ -839,6 +839,10 @@ void MobMovementManager::SendCommandToClients(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c->IsIdle()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_impl->Stats.TotalSent++;
|
||||
|
||||
if (anim != 0) {
|
||||
@@ -879,6 +883,10 @@ void MobMovementManager::SendCommandToClients(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c->IsIdle()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float distance = c->CalculateDistance(mob->GetX(), mob->GetY(), mob->GetZ());
|
||||
|
||||
bool match = false;
|
||||
|
||||
+307
-285
@@ -939,59 +939,61 @@ QuestInterface* QuestParserCollection::GetQIByNPCQuest(uint32 npc_id, std::strin
|
||||
|
||||
Strings::FindReplace(npc_name, "`", "-");
|
||||
|
||||
const std::string& npc_id_and_name = fmt::format(
|
||||
"{}_{}",
|
||||
npc_name,
|
||||
npc_id
|
||||
);
|
||||
for (auto & dir : path.GetQuestPaths()) {
|
||||
const std::string& npc_id_and_name = fmt::format(
|
||||
"{}_{}",
|
||||
npc_name,
|
||||
npc_id
|
||||
);
|
||||
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}",
|
||||
path.GetQuestsPath(),
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}",
|
||||
dir,
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName()
|
||||
);
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}",
|
||||
dir,
|
||||
zone->GetShortName()
|
||||
);
|
||||
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}",
|
||||
dir,
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/{}", zone_versioned_path, npc_id), // Local versioned by NPC ID (./quests/zone/v0/10.ext)
|
||||
fmt::format("{}/{}", zone_versioned_path, npc_name), // Local versioned by NPC Name (./quests/zone/v0/name.ext)
|
||||
fmt::format("{}/{}", zone_versioned_path, npc_id_and_name), // Local versioned by NPC ID and NPC Name (./quests/zone/v0/10_name.ext)
|
||||
fmt::format("{}/{}", zone_path, npc_id), // Local by NPC ID
|
||||
fmt::format("{}/{}", zone_path, npc_name), // Local by NPC Name
|
||||
fmt::format("{}/{}", zone_path, npc_id_and_name), // Local by NPC ID and NPC Name
|
||||
fmt::format("{}/{}", global_path, npc_id), // Global by NPC ID
|
||||
fmt::format("{}/{}", global_path, npc_name), // Global by NPC ID
|
||||
fmt::format("{}/{}", global_path, npc_id_and_name), // Global by NPC ID and NPC Name
|
||||
fmt::format("{}/default", zone_versioned_path), // Zone Versioned Default (./quests/zone/v0/default.ext)
|
||||
fmt::format("{}/default", zone_path), // Zone Default
|
||||
fmt::format("{}/default", global_path), // Global Default
|
||||
};
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/{}", zone_versioned_path, npc_id), // Local versioned by NPC ID (./quests/zone/v0/10.ext)
|
||||
fmt::format("{}/{}", zone_versioned_path, npc_name), // Local versioned by NPC Name (./quests/zone/v0/name.ext)
|
||||
fmt::format("{}/{}", zone_versioned_path, npc_id_and_name), // Local versioned by NPC ID and NPC Name (./quests/zone/v0/10_name.ext)
|
||||
fmt::format("{}/{}", zone_path, npc_id), // Local by NPC ID
|
||||
fmt::format("{}/{}", zone_path, npc_name), // Local by NPC Name
|
||||
fmt::format("{}/{}", zone_path, npc_id_and_name), // Local by NPC ID and NPC Name
|
||||
fmt::format("{}/{}", global_path, npc_id), // Global by NPC ID
|
||||
fmt::format("{}/{}", global_path, npc_name), // Global by NPC ID
|
||||
fmt::format("{}/{}", global_path, npc_id_and_name), // Global by NPC ID and NPC Name
|
||||
fmt::format("{}/default", zone_versioned_path), // Zone Versioned Default (./quests/zone/v0/default.ext)
|
||||
fmt::format("{}/default", zone_path), // Zone Default
|
||||
fmt::format("{}/default", global_path), // Global Default
|
||||
};
|
||||
|
||||
std::string file_name;
|
||||
std::string file_name;
|
||||
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1005,44 +1007,46 @@ QuestInterface* QuestParserCollection::GetQIByPlayerQuest(std::string& filename)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}",
|
||||
path.GetQuestsPath(),
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
for (auto & dir : path.GetQuestPaths()) {
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}",
|
||||
dir,
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName()
|
||||
);
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}",
|
||||
dir,
|
||||
zone->GetShortName()
|
||||
);
|
||||
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}",
|
||||
dir,
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/player", zone_versioned_path), // Local by Instance Version ./quests/zone/v0/player.ext
|
||||
fmt::format("{}/player_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version
|
||||
fmt::format("{}/player", zone_path), // Local
|
||||
fmt::format("{}/player", global_path) // Global
|
||||
};
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/player", zone_versioned_path), // Local by Instance Version ./quests/zone/v0/player.ext
|
||||
fmt::format("{}/player_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version
|
||||
fmt::format("{}/player", zone_path), // Local
|
||||
fmt::format("{}/player", global_path) // Global
|
||||
};
|
||||
|
||||
std::string file_name;
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
std::string file_name;
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1058,17 +1062,19 @@ QuestInterface* QuestParserCollection::GetQIByGlobalNPCQuest(std::string& filena
|
||||
|
||||
std::string file_name;
|
||||
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}/{}/global_npc.{}",
|
||||
path.GetQuestsPath(),
|
||||
QUEST_GLOBAL_DIRECTORY,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
for (auto & dir : path.GetQuestPaths()) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}/{}/global_npc.{}",
|
||||
dir,
|
||||
QUEST_GLOBAL_DIRECTORY,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1082,17 +1088,19 @@ QuestInterface* QuestParserCollection::GetQIByGlobalPlayerQuest(std::string& fil
|
||||
}
|
||||
|
||||
std::string file_name;
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}/{}/global_player.{}",
|
||||
path.GetQuestsPath(),
|
||||
QUEST_GLOBAL_DIRECTORY,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
for (auto & dir : path.GetQuestPaths()) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}/{}/global_player.{}",
|
||||
dir,
|
||||
QUEST_GLOBAL_DIRECTORY,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1105,45 +1113,47 @@ QuestInterface* QuestParserCollection::GetQIBySpellQuest(uint32 spell_id, std::s
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}/spells",
|
||||
path.GetQuestsPath(),
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
for (auto & dir : path.GetQuestPaths()) {
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}/spells",
|
||||
dir,
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}/spells",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName()
|
||||
);
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}/spells",
|
||||
dir,
|
||||
zone->GetShortName()
|
||||
);
|
||||
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}/spells",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}/spells",
|
||||
dir,
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/{}", zone_versioned_path, spell_id), // Local versioned by Spell ID ./quests/zone/v0/spells/10.ext
|
||||
fmt::format("{}/{}", zone_path, spell_id), // Local
|
||||
fmt::format("{}/{}", global_path, spell_id), // Global
|
||||
fmt::format("{}/default", zone_path), // Local Default
|
||||
fmt::format("{}/default", global_path) // Global Default
|
||||
};
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/{}", zone_versioned_path, spell_id), // Local versioned by Spell ID ./quests/zone/v0/spells/10.ext
|
||||
fmt::format("{}/{}", zone_path, spell_id), // Local
|
||||
fmt::format("{}/{}", global_path, spell_id), // Global
|
||||
fmt::format("{}/default", zone_path), // Local Default
|
||||
fmt::format("{}/default", global_path) // Global Default
|
||||
};
|
||||
|
||||
std::string file_name;
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
std::string file_name;
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1157,45 +1167,47 @@ QuestInterface* QuestParserCollection::GetQIByItemQuest(std::string item_script,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}/items",
|
||||
path.GetQuestsPath(),
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
for (auto & dir : path.GetQuestPaths()) {
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}/items",
|
||||
dir,
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}/items",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName()
|
||||
);
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}/items",
|
||||
dir,
|
||||
zone->GetShortName()
|
||||
);
|
||||
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}/items",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}/items",
|
||||
dir,
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/{}", zone_versioned_path, item_script), // Local versioned by Item Script ./quests/zone/v0/items/10.ext
|
||||
fmt::format("{}/{}", zone_path, item_script), // Local
|
||||
fmt::format("{}/{}", global_path, item_script), // Global
|
||||
fmt::format("{}/default", zone_path), // Local Default
|
||||
fmt::format("{}/default", global_path) // Global Default
|
||||
};
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/{}", zone_versioned_path, item_script), // Local versioned by Item Script ./quests/zone/v0/items/10.ext
|
||||
fmt::format("{}/{}", zone_path, item_script), // Local
|
||||
fmt::format("{}/{}", global_path, item_script), // Global
|
||||
fmt::format("{}/default", zone_path), // Local Default
|
||||
fmt::format("{}/default", global_path) // Global Default
|
||||
};
|
||||
|
||||
std::string file_name;
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
std::string file_name;
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1209,43 +1221,45 @@ QuestInterface* QuestParserCollection::GetQIByEncounterQuest(std::string encount
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}/encounters",
|
||||
path.GetQuestsPath(),
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
for (auto & dir : path.GetQuestPaths()) {
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}/encounters",
|
||||
dir,
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}/encounters",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName()
|
||||
);
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}/encounters",
|
||||
dir,
|
||||
zone->GetShortName()
|
||||
);
|
||||
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}/encounters",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}/encounters",
|
||||
dir,
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/{}", zone_versioned_path, encounter_name), // Local versioned ./quests/zone/v0/encounters/name.ext
|
||||
fmt::format("{}/{}", zone_path, encounter_name), // Local
|
||||
fmt::format("{}/{}", global_path, encounter_name) // Global
|
||||
};
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/{}", zone_versioned_path, encounter_name), // Local versioned ./quests/zone/v0/encounters/name.ext
|
||||
fmt::format("{}/{}", zone_path, encounter_name), // Local
|
||||
fmt::format("{}/{}", global_path, encounter_name) // Global
|
||||
};
|
||||
|
||||
std::string file_name;
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
std::string file_name;
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1259,44 +1273,46 @@ QuestInterface* QuestParserCollection::GetQIByBotQuest(std::string& filename)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}",
|
||||
path.GetQuestsPath(),
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
for (auto & dir : path.GetQuestPaths()) {
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}",
|
||||
dir,
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName()
|
||||
);
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}",
|
||||
dir,
|
||||
zone->GetShortName()
|
||||
);
|
||||
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}",
|
||||
dir,
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/bot", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/bot.ext
|
||||
fmt::format("{}/bot_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version
|
||||
fmt::format("{}/bot", zone_path), // Local
|
||||
fmt::format("{}/bot", global_path) // Global
|
||||
};
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/bot", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/bot.ext
|
||||
fmt::format("{}/bot_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version
|
||||
fmt::format("{}/bot", zone_path), // Local
|
||||
fmt::format("{}/bot", global_path) // Global
|
||||
};
|
||||
|
||||
std::string file_name;
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
std::string file_name;
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1311,17 +1327,19 @@ QuestInterface* QuestParserCollection::GetQIByGlobalBotQuest(std::string& filena
|
||||
}
|
||||
|
||||
std::string file_name;
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}/{}/global_bot.{}",
|
||||
path.GetQuestsPath(),
|
||||
QUEST_GLOBAL_DIRECTORY,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
for (auto & dir : path.GetQuestPaths()) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}/{}/global_bot.{}",
|
||||
dir,
|
||||
QUEST_GLOBAL_DIRECTORY,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1334,44 +1352,46 @@ QuestInterface* QuestParserCollection::GetQIByMercQuest(std::string& filename)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}",
|
||||
path.GetQuestsPath(),
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
for (auto & dir : path.GetQuestPaths()) {
|
||||
const std::string& global_path = fmt::format(
|
||||
"{}/{}",
|
||||
dir,
|
||||
QUEST_GLOBAL_DIRECTORY
|
||||
);
|
||||
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName()
|
||||
);
|
||||
const std::string& zone_path = fmt::format(
|
||||
"{}/{}",
|
||||
dir,
|
||||
zone->GetShortName()
|
||||
);
|
||||
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}",
|
||||
path.GetQuestsPath(),
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
const std::string& zone_versioned_path = fmt::format(
|
||||
"{}/{}/v{}",
|
||||
dir,
|
||||
zone->GetShortName(),
|
||||
zone->GetInstanceVersion()
|
||||
);
|
||||
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/merc", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/merc.ext
|
||||
fmt::format("{}/merc_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version
|
||||
fmt::format("{}/merc", zone_path), // Local
|
||||
fmt::format("{}/merc", global_path) // Global
|
||||
};
|
||||
std::vector<std::string> file_names = {
|
||||
fmt::format("{}/merc", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/merc.ext
|
||||
fmt::format("{}/merc_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version
|
||||
fmt::format("{}/merc", zone_path), // Local
|
||||
fmt::format("{}/merc", global_path) // Global
|
||||
};
|
||||
|
||||
std::string file_name;
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
std::string file_name;
|
||||
for (auto & file : file_names) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}.{}",
|
||||
file,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1386,17 +1406,19 @@ QuestInterface* QuestParserCollection::GetQIByGlobalMercQuest(std::string& filen
|
||||
}
|
||||
|
||||
std::string file_name;
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}/{}/global_merc.{}",
|
||||
path.GetQuestsPath(),
|
||||
QUEST_GLOBAL_DIRECTORY,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
for (auto & dir : path.GetQuestPaths()) {
|
||||
for (auto* e: _load_precedence) {
|
||||
file_name = fmt::format(
|
||||
"{}/{}/global_merc.{}",
|
||||
dir,
|
||||
QUEST_GLOBAL_DIRECTORY,
|
||||
_extensions.find(e->GetIdentifier())->second
|
||||
);
|
||||
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
if (File::Exists(file_name)) {
|
||||
filename = file_name;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ void SharedTaskZoneMessaging::HandleWorldMessage(ServerPacket *pack)
|
||||
->AcceptNewTask(
|
||||
c,
|
||||
(int) p->requested_task_id,
|
||||
(int) p->requested_npc_type_id,
|
||||
(int) p->requested_npc_entity_id,
|
||||
p->accept_time
|
||||
);
|
||||
c->LoadClientTaskState();
|
||||
|
||||
@@ -1968,7 +1968,7 @@ void ClientTaskState::RemoveTaskByTaskID(Client *client, uint32 task_id)
|
||||
void ClientTaskState::AcceptNewTask(
|
||||
Client *client,
|
||||
int task_id,
|
||||
int npc_type_id,
|
||||
int npc_entity_id,
|
||||
time_t accept_time,
|
||||
bool enforce_level_requirement
|
||||
)
|
||||
@@ -2001,7 +2001,7 @@ void ClientTaskState::AcceptNewTask(
|
||||
// fill
|
||||
r->requested_character_id = client->CharacterID();
|
||||
r->requested_task_id = task_id;
|
||||
r->requested_npc_type_id = npc_type_id;
|
||||
r->requested_npc_entity_id = npc_entity_id;
|
||||
|
||||
// send
|
||||
worldserver.SendPacket(pack);
|
||||
@@ -2190,11 +2190,11 @@ void ClientTaskState::AcceptNewTask(
|
||||
|
||||
task_manager->SaveClientState(client, this);
|
||||
|
||||
NPC *npc = entity_list.GetID(npc_type_id)->CastToNPC();
|
||||
NPC *npc = entity_list.GetNPCByID(npc_entity_id);
|
||||
if (npc) {
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::TASK_ACCEPT)) {
|
||||
auto e = PlayerEvent::TaskAcceptEvent{
|
||||
.npc_id = static_cast<uint32>(npc_type_id),
|
||||
.npc_id = npc->GetNPCTypeID(),
|
||||
.npc_name = npc->GetCleanName(),
|
||||
.task_id = static_cast<uint32>(task_id),
|
||||
.task_name = task_manager->GetTaskName(static_cast<uint32>(task_id)),
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
int GetTaskActivityDoneCount(TaskType task_type, int index, int activity_id);
|
||||
int GetTaskActivityDoneCountFromTaskID(int task_id, int activity_id);
|
||||
int GetTaskStartTime(TaskType task_type, int index);
|
||||
void AcceptNewTask(Client *client, int task_id, int npc_type_id, time_t accept_time, bool enforce_level_requirement = false);
|
||||
void AcceptNewTask(Client *client, int task_id, int npc_entity_id, time_t accept_time, bool enforce_level_requirement = false);
|
||||
void FailTask(Client *client, int task_id);
|
||||
int TaskTimeLeft(int task_id);
|
||||
bool IsTaskCompleted(int task_id, Client *c = nullptr);
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "../common/random.h"
|
||||
#include "../common/strings.h"
|
||||
#include "zonedb.h"
|
||||
#include "../common/zone_store.h"
|
||||
#include "../common/repositories/grid_repository.h"
|
||||
#include "../common/repositories/grid_entries_repository.h"
|
||||
#include "../common/repositories/zone_points_repository.h"
|
||||
@@ -46,10 +45,7 @@
|
||||
#include "../common/repositories/lootdrop_repository.h"
|
||||
#include "../common/repositories/lootdrop_entries_repository.h"
|
||||
#include "../common/repositories/base_data_repository.h"
|
||||
#include "../common/repositories/skill_caps_repository.h"
|
||||
#include "../common/repositories/zone_state_spawns_repository.h"
|
||||
#include "../common/repositories/spawn2_disabled_repository.h"
|
||||
#include "../common/repositories/player_titlesets_repository.h"
|
||||
|
||||
struct EXPModifier
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef EQEMU_ZONE_CLI_H
|
||||
#define EQEMU_ZONE_CLI_H
|
||||
|
||||
#include <iostream>
|
||||
#include "../common/cli/argh.h"
|
||||
|
||||
class ZoneCLI {
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
#define EQEMU_ZONE_EVENT_SCHEDULER_H
|
||||
|
||||
#include "../common/server_event_scheduler.h"
|
||||
#include "zone.h"
|
||||
#include "../common/content/world_content_service.h"
|
||||
|
||||
class Zone;
|
||||
|
||||
class ZoneEventScheduler : public ServerEventScheduler {
|
||||
public:
|
||||
void Process(Zone *zone, WorldContentService *content_service);
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#ifndef EQEMU_ZONE_RELOAD_H
|
||||
#define EQEMU_ZONE_RELOAD_H
|
||||
|
||||
|
||||
class ZoneReload {
|
||||
public:
|
||||
static void HotReloadQuests();
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
|
||||
#include <string>
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <cereal/types/map.hpp>
|
||||
#include "npc.h"
|
||||
#include "corpse.h"
|
||||
#include "zone.h"
|
||||
#include "../common/repositories/zone_state_spawns_repository.h"
|
||||
#include "../common/repositories/spawn2_disabled_repository.h"
|
||||
|
||||
struct LootEntryStateData {
|
||||
uint32 item_id = 0;
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
#include "../common/repositories/npc_types_tint_repository.h"
|
||||
#include "../common/repositories/merchantlist_temp_repository.h"
|
||||
#include "../common/repositories/character_exp_modifiers_repository.h"
|
||||
#include "../common/repositories/character_data_repository.h"
|
||||
#include "../common/repositories/character_corpses_repository.h"
|
||||
#include "../common/repositories/character_corpse_items_repository.h"
|
||||
#include "../common/repositories/zone_repository.h"
|
||||
|
||||
@@ -28,7 +28,6 @@ spawn2 mediumblob, npcs mediumblob, npc_loot mediumblob, gmspawntype mediumblob,
|
||||
#define ZONEDUMP_H
|
||||
#include "../common/faction.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/inventory_profile.h"
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user