Skip to content

Commit

Permalink
Add entity extract event
Browse files Browse the repository at this point in the history
  • Loading branch information
psiberx committed Nov 25, 2024
1 parent 411702f commit 4d765c8
Show file tree
Hide file tree
Showing 15 changed files with 606 additions and 37 deletions.
3 changes: 3 additions & 0 deletions scripts/Callback/Events/EntityBuilderEvent.reds
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public native class EntityBuilderEvent extends CallbackSystemEvent {
public native func GetEntityBuilder() -> ref<EntityBuilderWrapper>
}
1 change: 1 addition & 0 deletions scripts/Callback/Targets/EntityTarget.reds
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ public native class EntityTarget extends CallbackSystemTarget {
public static native func RecordID(recordID: TweakDBID) -> ref<EntityTarget>
public static native func Template(templatePath: ResRef) -> ref<EntityTarget>
public static native func Appearance(appearanceName: CName) -> ref<EntityTarget>
public static native func Definition(appearancePath: ResRef, opt definitionName: CName) -> ref<EntityTarget>
}
29 changes: 29 additions & 0 deletions scripts/Entity/EntityBuilderWrapper.reds
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
public native class EntityBuilderWrapper {
public native func HasEntity() -> Bool
public native func HasAppearance() -> Bool
public native func HasCustomAppearances() -> Bool
public native func GetRecordID() -> TweakDBID
public native func GetTemplatePath() -> ResRef
public native func GetAppearanceName() -> CName
public native func GetEntityID() -> EntityID
public native func GetEntityType() -> CName
public native func GetEntityParams() -> ref<entEntityParametersStorage>
public native func GetTemplate() -> ref<EntityBuilderTemplateWrapper>
public native func GetAppearance() -> ref<EntityBuilderAppearanceWrapper>
public native func GetCustomAppearances() -> array<ref<EntityBuilderAppearanceWrapper>>
}

public native class EntityBuilderTemplateWrapper {
public native func GetResource() -> ref<entEntityTemplate>
public native func GetAppearanceName() -> CName
public native func GetEntity() -> ref<Entity>
public native func GetComponents() -> array<ref<IComponent>>
public native func AddComponent(component: ref<IComponent>)
}

public native class EntityBuilderAppearanceWrapper {
public native func GetResource() -> ref<appearanceAppearanceResource>
public native func GetDefinition() -> ref<appearanceAppearanceDefinition>
public native func GetComponents() -> array<ref<IComponent>>
public native func AddComponent(component: ref<IComponent>)
}
2 changes: 2 additions & 0 deletions src/App/Callback/CallbackSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "App/Callback/Controllers/EntityAssembleHook.hpp"
#include "App/Callback/Controllers/EntityAttachHook.hpp"
#include "App/Callback/Controllers/EntityDetachHook.hpp"
#include "App/Callback/Controllers/EntityExtractHook.hpp"
#include "App/Callback/Controllers/EntityRequestComponentsHook.hpp"
#include "App/Callback/Controllers/EntityUninitializeHook.hpp"
#include "App/Callback/Controllers/PlayerSpawnedHook.hpp"
Expand All @@ -17,6 +18,7 @@ App::CallbackSystem::CallbackSystem()
: m_restored(false)
, m_pregame(false)
{
RegisterController<EntityExtractHook>();
RegisterController<EntityAssembleHook>();
RegisterController<EntityAttachHook>();
RegisterController<EntityDetachHook>();
Expand Down
44 changes: 44 additions & 0 deletions src/App/Callback/Controllers/EntityExtractHook.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include "App/Callback/CallbackSystem.hpp"
#include "App/Callback/CallbackSystemController.hpp"
#include "App/Callback/Events/EntityBuilderEvent.hpp"
#include "Core/Hooking/HookingAgent.hpp"
#include "Red/EntityBuilder.hpp"

namespace App
{
class EntityExtractHook
: public CallbackSystemController
, public Core::HookingAgent
{
public:
constexpr static auto EventName = Red::CName("Entity/Extract");

Core::Map<Red::CName, Red::CName> GetEvents() override
{
return {{EventName, Red::GetTypeName<EntityBuilderEvent>()}};
}

protected:
bool OnActivateHook() override
{
return IsHooked<Raw::EntityBuilder::ExtractComponentsJob>()
|| HookBefore<Raw::EntityBuilder::ExtractComponentsJob>(&OnExtractComponentsJob);
}

bool OnDeactivateHook() override
{
return !IsHooked<Raw::EntityBuilder::ExtractComponentsJob>()
|| Unhook<Raw::EntityBuilder::ExtractComponentsJob>();
}

inline static void OnExtractComponentsJob(Red::EntityBuilderJobParams* aParams, void*)
{
if (!aParams->entityBuilderWeak.Expired())
{
CallbackSystem::Get()->DispatchNativeEvent<EntityBuilderEvent>(EventName, aParams->entityBuilderWeak);
}
}
};
}
28 changes: 28 additions & 0 deletions src/App/Callback/Events/EntityBuilderEvent.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include "App/Callback/CallbackSystemEvent.hpp"
#include "App/Entity/EntityBuilderWrapper.hpp"

namespace App
{
struct EntityBuilderEvent : CallbackSystemEvent
{
EntityBuilderEvent() = default;

EntityBuilderEvent(Red::CName aName, const Red::WeakPtr<Red::EntityBuilder>& aEntityBuilder)
: CallbackSystemEvent(aName)
, entityBuilder(Red::MakeHandle<EntityBuilderWrapper>(aEntityBuilder))
{
}

Red::Handle<EntityBuilderWrapper> entityBuilder;

RTTI_IMPL_TYPEINFO(App::EntityBuilderEvent);
RTTI_IMPL_ALLOCATOR();
};
}

RTTI_DEFINE_CLASS(App::EntityBuilderEvent, {
RTTI_PARENT(App::CallbackSystemEvent);
RTTI_GETTER(entityBuilder);
});
127 changes: 111 additions & 16 deletions src/App/Callback/Targets/EntityTarget.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#pragma once

#include "App/Callback/CallbackSystemTarget.hpp"
#include "App/Callback/Events/EntityBuilderEvent.hpp"
#include "App/Callback/Events/EntityLifecycleEvent.hpp"
#include "App/Callback/Events/VehicleLightControlEvent.hpp"

namespace App
{
Expand All @@ -11,30 +13,109 @@ struct EntityTarget : CallbackSystemTarget

bool Matches(const Red::Handle<CallbackSystemEvent>& aEvent) override
{
auto* entity = aEvent.GetPtr<EntityLifecycleEvent>()->entity.instance;
switch (aEvent->GetType()->GetName())
{
case Red::GetTypeName<EntityBuilderEvent>():
{
auto* builder = aEvent.GetPtr<EntityBuilderEvent>()->entityBuilder->builder.instance;

if (entityID && builder->request && entityID != builder->request->entityID)
return false;

if (entityType)
{
if (!builder->entityExtractor)
return false;

auto rootIndex = builder->entityTemplate->compiledDataHeader.rootIndex;

if (rootIndex < 0)
return false;

if (entityID && entityID != entity->entityID)
return false;
if (!builder->entityExtractor->results[rootIndex]->GetType()->IsA(entityType))
return false;
}

if (entityType && !entity->GetType()->IsA(entityType))
return false;
if (templatePath && templatePath != builder->entityTemplate->path)
return false;

if (templatePath && templatePath != entity->templatePath)
return false;
if (appearanceName && builder->request && appearanceName != builder->request->appearanceName)
return false;

if (appearanceName && appearanceName != entity->appearanceName)
return false;
if (recordID && builder->request && recordID != builder->request->recordID)
return false;

if (recordID)
if (appearancePath)
{
if (builder->appearance.resource)
{
if (appearancePath != builder->appearance.resource->path)
return false;

if (definitionName && definitionName != builder->appearance.definition->name)
return false;
}
else if (builder->appearances.size != 0)
{
auto match = false;

for (const auto& appearance : builder->appearances)
{
if (appearancePath != appearance.resource->path)
continue;

if (definitionName && definitionName != appearance.definition->name)
continue;

match = true;
break;
}

if (!match)
return false;
}
else
{
return false;
}
}

break;
}
case Red::GetTypeName<EntityLifecycleEvent>():
case Red::GetTypeName<VehicleLightControlEvent>():
{
auto gameObject = Red::Cast<Red::GameObject>(entity);
if (!gameObject)
auto* entity = aEvent.GetPtr<EntityLifecycleEvent>()->entity.instance;

if (appearancePath || definitionName)
return false;

if (entityID && entityID != entity->entityID)
return false;

Red::TweakDBID objectID;
Red::CallGlobal("gameObject::GetTDBID;GameObject", objectID, Red::AsWeakHandle(gameObject));
if (recordID != objectID)
if (entityType && !entity->GetType()->IsA(entityType))
return false;

if (templatePath && templatePath != entity->templatePath)
return false;

if (appearanceName && appearanceName != entity->appearanceName)
return false;

if (recordID)
{
auto gameObject = Red::Cast<Red::GameObject>(entity);
if (!gameObject)
return false;

Red::TweakDBID objectID;
Red::CallGlobal("gameObject::GetTDBID;GameObject", objectID, Red::AsWeakHandle(gameObject));
if (recordID != objectID)
return false;
}

break;
}
}

return true;
Expand All @@ -50,7 +131,9 @@ struct EntityTarget : CallbackSystemTarget

bool Supports(Red::CName aEventType) override
{
return Red::GetClass(aEventType)->IsA(Red::GetClass<EntityLifecycleEvent>());
return aEventType == Red::GetTypeName<EntityBuilderEvent>()
|| aEventType == Red::GetTypeName<EntityLifecycleEvent>()
|| aEventType == Red::GetTypeName<VehicleLightControlEvent>();
}

static Red::Handle<EntityTarget> ID(Red::EntityID aEntityID)
Expand Down Expand Up @@ -93,11 +176,22 @@ struct EntityTarget : CallbackSystemTarget
return target;
}

static Red::Handle<EntityTarget> Definition(const Red::RaRef<>& aResource, Red::Optional<Red::CName> aName)
{
auto target = Red::MakeHandle<EntityTarget>();
target->appearancePath = aResource.path;
target->definitionName = aName;

return target;
}

Red::EntityID entityID{};
Red::CClass* entityType{};
Red::TweakDBID recordID{};
Red::ResourcePath templatePath{};
Red::CName appearanceName{};
Red::ResourcePath appearancePath{};
Red::CName definitionName{};

RTTI_IMPL_TYPEINFO(App::EntityTarget);
RTTI_IMPL_ALLOCATOR();
Expand All @@ -111,4 +205,5 @@ RTTI_DEFINE_CLASS(App::EntityTarget, {
RTTI_METHOD(RecordID);
RTTI_METHOD(Template);
RTTI_METHOD(Appearance);
RTTI_METHOD(Definition);
});
Loading

0 comments on commit 4d765c8

Please sign in to comment.