x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Generic Network Action System - Extracting RPC method definitions

Hi everybody,

i am currently trying to write a generic action system for ingame events where you can easily dispatch an

action locally, to the server or to both. In addition you can register callbacks to handle the execution of all actions (preExecute, onExecute and afterExecute).

Dispatching actions is completely handled by the GameActionDispatcher ( one is spawned for each player and stored in the player controller) itself and as easy as calling a single function:

 GetGameActionDispatcher(this)->ExecuteAction<FThrowAction, ActionExecutionType::Net>(GetPawn(), force);

An action is basically just a simple struct containing the parameter data like this:

 USTRUCT()
 struct BOUNCE_API FThrowAction : public FGameAction
 {
     GENERATED_USTRUCT_BODY()
     
 public:
     FThrowAction();
 
     void init(AActor* actor, FVector2D force);
 
     UPROPERTY()
     TWeakObjectPtr<AActor> Actor;
 
     UPROPERTY()
     FVector2D Force;
 };

This is the base of the Dispatcher implementation:

 UCLASS()
 class BOUNCE_API AGameActionDispatcher : public AActor
 {
     template<class ActionClass, ActionExecutionType Type>
     friend class TypeBasedGameActionExecution;
 
     GENERATED_BODY()
 
 public:
     AGameActionDispatcher();
 
     template<class ActionClass, ActionExecutionType Type, typename ... Params>
     void ExecuteAction(Params... params);
 
 private:
     **//list of RPC methods - THIS HAS TO BE IN AN EXTRA USER DEFINED CLASS**
     UFUNCTION(Server, WithValidation, Reliable)
     void executeServer(FThrowAction action);
     //... further rpc calls
 
     // wrapper methods for local and net execution
     template<class ActionClass>
     void ExecuteNet(const ActionClass& action);
 
     void ExecuteLocal(const FGameAction& action);
 };
 
 template<class ActionClass, ActionExecutionType Type, typename ... Params>
 void AGameActionDispatcher::ExecuteAction(Params... args)
 {
     ActionClass action;
     action.init(args...);
 
     TypeBasedGameActionExecution<ActionClass, Type>::run(this, action);
 }
 
 // template implementation
 template<class ActionClass>
 void AGameActionDispatcher::ExecuteNet(const ActionClass& action)
 {
     ExecuteLocal(action);
 
     if (Role != ROLE_Authority)
     {
         executeServer(action);
     }
 }

Further relevant code can be found further down.

To keep it as simple callable as possible with minimal effort of writing new functions, all the magic in the background is heavily template based because for the RPC Calls i need to specify the correct Action type (obviously sending non replicated pointers does not work so i cannot take advantage of polymorphism).

These RPC calls are exactly my problem. Currently these method specifications are directly inside of my Dispatcher class. However in terms of reusability and potentially making a library out of it, i would like to extract them so the user can specify them in terms of their needs.

Ideas i tried:

  • Defining the RPC methods in a macro and place that call in the Dispatcher header -> fails because the UBT runs before evaluating the macro

  • Extract the RPC methods into an "BaseRPCChannelComponent" class deriving from UActorComponent. Then add a setter for the rpc channel to the dispatcher and call rpcchannel->executeServer(...). Problem is since the base channel class obviously does not have the executeServer rpc functions. I would also need to concrete RPCChannelComponent type of the user created one here.

    UCLASS() class BOUNCE_API UBaseRPCChannelComponent : public UActorComponent { friend class AGameActionDispatcher;

       GENERATED_BODY()
     
     public:
         UBaseRPCChannelComponent();
         
     private:
         // Derive from this class and list server rpc calls for each game action like this
         /*UFUNCTION(Server, Reliable, WithValidation)
         void ExecuteServer(ActionClass action);*/
     
         // auto generate template validate and implementation functions for server methods
         template<class ActionClass>
         bool ExecuteServer_Validate(ActionClass action);
     
         template<class ActionClass>
         void ExecuteServer_Implementation(ActionClass action);
     
         AGameActionDispatcher* GetDispatcher();
     };
     
     template<class ActionClass>
     bool UBaseRPCChannelComponent::ExecuteServer_Validate(ActionClass action)
     {
         return action.validate();
     }
     
     template<class ActionClass>
     void UBaseRPCChannelComponent::ExecuteServer_Implementation(ActionClass action)
     {
         GetDispatcher()->ExecuteLocal(action);
     }
     void AGameActionDispatcher::UseRPCChannel(TSubclassOf<UBaseRPCChannelComponent> channelClass)
     {
         if (RPCChannel)
         {
             RPCChannel->DestroyComponent();
         }
     
         RPCChannel = ConstructObject<UBaseRPCChannelComponent>(channelClass, this, FName(TEXT("RPCChannelComponent")));
     }
    
     // template implementation
     template<class ActionClass>
     void AGameActionDispatcher::ExecuteNet(const ActionClass& action)
     {
         ExecuteLocal(action);
     
         if (Role != ROLE_Authority && RPCChannel)
         {
             RPCChannel->executeServer(action);
         }
     }
    
  • Ok since i need the RPC channels concrete type i came to templates again. And because i have to store the RPC channel as a member variable i would have to make the Dispatcher itself a template which does not work with UCLASS definitions... So i could led the user derive from my templated dispatcher with the rpc channel. But then again i do not know the users dispatcher class to refer to it and store in the player controller

I think u see where i am stuck now xD

Do you have any ideas on how to solve this? Or maybe know about a completely different approach than what i tried?

Greetings.

TypeBasedGameActionExecution - Partially specialized template class to only generate the executeNet and executeServer methods when the execution type requires it.

 template<class ActionClass, ActionExecutionType Type>
 class TypeBasedGameActionExecution
 {
 public:
     static void run(AGameActionDispatcher* dispatcher, ActionClass action)
     {
         // do nothing, work is done based on type in specialized templates
     }
 };
 
 template<class ActionClass>
 class TypeBasedGameActionExecution < ActionClass, ActionExecutionType::Local >
 {
 public:
     static void run(AGameActionDispatcher* dispatcher, ActionClass action)
     {
         dispatcher->ExecuteLocal(action);
     }
 };
 
 template<class ActionClass>
 class TypeBasedGameActionExecution < ActionClass, ActionExecutionType::Server >
 {
 public:
     static void run(AGameActionDispatcher* dispatcher, ActionClass action)
     {
         dispatcher->executeServer(action);
     }
 };
 
 template<class ActionClass>
 class TypeBasedGameActionExecution < ActionClass, ActionExecutionType::Net >
 {
 public:
     static void run(AGameActionDispatcher* dispatcher, ActionClass action)
     {
         dispatcher->ExecuteNet(action);
     }
 };
Product Version: Not Selected
Tags:
more ▼

asked May 07 '15 at 10:41 AM in C++ Programming

avatar image

Phenex
61 2 5 9

avatar image Phenex May 08 '15 at 11:31 AM

I found another big issue with my approach...

U cannot define multiple RPC server functions with the ame name that differ by parameter types...

(comments are locked)
10|2000 characters needed characters left

0 answers: sort voted first
Be the first one to answer this question
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question