/** * UniversalSlashingSimulator - ProcessEvent Dispatcher Implementation */ #include "ProcessEventDispatcher.h" #include "../../Core/Memory/Memory.h" #include "../../Core/Logging/Log.h" #include "../EngineCore.h" #include namespace USS { //========================================================================= // FProcessEventContext Methods //========================================================================= const FParsedParameter* FProcessEventContext::GetParam(const char* Name) const { if (!Name) return nullptr; for (const auto& Param : Params) { if (Param.Name == Name) { return &Param; } } return nullptr; } //========================================================================= // FEventFilter Methods //========================================================================= bool FEventFilter::Matches(const FProcessEventContext& Context) const { if (!ObjectClassFilter.empty()) { if (Context.ObjectClassName.find(ObjectClassFilter) == std::string::npos) return false; } if (!FunctionNameFilter.empty()) { if (Context.FunctionName != FunctionNameFilter) return false; } if (!FunctionNamePrefix.empty()) { if (Context.FunctionName.find(FunctionNamePrefix) != 0) return false; } if (bServerOnly && !Context.bIsRPC) return false; if (bClientOnly && Context.bIsRPC) return false; return true; } //========================================================================= // FProcessEventDispatcher Implementation //========================================================================= static FProcessEventDispatcher g_ProcessEventDispatcher; FProcessEventDispatcher& GetProcessEventDispatcher() { return g_ProcessEventDispatcher; } FProcessEventDispatcher::FProcessEventDispatcher() : m_bInitialized(false) , m_NextHandlerId(1) , m_bHandlersDirty(false) , m_TotalEventsProcessed(0) , m_TotalEventsHandled(0) , m_TotalEventsBlocked(0) { } FProcessEventDispatcher::~FProcessEventDispatcher() { Shutdown(); } EResult FProcessEventDispatcher::Initialize() { if (m_bInitialized) return EResult::AlreadyInitialized; USS_LOG("Initializing ProcessEvent Dispatcher..."); if (!GetPropertyIterator().IsInitialized()) { EResult Result = GetPropertyIterator().Initialize(); if (Result != EResult::Success) { USS_ERROR("Failed to initialize property iterator"); return Result; } } m_Handlers.clear(); m_FunctionCache.clear(); m_TotalEventsProcessed = 0; m_TotalEventsHandled = 0; m_TotalEventsBlocked = 0; USS_LOG("ProcessEvent Dispatcher initialized"); m_bInitialized = true; return EResult::Success; } void FProcessEventDispatcher::Shutdown() { if (!m_bInitialized) return; USS_LOG("Shutting down ProcessEvent Dispatcher..."); USS_LOG(" Events processed: %llu", m_TotalEventsProcessed); USS_LOG(" Events handled: %llu", m_TotalEventsHandled); USS_LOG(" Events blocked: %llu", m_TotalEventsBlocked); m_Handlers.clear(); m_FunctionCache.clear(); m_bInitialized = false; } bool FProcessEventDispatcher::OnProcessEvent(void* Object, void* Function, void* Parameters) { if (!m_bInitialized) return true; ++m_TotalEventsProcessed; if (m_bHandlersDirty) { SortHandlers(); } if (m_Handlers.empty()) return true; FProcessEventContext Context; Context.Object = Object; Context.Function = Function; Context.Parameters = Parameters; Context.ObjectName = GetEngineCore().GetObjectName(Object); Context.ObjectClassName = GetEngineCore().GetObjectClassName(Object); Context.FunctionName = GetEngineCore().GetObjectName(Function); Context.bIsRPC = (Context.FunctionName.find("Server") == 0) || (Context.FunctionName.find("Client") == 0); Context.bIsMulticast = (Context.FunctionName.find("Multicast") != std::string::npos); bool bNeedsParsing = false; for (const auto& Handler : m_Handlers) { if (Handler.bEnabled && Handler.Filter.Matches(Context)) { bNeedsParsing = true; break; } } if (bNeedsParsing) { ParseParameters(Function, Parameters, Context); } bool bAllowExecution = true; for (const auto& Handler : m_Handlers) { if (!Handler.bEnabled) continue; if (!Handler.Filter.Matches(Context)) continue; ++m_TotalEventsHandled; bool bContinue = Handler.Handler(Context); if (!bContinue) { bAllowExecution = false; ++m_TotalEventsBlocked; break; } } return bAllowExecution; } int32 FProcessEventDispatcher::RegisterHandler( const std::string& Name, const FEventFilter& Filter, FProcessEventHandler Handler, int32 Priority) { if (!Handler) return 0; FRegisteredHandler Registration; Registration.HandlerId = m_NextHandlerId++; Registration.Name = Name; Registration.Filter = Filter; Registration.Handler = std::move(Handler); Registration.Priority = Priority; Registration.bEnabled = true; m_Handlers.push_back(std::move(Registration)); m_bHandlersDirty = true; USS_LOG("Registered ProcessEvent handler: %s (ID: %d, Priority: %d)", Name.c_str(), Registration.HandlerId, Priority); return Registration.HandlerId; } void FProcessEventDispatcher::UnregisterHandler(int32 HandlerId) { auto It = std::remove_if(m_Handlers.begin(), m_Handlers.end(), [HandlerId](const FRegisteredHandler& H) { return H.HandlerId == HandlerId; }); if (It != m_Handlers.end()) { USS_LOG("Unregistered ProcessEvent handler ID: %d", HandlerId); m_Handlers.erase(It, m_Handlers.end()); } } void FProcessEventDispatcher::SetHandlerEnabled(int32 HandlerId, bool bEnabled) { for (auto& Handler : m_Handlers) { if (Handler.HandlerId == HandlerId) { Handler.bEnabled = bEnabled; USS_LOG("Handler %d %s", HandlerId, bEnabled ? "enabled" : "disabled"); break; } } } bool FProcessEventDispatcher::ParseParameters(void* Function, void* Parameters, FProcessEventContext& OutContext) { if (!Function || !Parameters) return false; std::vector ParamInfos; if (!GetFunctionInfo(Function, ParamInfos)) return false; OutContext.Params.clear(); OutContext.Params.reserve(ParamInfos.size()); for (const auto& PropInfo : ParamInfos) { if (!(PropInfo.PropertyFlags & EPropertyFlags::CPF_Parm)) continue; FParsedParameter Param; if (ReadParameterValue(Parameters, PropInfo, Param)) { if (PropInfo.PropertyFlags & EPropertyFlags::CPF_ReturnParm) { OutContext.bHasReturnValue = true; } OutContext.Params.push_back(std::move(Param)); } } return true; } bool FProcessEventDispatcher::ReadParameterValue(void* Parameters, const FPropertyInfo& PropInfo, FParsedParameter& OutParam) { if (!Parameters) return false; OutParam.Name = PropInfo.Name; OutParam.Type = PropInfo.Type; OutParam.Offset = PropInfo.Offset; OutParam.Size = PropInfo.ElementSize; OutParam.Flags = PropInfo.PropertyFlags; uintptr ParamAddr = reinterpret_cast(Parameters) + PropInfo.Offset; switch (PropInfo.Type) { case EPropertyType::BoolProperty: Memory::Read(ParamAddr, OutParam.BoolValue); break; case EPropertyType::ByteProperty: case EPropertyType::Int8Property: { int8 Value = 0; Memory::Read(ParamAddr, Value); OutParam.IntValue = Value; break; } case EPropertyType::Int16Property: case EPropertyType::UInt16Property: { int16 Value = 0; Memory::Read(ParamAddr, Value); OutParam.IntValue = Value; break; } case EPropertyType::IntProperty: case EPropertyType::UInt32Property: Memory::Read(ParamAddr, OutParam.IntValue); break; case EPropertyType::Int64Property: case EPropertyType::UInt64Property: Memory::Read(ParamAddr, OutParam.Int64Value); break; case EPropertyType::FloatProperty: Memory::Read(ParamAddr, OutParam.FloatValue); break; case EPropertyType::DoubleProperty: Memory::Read(ParamAddr, OutParam.DoubleValue); break; case EPropertyType::ObjectProperty: case EPropertyType::ClassProperty: case EPropertyType::InterfaceProperty: case EPropertyType::WeakObjectProperty: case EPropertyType::LazyObjectProperty: case EPropertyType::SoftObjectProperty: Memory::Read(ParamAddr, OutParam.PointerValue); break; case EPropertyType::NameProperty: { // FName is typically int32 ComparisonIndex + int32 Number int32 NameIndex = 0; Memory::Read(ParamAddr, NameIndex); OutParam.StringValue = GetEngineCore().GetNameFromIndex(NameIndex); break; } case EPropertyType::StrProperty: { // FString is TArray // Try to read as FString uintptr DataPtr = 0; int32 Len = 0; Memory::Read(ParamAddr, DataPtr); Memory::Read(ParamAddr + sizeof(uintptr), Len); if (DataPtr && Len > 0 && Len < 4096) { // Read as wide string std::wstring WideStr(Len, L'\0'); for (int32 i = 0; i < Len; ++i) { wchar_t Ch = 0; Memory::Read(DataPtr + (i * sizeof(wchar_t)), Ch); WideStr[i] = Ch; } // Convert to narrow OutParam.StringValue.reserve(Len); for (wchar_t Ch : WideStr) { if (Ch == 0) break; OutParam.StringValue += static_cast(Ch); } } break; } case EPropertyType::StructProperty: // Store pointer to struct data OutParam.PointerValue = reinterpret_cast(ParamAddr); break; case EPropertyType::ArrayProperty: // Store pointer to array OutParam.PointerValue = reinterpret_cast(ParamAddr); break; default: // Store raw pointer for unknown types OutParam.PointerValue = reinterpret_cast(ParamAddr); break; } return true; } bool FProcessEventDispatcher::WriteParameterValue(void* Parameters, const FPropertyInfo& PropInfo, const FParsedParameter& Param) { if (!Parameters) return false; uintptr ParamAddr = reinterpret_cast(Parameters) + PropInfo.Offset; switch (PropInfo.Type) { case EPropertyType::BoolProperty: return Memory::Write(ParamAddr, Param.BoolValue); case EPropertyType::IntProperty: return Memory::Write(ParamAddr, Param.IntValue); case EPropertyType::Int64Property: return Memory::Write(ParamAddr, Param.Int64Value); case EPropertyType::FloatProperty: return Memory::Write(ParamAddr, Param.FloatValue); case EPropertyType::DoubleProperty: return Memory::Write(ParamAddr, Param.DoubleValue); case EPropertyType::ObjectProperty: return Memory::Write(ParamAddr, Param.PointerValue); default: return false; } } bool FProcessEventDispatcher::GetFunctionInfo(void* Function, std::vector& OutParams) { if (!Function) return false; // Check cache auto It = m_FunctionCache.find(Function); if (It != m_FunctionCache.end()) { OutParams = It->second; return true; } // Parse function parameters using property iterator std::vector Params; GetPropertyIterator().ForEachProperty(Function, [&Params](const FPropertyInfo& Info) -> bool { if (Info.PropertyFlags & EPropertyFlags::CPF_Parm) { Params.push_back(Info); } return true; // Continue }, false); // Don't include super (functions don't inherit params) // Sort by offset to ensure correct parameter order std::sort(Params.begin(), Params.end(), [](const FPropertyInfo& A, const FPropertyInfo& B) { return A.Offset < B.Offset; }); // Cache result m_FunctionCache[Function] = Params; OutParams = std::move(Params); return true; } void FProcessEventDispatcher::SortHandlers() { std::sort(m_Handlers.begin(), m_Handlers.end(), [](const FRegisteredHandler& A, const FRegisteredHandler& B) { return A.Priority > B.Priority; }); m_bHandlersDirty = false; } }