// // Created by dannu on 4/21/2026. // #pragma once #include #include "common/emu_versions.h" #include "zone/client.h" #include "zone/mob.h" namespace ZoneClient { namespace Message { class IMessage; } // store all static functions for the different patches here class ClientPatch { public: using ClientList = std::unordered_map; static const std::shared_ptr& GetMessageComponent(EQ::versions::ClientVersion version); template static void QueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args) { static_assert(std::is_member_function_pointer_v); EQApplicationPacket* app = std::invoke(fun, obj, std::forward(args)...); if (app != nullptr) { c->QueuePacket(app); delete app; } } // packet generator queue functions static auto QueueClients(Mob* sender, bool ignore_sender = false, bool ackreq = true) { return [=](Fun fun, std::function component_getter, Args&&... args) { static_assert(std::is_member_function_pointer_v && "Function is required to be a member function"); std::unordered_map build_packets; std::unordered_map client_list = entity_list.GetClientList(); for (auto [_, ent] : client_list) { if (!ignore_sender || ent != sender) { auto [packet, _] = build_packets.try_emplace( ent->ClientVersion(), std::invoke(fun, component_getter(ent), std::forward(args)...)); if (packet->second != nullptr) ent->QueuePacket(packet->second, ackreq, Client::CLIENT_CONNECTED); } } for (auto [_, packet] : build_packets) if (packet != nullptr) delete packet; }; } static auto QueueCloseClients( Mob* sender, bool ignore_sender = false, float distance = 200, Mob* skipped_mob = nullptr, bool is_ack_required = true, eqFilterType filter = FilterNone) { if (distance <= 0) distance = static_cast(zone->GetClientUpdateRange()); return [=](Fun fun, std::function component_getter, Args&&... args) { static_assert(std::is_member_function_pointer_v && "Function is required to be a member function"); if (sender == nullptr) { QueueClients(sender, ignore_sender, is_ack_required)(fun, component_getter, std::forward(args)...); } else { float distance_squared = distance * distance; std::unordered_map build_packets; for (auto& [_, mob] : sender->GetCloseMobList(distance)) { if (mob && mob->IsClient()) { Client* client = mob->CastToClient(); if ((!ignore_sender || client != sender) && client != skipped_mob && DistanceSquared(client->GetPosition(), sender->GetPosition()) < distance_squared && client->Connected() && client->ShouldGetPacket(sender, filter)) { auto [packet, _] = build_packets.try_emplace( client->ClientVersion(), std::invoke(fun, component_getter(client), std::forward(args)...)); if (packet->second != nullptr) client->QueuePacket(packet->second, is_ack_required, Client::CLIENT_CONNECTED); } } } for (auto [_, packet] : build_packets) if (packet != nullptr) delete packet;; } }; } }; }