diff --git a/common/eq_stream_intf.h b/common/eq_stream_intf.h index a48735dba..17a025a18 100644 --- a/common/eq_stream_intf.h +++ b/common/eq_stream_intf.h @@ -19,6 +19,47 @@ typedef enum { class EQApplicationPacket; class OpcodeManager; +struct EQStreamManagerInterfaceOptions +{ + EQStreamManagerInterfaceOptions() { + opcode_size = 2; + } + + EQStreamManagerInterfaceOptions(int port, bool encoded, bool compressed) { + opcode_size = 2; + track_opcode_stats = false; + + //World seems to support both compression and xor zone supports one or the others. + //Enforce one or the other in the convienence construct + //Login I had trouble getting to recognize compression at all + //but that might be because it was still a bit buggy when i was testing that. + if (compressed) { + daybreak_options.encode_passes[0] = EQ::Net::EncodeCompression; + } + else if (encoded) { + daybreak_options.encode_passes[0] = EQ::Net::EncodeXOR; + } + + daybreak_options.port = port; + } + + int opcode_size; + bool track_opcode_stats; + EQ::Net::DaybreakConnectionManagerOptions daybreak_options; +}; + +class EQStreamManagerInterface +{ +public: + EQStreamManagerInterface(const EQStreamManagerInterfaceOptions &options) { m_options = options; } + virtual ~EQStreamManagerInterface() { }; + + const EQStreamManagerInterfaceOptions& GetOptions() const { return m_options; } + EQStreamManagerInterfaceOptions& MutateOptions() { return m_options; } +protected: + EQStreamManagerInterfaceOptions m_options; +}; + class EQStreamInterface { public: virtual ~EQStreamInterface() {} @@ -60,8 +101,9 @@ public: virtual EQStreamState GetState() = 0; virtual void SetOpcodeManager(OpcodeManager **opm) = 0; virtual const EQEmu::versions::ClientVersion ClientVersion() const { return EQEmu::versions::ClientVersion::Unknown; } - virtual std::shared_ptr GetRawConnection() const = 0; virtual Stats GetStats() const = 0; + virtual void ResetStats() = 0; + virtual EQStreamManagerInterface* GetManager() const = 0; }; #endif /*EQSTREAMINTF_H_*/ diff --git a/common/eq_stream_proxy.cpp b/common/eq_stream_proxy.cpp index e7021b8b1..402deaa34 100644 --- a/common/eq_stream_proxy.cpp +++ b/common/eq_stream_proxy.cpp @@ -90,15 +90,21 @@ void EQStreamProxy::RemoveData() { m_stream->RemoveData(); } -std::shared_ptr EQStreamProxy::GetRawConnection() const { - return m_stream->GetRawConnection(); -} - EQStreamInterface::Stats EQStreamProxy::GetStats() const { return m_stream->GetStats(); } +void EQStreamProxy::ResetStats() +{ + m_stream->ResetStats(); +} + +EQStreamManagerInterface *EQStreamProxy::GetManager() const +{ + return m_stream->GetManager(); +} + bool EQStreamProxy::CheckState(EQStreamState state) { if(m_stream) return(m_stream->CheckState(state)); diff --git a/common/eq_stream_proxy.h b/common/eq_stream_proxy.h index ebb82490a..92de5a463 100644 --- a/common/eq_stream_proxy.h +++ b/common/eq_stream_proxy.h @@ -31,8 +31,9 @@ public: virtual const EQEmu::versions::ClientVersion ClientVersion() const; virtual EQStreamState GetState(); virtual void SetOpcodeManager(OpcodeManager **opm); - virtual std::shared_ptr GetRawConnection() const; virtual Stats GetStats() const; + virtual void ResetStats(); + virtual EQStreamManagerInterface* GetManager() const; protected: std::shared_ptr const m_stream; //we own this stream object. diff --git a/common/net/daybreak_connection.h b/common/net/daybreak_connection.h index 027b3345e..56ed0a7d3 100644 --- a/common/net/daybreak_connection.h +++ b/common/net/daybreak_connection.h @@ -244,7 +244,7 @@ namespace EQ encode_passes[0] = DaybreakEncodeType::EncodeNone; encode_passes[1] = DaybreakEncodeType::EncodeNone; port = 0; - hold_size = 448; + hold_size = 512; hold_length_ms = 50; simulated_in_packet_loss = 0; simulated_out_packet_loss = 0; diff --git a/common/net/eqstream.cpp b/common/net/eqstream.cpp index 1f9635e82..c30e1ef85 100644 --- a/common/net/eqstream.cpp +++ b/common/net/eqstream.cpp @@ -2,10 +2,8 @@ #include "../eqemu_logsys.h" #include "../eqemu_logsys_fmt.h" -EQ::Net::EQStreamManager::EQStreamManager(EQStreamManagerOptions &options) : m_daybreak(options.daybreak_options) +EQ::Net::EQStreamManager::EQStreamManager(const EQStreamManagerInterfaceOptions &options) : EQStreamManagerInterface(options), m_daybreak(options.daybreak_options) { - m_options = options; - m_daybreak.OnNewConnection(std::bind(&EQStreamManager::DaybreakNewConnection, this, std::placeholders::_1)); m_daybreak.OnConnectionStateChange(std::bind(&EQStreamManager::DaybreakConnectionStateChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); m_daybreak.OnPacketRecv(std::bind(&EQStreamManager::DaybreakPacketRecv, this, std::placeholders::_1, std::placeholders::_2)); @@ -49,7 +47,7 @@ void EQ::Net::EQStreamManager::DaybreakPacketRecv(std::shared_ptr connection) +EQ::Net::EQStream::EQStream(EQStreamManagerInterface *owner, std::shared_ptr connection) { m_owner = owner; m_connection = connection; @@ -67,14 +65,14 @@ void EQ::Net::EQStream::QueuePacket(const EQApplicationPacket *p, bool ack_req) opcode = p->GetOpcodeBypass(); } else { - if (m_owner->m_options.track_opcode_stats) { + if (m_owner->GetOptions().track_opcode_stats) { m_packet_sent_count[p->GetOpcode()]++; //Wont bother with bypass tracking of these since those are rare for testing anyway } opcode = (*m_opcode_manager)->EmuToEQ(p->GetOpcode()); } EQ::Net::DynamicPacket out; - switch (m_owner->m_options.opcode_size) { + switch (m_owner->GetOptions().opcode_size) { case 1: out.PutUInt8(0, opcode); out.PutData(1, p->pBuffer, p->size); @@ -109,7 +107,7 @@ EQApplicationPacket *EQ::Net::EQStream::PopPacket() { auto &p = m_packet_queue.front(); uint16 opcode = 0; - switch (m_owner->m_options.opcode_size) { + switch (m_owner->GetOptions().opcode_size) { case 1: opcode = p->GetUInt8(0); break; @@ -119,11 +117,11 @@ EQApplicationPacket *EQ::Net::EQStream::PopPacket() { } EmuOpcode emu_op = (*m_opcode_manager)->EQToEmu(opcode); - if (m_owner->m_options.track_opcode_stats) { + if (m_owner->GetOptions().track_opcode_stats) { m_packet_recv_count[emu_op]++; } - EQApplicationPacket *ret = new EQApplicationPacket(emu_op, (unsigned char*)p->Data() + m_owner->m_options.opcode_size, p->Length() - m_owner->m_options.opcode_size); + EQApplicationPacket *ret = new EQApplicationPacket(emu_op, (unsigned char*)p->Data() + m_owner->GetOptions().opcode_size, p->Length() - m_owner->GetOptions().opcode_size); ret->SetProtocolOpcode(opcode); m_packet_queue.pop_front(); return ret; @@ -138,11 +136,11 @@ void EQ::Net::EQStream::Close() { std::string EQ::Net::EQStream::GetRemoteAddr() const { - return GetRawConnection()->RemoteEndpoint(); + return m_connection->RemoteEndpoint(); } uint32 EQ::Net::EQStream::GetRemoteIP() const { - return inet_addr(GetRawConnection()->RemoteEndpoint().c_str()); + return inet_addr(m_connection->RemoteEndpoint().c_str()); } bool EQ::Net::EQStream::CheckState(EQStreamState state) { @@ -153,8 +151,8 @@ EQStreamInterface::MatchState EQ::Net::EQStream::CheckSignature(const Signature if (!m_packet_queue.empty()) { auto p = m_packet_queue.front().get(); uint16 opcode = 0; - size_t length = p->Length() - m_owner->m_options.opcode_size; - switch (m_owner->m_options.opcode_size) { + size_t length = p->Length() - m_owner->GetOptions().opcode_size; + switch (m_owner->GetOptions().opcode_size) { case 1: opcode = p->GetUInt8(0); break; @@ -167,8 +165,8 @@ EQStreamInterface::MatchState EQ::Net::EQStream::CheckSignature(const Signature if (m_packet_queue.size() > 1) { p = m_packet_queue[1].get(); opcode = 0; - length = p->Length() - m_owner->m_options.opcode_size; - switch (m_owner->m_options.opcode_size) { + length = p->Length() - m_owner->GetOptions().opcode_size; + switch (m_owner->GetOptions().opcode_size) { case 1: opcode = p->GetUInt8(0); break; @@ -185,23 +183,23 @@ EQStreamInterface::MatchState EQ::Net::EQStream::CheckSignature(const Signature if (opcode == sig->first_eq_opcode) { if (length == sig->first_length) { LogF(Logs::General, Logs::Netcode, "[IDENT_TRACE] {0}:{1}: First opcode matched {2:#x} and length matched {3}", - GetRawConnection()->RemoteEndpoint(), m_connection->RemotePort(), sig->first_eq_opcode, length); + m_connection->RemoteEndpoint(), m_connection->RemotePort(), sig->first_eq_opcode, length); return MatchSuccessful; } else if (length == 0) { LogF(Logs::General, Logs::Netcode, "[IDENT_TRACE] {0}:{1}: First opcode matched {2:#x} and length is ignored.", - GetRawConnection()->RemoteEndpoint(), m_connection->RemotePort(), sig->first_eq_opcode); + m_connection->RemoteEndpoint(), m_connection->RemotePort(), sig->first_eq_opcode); return MatchSuccessful; } else { LogF(Logs::General, Logs::Netcode, "[IDENT_TRACE] {0}:{1}: First opcode matched {2:#x} but length {3} did not match expected {4}", - GetRawConnection()->RemoteEndpoint(), m_connection->RemotePort(), sig->first_eq_opcode, length, sig->first_length); + m_connection->RemoteEndpoint(), m_connection->RemotePort(), sig->first_eq_opcode, length, sig->first_length); return MatchFailed; } } else { LogF(Logs::General, Logs::Netcode, "[IDENT_TRACE] {0}:{1}: First opcode {1:#x} did not match expected {2:#x}", - GetRawConnection()->RemoteEndpoint(), m_connection->RemotePort(), opcode, sig->first_eq_opcode); + m_connection->RemoteEndpoint(), m_connection->RemotePort(), opcode, sig->first_eq_opcode); return MatchFailed; } } @@ -243,3 +241,13 @@ EQ::Net::EQStream::Stats EQ::Net::EQStream::GetStats() const return ret; } + +void EQ::Net::EQStream::ResetStats() +{ + m_connection->ResetStats(); +} + +EQStreamManagerInterface *EQ::Net::EQStream::GetManager() const +{ + return m_owner; +} diff --git a/common/net/eqstream.h b/common/net/eqstream.h index 1ff26c04f..1d253d4f6 100644 --- a/common/net/eqstream.h +++ b/common/net/eqstream.h @@ -12,46 +12,16 @@ namespace EQ { namespace Net { - struct EQStreamManagerOptions - { - EQStreamManagerOptions() { - opcode_size = 2; - } - - EQStreamManagerOptions(int port, bool encoded, bool compressed) { - opcode_size = 2; - track_opcode_stats = false; - - //World seems to support both compression and xor zone supports one or the others. - //Enforce one or the other in the convienence construct - //Login I had trouble getting to recognize compression at all - //but that might be because it was still a bit buggy when i was testing that. - if (compressed) { - daybreak_options.encode_passes[0] = EncodeCompression; - } - else if (encoded) { - daybreak_options.encode_passes[0] = EncodeXOR; - } - - daybreak_options.port = port; - } - - int opcode_size; - bool track_opcode_stats; - DaybreakConnectionManagerOptions daybreak_options; - }; - class EQStream; - class EQStreamManager + class EQStreamManager : public EQStreamManagerInterface { public: - EQStreamManager(EQStreamManagerOptions &options); + EQStreamManager(const EQStreamManagerInterfaceOptions &options); ~EQStreamManager(); void OnNewConnection(std::function)> func) { m_on_new_connection = func; } void OnConnectionStateChange(std::function, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; } private: - EQStreamManagerOptions m_options; DaybreakConnectionManager m_daybreak; std::function)> m_on_new_connection; std::function, DbProtocolStatus, DbProtocolStatus)> m_on_connection_state_change; @@ -66,7 +36,7 @@ namespace EQ class EQStream : public EQStreamInterface { public: - EQStream(EQStreamManager *parent, std::shared_ptr connection); + EQStream(EQStreamManagerInterface *parent, std::shared_ptr connection); ~EQStream(); virtual void QueuePacket(const EQApplicationPacket *p, bool ack_req = true); @@ -87,13 +57,11 @@ namespace EQ m_opcode_manager = opm; } - virtual std::shared_ptr GetRawConnection() const { - return m_connection; - } - virtual Stats GetStats() const; + virtual void ResetStats(); + virtual EQStreamManagerInterface* GetManager() const; private: - EQStreamManager *m_owner; + EQStreamManagerInterface *m_owner; std::shared_ptr m_connection; OpcodeManager **m_opcode_manager; std::deque> m_packet_queue; diff --git a/common/ruletypes.h b/common/ruletypes.h index 911c65814..aad194bb4 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -286,35 +286,11 @@ RULE_INT(Map, FindBestZHeightAdjust, 1) // Adds this to the current Z before se RULE_CATEGORY_END() RULE_CATEGORY(Pathing) -// Some of these rules may benefit by being made into columns in the zone table, -// for instance, in dungeons, the min LOS distances could be substantially lowered. -RULE_BOOL(Pathing, Aggro, true) // Enable pathing for aggroed mobs. -RULE_BOOL(Pathing, AggroReturnToGrid, true) // Enable pathing for aggroed roaming mobs returning to their previous waypoint. RULE_BOOL(Pathing, Guard, true) // Enable pathing for mobs moving to their guard point. RULE_BOOL(Pathing, Find, true) // Enable pathing for FindPerson requests from the client. RULE_BOOL(Pathing, Fear, true) // Enable pathing for fear -RULE_REAL(Pathing, ZDiffThresholdNew, 80) // If a mob las LOS to it's target, it will run to it if the Z difference is < this. -RULE_INT(Pathing, LOSCheckFrequency, 1000) // A mob will check for LOS to it's target this often (milliseconds). -RULE_INT(Pathing, RouteUpdateFrequencyShort, 1000) // How often a new route will be calculated if the target has moved. -RULE_INT(Pathing, RouteUpdateFrequencyLong, 5000) // How often a new route will be calculated if the target has moved. -// When a path has a path node route and it's target changes position, if it has RouteUpdateFrequencyNodeCount or less nodes to go on it's -// current path, it will recalculate it's path based on the RouteUpdateFrequencyShort timer, otherwise it will use the -// RouteUpdateFrequencyLong timer. -RULE_INT(Pathing, RouteUpdateFrequencyNodeCount, 5) -RULE_REAL(Pathing, MinDistanceForLOSCheckShort, 40000) // (NoRoot). While following a path, only check for LOS to target within this distance. -RULE_REAL(Pathing, MinDistanceForLOSCheckLong, 1000000) // (NoRoot). Min distance when initially attempting to acquire the target. -RULE_INT(Pathing, MinNodesLeftForLOSCheck, 4) // Only check for LOS when we are down to this many path nodes left to run. -// This next rule was put in for situations where the mob and it's target may be on different sides of a 'hazard', e.g. a pit -// If the mob has LOS to it's target, even though there is a hazard in it's way, it may break off from the node path and run at -// the target, only to later detect the hazard and re-acquire a node path. Depending upon the placement of the path nodes, this -// can lead to the mob looping. The rule is intended to allow the mob to at least get closer to it's target each time before -// checking LOS and trying to head straight for it. -RULE_INT(Pathing, MinNodesTraversedForLOSCheck, 3) // Only check for LOS after we have traversed this many path nodes. -RULE_INT(Pathing, CullNodesFromStart, 1) // Checks LOS from Start point to second node for this many nodes and removes first node if there is LOS -RULE_INT(Pathing, CullNodesFromEnd, 1) // Checks LOS from End point to second to last node for this many nodes and removes last node if there is LOS -RULE_REAL(Pathing, CandidateNodeRangeXY, 400) // When searching for path start/end nodes, only nodes within this range will be considered. -RULE_REAL(Pathing, CandidateNodeRangeZ, 10) // When searching for path start/end nodes, only nodes within this range will be considered. -RULE_REAL(Pathing, NavmeshStepSize, 30.0f) +RULE_REAL(Pathing, NavmeshStepSize, 100.0f) +RULE_REAL(Pathing, ShortMovementUpdateRange, 130.0f) RULE_CATEGORY_END() RULE_CATEGORY(Watermap) @@ -710,6 +686,7 @@ RULE_REAL(Network, ResendDelayFactor, 1.5) RULE_INT(Network, ResendDelayMinMS, 100) RULE_INT(Network, ResendDelayMaxMS, 5000) RULE_REAL(Network, ClientDataRate, 0.0) // KB / sec, 0.0 disabled +RULE_BOOL(Network, TrackOpcodeStats, false) RULE_CATEGORY_END() RULE_CATEGORY(QueryServ) diff --git a/loginserver/client_manager.cpp b/loginserver/client_manager.cpp index 570a4be1f..4117430a7 100644 --- a/loginserver/client_manager.cpp +++ b/loginserver/client_manager.cpp @@ -27,7 +27,7 @@ extern bool run_server; ClientManager::ClientManager() { int titanium_port = atoi(server.config->GetVariable("Titanium", "port").c_str()); - EQ::Net::EQStreamManagerOptions titanium_opts(titanium_port, false, false); + EQStreamManagerInterfaceOptions titanium_opts(titanium_port, false, false); titanium_stream = new EQ::Net::EQStreamManager(titanium_opts); titanium_ops = new RegularOpcodeManager; if (!titanium_ops->LoadOpcodes(server.config->GetVariable("Titanium", "opcodes").c_str())) @@ -38,14 +38,14 @@ ClientManager::ClientManager() } titanium_stream->OnNewConnection([this](std::shared_ptr stream) { - LogF(Logs::General, Logs::Login_Server, "New Titanium client connection from {0}:{1}", stream->GetRawConnection()->RemoteEndpoint(), stream->GetRemotePort()); + LogF(Logs::General, Logs::Login_Server, "New Titanium client connection from {0}:{1}", stream->GetRemoteIP(), stream->GetRemotePort()); stream->SetOpcodeManager(&titanium_ops); Client *c = new Client(stream, cv_titanium); clients.push_back(c); }); int sod_port = atoi(server.config->GetVariable("SoD", "port").c_str()); - EQ::Net::EQStreamManagerOptions sod_opts(sod_port, false, false); + EQStreamManagerInterfaceOptions sod_opts(sod_port, false, false); sod_stream = new EQ::Net::EQStreamManager(sod_opts); sod_ops = new RegularOpcodeManager; if (!sod_ops->LoadOpcodes(server.config->GetVariable("SoD", "opcodes").c_str())) @@ -56,7 +56,7 @@ ClientManager::ClientManager() } sod_stream->OnNewConnection([this](std::shared_ptr stream) { - LogF(Logs::General, Logs::Login_Server, "New SoD client connection from {0}:{1}", stream->GetRawConnection()->RemoteEndpoint(), stream->GetRemotePort()); + LogF(Logs::General, Logs::Login_Server, "New SoD client connection from {0}:{1}", stream->GetRemoteIP(), stream->GetRemotePort()); stream->SetOpcodeManager(&sod_ops); Client *c = new Client(stream, cv_sod); clients.push_back(c); diff --git a/ucs/clientlist.cpp b/ucs/clientlist.cpp index b7adb84eb..03579f550 100644 --- a/ucs/clientlist.cpp +++ b/ucs/clientlist.cpp @@ -467,7 +467,7 @@ static void ProcessCommandIgnore(Client *c, std::string Ignoree) { } Clientlist::Clientlist(int ChatPort) { - EQ::Net::EQStreamManagerOptions chat_opts(ChatPort, false, false); + EQStreamManagerInterfaceOptions chat_opts(ChatPort, false, false); chat_opts.opcode_size = 1; chat_opts.daybreak_options.stale_connection_ms = 300000; chat_opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS); @@ -483,7 +483,7 @@ Clientlist::Clientlist(int ChatPort) { exit(1); chatsf->OnNewConnection([this](std::shared_ptr stream) { - LogF(Logs::General, Logs::Login_Server, "New Client UDP connection from {0}:{1}", stream->GetRawConnection()->RemoteEndpoint(), stream->GetRemotePort()); + LogF(Logs::General, Logs::Login_Server, "New Client UDP connection from {0}:{1}", stream->GetRemoteIP(), stream->GetRemotePort()); stream->SetOpcodeManager(&ChatOpMgr); auto c = new Client(stream); diff --git a/world/net.cpp b/world/net.cpp index e8c203179..ce5900d30 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -498,7 +498,7 @@ int main(int argc, char** argv) { web_interface.RemoveConnection(connection); }); - EQ::Net::EQStreamManagerOptions opts(9000, false, false); + EQStreamManagerInterfaceOptions opts(9000, false, false); opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS); opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor); opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS); @@ -522,7 +522,7 @@ int main(int argc, char** argv) { eqsm.OnNewConnection([&stream_identifier](std::shared_ptr stream) { stream_identifier.AddStream(stream); - LogF(Logs::Detail, Logs::World_Server, "New connection from IP {0}:{1}", stream->GetRawConnection()->RemoteEndpoint(), ntohs(stream->GetRemotePort())); + LogF(Logs::Detail, Logs::World_Server, "New connection from IP {0}:{1}", stream->GetRemoteIP(), ntohs(stream->GetRemotePort())); }); while (RunLoops) { diff --git a/zone/command.cpp b/zone/command.cpp index 202f62316..318c60168 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -9486,14 +9486,21 @@ void command_netstats(Client *c, const Seperator *sep) if (c->GetTarget() && c->GetTarget()->IsClient()) { client = c->GetTarget()->CastToClient(); } - + + if (strcasecmp(sep->arg[1], "reset") == 0) { + auto connection = c->Connection(); + c->Message(0, "Resetting client stats (packet loss will not read correctly after reset)."); + connection->ResetStats(); + return; + } + auto connection = c->Connection(); - auto &opts = connection->GetRawConnection()->GetManager()->GetOptions(); + auto &opts = connection->GetManager()->GetOptions(); auto eqs_stats = connection->GetStats(); auto &stats = eqs_stats.DaybreakStats; auto now = EQ::Net::Clock::now(); auto sec_since_stats_reset = std::chrono::duration_cast>(now - stats.created).count(); - + c->Message(0, "Netstats:"); c->Message(0, "--------------------------------------------------------------------"); c->Message(0, "Sent Bytes: %u (%.2f/sec)", stats.sent_bytes, stats.sent_bytes / sec_since_stats_reset); @@ -9516,29 +9523,31 @@ void command_netstats(Client *c, const Seperator *sep) c->Message(0, "Resent Fragments: %u (%.2f/sec)", stats.resent_fragments, stats.resent_fragments / sec_since_stats_reset); c->Message(0, "Resent Non-Fragments: %u (%.2f/sec)", stats.resent_full, stats.resent_full / sec_since_stats_reset); c->Message(0, "Dropped Datarate Packets: %u (%.2f/sec)", stats.dropped_datarate_packets, stats.dropped_datarate_packets / sec_since_stats_reset); - - if (opts.outgoing_data_rate > 0.0) { - c->Message(0, "Outgoing Link Saturation %.2f%% (%.2fkb/sec)", 100.0 * (1.0 - ((opts.outgoing_data_rate - stats.datarate_remaining) / opts.outgoing_data_rate)), opts.outgoing_data_rate); + + if (opts.daybreak_options.outgoing_data_rate > 0.0) { + c->Message(0, "Outgoing Link Saturation %.2f%% (%.2fkb/sec)", 100.0 * (1.0 - ((opts.daybreak_options.outgoing_data_rate - stats.datarate_remaining) / opts.daybreak_options.outgoing_data_rate)), opts.daybreak_options.outgoing_data_rate); } + + if (opts.track_opcode_stats) { + c->Message(0, "--------------------------------------------------------------------"); + c->Message(0, "Sent Packet Types"); + for (auto i = 0; i < _maxEmuOpcode; ++i) { + auto cnt = eqs_stats.SentCount[i]; + if (cnt > 0) { + c->Message(0, "%s: %u (%.2f / sec)", OpcodeNames[i], cnt, cnt / sec_since_stats_reset); + } + } - c->Message(0, "--------------------------------------------------------------------"); - c->Message(0, "Sent Packet Types"); - for (auto i = 0; i < _maxEmuOpcode; ++i) { - auto cnt = eqs_stats.SentCount[i]; - if (cnt > 0) { - c->Message(0, "%s: %u", OpcodeNames[i], cnt); + c->Message(0, "--------------------------------------------------------------------"); + c->Message(0, "Recv Packet Types"); + for (auto i = 0; i < _maxEmuOpcode; ++i) { + auto cnt = eqs_stats.RecvCount[i]; + if (cnt > 0) { + c->Message(0, "%s: %u (%.2f / sec)", OpcodeNames[i], cnt, cnt / sec_since_stats_reset); + } } } - - c->Message(0, "--------------------------------------------------------------------"); - c->Message(0, "Recv Packet Types"); - for (auto i = 0; i < _maxEmuOpcode; ++i) { - auto cnt = eqs_stats.RecvCount[i]; - if (cnt > 0) { - c->Message(0, "%s: %u", OpcodeNames[i], cnt); - } - } - + c->Message(0, "--------------------------------------------------------------------"); } } @@ -12208,33 +12217,32 @@ void command_network(Client *c, const Seperator *sep) if (!strcasecmp(sep->arg[1], "getopt")) { auto eqsi = c->Connection(); - auto dbc = eqsi->GetRawConnection(); - auto manager = dbc->GetManager(); + auto manager = eqsi->GetManager(); auto &opts = manager->GetOptions(); - + if (!strcasecmp(sep->arg[2], "all")) { - c->Message(0, "max_packet_size: %llu", opts.max_packet_size); - c->Message(0, "max_connection_count: %llu", opts.max_connection_count); - c->Message(0, "keepalive_delay_ms: %llu", opts.keepalive_delay_ms); - c->Message(0, "resend_delay_factor: %.2f", opts.resend_delay_factor); - c->Message(0, "resend_delay_ms: %llu", opts.resend_delay_ms); - c->Message(0, "resend_delay_min: %llu", opts.resend_delay_min); - c->Message(0, "resend_delay_max: %llu", opts.resend_delay_max); - c->Message(0, "connect_delay_ms: %llu", opts.connect_delay_ms); - c->Message(0, "connect_stale_ms: %llu", opts.connect_stale_ms); - c->Message(0, "stale_connection_ms: %llu", opts.stale_connection_ms); - c->Message(0, "crc_length: %llu", opts.crc_length); - c->Message(0, "hold_size: %llu", opts.hold_size); - c->Message(0, "hold_length_ms: %llu", opts.hold_length_ms); - c->Message(0, "simulated_in_packet_loss: %llu", opts.simulated_in_packet_loss); - c->Message(0, "simulated_out_packet_loss: %llu", opts.simulated_out_packet_loss); - c->Message(0, "tic_rate_hertz: %.2f", opts.tic_rate_hertz); - c->Message(0, "resend_timeout: %llu", opts.resend_timeout); - c->Message(0, "connection_close_time: %llu", opts.connection_close_time); - c->Message(0, "encode_passes[0]: %llu", opts.encode_passes[0]); - c->Message(0, "encode_passes[1]: %llu", opts.encode_passes[1]); - c->Message(0, "port: %llu", opts.port); + c->Message(0, "max_packet_size: %llu", opts.daybreak_options.max_packet_size); + c->Message(0, "max_connection_count: %llu", opts.daybreak_options.max_connection_count); + c->Message(0, "keepalive_delay_ms: %llu", opts.daybreak_options.keepalive_delay_ms); + c->Message(0, "resend_delay_factor: %.2f", opts.daybreak_options.resend_delay_factor); + c->Message(0, "resend_delay_ms: %llu", opts.daybreak_options.resend_delay_ms); + c->Message(0, "resend_delay_min: %llu", opts.daybreak_options.resend_delay_min); + c->Message(0, "resend_delay_max: %llu", opts.daybreak_options.resend_delay_max); + c->Message(0, "connect_delay_ms: %llu", opts.daybreak_options.connect_delay_ms); + c->Message(0, "connect_stale_ms: %llu", opts.daybreak_options.connect_stale_ms); + c->Message(0, "stale_connection_ms: %llu", opts.daybreak_options.stale_connection_ms); + c->Message(0, "crc_length: %llu", opts.daybreak_options.crc_length); + c->Message(0, "hold_size: %llu", opts.daybreak_options.hold_size); + c->Message(0, "hold_length_ms: %llu", opts.daybreak_options.hold_length_ms); + c->Message(0, "simulated_in_packet_loss: %llu", opts.daybreak_options.simulated_in_packet_loss); + c->Message(0, "simulated_out_packet_loss: %llu", opts.daybreak_options.simulated_out_packet_loss); + c->Message(0, "tic_rate_hertz: %.2f", opts.daybreak_options.tic_rate_hertz); + c->Message(0, "resend_timeout: %llu", opts.daybreak_options.resend_timeout); + c->Message(0, "connection_close_time: %llu", opts.daybreak_options.connection_close_time); + c->Message(0, "encode_passes[0]: %llu", opts.daybreak_options.encode_passes[0]); + c->Message(0, "encode_passes[1]: %llu", opts.daybreak_options.encode_passes[1]); + c->Message(0, "port: %llu", opts.daybreak_options.port); } else { c->Message(0, "Unknown get option: %s", sep->arg[2]); @@ -12267,76 +12275,75 @@ void command_network(Client *c, const Seperator *sep) else if (!strcasecmp(sep->arg[1], "setopt")) { auto eqsi = c->Connection(); - auto dbc = eqsi->GetRawConnection(); - auto manager = dbc->GetManager(); - auto &opts = manager->GetOptions(); - + auto manager = eqsi->GetManager(); + auto &opts = manager->MutateOptions(); + if (!strcasecmp(sep->arg[3], "")) { c->Message(0, "Missing value for set"); return; } - + std::string value = sep->arg[3]; if (!strcasecmp(sep->arg[2], "max_connection_count")) { - opts.max_connection_count = std::stoull(value); + opts.daybreak_options.max_connection_count = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "keepalive_delay_ms")) { - opts.keepalive_delay_ms = std::stoull(value); + opts.daybreak_options.keepalive_delay_ms = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "resend_delay_factor")) { - opts.resend_delay_factor = std::stod(value); + opts.daybreak_options.resend_delay_factor = std::stod(value); } else if (!strcasecmp(sep->arg[2], "resend_delay_ms")) { - opts.resend_delay_ms = std::stoull(value); + opts.daybreak_options.resend_delay_ms = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "resend_delay_min")) { - opts.resend_delay_min = std::stoull(value); + opts.daybreak_options.resend_delay_min = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "resend_delay_max")) { - opts.resend_delay_max = std::stoull(value); + opts.daybreak_options.resend_delay_max = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "connect_delay_ms")) { - opts.connect_delay_ms = std::stoull(value); + opts.daybreak_options.connect_delay_ms = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "connect_stale_ms")) { - opts.connect_stale_ms = std::stoull(value); + opts.daybreak_options.connect_stale_ms = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "stale_connection_ms")) { - opts.stale_connection_ms = std::stoull(value); + opts.daybreak_options.stale_connection_ms = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "hold_size")) { - opts.hold_size = std::stoull(value); + opts.daybreak_options.hold_size = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "hold_length_ms")) { - opts.hold_length_ms = std::stoull(value); + opts.daybreak_options.hold_length_ms = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "simulated_in_packet_loss")) { - opts.simulated_in_packet_loss = std::stoull(value); + opts.daybreak_options.simulated_in_packet_loss = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "simulated_out_packet_loss")) { - opts.simulated_out_packet_loss = std::stoull(value); + opts.daybreak_options.simulated_out_packet_loss = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "resend_timeout")) { - opts.resend_timeout = std::stoull(value); + opts.daybreak_options.resend_timeout = std::stoull(value); } else if (!strcasecmp(sep->arg[2], "connection_close_time")) { - opts.connection_close_time = std::stoull(value); + opts.daybreak_options.connection_close_time = std::stoull(value); } else { c->Message(0, "Unknown set option: %s", sep->arg[2]); diff --git a/zone/mob_movement_manager.cpp b/zone/mob_movement_manager.cpp index 23cccc8f4..cd47270d8 100644 --- a/zone/mob_movement_manager.cpp +++ b/zone/mob_movement_manager.cpp @@ -671,24 +671,27 @@ void MobMovementManager::SendCommandToClients(Mob *m, float dx, float dy, float } } else { + float short_range = RuleR(Pathing, ShortMovementUpdateRange); + float long_range = zone->GetMaxMovementUpdateRange(); + for (auto &c : _impl->Clients) { float dist = c->CalculateDistance(m->GetX(), m->GetY(), m->GetZ()); bool match = false; if (range & ClientRangeClose) { - if (dist < 250.0f) { + if (dist < short_range) { match = true; } } if (!match && range & ClientRangeMedium) { - if (dist >= 250.0f && dist < 1500.0f) { + if (dist >= short_range && dist < long_range) { match = true; } } if (!match && range & ClientRangeLong) { - if (dist >= 1500.0f) { + if (dist >= long_range) { match = true; } } diff --git a/zone/net.cpp b/zone/net.cpp index a057b411a..0b1183136 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -500,18 +500,19 @@ int main(int argc, char** argv) { if (!eqsf_open && Config->ZonePort != 0) { Log(Logs::General, Logs::Zone_Server, "Starting EQ Network server on port %d", Config->ZonePort); - EQ::Net::EQStreamManagerOptions opts(Config->ZonePort, false, true); + EQStreamManagerInterfaceOptions opts(Config->ZonePort, false, true); opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS); opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor); opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS); opts.daybreak_options.resend_delay_max = RuleI(Network, ResendDelayMaxMS); opts.daybreak_options.outgoing_data_rate = RuleR(Network, ClientDataRate); + opts.track_opcode_stats = RuleB(Network, TrackOpcodeStats); eqsm.reset(new EQ::Net::EQStreamManager(opts)); eqsf_open = true; eqsm->OnNewConnection([&stream_identifier](std::shared_ptr stream) { stream_identifier.AddStream(stream); - LogF(Logs::Detail, Logs::World_Server, "New connection from IP {0}:{1}", stream->GetRawConnection()->RemoteEndpoint(), ntohs(stream->GetRemotePort())); + LogF(Logs::Detail, Logs::World_Server, "New connection from IP {0}:{1}", stream->GetRemoteIP(), ntohs(stream->GetRemotePort())); }); } diff --git a/zone/oriented_bounding_box.cpp b/zone/oriented_bounding_box.cpp index 6b9834c7d..ca248ba1d 100644 --- a/zone/oriented_bounding_box.cpp +++ b/zone/oriented_bounding_box.cpp @@ -41,7 +41,7 @@ glm::mat4 CreateScaleMatrix(float sx, float sy, float sz) { return scale; } -OrientedBoundingBox::OrientedBoundingBox(glm::vec3 pos, glm::vec3 rot, glm::vec3 scale, glm::vec3 extents) { +OrientedBoundingBox::OrientedBoundingBox(const glm::vec3 &pos, const glm::vec3 &rot, const glm::vec3 &scale, const glm::vec3 &extents) { min_x = -extents.x; max_x = extents.x; @@ -81,7 +81,7 @@ OrientedBoundingBox::OrientedBoundingBox(glm::vec3 pos, glm::vec3 rot, glm::vec3 inverted_transformation = glm::inverse(transformation); } -bool OrientedBoundingBox::ContainsPoint(glm::vec3 p) const { +bool OrientedBoundingBox::ContainsPoint(const glm::vec3 &p) const { glm::vec4 pt(p.x, p.y, p.z, 1); glm::vec4 box_space_p = inverted_transformation * pt; diff --git a/zone/oriented_bounding_box.h b/zone/oriented_bounding_box.h index 33482a1f4..b662af84b 100644 --- a/zone/oriented_bounding_box.h +++ b/zone/oriented_bounding_box.h @@ -8,10 +8,10 @@ class OrientedBoundingBox { public: OrientedBoundingBox() { } - OrientedBoundingBox(glm::vec3 pos, glm::vec3 rot, glm::vec3 scale, glm::vec3 extents); + OrientedBoundingBox(const glm::vec3 &pos, const glm::vec3 &rot, const glm::vec3 &scale, const glm::vec3 &extents); ~OrientedBoundingBox() { } - bool ContainsPoint(glm::vec3 p) const; + bool ContainsPoint(const glm::vec3 &p) const; glm::mat4& GetTransformation() { return transformation; } glm::mat4& GetInvertedTransformation() { return inverted_transformation; } diff --git a/zone/pathfinder_nav_mesh.cpp b/zone/pathfinder_nav_mesh.cpp index d4879f6f7..61ca484f5 100644 --- a/zone/pathfinder_nav_mesh.cpp +++ b/zone/pathfinder_nav_mesh.cpp @@ -12,7 +12,7 @@ extern Zone *zone; -const int MaxNavmeshNodes = 4096; +const int MaxNavmeshNodes = 1024; struct PathfinderNavmesh::Implementation { diff --git a/zone/water_map_v2.cpp b/zone/water_map_v2.cpp index 03ae76fa4..aa023219c 100644 --- a/zone/water_map_v2.cpp +++ b/zone/water_map_v2.cpp @@ -30,7 +30,8 @@ bool WaterMapV2::InLava(const glm::vec3& location) const { } bool WaterMapV2::InLiquid(const glm::vec3& location) const { - return InWater(location) || InLava(location) || InVWater(location); + auto rt = ReturnRegionType(location); + return rt == RegionTypeWater || rt == RegionTypeVWater || rt == RegionTypeLava; } bool WaterMapV2::InPvP(const glm::vec3& location) const { diff --git a/zone/zone.cpp b/zone/zone.cpp index 4157683dc..88b0253a2 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1070,14 +1070,14 @@ bool Zone::LoadZoneCFG(const char* filename, uint16 instance_id) map_name = nullptr; if(!database.GetZoneCFG(database.GetZoneID(filename), instance_id, &newzone_data, can_bind, - can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, allow_mercs, zone_type, default_ruleset, &map_name)) + can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, allow_mercs, max_movement_update_range, zone_type, default_ruleset, &map_name)) { // If loading a non-zero instance failed, try loading the default if (instance_id != 0) { safe_delete_array(map_name); if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind, can_combat, can_levitate, - can_castoutdoor, is_city, is_hotzone, allow_mercs, zone_type, default_ruleset, &map_name)) + can_castoutdoor, is_city, is_hotzone, allow_mercs, max_movement_update_range, zone_type, default_ruleset, &map_name)) { Log(Logs::General, Logs::Error, "Error loading the Zone Config."); return false; diff --git a/zone/zone.h b/zone/zone.h index 1ea0c0828..e86fdc339 100755 --- a/zone/zone.h +++ b/zone/zone.h @@ -313,6 +313,8 @@ public: } } + double GetMaxMovementUpdateRange() const { return max_movement_update_range; } + /** * Modding hooks */ @@ -332,6 +334,7 @@ private: bool m_ucss_available; bool staticzone; bool zone_has_current_time; + double max_movement_update_range; char *long_name; char *map_name; char *short_name; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 82bc5ae29..61e957e02 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -80,7 +80,21 @@ bool ZoneDatabase::SaveZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct return true; } -bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct *zone_data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, bool &allow_mercs, uint8 &zone_type, int &ruleset, char **map_filename) { +bool ZoneDatabase::GetZoneCFG( + uint32 zoneid, + uint16 instance_id, + NewZone_Struct *zone_data, + bool &can_bind, + bool &can_combat, + bool &can_levitate, + bool &can_castoutdoor, + bool &is_city, + bool &is_hotzone, + bool &allow_mercs, + double &max_movement_update_range, + uint8 &zone_type, + int &ruleset, + char **map_filename) { *map_filename = new char[100]; zone_data->zone_id = zoneid; @@ -147,7 +161,8 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct "fast_regen_hp, " // 57 "fast_regen_mana, " // 58 "fast_regen_endurance, " // 59 - "npc_max_aggro_dist " // 60 + "npc_max_aggro_dist, " // 60 + "max_movement_update_range " // 61 "FROM zone WHERE zoneidnumber = %i AND version = %i", zoneid, instance_id); auto results = QueryDatabase(query); @@ -206,7 +221,7 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct can_levitate = atoi(row[33]) == 0 ? false : true; can_castoutdoor = atoi(row[34]) == 0 ? false : true; is_hotzone = atoi(row[35]) == 0 ? false : true; - + max_movement_update_range = atof(row[61]); ruleset = atoi(row[36]); zone_data->SuspendBuffs = atoi(row[37]); diff --git a/zone/zonedb.h b/zone/zonedb.h index 843bdace5..bbf7be7ea 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -382,7 +382,21 @@ public: bool LoadAlternateAdvancement(Client *c); /* Zone related */ - bool GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct *data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, bool &allow_mercs, uint8 &zone_type, int &ruleset, char **map_filename); + bool GetZoneCFG( + uint32 zoneid, + uint16 instance_id, + NewZone_Struct *data, + bool &can_bind, + bool &can_combat, + bool &can_levitate, + bool &can_castoutdoor, + bool &is_city, + bool &is_hotzone, + bool &allow_mercs, + double &max_movement_update_range, + uint8 &zone_type, + int &ruleset, + char **map_filename); bool SaveZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct* zd); bool LoadStaticZonePoints(LinkedList* zone_point_list,const char* zonename, uint32 version); bool UpdateZoneSafeCoords(const char* zonename, const glm::vec3& location);