Is it possible to create a struct with dispatcher built in?

My problem:
Character stat struct:
float Base
float Additive
float Multiplier
float Current

What I want to achieve is:

  • Whenever a value changes I want “Current” clamped to 0, (Base+Additive)*Multiplier.
  • Whenever a value changes I want to call an event dispatcher

If only I get the dispatcher thing working I’m already happy (as I can achieve the other through some extra time).
I’ve seen that the FVector and the like structs in the system have some functionality, like operations and the like in them but I saw no dispatcher done and what I’ve managed to find on this topic wasn’t really reassuring so far.

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Stat.generated.h"

/**
 * Containes values for Character Stat data along with dispatch on value change.
 */
USTRUCT(BlueprintType)
struct FStat
{
	GENERATED_USTRUCT_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "StructTest")
	float Base;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "StructTest")
	float Additive;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "StructTest")
	float Multiplier;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "StructTest")
	float Current;
};

Is it even possible to have a sort of built-in dispatcher in my struct so if I have a 100 I can bind to each of that 100 one by one? For example, character movement buff changes maxspeed so I change speed on the character movement component. Writing a “SetValue” function by hand for each and every variable in my character attributes seems like an utterly ridiculous proposition.

Dont think so on UStruct but you can on UObject

That is how it’s done. I wouldn’t overcomplicate the struct because it’s just a “dumb” container to hold data, you usually do implementation on whatever uses that struct for its own purposes. So a component tracking health, magic and stamina points would implement a setter and an event to execute when the setter is called. The struct is not aware of anything, it’s just used to hold stuff for the component. Specific logic doesn’t rlly belong in the struct.

Technically you could run over all struct properties on tick and check if any value changed (think of widget property bindings) but obviously that sucks for performance. There is no generic “if changed then do” for all data types.

Testing it on every tick sounds like unnecessary overhead by default. Putting an event/dispatcher call within SetValue works just fine for 1-2 variables but I have much larger numbers.

Tried a map where the key is an enum with the name of the stats basically while the value is a struct of the floats mentioned above and writing a single SetValue function as all of the clamping uses 1 single logic of max=(A+B)*C. My problem is that I kind of want to replicate the values and Map doesn’t have replication afaik.

The original approach/workaround I had was using an array where the index of the value is the same as the Enum index for the given stat and it does work buuuuut… it’s an array and setting up default values or anything by hand in blueprint etc. is a pain.

Tbh.it feels more and more like I should set up the enum through c++ so I can avoid the atrocious clicking when adding 1 enum entry in the middle of 50 and find a workaround to the Map/Dictionary not replicating problem instead :).

thats basically what i did but with GameplayTags instead of Enums

Yeah, enums have some quirks I don’t like but on the other hand I can use their indexes as it’s pretty much an array of strings.
But I guess what I originally wanted isn’t possible so I should just mark that as the “solution” and look at my goal from a different angle. Like since the character stats are mostly just affected by modifiers, buffs and the like, those getting replicated as the players do need to know what is the cause of their problems I can just simply Not replicate the struct and let the functionality on the client side deal with the updates as the modifiers roll in. Server side is the only one that really matters anyways.

your on the right track, I create an attribute actor component, i put the event dispatcher in there which returns the AttributeGameplayTag

Then i Set/Get attributes by Tag and whenever it changes it calls the dispatcher

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.