not sure if it should be reported as a bug.
trying to init some stuff on BeginPlay for server version of the actor, and replicate it to clients, but BeginPlay doesn’t replicate it (multicast) to clients unless given a delay, as would the clients not yet exist at the time of the call.
the above fails, whilst the below works as expected. i would however like to avoid such hacky workarounds as time-dependent solutions are bug-prone as hell, leaving the performance damage aside.
That’s well known issue. It’s not a good idea to use RPCs on BeginPlay due to delay with actors spawning on clients.
For initialization you can use ReplicatedWith (RepNotify) properties.
For example you can create ReplicatedWith (RepNotify) boolean property “IsInitialized”, specify its replication notifier function and set its value to True in BeginPlay on server. Then, when actor will be spawned on the clients, IsInitialized will be replicated and your replication notifier will be called on every client. So this is a good moment to continue initialization on the clients and from this point you can use RPCs for sure.
thanks, seems reasonable. can you think of any other way that doesn’t use a variable? i would like to avoid extra variables as this class is heavily used in the game.
Just one replicated variable that changes and replicates just once after object initialization (begin play on server side) can’t cause overhead for the network at all. Even if you have thousand instances of such replicated class.
Variables replicate to the clients only if they’re changed. So if you’re not going to change values on each server tick you have nothing to worry about.
Just 1 kb for 1000 intances - one boolean variable per instance takes 1 byte. You can also use bitfields (c++ only) if you want to use 1 bit per one boolean. With bitfields you can pack 8 booleans of one class (instance) in 1 byte. So if your class has more than one boolean it makes sense to use bitfields.
Also, it’s not necessary to create an extra boolean variable. You can use any other “replicated” variable that you’re changing during BeginPlay on server side. In my projects I often use just last changed “replicated” variable in chain on server side. To the moment of firing replication notifier on clients all other variables in chain already replicated.
Anyway variable’s replication notifier is the only way to be sure that client is ready to work with RPCs after BeginPlay on server. Usage of delay/timers is the worst way - it’s noticeable for the players and leads to bugs (if delay/timer duration is less than real latency).
do blueprints really use 1byte per boolean? it sounds strange. i have always thought they consume sizeof(int).
i also do use bitfields but my first bitfields is already full and that would be the 9th and probably last boolean here, bummer indeed
i didn’t quite understand what do you mean by “last changed “replicated” variable in chain on server side.”. can you please try to explain in other words?
I see no reason to consume sizeof(int) for a boolean variable) Of course it’s always 1 byte.
“Last changed variable in chain” means last changed replicated variable in function. It’s not a term, it’s just an explanation. For example if you have three replicated variables in your class and you set their values during BeginPlay you need to have replication notifier only for the last changed one. To the monent of call of replication notifier on client, all replicated variables already up to date, since they was changed on server before the last changed variable.
regards sizeof(int), that’s how C++ compilers implement it. there are historical reasons behind it mainly as far as i remember, but sizeof(bool) == sizeof(int). nativized BP are translated to C++ bools i guess. i can’t say i know about the VM bools though
@Arty-McLabin The result of sizeof(bool) is implementation defined. Most of modern compilers returns 1 byte. You can check it here with desired compiler - Compiler Explorer
Blueprints work via C++ under the hood regardless of nativization.
@Acrossfy interesting. you seem to be right indeed. i guess i were trik’d in my early programming days and have thought that compilers use sizeof(int)=sizeof(bool) for better performance of assignment and memory movement. it seems to be indeed the case with .NET by the way, but it is irrelevant here :]