mirror of
https://github.com/storytold/EventCenterPlugin.git
synced 2026-10-09 00:09:42 +00:00
cleanup and remove RedisPlugin
This commit is contained in:
@@ -20,3 +20,30 @@ I stand up a websocket+pubsub system like so:
|
||||
```
|
||||
PS C:\Users\echel\OneDrive\Documents\Unreal Projects\RedisTestProject\Plugins\EventCenterPlugin> .\python\Scripts\Activate.ps1
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
A few collected notes, since I'm still new to Unreal engine and I'm cleaning up my debug code.
|
||||
|
||||
To log to the game screen,
|
||||
|
||||
```
|
||||
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Message goes here");
|
||||
```
|
||||
|
||||
Time based handling in Tick(),
|
||||
|
||||
```
|
||||
void AEventSourceActor::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
float time = GetGameTimeSinceCreation();
|
||||
|
||||
if (time - timerLastTime > 15.0) {
|
||||
timerLastTime = time;
|
||||
// Do the thing
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -14,12 +14,6 @@ public class EventCenterPlugin : ModuleRules
|
||||
new string[] {
|
||||
// ... add public include paths required here ...
|
||||
|
||||
// NB(bt): Using the commercial Redis Plugin by GameSeed (AKA "SDRedis")
|
||||
// Add this in the Unreal Engine Plugins menu.
|
||||
// If not present, use the Epic Games Launcher's Unreal Library Marketplace.
|
||||
"RedisPlugin/Public",
|
||||
"RedisPlugin/Classes",
|
||||
|
||||
// NB(bt): Using the commercial BlueprintWebSocket plugin described in README.md
|
||||
// Add this in the Unreal Engine Plugins menu.
|
||||
// If not present, use the Epic Games Launcher's Unreal Library Marketplace.
|
||||
@@ -42,11 +36,6 @@ public class EventCenterPlugin : ModuleRules
|
||||
"Core",
|
||||
// ... add other public dependencies that you statically link with here ...
|
||||
|
||||
// NB(bt): Using the commercial Redis Plugin by GameSeed (AKA "SDRedis")
|
||||
// Add this in the Unreal Engine Plugins menu.
|
||||
// If not present, use the Epic Games Launcher's Unreal Library Marketplace.
|
||||
"RedisPlugin",
|
||||
|
||||
// NB(bt): Using the commercial BlueprintWebSocket plugin described in README.md
|
||||
// Add this in the Unreal Engine Plugins menu.
|
||||
// If not present, use the Epic Games Launcher's Unreal Library Marketplace.
|
||||
|
||||
@@ -5,49 +5,20 @@
|
||||
DEFINE_LOG_CATEGORY(EventSourceLog);
|
||||
|
||||
AEventSourceActor::AEventSourceActor() :
|
||||
redis(nullptr),
|
||||
WebSocket(nullptr)
|
||||
{
|
||||
UE_LOG(EventSourceLog, Log, TEXT("CTOR()"));
|
||||
|
||||
// Set this actor to call Tick() every frame.
|
||||
// You can turn this off to improve performance if you don't need it.
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
|
||||
//redis = NewObject<URedisObject>(this, TEXT("RedisObject"));
|
||||
//redis = CreateDefaultSubobject<URedisObject>(TEXT("RedisObject"));
|
||||
|
||||
//RootComponent = redis;
|
||||
|
||||
}
|
||||
|
||||
AEventSourceActor::~AEventSourceActor()
|
||||
{
|
||||
// TODO: Memory leak (somehow placing a BP derivation into the editor causes the below lines to segfault)
|
||||
//delete redis;
|
||||
//redis = nullptr;
|
||||
/*if (redis != nullptr) {
|
||||
delete redis;
|
||||
redis = nullptr;
|
||||
}*/
|
||||
}
|
||||
|
||||
void AEventSourceActor::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "BeginPlay() - 2");
|
||||
UE_LOG(EventSourceLog, Log, TEXT("BeginPlay()"));
|
||||
|
||||
if (redis == nullptr) {
|
||||
UE_LOG(EventSourceLog, Log, TEXT("BeginPlay(): Creating redis instance"));
|
||||
redis = NewObject<URedisObject>(this, TEXT("RedisObject"));
|
||||
}
|
||||
|
||||
UE_LOG(EventSourceLog, Log, TEXT("BeginPlay(): Redis is null? ? %d"), redis == nullptr);
|
||||
//UE_LOG(EventSourceLog, Log, TEXT("BeginPlay(): Redis host: %s"), redisHost);
|
||||
UE_LOG(EventSourceLog, Log, TEXT("BeginPlay(): Redis port: %d"), redisPort);
|
||||
//UE_LOG(EventSourceLog, Log, TEXT("BeginPlay(): Redis password (no secrets): %s"), redisPassword);
|
||||
}
|
||||
|
||||
void AEventSourceActor::BeginDestroy()
|
||||
@@ -59,81 +30,7 @@ void AEventSourceActor::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
float time = GetGameTimeSinceCreation();
|
||||
|
||||
if (time - timerLastTime > 15.0) {
|
||||
timerLastTime = time;
|
||||
//GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "seconds elapsed");
|
||||
//redis->Unsubscribe(TEXT("second"));
|
||||
//redis->Subscribe(TEXT("second"));
|
||||
}
|
||||
|
||||
|
||||
// NB: Handled by RedisObject internal delegate
|
||||
//redis->Tick(DeltaTime);
|
||||
}
|
||||
|
||||
void AEventSourceActor::ConstructClient()
|
||||
{
|
||||
if (redis != nullptr) {
|
||||
UE_LOG(EventSourceLog, Log, TEXT("Construct(): Redis is NOT null"));
|
||||
return;
|
||||
}
|
||||
|
||||
UE_LOG(EventSourceLog, Log, TEXT("construct(): redis = new Redis()"));
|
||||
redis = NewObject<URedisObject>(this, TEXT("RedisObject"));
|
||||
}
|
||||
|
||||
|
||||
void AEventSourceActor::Init()
|
||||
{
|
||||
if (redis == nullptr) {
|
||||
UE_LOG(EventSourceLog, Log, TEXT("Init(): Redis is null"));
|
||||
return;
|
||||
}
|
||||
|
||||
//UE_LOG(EventSourceLog, Log, TEXT("construct(): redis = new Redis()"));
|
||||
//redis = NewObject<URedisObject>(this, TEXT("RedisObject"));
|
||||
UE_LOG(EventSourceLog, Log, TEXT("Init(): redis->Init()"));
|
||||
redis->Init(redisHost, redisPort, redisPassword);
|
||||
}
|
||||
|
||||
void AEventSourceActor::Subscribe(const FString& Channel)
|
||||
{
|
||||
if (redis == nullptr) {
|
||||
UE_LOG(EventSourceLog, Log, TEXT("Subscribe(): Redis is null"));
|
||||
return;
|
||||
}
|
||||
|
||||
UE_LOG(EventSourceLog, Log, TEXT("Subscribe(): redis->Subscribe()"));
|
||||
redis->Subscribe(Channel);
|
||||
|
||||
if (!redis->SubscribeReply.IsBound()) {
|
||||
UE_LOG(EventSourceLog, Log, TEXT("Subscribe(): binding event"));
|
||||
redis->SubscribeReply.AddDynamic(this, &AEventSourceActor::InternalSubscribeCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void AEventSourceActor::Unsubscribe(const FString& Channel)
|
||||
{
|
||||
if (redis == nullptr) {
|
||||
UE_LOG(EventSourceLog, Log, TEXT("Unsubscribe(): Redis is null"));
|
||||
return;
|
||||
}
|
||||
|
||||
UE_LOG(EventSourceLog, Log, TEXT("Unsubscribe(): redis->Unsubscribe()"));
|
||||
redis->Unsubscribe(Channel);
|
||||
}
|
||||
|
||||
void AEventSourceActor::InternalSubscribeCallback(FString Channel, FString Message)
|
||||
{
|
||||
//UE_LOG(EventSourceLog, Log, TEXT("SubscribeCallback(): %s %s"), Channel, Message);
|
||||
UE_LOG(EventSourceLog, Log, TEXT("SubscribeCallback(): called"));
|
||||
|
||||
if (MyDelegate.IsBound()) {
|
||||
MyDelegate.Broadcast(Channel, Message);
|
||||
|
||||
}
|
||||
// TODO(bt): If our callbacks aren't enough to restore broken connections, add some logic here.
|
||||
}
|
||||
|
||||
// ======================================= web sockets =============================================
|
||||
@@ -142,33 +39,24 @@ void AEventSourceActor::OnConnected()
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "OnConnected");
|
||||
UE_LOG(EventSourceLog, Log, TEXT("OnConnected"));
|
||||
|
||||
//WebSocket->SendMessage(TEXT("Hello Server!"));
|
||||
}
|
||||
|
||||
void AEventSourceActor::OnConnectionError(const FString& Error)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "OnConnectionError");
|
||||
UE_LOG(EventSourceLog, Log, TEXT("OnConnectionError"));
|
||||
|
||||
// Connection failed.
|
||||
UE_LOG(EventSourceLog, Error, TEXT("Failed to connect: %s."), *Error);
|
||||
UE_LOG(EventSourceLog, Error, TEXT("OnConnectionError. Failed to connect: %s."), *Error);
|
||||
}
|
||||
|
||||
void AEventSourceActor::OnClosed(int64 StatusCode, const FString& Reason, bool bWasClean)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "OnClosed");
|
||||
UE_LOG(EventSourceLog, Log, TEXT("OnClosed"));
|
||||
|
||||
UE_LOG(EventSourceLog, Warning, TEXT("Connection closed: %d:%s. Clean: %d"), StatusCode, *Reason, bWasClean);
|
||||
UE_LOG(EventSourceLog, Warning, TEXT("OnClosed. Connection closed: %d:%s. Clean: %d"), StatusCode, *Reason, bWasClean);
|
||||
}
|
||||
|
||||
void AEventSourceActor::OnMessage(const FString& Message)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "OnMessage");
|
||||
UE_LOG(EventSourceLog, Log, TEXT("OnMessage"));
|
||||
|
||||
UE_LOG(EventSourceLog, Log, TEXT("New message: %s"), *Message);
|
||||
UE_LOG(EventSourceLog, Log, TEXT("OnMessage. New message: %s"), *Message);
|
||||
|
||||
FString channel, payload;
|
||||
bool result = Message.Split(TEXT("|"), &channel, &payload);
|
||||
@@ -194,16 +82,13 @@ void AEventSourceActor::OnMessage(const FString& Message)
|
||||
void AEventSourceActor::OnRawMessage(const TArray<uint8>& Data, int32 BytesRemaining)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "OnRawMessage");
|
||||
UE_LOG(EventSourceLog, Log, TEXT("OnRawMessage"));
|
||||
|
||||
UE_LOG(EventSourceLog, Log, TEXT("New binary message: %d bytes and %d bytes remaining."), Data.Num(), BytesRemaining);
|
||||
UE_LOG(EventSourceLog, Log, TEXT("OnRawMessage. New binary message: %d bytes and %d bytes remaining."), Data.Num(), BytesRemaining);
|
||||
}
|
||||
|
||||
void AEventSourceActor::OnMessageSent(const FString& Message)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "OnMessageSent");
|
||||
UE_LOG(EventSourceLog, Log, TEXT("OnMessageSent"));
|
||||
UE_LOG(EventSourceLog, Log, TEXT("We just sent %s to the server."), *Message);
|
||||
UE_LOG(EventSourceLog, Log, TEXT("OnMessageSent. We just sent %s to the server."), *Message);
|
||||
}
|
||||
|
||||
void AEventSourceActor::SetupWebSockets()
|
||||
@@ -225,34 +110,6 @@ void AEventSourceActor::SetupWebSockets()
|
||||
WebSocket->Connect(TEXT("ws://localhost:8765/"), TEXT("ws"));
|
||||
}
|
||||
|
||||
/*void AEventSourceActor::AssignEvent(FString& eventName, TScriptInterface<IEventHandlerInterface> handler)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "AssignEvent");
|
||||
UE_LOG(EventSourceLog, Log, TEXT("AssignEvent"));
|
||||
|
||||
//TScriptDelegate<TWeakPtr> ourDelegate = TScriptDelegate<TWeakPtr>();
|
||||
|
||||
//ourDelegate.BindUFunction(handler.GetObject(), &IEventHandlerInterface::HandleEvent);
|
||||
|
||||
IEventHandlerInterface* iface = Cast<IEventHandlerInterface>(handler.GetObject());
|
||||
|
||||
|
||||
//MyDelegate2.AddDynamic(iface, &IEventHandlerInterface::HandleEvent2);
|
||||
//MyDelegate2.AddDynamic((UObject*)iface, &IEventHandlerInterface::HandleEvent2);
|
||||
|
||||
//MyDelegate2.AddDynamic(handler.GetObject(), &IEventHandlerInterface::HandleEvent2);
|
||||
//MyDelegate2.AddDynamic(handler.GetObject(), "HandleEvent2");
|
||||
|
||||
UObject* uobject = Cast<UObject>(handler.GetObject());
|
||||
|
||||
//MyDelegate2.AddDynamic(handler->_getUObject(), &IEventHandlerInterface::HandleEvent2);
|
||||
}*/
|
||||
|
||||
/*void AEventSourceActor::AssignEvent2(FString& eventName, UObject& object, FMySubscriberRefDelegate& theDelegate)
|
||||
{
|
||||
|
||||
}*/
|
||||
|
||||
void AEventSourceActor::BindSingleDelegateForChannel(const FString& channel, const FMySubscriberRefDelegate& delegateDef)
|
||||
{
|
||||
delegateSubscriptions.Add(channel, delegateDef);
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/NoExportTypes.h"
|
||||
|
||||
// RedisPlugin
|
||||
#include "RedisObject.h"
|
||||
|
||||
// Event system
|
||||
#include "EventHandlerInterface.h"
|
||||
|
||||
@@ -21,16 +18,16 @@ DECLARE_LOG_CATEGORY_EXTERN(EventSourceLog, Log, All);
|
||||
|
||||
// TODO(bt): Make this not an actor. Consider UObject. Also consider a singleton.
|
||||
|
||||
// NB(bt): We can't use `DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams` multicast
|
||||
// due to an Unreal Engine limitation
|
||||
DECLARE_DYNAMIC_DELEGATE_TwoParams(FMySubscriberRefDelegate, const FString&, Channel, const FString&, Message);
|
||||
|
||||
/**
|
||||
* AEventSourceActor
|
||||
*
|
||||
* Manages an underlying Redis pubsub subscription and coordinates dispatch to other actors.
|
||||
*/
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FMySubscriberDelegate, FString, Channel, FString, Message);
|
||||
|
||||
DECLARE_DYNAMIC_DELEGATE_TwoParams(FMySubscriberRefDelegate, const FString&, Channel, const FString&, Message);
|
||||
|
||||
// NB(bt): "Blueprintable" seems to remove the ability to add BP event nodes.
|
||||
UCLASS()
|
||||
class EVENTCENTERPLUGIN_API AEventSourceActor : public AActor
|
||||
@@ -42,58 +39,20 @@ public:
|
||||
AEventSourceActor();
|
||||
~AEventSourceActor();
|
||||
|
||||
/** Redis Hostname */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EventCenter")
|
||||
FString redisHost;
|
||||
|
||||
/** Redis Port */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EventCenter")
|
||||
int32 redisPort = 6379;
|
||||
|
||||
/** Redis Password */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "EventCenter")
|
||||
FString redisPassword;
|
||||
|
||||
/** Construct Redis Object.*/
|
||||
UFUNCTION(BlueprintCallable, Category = "EventCenter")
|
||||
void ConstructClient();
|
||||
|
||||
/** Connect to Redis.*/
|
||||
UFUNCTION(BlueprintCallable, Category = "EventCenter")
|
||||
void Init();
|
||||
|
||||
/** Subscribe to a named Redis PubSub channel. */
|
||||
UFUNCTION(BlueprintCallable, Category = "EventCenter")
|
||||
void Subscribe(const FString& Channel);
|
||||
|
||||
/** Unsubscribe from a named Redis PubSub channel. */
|
||||
UFUNCTION(BlueprintCallable, Category = "EventCenter")
|
||||
void Unsubscribe(const FString& Channel);
|
||||
|
||||
/** This allows event binding from blueprint. */
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FMySubscriberDelegate MyDelegate;
|
||||
|
||||
/**
|
||||
* Bind a delegate to a channel. Note that we can't multicast.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "EventCenter")
|
||||
void BindSingleDelegateForChannel(const FString& channel, const FMySubscriberRefDelegate& delegateDef);
|
||||
|
||||
/** Set up websockets.*/
|
||||
UFUNCTION(BlueprintCallable, Category = "EventCenter")
|
||||
void SetupWebSockets();
|
||||
|
||||
/** This is an experiment */
|
||||
//UFUNCTION(BlueprintCallable, Category = "EventCenter")
|
||||
//void AssignEvent(FString& eventName, TScriptInterface<IEventHandlerInterface> handler);
|
||||
|
||||
|
||||
// This won't work because we don't know what the function is
|
||||
//void AssignEvent2(FString& eventName, UObject& object, FMySubscriberRefDelegate& theDelegate);
|
||||
|
||||
//FMySubscriberRefDelegate MyDelegate2;
|
||||
|
||||
/**
|
||||
* Bind a delegate to a channel.
|
||||
*
|
||||
* Note that we can't multicast due to Unreal limitations. As a workaround, bind
|
||||
* different channels for other events,or have the events delegates themselves
|
||||
* perform the multicasting downstream of us.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "EventCenter")
|
||||
void BindSingleDelegateForChannel(const FString& channel,
|
||||
const FMySubscriberRefDelegate& delegateDef);
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
@@ -110,26 +69,14 @@ protected:
|
||||
UFUNCTION() void OnMessageSent(const FString& Message);
|
||||
|
||||
private:
|
||||
URedisObject* redis;
|
||||
|
||||
UPROPERTY()
|
||||
UBlueprintWebSocket* WebSocket;
|
||||
|
||||
|
||||
// TODO(bt): Value type can be wrapped in a class to add additional routing.
|
||||
// Multiple delegation signatures, "pause/muting", etc.
|
||||
TMap<FString, FMySubscriberRefDelegate> delegateSubscriptions;
|
||||
|
||||
// Handle callbacks.
|
||||
// NB(bt): Declared 'UFUNCTION()' so reflection enables as a delegate callback.
|
||||
UFUNCTION()
|
||||
void InternalSubscribeCallback(FString Channel, FString Message);
|
||||
|
||||
// For a timer calculation.
|
||||
float timerLastTime = 0.0f;
|
||||
|
||||
public:
|
||||
// Called every frame
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user