Skip to content

Commit

Permalink
Add feature #19
Browse files Browse the repository at this point in the history
- Adds gameplay tag wrappers and functions to allow selecting event names from a list instead of via string
- gameplay tags already have a . denominated tree list so it is very fitting
- tag to domain & event assumes event is without periods and everything else is domain
  • Loading branch information
getnamo committed Mar 11, 2021
1 parent c39b743 commit b4c4ac9
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 9 deletions.
2 changes: 1 addition & 1 deletion GlobalEventSystem.uplugin
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"FileVersion": 3,
"Version": 1,
"VersionName": "0.6.8",
"VersionName": "0.6.9",
"FriendlyName": "GlobalEventSystem",
"Description": "Loosely coupled internal event system.",
"Category": "Utility",
Expand Down
1 change: 1 addition & 0 deletions Source/GlobalEventSystem/GlobalEventSystem.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public GlobalEventSystem(ReadOnlyTargetRules Target) : base(Target)
"Engine",
"Slate",
"SlateCore",
"GameplayTags"
// ... add private dependencies that you statically link with here ...
}
);
Expand Down
4 changes: 2 additions & 2 deletions Source/GlobalEventSystem/Private/GESBaseReceiverComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ void UGESBaseReceiverComponent::BeginPlay()
if (BindSettings.ReceivingFunction == TEXT("OnEvent(component)"))
{
InternalListener.BindDynamic(this, &UGESBaseReceiverComponent::HandleInternalEvent);
UGlobalEventSystemBPLibrary::GESBindEventToWildcardDelegate(this, InternalListener, BindSettings.Domain, BindSettings.Event);
UGlobalEventSystemBPLibrary::GESBindEventToDelegate(this, InternalListener, BindSettings.Domain, BindSettings.Event);
}
else
{
Expand All @@ -35,7 +35,7 @@ void UGESBaseReceiverComponent::EndPlay(const EEndPlayReason::Type EndPlayReason
{
if (BindSettings.ReceivingFunction == TEXT("OnEvent(component)"))
{
UGlobalEventSystemBPLibrary::GESUnbindWildcardDelegate(this, InternalListener, BindSettings.Domain, BindSettings.Event);
UGlobalEventSystemBPLibrary::GESUnbindDelegate(this, InternalListener, BindSettings.Domain, BindSettings.Event);
PinnedData.CleanupPinnedData();
}
else
Expand Down
69 changes: 67 additions & 2 deletions Source/GlobalEventSystem/Private/GlobalEventSystemBPLibrary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ void UGlobalEventSystemBPLibrary::GESUnbindEvent(UObject* WorldContextObject, co
FGESHandler::DefaultHandler()->RemoveListener(Domain, Event, Listener);
}

void UGlobalEventSystemBPLibrary::GESUnbindTagEvent(UObject* WorldContextObject, FGameplayTag Tag, const FString& ReceivingFunction /*= TEXT("")*/)
{
FString Domain;
FString Event;
Conv_TagToDomainAndEvent(Tag, Domain, Event);
GESUnbindEvent(WorldContextObject, Domain, Event, ReceivingFunction);
}

void UGlobalEventSystemBPLibrary::GESUnbindAllEventsForContext(UObject* WorldContextObject, UObject* Context /*= nullptr*/)
{
if (Context == nullptr)
Expand All @@ -26,7 +34,7 @@ void UGlobalEventSystemBPLibrary::GESUnbindAllEventsForContext(UObject* WorldCon
FGESHandler::DefaultHandler()->RemoveAllListenersForReceiver(Context);
}

void UGlobalEventSystemBPLibrary::GESUnbindWildcardDelegate(UObject* WorldContextObject, const FGESOnePropertySignature& ReceivingFunction, const FString& Domain /*= TEXT("global.default")*/, const FString& Event /*= TEXT("")*/)
void UGlobalEventSystemBPLibrary::GESUnbindDelegate(UObject* WorldContextObject, const FGESOnePropertySignature& ReceivingFunction, const FString& Domain /*= TEXT("global.default")*/, const FString& Event /*= TEXT("")*/)
{
FGESEventListener Listener;
Listener.ReceiverWCO = WorldContextObject;
Expand All @@ -45,6 +53,14 @@ void UGlobalEventSystemBPLibrary::GESUnbindWildcardDelegate(UObject* WorldContex
FGESHandler::DefaultHandler()->RemoveListener(Domain, Event, Listener);
}

void UGlobalEventSystemBPLibrary::GESUnbindTagDelegate(UObject* WorldContextObject, FGameplayTag Tag, const FGESOnePropertySignature& ReceivingFunction)
{
FString Domain;
FString Event;
Conv_TagToDomainAndEvent(Tag, Domain, Event);
GESUnbindDelegate(WorldContextObject, ReceivingFunction, Domain, Event);
}

void UGlobalEventSystemBPLibrary::GESBindEvent(UObject* WorldContextObject, const FString& Domain /*= TEXT("global.default")*/, const FString& Event /*= TEXT("")*/, const FString& ReceivingFunction /*= TEXT("")*/)
{
FGESEventListener Listener;
Expand All @@ -55,7 +71,29 @@ void UGlobalEventSystemBPLibrary::GESBindEvent(UObject* WorldContextObject, cons
FGESHandler::DefaultHandler()->AddListener(Domain, Event, Listener);
}

void UGlobalEventSystemBPLibrary::GESBindEventToWildcardDelegate(UObject* WorldContextObject, const FGESOnePropertySignature& ReceivingFunction, const FString& Domain /*= TEXT("global.default")*/, const FString& Event /*= TEXT("")*/)
void UGlobalEventSystemBPLibrary::GESBindTagEvent(UObject* WorldContextObject, FGameplayTag DomainedEventTag, const FString& ReceivingFunction /*= TEXT("")*/)
{
FGESEventListener Listener;
Listener.ReceiverWCO = WorldContextObject;
Listener.FunctionName = ReceivingFunction;
Listener.LinkFunction(); //this makes the function valid by finding a reference to it

FString Domain;
FString Event;
Conv_TagToDomainAndEvent(DomainedEventTag, Domain, Event);

FGESHandler::DefaultHandler()->AddListener(Domain, Event, Listener);
}

void UGlobalEventSystemBPLibrary::GESBindTagEventToDelegate(UObject* WorldContextObject, FGameplayTag DomainedEventTag, const FGESOnePropertySignature& ReceivingFunction)
{
FString Domain;
FString Event;
Conv_TagToDomainAndEvent(DomainedEventTag, Domain, Event);
GESBindEventToDelegate(WorldContextObject, ReceivingFunction, Domain, Event);
}

void UGlobalEventSystemBPLibrary::GESBindEventToDelegate(UObject* WorldContextObject, const FGESOnePropertySignature& ReceivingFunction, const FString& Domain /*= TEXT("global.default")*/, const FString& Event /*= TEXT("")*/)
{
FGESEventListener Listener;
Listener.ReceiverWCO = WorldContextObject;
Expand Down Expand Up @@ -93,6 +131,20 @@ void UGlobalEventSystemBPLibrary::GESEmitEvent(UObject* WorldContextObject, bool
FGESHandler::DefaultHandler()->EmitEvent(EmitData);
}

void UGlobalEventSystemBPLibrary::GESEmitTagEvent(UObject* WorldContextObject, FGameplayTag DomainedEventTag, bool bPinned /*= false*/)
{
FGESEmitContext EmitData;
EmitData.bPinned = bPinned;
Conv_TagToDomainAndEvent(DomainedEventTag, EmitData.Domain, EmitData.Event);
EmitData.WorldContext = WorldContextObject;
FGESHandler::DefaultHandler()->EmitEvent(EmitData);
}

void UGlobalEventSystemBPLibrary::GESEmitTagEventOneParam(UObject* WorldContextObject, TFieldPath<FProperty> ParameterData, FGameplayTag DomainedEventTag, bool bPinned /*= false*/)
{
//this never gets called due to custom thunk
}

void UGlobalEventSystemBPLibrary::GESUnpinEvent(UObject* WorldContextObject, const FString& Domain /*= TEXT("global.default")*/, const FString& Event /*= TEXT("")*/)
{
FGESHandler::DefaultHandler()->UnpinEvent(Domain, Event);
Expand Down Expand Up @@ -329,3 +381,16 @@ bool UGlobalEventSystemBPLibrary::Conv_PropToObject(const FGESWildcardProperty&
}
}

void UGlobalEventSystemBPLibrary::Conv_TagToDomainAndEvent(FGameplayTag InTag, FString& OutDomain, FString& OutEvent)
{
FString DomainAndEvent = InTag.GetTagName().ToString();

bool bFound = DomainAndEvent.Split(TEXT("."), &OutDomain, &OutEvent, ESearchCase::IgnoreCase, ESearchDir::FromEnd);

if (!bFound)
{
OutDomain = TEXT("global.default");
OutEvent = DomainAndEvent;
}
}

80 changes: 76 additions & 4 deletions Source/GlobalEventSystem/Public/GlobalEventSystemBPLibrary.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "Kismet/BlueprintFunctionLibrary.h"
#include "GESHandler.h"
#include "GameplayTagContainer.h"
#include "GlobalEventSystemBPLibrary.generated.h"

/*
Expand All @@ -20,6 +21,13 @@ class GLOBALEVENTSYSTEM_API UGlobalEventSystemBPLibrary : public UBlueprintFunct
UFUNCTION(BlueprintCallable, meta = (Keywords = "ges sever stoplisten", WorldContext = "WorldContextObject"), Category = "GlobalEventSystem")
static void GESUnbindEvent(UObject* WorldContextObject, const FString& Domain = TEXT("global.default"), const FString& Event = TEXT(""), const FString& ReceivingFunction = TEXT(""));

/**
* Remove this listener from the specified GESEvent given by GameplayTag.
*/
UFUNCTION(BlueprintCallable, meta = (Keywords = "ges sever stoplisten", WorldContext = "WorldContextObject"), Category = "GlobalEventSystem")
static void GESUnbindTagEvent(UObject* WorldContextObject, FGameplayTag Tag, const FString& ReceivingFunction = TEXT(""));


/**
* Call this on endplay to remove all events associated with this graph. If context isn't specified, graph context used (default use case).
*/
Expand All @@ -28,23 +36,37 @@ class GLOBALEVENTSYSTEM_API UGlobalEventSystemBPLibrary : public UBlueprintFunct


UFUNCTION(BlueprintCallable, meta = (Keywords = "ges sever stoplisten", WorldContext = "WorldContextObject"), Category = "GlobalEventSystem")
static void GESUnbindWildcardDelegate(UObject* WorldContextObject, const FGESOnePropertySignature& ReceivingFunction, const FString& Domain = TEXT("global.default"), const FString& Event = TEXT(""));
static void GESUnbindDelegate(UObject* WorldContextObject, const FGESOnePropertySignature& ReceivingFunction, const FString& Domain = TEXT("global.default"), const FString& Event = TEXT(""));

UFUNCTION(BlueprintCallable, meta = (Keywords = "ges sever stoplisten", WorldContext = "WorldContextObject"), Category = "GlobalEventSystem")
static void GESUnbindTagDelegate(UObject* WorldContextObject, FGameplayTag Tag, const FGESOnePropertySignature& ReceivingFunction);

/**
* Bind a function (to current caller) to GES event. Make sure to match your receiving function parameters to the GESEvent ones.
*/
UFUNCTION(BlueprintCallable, meta = (Keywords = "ges create listen", WorldContext = "WorldContextObject"), Category = "GlobalEventSystem")
static void GESBindEvent(UObject* WorldContextObject, const FString& Domain = TEXT("global.default"), const FString& Event = TEXT(""), const FString& ReceivingFunction = TEXT(""));

/**
* Bind a function (to current caller) to GES event defined by a GamePlayTag
*/
UFUNCTION(BlueprintCallable, meta = (Keywords = "ges create listen", WorldContext = "WorldContextObject"), Category = "GlobalEventSystem")
static void GESBindTagEvent(UObject* WorldContextObject, FGameplayTag DomainedEventTag, const FString& ReceivingFunction = TEXT(""));

/**
* Bind a function (to current caller) to GES event defined by a GamePlayTag
*/
UFUNCTION(BlueprintCallable, meta = (Keywords = "ges create listen", WorldContext = "WorldContextObject"), Category = "GlobalEventSystem")
static void GESBindTagEventToDelegate(UObject* WorldContextObject, FGameplayTag DomainedEventTag, const FGESOnePropertySignature& ReceivingFunction);

/**
* Bind an event delegate to GES event. Use blueprint utility to decode UProperty.
*/
UFUNCTION(BlueprintCallable, meta = (Keywords = "ges create listen", WorldContext = "WorldContextObject"), Category = "GlobalEventSystem")
static void GESBindEventToWildcardDelegate(UObject* WorldContextObject, const FGESOnePropertySignature& ReceivingFunction, const FString& Domain = TEXT("global.default"), const FString& Event = TEXT(""));
static void GESBindEventToDelegate(UObject* WorldContextObject, const FGESOnePropertySignature& ReceivingFunction, const FString& Domain = TEXT("global.default"), const FString& Event = TEXT(""));

/**
* Emit desired event with data. Data can be any property (just not UObjects at this time).
* Emit desired event with data. Data can be any single property (wrap arrays/maps etc in a struct or object)
* Pinning an event means it will emit to future listeners even if the event has already been
* emitted.
*/
Expand All @@ -53,10 +75,29 @@ class GLOBALEVENTSYSTEM_API UGlobalEventSystemBPLibrary : public UBlueprintFunct

/**
* Just emits the event with no additional data
* Pinning an event means it will emit to future listeners even if the event has already been
* emitted.
*/
UFUNCTION(BlueprintCallable, meta=(WorldContext = "WorldContextObject"), Category = "GlobalEventSystem")
static void GESEmitEvent(UObject* WorldContextObject, bool bPinned = false, const FString& Domain = TEXT("global.default"), const FString& Event = TEXT(""));

/**
* Just emits the event with no additional data using GameplayTags to define domain and event.
* Pinning an event means it will emit to future listeners even if the event has already been
* emitted.
*/
UFUNCTION(BlueprintCallable, meta = (WorldContext = "WorldContextObject"), Category = "GlobalEventSystem")
static void GESEmitTagEvent(UObject* WorldContextObject, FGameplayTag DomainedEventTag, bool bPinned = false);

/**
* Emit desired event with data using GameplayTags to define domain and event. Data can be any single
* property (wrap arrays/maps etc in a struct or object).
* Pinning an event means it will emit to future listeners even if the event has already been
* emitted.
*/
UFUNCTION(BlueprintCallable, CustomThunk, Category = "GlobalEventSystem", meta = (CustomStructureParam = "ParameterData", WorldContext = "WorldContextObject"))
static void GESEmitTagEventOneParam(UObject* WorldContextObject, TFieldPath<FProperty> ParameterData, FGameplayTag DomainedEventTag, bool bPinned = false);

/**
* If an event was pinned, this will unpin it. If you wish to re-pin a different event you need to unpin the old event first.
*/
Expand Down Expand Up @@ -103,6 +144,10 @@ class GLOBALEVENTSYSTEM_API UGlobalEventSystemBPLibrary : public UBlueprintFunct
UFUNCTION(BlueprintPure, meta = (DisplayName = "To Object (Wildcard Property)", BlueprintAutocast), Category = "Utilities|GES")
static bool Conv_PropToObject(const FGESWildcardProperty& InProp, UObject*& OutObject);

/** Convert a GameplayTag into a Domain and Event string pair */
UFUNCTION(BlueprintPure, meta = (DisplayName = "To Domain and Event (GameplayTag)", BlueprintAutocast), Category = "Utilities|GES")
static void Conv_TagToDomainAndEvent(FGameplayTag InTag, FString& OutDomain, FString& OutEvent);

//Convert property into c++ accessible form
DECLARE_FUNCTION(execGESEmitEventOneParam)
{
Expand All @@ -129,6 +174,34 @@ class GLOBALEVENTSYSTEM_API UGlobalEventSystemBPLibrary : public UBlueprintFunct
P_NATIVE_END;
}

DECLARE_FUNCTION(execGESEmitTagEventOneParam)
{
Stack.MostRecentProperty = nullptr;
FGESPropertyEmitContext EmitData;

Stack.StepCompiledIn<FObjectProperty>(&EmitData.WorldContext);

//Determine wildcard property
Stack.Step(Stack.Object, NULL);
FProperty* ParameterProp = CastField<FProperty>(Stack.MostRecentProperty);
void* PropPtr = Stack.MostRecentPropertyAddress;

EmitData.Property = ParameterProp;
EmitData.PropertyPtr = PropPtr;

FGameplayTag Tag;
Stack.StepCompiledIn<FStructProperty>(&Tag);
Conv_TagToDomainAndEvent(Tag, EmitData.Domain, EmitData.Event);


Stack.StepCompiledIn<FBoolProperty>(&EmitData.bPinned);

P_FINISH;
P_NATIVE_BEGIN;
HandleEmit(EmitData);
P_NATIVE_END;
}

DECLARE_FUNCTION(execConv_PropToStruct)
{
Stack.MostRecentProperty = nullptr;
Expand Down Expand Up @@ -159,5 +232,4 @@ class GLOBALEVENTSYSTEM_API UGlobalEventSystemBPLibrary : public UBlueprintFunct
private:
static void HandleEmit(const FGESPropertyEmitContext& EmitData);
static bool HandlePropToStruct(const FGESWildcardProperty& InProp, FGESWildcardProperty& FullProp);
//todo add support for array type props
};

0 comments on commit b4c4ac9

Please sign in to comment.