#multiplayer
1 messages · Page 256 of 1
Ya, just daily rant.
I think I enjoy using UE more than some people because of my past engine experiences 😅 (not saying you with this)
Ya I wouldn't still be using it since 2014 if I weren't enjoying it. Stuff like a drop of 60FPS when you have a BP Editor open just drives me nuts though.
wait so having bp's open while playing hurts performnace that badly?? lol this could be magnificient news tbh, cause i always wondered why my frames aren't nearly what some peoples are, but i typically will have many bps open while im testing things. or does playing in Standalone change any of that ?
This was just playing in the Editor. I rarely ever play in standalone. And performance profiling only matters in package builds.
Found what you're talking about. Made a change locally, and pushed the delta as PR, https://github.com/EpicGames/UnrealEngine/pull/13287, opened a UDN to get some feedback. Will let you know if there are hidden dangers they mention
editor for me has always been much worse, and i typically do standalone while testing things (not necessarily profiling anything) but good to know for ref if im having unwarrantedly low frames
Appreciated. Will forward that. Could you share the UDN post if it's public/available? My wife wanted to post on UDN next week anyway.
Are you actually still with Epic? Sounds like you are onto your next adventure but you still have the Epic role here on the server
My wife will leave a comment on your PR. Just fyi.
This makes it work.
Replicate Component is off, and where I previously just did the attachment serverside and let it replicate out, instead I set a property per-part with parent actor and relative transform, and the onrep of that attaches locally. Workes beautifully
is there a way to separate between ROLE_Authority and ROLE_AutonomousProxy on P2P mode ?
GetLocalRole() always returns ROLE_Authority for me and I'm not sure how to differentiate between both
There is no such thing as P2P in Unreal. Do you mean Listenserver?
Generally speaking, roles are pretty useless outside of certain specific cases I find. You probably generally want to care more about whether you're on server or not, and whether the pawn or controller you have is the local controller or is locally controlled.
yes
lol Datura changed his name just to counter it 🤣
LogBlueprintUserMessages: [BP_BasePotato_C_0] Server: Local: ROLE Authority
LogBlueprintUserMessages: [BP_BasePotato_C_0] Server: Remote: ROLE Simulated Proxy
LogBlueprintUserMessages: [BP_BasePotato_C_1] Server: Local: ROLE Authority
LogBlueprintUserMessages: [BP_BasePotato_C_1] Server: Remote: ROLE Simulated Proxy
LogBlueprintUserMessages: [BP_BasePotato_C_0] Client 1: Local: ROLE Autonomous Proxy
LogBlueprintUserMessages: [BP_BasePotato_C_0] Client 1: Remote: ROLE Authority
LogBlueprintUserMessages: [BP_BasePotato_C_1] Client 1: Local: ROLE Simulated Proxy
LogBlueprintUserMessages: [BP_BasePotato_C_1] Client 1: Remote: ROLE Authority
These are controlled pawns, only difference is that on Client1, the local role is different.
Also means there's no means to tell if the server is in "control" of the actor like you could with the Autonomous Proxy check locally on clients.
I want to implement multiple walking speeds. I imagine a RPC is the best way to update the speed, but would there be any issue if the speed was changed rapidly? Like for example if the change movement speed was bound to mouse wheel.
I see .. thx for the clarification 👍
You can, however, use IsLocallyControlled.
Which will be false for the Server on the Client's Pawn
How did you add the audio?
Only the root part has replicate movement turned on, physics replication settings are tuned a bit, and it behaves very well.
Not bad per vehicle
What do i do, if i have a gameplay ability (Local predicted) thats called on the client, where input from the player is gotten, for example the player is moving to the left during activation, but then when the server calls the function, it dosent get the input because its the server. And therefore the data arent syncronised, messing up the ability.
This is what my log from one ability activation looks like if it helps:
LogTemp: Error: === DASH ABILITY ACTIVATED === Role: Client
LogTemp: SDashAbility: ForwardInput: -0.000000, RightInput: -1.000000
LogTemp: Error: === DASH ABILITY ACTIVATED === Role: Server
LogTemp: SDashAbility: ForwardInput: 0.000000, RightInput: 0.000000
LogTemp: SDashAbility: OnDashFinished
LogTemp: SDashAbilityTask: Task Destroyed
LogTemp: Display: Dash Ability Ended
LogTemp: SDashAbilityTask: Task Destroyed
LogTemp: Display: Dash Ability Ended
Might want to use insights in the future 😅
The other thing is quite outdated by now
Use something both have access to, like the input acceleration of the character movement component
Or use targeting data and send the input over
okay thank you
so im a dipshit lol
i got my whole gun replicating and i was like man for whatever reason the ability handle is always invalid right?
the blueprint wasn't set to replicate
got another quick question
// Copyright 2025 Dale "Stropheum" Diaz
#pragma once
#include "CoreMinimal.h"
#include "Abilities/Tasks/AbilityTask.h"
#include "AbilityTask_OnTickEvent.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FTickEventDelegate, float, DeltaTime);
/**
* Fires an event on tick
*/
UCLASS()
class GASGUN_API UAbilityTask_OnTickEvent : public UAbilityTask
{
GENERATED_BODY()
public:
UAbilityTask_OnTickEvent();
// Am I implicitly replicated?
UPROPERTY(BlueprintAssignable)
FTickEventDelegate TickEventReceived;
UFUNCTION(BlueprintCallable, Meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "True"), Category = "Ability Tasks")
static UAbilityTask_OnTickEvent* OnTickEvent(UGameplayAbility* OwningAbility, const FName TaskInstanceName);
protected:
virtual void TickTask(const float DeltaTime) override;
void EventReceived(const float DeltaTime) const;
virtual void OnDestroy(const bool bInOwnerFinished) override;
};
do multicast delegate properties need to be marked as replicated or are they implicitly replicated?
my brain's a little sideways cause i'm learning GAS at the same time so i think there's a lot of built-in replication with tasks, effects, abilities, etc. so maybe every property inside a task is implicitly replicated
I am having a hard time understanding the best locations to put things for player specific information that relates to a game objective. For example, should this be on a player state or the game state where the team info is stored?
The team a player is on. Would this be better as an array in game state for teams and each team has an array of player states, or would this be a value on the player state directly and the game state checks their team when needed? Or should it be on both?
Is this something that really matters or is it just preference? I know that both have server and all client access, so it seems that it would work either way. I just don't know if there is an option that is less "safe" or poor practice for replication and management
No, they are binded and executed locally.
appreciate you
properties in tasks don't replicate. it's a little tricky to use normal property replication with abilities
usually better off with using target data
that's only if peers need access to the property right? the ability itself will just work?
Oh yeah, I was thinking about that as my last resort 👍
Checking remote role should tell you the same. But there is nothing wrong with islocallycontrolled
Well it should at least
Remote role of the other pawn should be auto proxy. But maybe not
That suggests it's not. I was ander the impression that the LocalRole and RemoteRole would be simply inverted.
same here, but then Datura made it clear
Something is not right though.
huh
Very first row shows what I would expect to see
yeah
And that table isn't even complete
Cause it doesn't list Auth -> Sim
Which would be the locally controlled one of the Server I guess.
I guess I'll play around with the code and double check
hmmm .. for some reason isLocallyControlled always returns true on the client who acts as server as well .. (in the pawn's Tick method)
Maybe smth is wrong with my project .. or with my engine version
IsLocallyControlled is true on the Pawn that is actively controlled by the player.
e.g. if you play only with the ListenServer, no Client connected, and you print on Tick in the Pawn, you get true.
If you have a Client connect afterwards, it should print two times true and two times false.
Client locally for its own Pawn -> True
Client locally for the ListenServer's Pawn -> False
ListenServer for its own Pawn -> True
ListenServer for the Client's Pawn -> False
huh .. so there is no way to separate between Server and Client on the ListenServer own pawn ..
wdym
I thought on the ListenServer, I could choose to do things only on server, and some other things only on the client of the same instance
so like, separating between ROLE_Authority and ROLE_AutonomousProxy on the same single instance
Yeah but you can. IsLocallyControlled is false for Clients on the ListenServer pawn
Well I keep getting IsLocallyControlled -> true always .. on the ListenServer's Pawn
I'll attempt updating unreal first to the latest minor version and we'll see
If the listen server is the one calling the function, ofc it will be true on it's pawn.
Imagine you are the server and you are playing with 3 of yours friends. Each possess a pawn.
The pawn that you possess will return IsLocallyControlled true (listen server or not) while the one that you don't possess will return false.
Yeah I get it actually, what I'm trying to achieve is smth like IsRunningDedicatedServer .. but while still being at P2P in a sense .. cause I'm just testing for now .. and wouldn't want to switch to a dedicatedserver architecture right now
but its probably not possible
hello everyone. if the server changes the value of a replicated variable many times per second like lets say 10 times per second, does that add extra network load for everyone? i cant seem to find the answer online and idk how replicated variables work under the hood
oh wait, I get it now
Alright imma try that
Changing a replicated Variable on the Server will cause it to mark the owning Object dirty whill will cause it to be regarded for replication.
So, yeah, if you constantly change a variable it will come with a cost.
do you know if its a significant cost? i am thinking of using it for my full auto guns
It's sadly one of those "it depends" ones.
You will need to profile your game to figure that one out
i see. thanks for the help!
I'd use NetworkProfiler specifically and check how much it takes .. cause that tool gives you a great overall look rather than Networking Insights which gives a very close look
Hi how can i solve the jitter in the right editor left one is the server , the photo is how i handle movement
check out L_PhysicsSimulatedCharacter from the "Mover Example" plugins.. dunno if it works for pure blueprint though
using direct RPC's to server to move the player like that wont work too well
How exactly do i set up targeting data?
Is it correct that i have to make this:
struct FGameplayAbilityTargetData_DashDirection : public FGameplayAbilityTargetData```
But how do i implement it in my ability? Is there any C++ documentation on this or what should i do to get help?
I'm pretty sure there are tutorials about this if you look around google or #gameplay-ability-system
This is usually used in combination with the WaitTargetData node
But there is also a new Targeting System iirc, which I don't know how that works
huhhh
?
Is it actually out in 5.6
If I have a replicated actor (spawned in game) with a non replicated collision component, I am assuming that OnBeginOverlap for that component will only get called on server (inside the replicator actor blueprint), after being hit by a player pawn?
or is it because the actor itself is replicated, onbeginoverlap gets called on client versions of the actor as well?
Even though the component isn't replicated
This.
Okay thanks, I think I may have had some duplicate calls
Hi, would you recommend any decent plugin for network smoothing?
SmoothSync
Anyone tried upgrading ACharacter::GetLifetimeReplicatedProps to be push based? Im curious why epic hasn't yet, there's a few classes they've shyed away from upgrading
Are there properties in there that constantly update anyway? Maybe the focus wasn't on those classes
If only one property is marked dirty the whole actor will be polled anyway 
I feel like every time I read that peeps are using this it's because they still have issues with jitter. I wonder if that plugin is not good, not correctly set up, or not doing what those peeps expected from it
Even using it may cause a lot of jitter 🙂 but it does the job if you don't wanna code smoothing
why is your function called Rotate adding force
Show the component layout of that thing with forces being applied, and also the replication settings
your space taxi is very similar to my vehicles, we can get you smooth as butter
it is rotating in x axis others are up-down etc
First off make 1 function that does all the forces and torques on that thing
it should be running on tick, you can gate by HasAuthority if you want but it'll work either way
Then make sure the thing simulating physics is its root component, make sure in actor settings you have Replicates and ReplicateMovement turned on
Have Component Replicates turned OFF for the physics simulating component
and then dial in your physics replication settings, I'd set position and rotation lerp both to 0
Also on tick, draw debug a box with different colors for server and client so you can see how smoothly it's following the servers state and when it corrects
Like this, see my red and green boxes for the tire hubs?
https://www.youtube.com/watch?v=0X7yCnfye3c
can i dm you?
SetActorHiddenInGame(true);
should this thing replicate? like for AI controlled characters
bHidden replicates..
Iirc that "thing" even causes actors to being non-relevant
I'm just thinking on how to implement death..
For now I'm spawning corpse actor with non looping death animation meanwhile hiding the original actor, before descturction
Depends on what you want to do. One way to implement death is to Tear the Actor off.
bIsDead
and I can't make it work good. There's a delay where I can still see the actor
Tearing the Actor off will call TornOff (or whatever it's called) on the Client.
A torn off Actor won't replicated anymore and the Client can handle the clean up.
That's how UT implemented its death iirc.
Well, "won't replicate" in the sense off the Actor is now cut off. It still exists on the Clients until manually removed.
The problem is that it takes time for SetActorHiddenInGame to replicate and it's not in sync with spawing of Corpse actor
Does the Corpse need to replicate?
yea
Like, the Actor itself
You could have a Struct with the bIsDead boolean and pointer to the Corpse Actor.
Spawn it "Invisible" and show it once the Struct replicates properly (OnRep)
In that OnRep you can also locally hide the dead character.
Then it should align time-wise.
why not just OnRep_bIsDead which makes them lootable and ragdoll and not controllable etc
Are you trying to predict death or does it always come down from the server?
the problem is not in death itself
void ASomeCharacter::OnRep_DeathInfo
{
if (DeathInfo.bIsDead && IsValid(DeathInfo.CorpseActor))
{
DeathInfo.CorseActors->SetHiddenInGame(false);
SetHiddenInGame(true);
}
}
fwiw, most peeps would probably just have the lootable corpse be the dead character directly.
Why do you have a whole other actor for the corpse? Why not just have the state of the character be dead
then you can get revival for free, voila, you're not dead anymore
But I guess nothing speaks against having it a separate actor if that is useful to you in more cases
I'd just keep that energy across the board
for PCs I'm not actually destroying them on death, just hiding them and teleporting to respawn location
but they leave their loot behind
so corpse is needed
why not just leave them there and make a new one?
do NPCs not have an ASC?
they do
IDK i like keeping things consistent but whatever works works
maybe you're right, I'm really new to all this stuff xD
I'm a really big fan of everything being as consistent as possible, but it can have its own downsides
Makes testing easy though, if there's litereally zero difference between a PC and NPC then you can just possess and NPC and drive them around and test them out
yea, ASC is on the Character. that's why I do it this way :/ I don't care about NPCs ASC, since they dont' develop, but PCs ASC is valuable. there's some stuff being saved, like experience gained, stats and so on. I also save it in persistant storage, so I can restore any time. But I use it on login right now only.
why I don't save it on player state, I read some stuff that it's more expensive network wise and thought my game could have like 50 people online on one server. So it's a bit less to replicate.
I found the issue people. I have invisibility component that I run on client to hide/show actor depending on it's visibiltity to particular player and it wasn't taking into account that character can be dead 🙂
so the death flow was hidding an actor, but the invisibilty component thought that it was supposed to be visible
(now it runs on tick, which is meh, I will redo it later on events, but now too lazy)
here s the trick that works for me. I had similar issue and read your comment. It also helped me to fix it.
so you have to make bAutoManageActiveCameraTarget false to make the new GameplayCameraComponent works on the client properly
@thin stratus have you or your wife worked around https://issues.unrealengine.com/issue/UE-261257 ? Was thinking of just forcing the update
Welp, went to use Chaos Mover, if you turn on the plugin it crashes on startup, good start 
guys, how do I make sure that StaticMeshComponent got StaticMesh replicated to the client after SetStaticMesh?
Why are you even still trying.
Don't think so. But I think if you have further Iris questions you might as well DM her directly. I only ever learned how to use Iris.
I'm sadly banished into the NPP/Mover corner, fixing that mess.
There is a target fix on the issue, so I assume there must be a CL sitting around somewhere.
The StaticMesh property is not replicated. You need to handle replication of that with your OnRep variable in the Actor that has the StaticMeshComponent.
So I put ReplicateUsing on the property of Component, right?
No. You need a StaticMesh variable in your Actor that is ReplicatedUsing.
The Component doesn't need to be replicated.
Ah. Okay.
in your case the mesh asset is dependent on some other data right?
just replicate the minimum data needed to figure out what mesh to use
Scary bug... I tried just forcing the net update and it seems to work okay
// something listening to OnTickFlush etc (I guess post tick would be smarter)
UNetDriver* NetDriver = GetWorld() ? GetNetDriver() : nullptr;
if (NetDriver && NetDriver->ClientConnections.IsEmpty()) {
if (UReplicationSystem* ReplicationSystem = NetDriver->GetReplicationSystem()) {
ReplicationSystem->NetUpdate(DeltaTime);
ReplicationSystem->PostSendUpdate();
}
}
I think you could probably skip ahead to the clear out bit but I'm too lazy to use the macro to expose it
I would probably run this at some interval because it's a bit expensive
btw, earlier I set ReplicateComponent in blueprints for it. It's not needed? Because now I get some ensure and warning message about static mesh being changed without calling notify :/
they told you the component doesn't need to be replicated so no
your goal is to send information about what mesh it is, not the state of the entire component that will never change besides the static mesh
you COULD replicate the compont if for some reason it is worthwhile to replicate all of its attachment state and pay for handling a new network object
this damn checkbox is so conveniently there xD
you can just check it and forget it exists
I also talk to chat gpt about it, the advice is invaluable xD
First it advised to give it a lil of delay, then to wait a lil bit longer
nothing cleans up those lambdas and they should probably just be weak
createuobject expects a full member function though iirc
Yeah.
but yeah chatgpt is already creating unsafe code here, very useful...
If you create code using chatgpt, you deserve what you get.
I think delaying one or 2 frames is not a bad idea though for many rendering related things with meshes etc
many visual artifacts can be avoided that way
but the way it's doing it here sucks
just changing it to CreateWeakLambda with the object as the weak handle should be fine
I wonder is there any case in the universe when you should wait 2 ticks? xD
this lambda lifecycle will be attached to this?
how so? you are just passing a lambda
you don't designate anything to own the lambda
if you wanted to you could store a handle to the lambda and manually reset it
With what you've done, the moment the actor (?) is gc'd, your game will crash.
I mean it's highly unlikely it will be gc'd within 2 ticks, but edge cases...
why assume that when you don't have to
Indeed.
nono, I'm not doing it. I actually try to not use lambda anywhere xD
Actually the funniest part for me was - waiting 2 ticks. that's funny 🙂
lambdas are just fine provided you are careful to not do one of a couple things
- never capture stuff by reference in a lambda that will outlive the thing that it has as a reference (for example a local var)
(totally fine in things that fire once and are no longer used etc) - dont assign non-object tracked lambdas and ignore cleaning them up
meh, I can kind of imagine there being some weird case where you need to wait one more time
that's weird but I can see it being a thing I guess
[&] is the devil
and yeah use & all you want for things like "find by predicate" where the lambda is no longer used after
but for long-term lambdas like delegates like timers etc you are going to explode in subtle ways
it's possible to manually copy things into weak ptrs in the capture arguments for example
which is a nice way to basically make damn sure you can't get tripped up by GC
Capturing shared pointers in lambdas is the best debug problem.
also accidentally messing with the containing memory in a lambda or something
like a for loop that moves the thing its iterating on
I honestly am surprsied what you can get away with without a check firing sometimes
although that has nothing to do with lambdas
no lambda's here
lambda's are like regexp. Once you want to solve a problem with lambda you have two problems
Hey yall so my friend did some testing on multiserver replication plugin and he managed to get it working
Here the video
In this video we explore the hidden MMO server in Unreal Engine 5.6. We cover how it works and how you can set it up.
Open World Server 2 & Hub World MMO Discord: https://discord.gg/qZ76Cmxcgp
There some additional explanation in his discord lounge channel
Its really cool
Maybe @thin stratus would be interested in this since i remember some brief discussion on this few days ago
when you're using SendMessageToUser you specific a flag and this one is the one reliable, but if you want to send data larger than k_cbMaxSteamNetworkingSocketsMessageSizeSend (which is 512x1024 / 524288), what flag to you want to set (also needs to be reliable)? This flag seems to send upto the max socket message size send and I am wondering if there is a way to bypass that for sending several mb of data
I'm not, I realized it's an immediately stupid idea because it all uses async physics and the input latency sucks ass
just using vaei's push pawn now with some hacks, fuck it we ball
My camera is attached to my 3rd person mesh for camera movement, i also have anim notifies that play particles on certain animations, when i play those notifies the particles play twice, once in the 3rd person mesh that i cant turn off because of the animations and once in the first person mesh, i cant really turn one or the other off since the game is multiplayer. Whats my best option to have the third person mesh anim notify not play in the owning client?
You probably don't want to use unreal's built in networking to send that large amount of data. You'd probably be better off just establishing a TCP socket server and sending through it..
Hey, do you have any good plugin for chat recommendations?
show your code for how you're playing the particles
its not code, its just a notify in the animation
but i was wondering that maybe there is a way to turn them on/off in code
What does the notify do?
it just plays a particle effect
oh so you have 2 anim instances running on all machines, just the mesh is invisible
ye
just don't run the anim instance when mesh is invisible
so cam is driven by 3pp anim but mesh is hidden, and 1pp is visible for owner?
ye
sounds like a mess lol
well, thats how the default fps pawn is setup if i am not mistaken, i just went with it
does anything about the 1pp mesh or anim matter for these particles?
You can probably make a custom anim notify that chooses whether or not to play based on if 1pp or 3pp and if locally controlled
I made two functions in my Inventory component one is destroy actor on server one is destroy actor Multicast.. When I remove the item I call the destroy actor on server and pass the actor but it only works on the server on the client the actor is not getting destroyed.. How can I fix this issue? Anything you need in regards of helping me.. Screen shots etc just let me know
Just delete every multicast from your project
is the actor a replicated actor?
if it is, just destroy it on server and it'll go poof on clients
multicasts have their place but they are pretty much mostly useful for either stuff that's transient or where data has to stream as fast as possible to everyone
The actor is set to replicate and I handle the destroy actor on server.. but client doesn't destroy actor only server
show the code
all the code leading up to the actor being destroyed
no
just destroy actor on server right after the event called Destroy Actor On Server
that's it
Show how the actor gets spawned, then show the entire code path from input (the button you press) to DestroyActor
https://blueprintue.com/blueprint/9mvnkwj_/ easier to share blueprints this way
then I press the button and call remove attached item wich is the first code I sent you
the remove attached item function has the destroy actor at the end
i didnt know this was a thing, i will take a look into it
put breakpoints and make sure execution makes it to the end
might not be finding it
It's coming up as not valid.. when I remove it from the equipment slot
Destroy actor is never called
Now I just gotta figure out why
Man im stumped
Figured it out.. thanks for your help @dark edge
what was it
What's the right way to replicate a physics door's movement without it getting out of sync when lag is involved?
Had to destroy the spawned actor instead of using the find node
That means you weren't setting the map value to the spawned actor to begin with
just replicate movement
depending on what you mean by lag and out of sync
I put min and max latency to 250 to test and sometimes the door moves differently on client than how it moves on server, this then causes it to be out of sync until the client one reaches the same position of the server again. This makes it so that, for example, the client can go through the door even if it's closed on his screen
it should never be permanently out of sync, is the door the root component of whatever actor?
show the component layout
I just noticed there's a Net Update Frequency option under replication, would that make it better by any chance?
if you turn on Component Replicates it'll work
it'll be shitty though, the network physics smoothing ONLY applies to the root component of an actor AFAIK
Oh yeah I tried that before it jitters a lot
That's why I wanted to try something else
I think that might be your only option besides making the actual door bit a separate actor
I was reading an article about Physics Prediction but it is experimental on 5.4
Thanks for the explaination btw
What about the fact the door takes like some milliseconds to open when it lags? Is that fixable in some way or players that lag will just have to live with it?
that's mostly down to the fact that character is predicted and this door is not
is your game "Characters and Doors: The Game"?
And character is kinematic and door is physics
you'd probably have better luck and smoother action just making your own door system
Characters and Doors: The Game 3 - Revenge of the Windows
I though that using rep notify etc would suffice
that's what I use for my vehicles, so the settings are a lot looser than you'd use for doors
🗿 Yes
your character hits the door on your screen ping/2 ms before your character hits the door on the server and ping ms before it hits the door on other clients
What happens if 2 characters barge through a door in opposite directions at the same time?
They both see themselves getting there first
so who wins, which way does the door go
add physics on characters and live with lag
lol
don't do that
I do that but my things aren't characters
lag is fine for tanks and war contraptions
I was honestly contemplating the option of using GAS for my doors too to fix the 2ms delay fix (so that GAS could take care of it hopefully) but I'm kinda lost ngl
You basically have a spectrum between:
"Everyone sees the exact same thing happen, in the exact same order, and with the exact same timing, but with latency between their inputs and anything happening in the world"
and
"Everyone sees their actions play out instantly, but they all fundamentally disagree on ordering and timing. You need to hide that discrepancy"
you could cover up latency with the headbutt anim
Yeah I'll just live with the delay tbh, at least the door opens at the same time on every client
🙏 for real
I think Halo did that for grenades
I though I solved it
a grenade toss is slower on performing client than on others, so it enters flight at the same "time" on all screens
are people opening doors and peeking or slamming through them?
That'd be crazy work but It would work
Just opening, and they simulate physics only while open
I'd just predict the opening
and favor the shooter
someone has to be right, it's better that it's the guy lookng where the bullets are going than the other guy
yeah you're right I'll do that
thanks for the help
My door simulator game is growing day by day lol
This game finna be a banger
Time to kickstart it.
what are your door settings, i'm curious
just actor replicates and replicate movement, with the mesh simulating physics and a constraint so it can only swing
I'm talking about the physics replication settings where you can tune how stiff the corrections are and when it snaps
I have two static meshes and two replicated physic meshes for turning off and on for clicking on clients
I just wonder if mine is a bad idea
I have a door open and door closed static and physical mesh that I alternate physics and traces
and other things
If you want physics replication smoothing the mesh simulating physics has to be the root of the actor
afaik
sorry I was on the phone
anyways the door
my doors have a trigger to set the unit that comes near as hostile and attacks
if they are hostile doors
friendly doors auto open and close
terrible system
On this topic, I now added the fact that the door also opens on client at the same time as server, so on interacting client it opens instantly and on others watching it opens 2ms late, you mean something like this, right?
you have an OnRep for a variable controlling whether the door is open
it will give you the right value for late joining people
the OnRep you manuall call on the listen server if that is hosting the game
that is if the server does the interaction
if the client does, fine, do a client -> server RPC to open door, set the replicated variable, that varaible has an OnRep
which tells the client to swap the physics mesh and render mesh with open instead of closed
Yeah I do that through a server custom event, but with 250 ms it would open the door a bit late on client, so I added this visual feedback of it opening instantly even if it happens only on client, basically I open the door on client AND use a rep notify to open it on all other clients too through the server
how do you move though the open door
Since the delay is very small it's pretty much unnoticable even if you ran into it while opening it
On the other hand before you'd just look at the closed door while waiting for the little delay, making it feel a bit junky
i think you're thinking about something I want to solve
I'm just wondering if just doing the logic twice, one on rep notify and one on client is the right way to do it
the problem is that rep notify fore movement is one way
there is one source for movement for Ai Moveto
assuming that iss what you are using
I'm dealing with player interaction right now
ok
I don't really know how I'do that with an AI task tbh
In that case I think the delay shouldn't be a problem if you are using rep notify, but I'm no expert
sorry cat one sec
I run the server sided one before the client sided one if that's what you are asking
is this prediction?
so mine is a command based AI with issuing breaking commands to state trees
if that helps
I don't think so, I just give the visual feedback to the client to make it feel less junky I guess
is that with mover?
Never used state trees lol
whats a mover
mover 2.0 vs CMC
i've run into a ton of issues moving characters with the new system vs the old
things that don't make a lot of sense
This is the first time I hear about mover 2.0 so i dont know nothing about it
I just use the cmc
then no worries
your multiplayer should be simple then
i mean, "Mount Your Friends" sold a million copies so why not
Fact, door simulator is the way to go
Hey folks, I wanna try myself on multiplayer. Do you have a library or a tutorial to recommend?
The pinned messages have some great stuff
Ight good thanks
250 ms gonna sucks anyway.
If you allow client to go ahead how are you going to reconcile incorrect unsyncronized value?
Prediction makes the game feel smoother but you can't get away with everything and a lot of time you just have to live without it.
Think about if a door can be locked. Another player with lower ping already lock the door, but you went ahead and open the door before you receive the locked state from the server.
So how will you fix that situation? By telling the player psych your move is illegal and gently close the door back?
Good point, you think I'm better off not letting the client going a bit ahead?
Cause I was probably gonna add a locking mechanism
For a door, I will not predict it.
interaction in general shouldn't be predicted imo
It's the same as picking up item.
You pick it up instantly but in reality someone else already picked it up because you have high delay
Some things you can get away is like the visual stuff
E.g dropping ammo count in hud.
Normal melee attack should be predicted too as well as movement.
I see, but with the high delay on items I can pick it up more than once
since it doesn't disappear instantly
I guess that could be fixed with a "do once" or something maybe?
How would you fix this? I'm kinda lost
Yeah I'm thinking how I'd do that
I would try hiding it locally and adding a small timeout to check the real state from the authority or something, not as a new command but just checking if it should actually re-show itself just in case the pickup transaction was rejected
the pickup just still existing in-world might serve as the indicator it wasn't picked up
I could make it not interactable after one interaction and hide it on client but doesn't that mean that someone with higher latency could still see it and pick it up before the server makes it disappear?
Your server should validate that it is an alive item before granting it anyway
High latency players are expected to have a degraded experience.
I don't mean predict actually picking it up, I mean predicting that you TRIED to pick it up locally and visually represent that
Oh I see what you mean now
https://youtu.be/h47zZrqjgLc?t=1601
this presentation is a pretty great example of how you can make something responsive but also server authoratative
In this 2011 GDC session, Bungie's David Aldridge discusses the programming that drove Halo: Reach's online networking.
Register for GDC: http://ubm.io/2gk5KTU
Join the GDC mailing list: http://www.gdconf.com/subscribe
Follow GDC on Twitter: https://twitter.com/Official_GDC
GDC talks cover a range of developmental topics including game des...
the grenade throw is shown visually as an animation, but the REAL grenade doesn't appear into ping~ time later
Ohh nice thanks for the link
but since there's a hand shown tossing something it feels fine because something happened when they pressed a button
a bit more simple than picking stuff up but the idea is similar
And that's what's important
Yeah, thanks for the help and the link
Tomorrow ill look further into it and try to fix the fixable, I can't help a players that lag too much but at least I don't want item cloning and stuff like that
for example I think if you wanted to you could have the "I want to pick something up" sent immediately and have the server negotiate "speeding it up" based on the ping of the sender within reason
that way if the animation for picking something up is 200ms or something you can send it ahead of time and then advance by their ping, then send back the result faster for the higher ping (an extreme example, 200ms is quite high)
some games will allow things to be predicted up to a certain point, for example battlefield will actually make your bullets non predicted once you exceeed a certain ping
theres a lot of different ways to do this kind of thing
Doesn't seem easy BUT would surely make a great result without giving autohority to server
client*
focus on just making it work transactionally first imo without issue
Tomorrow I'll have to dedicate my day to master this networking stuff a bit
At least I can give a great experience to a high latency client too
Thanks again 🙏
https://youtu.be/h47zZrqjgLc?si=NdosPQgvzg-2OvEk&t=5289
Hint at Destiny lol
Overwatch has a similar example with the grenade of the Cowboy.
We do the exact same thing, it works.
The throw animation comes into the center of the screen for a few frames, which helps hide the latency.
Players dont notice a thing
Up to a certain ping of course.
We have a pool of local (predicted) projectiles and a global (server authoritative) one. When people do anything projectiley it uses the local one until the server confirms it, then moves the predicted one into the right spot in the global pool and moves the one from the global pool into the prediction pool, or just resets it if it's unconfirmed. Makes things very smooth. Never really any corrections.
Our projectiles just do local sim with no server updates, unless they bounce or hit something, then the server sends an update to make sure the client's still doing it correctly.
Isnt that similar to what UT did?
Quite possibly!
Do you guys just smooth the predicted one to where the auth one is when it comes down?
Yup
It actually works just fine, tbh.
Apparently Mover is simming the player latency-time into the future anyway, so when it sends a fire request to the server, the position it thinks it's firing from is already roughly where it should be, even accounting for ping.
Nope. Just players. We have a backwards reconciliation thing which handles projectile interaction with players.
Certainly helps if they are the only thing they dynamically interact with
Pretty much players and projectiles are the only things taht really move, but it should just work generally for anything. Other than players, all our stuff is just simulated client-side with the server sending a correction on important events, rather than constantly.
And that's working fine with player speeds of 300+ kph.
We actually had a problem with projectiles being fired at high speed because we didn't realise Mover was already running the local player in the future, with respect to the server.
Yeah high speed stuff sucks
tribes??
The only advantage of high speed is that, generally, you don't change velocity all that easily.
Unless you hit something.
Tribes-inspired, yeah.
yeah but man, the cost of missing is crazy high
I wish the built in cmc interpolation was more tweakable honestly
We got fed up of HiRez being HiRez, so we did our own thing 😄
it's frustrating it extrapolates hard-coded
sometimes extrapolation is undesirable
had to roll my own thing
Honestly this is the kind of thing that led us to use Mover, tbh. Our physics guy didn't like the bulkiness of character/cmc and was like, "let's try mover" and we never really looked back.
effin' A' this is annoying
replicated attachment doesn't work without Component Replicates
but Component Replicates clobbers movement replication with physics
hot take: you could probably rip out the physwalking/physfalling and replace them with mover's and get pretty close lol
I think you're the only person I'm seeing saying anything good about Mover, lol
You could make your own attachment replication system?
you would need to make sure it updates floors the same way
Yeah that's where I'm at, just OnRep some Parent, Transform struct and call it a day?
Make it atomic and you're away!
yeah and you can probably make one that isn't 50 separate properties which are going to explode instantly
what do you mean by atomic
If you have a struct containing the parent and transform, and mark the struct as atomic, it will always send both at the same time.
yeah just making it a struct would do that right? Nothing I gotta do to make sure I don't get half a struct somehow
So you don't get an attach parent or transform being sent without the other.
is splitting it an option otherwise?
oh wtf
TIL
By default struct properties are independently replicated and may lead to data that isn't quite in sync.
lmao i thought jsut being in a struct made it atomic
E.g. a frame or two of attaching with the wrong transform.
might explain some weird bugs I've had
😄
you could seriously just swap to iris to try it out, it's not a big conversion unless you have many custom serializers and rep graph
for now just try the simple thing by marking it atomic I guess though
YES SIR I AM AIMING AT 40,234.53333, 0, 0 FOR A FEW FRAMES, WHY DO YOU ASK?
What's the elevator pitch for Iris?
It takes you to a different floor
vastly faster than the default but doesn't support everything yet, no replays
it's mostly seamless for simple replication without custom serializers
and most things in the engine have the iris conversion done already
Whats the catch with custom serializers? Is it just some new function call or something?
you don't really benefit much unless you have many replicated objects though imo
oh god lol, if only
it's a massive chain of macros and templates that is 4x more code than the old setup but much faster
Lovely
but default iris serialization is so good you might not really need it most of the time imo
What about FastArrays?
Cool
you just change them to be IrisFastArraySerializers
Nice
Do you actually have to do anything if you just mark the stuff you want as Replicated and want regular ol' replication?
default Tarrays are also delta serialized now
but you can't onrep per instance so fast arrays are still useful
They certainly are useful
no, default replication works
I love them
notice the part where I mentioned it's mostly seamless unless you use repgraph and many custom serializers
I have mostly 1-2 with constantly changing state per player so yeah probably not worth the trouble
What are the advantages of custom serializers specifically? Like some use cases?
however you may find some small subtle changes in onrep order depending on how much you rely on those
being able to not send things you don't need to
Hmm .. so if I may ask, does the projectile just uses a normal ProjectileMovement component ?
for example the hit result custom serializer is very aggressive. it will avoid sending nearly anything if you don't have a hit
by default it would send the things as zero'd with a bitset for the ones that are zero'd iirc
which is still small but not as small as a single bit
We have our own version of that, but, yes, something very similar.
Nice
ultimately a custom serializer is for
- things that aren't serialized by default that you want to serialize
- you knowning that the existence or absence of some information precludes needing to send others, or needing to customize or forward the bits to something fancy
Does Iris have a way to send data similar to an rpc that isn't attached to a property?
Or do you still use regular rpcs?
Iris uses all ofthe regular replication onreps, and rpcs of the regular unreal netcode
it's just different internally
I see .. in my case, I'm just going to try to put the movement logic for the projectile, in the character's Mover .. as projectiles essentially just goes straight with constant speed
Cool cool.
but then still have gonna have some hard time with the projectile prediction and mispredictions
Sounds like a lot of overhead
If a projectile just flies at a constant velocity then it's just a function to figure out where it was or will be or could have been at any time
What is purpose of struct FGameplayEffectContextNetSerializer, GAS has bunch of it with Iris.
that is a custom net serializer
it is needed because those are not simple types that can have automatic serializers created for them
Its quite easy if you just subtract where the Projectile is from where it isn't.
This is exactly why we don't use mover for them. We know exactly where they should be based on a start point, initial velocity, gravity and current time. We send new starting conditions if it bounces.
and voila, Verlet integration
for this one it mostly is just forwarding the types to other serializers
If it takes more than 2 nouns to name your type, you don't need it
iris is not about simplicity lol
I honestly think they kind of goofed with how annoying serializers are
the speed is there but it feels like... I don't really think we need this most of the time
Tim's vision of Fortnite does though
Many years ago, I made a type with like 60 characters in the name lol. It generated equally spaced points on a sphere given a minimum separation distance.
So you'll take it and you'll like it.
SphericalPointSpacer
That's 3.
1 adjective and 2 nouns
The code is not simple as you said. 
Well true.
yeah I would say you are not going to need to make a custom iris serializer most of the time
Is a serializer just "Jam the info I need in as effecient as possible of a format and also here's how you unjam it"?
it turns the passed in struct data into a bit stream
oh well, so you mean .. just separate it completely from character's Mover 🤔
that should be less complicated
and you read the EXACT SAME (or else) amount of bits on the other end
that's how you can turn a uint16 into 8 bits
with some statistical analysis you basically... compress it
so for example the first bit can denote it being 0
if it tends to be 0 often, that's nice because now you can send 0 as a single bit
but now it's not zero, so you set that first bit to 1, then now what
I mean on average
this is just an example, it's all a game of hierarchical "branches" where you use a bit to say "actually, there's more!"
so for example if you have a uint16 and 99% of the time people only sent values that use the first 8 bits
Seems like this is "cross it when you need to" territory unless you know you're having to do some serious bit hosing
We have our own system for this based around the needs of our game's networking. We went a bit ham on it. It basically replicates a tcp/ip type system with serialized data over unrealiable rpcs 😂
you can do something like
XIsNotZero, (bits 1 to 8) BitThatSaysWeEndOrUSeMoreBits (bits 2 to 16)
my guy didnt you just reinvent reliable
again
Yes. It was a lot of fun!
So basically if most uint16s are only using the lower 8 you only need to send
0,(0000 0011) 0 (denotes done)
(0000 0000) (0000 0011) etc
instead of
but the cost is for the actual situation of needing the full range of bits you have 2 extra bits, but who cares
At what amount of kbps/client do you start thinking about this stuff?
what's a good sane limit
almost every type in the engine is quantized fairly well as is
most of your transforms are already sent as a fraction of the real number
64 bits per double is a lot
and yes I think if you don't have much moving around in the game this is mostly pointless
less data is always good but how much it really matters I am not sure
the built in limits are quite conservative
as for what to aim for I am not sure, it would depend on target hardware
for example a wifi phone game is going to get punished hard for wasting bits due to the shitty speed
the largest optimization will be just not sending as many updates for distant objects in most games
We use that 7-bit with a continuation bit encoding quite a bit.
yeah it's 99% of serialization
very much just "a bit that denotes if there's more stuff or not"
Iris does a lot more to help make masks per member for you which is cool and can delta serialize per type
but I'm not really sure how it compares to the old setup for a typical actor
I can say for damn sure it will be at least partially faster cpu wise, it is insanely tryhard C arrays internally
I'm sure it depends on what needs to be sent and when
"hey you exist here" isn't much average bandwidth
yes it is depending on the object
We use a byte with bitflags a lot too. Denoting whether some parts of data is there or not, how big it is, etc.
if it's new from relevancy the bunch could be quite large and might even include new unmapped packages
the question I am most frustrated by: how the hell do you know when it's too much?
Yes, that's UTs implementation. Although whatever UT did can probably be done more gracefully nowadays.
generally unreal just kinds of stops sending things as much when it starts capping out and there is... no feedback at all for why or when that happens
insanely frustrating in an engine that is generally good at advertising wtf is happening for stuff like this
basically at a high level each connection has a cap of bandwidth
and once you hit that unreal will stop sending as much and stop writing
until it waits a bit
for example you might start seeing properties coming in slower or over time that used to be nearly constant
One of the reasons we actually did our own thing is because we were getting reliable rpcs just dropped for no reason. They'd be sent and never received in low fps situations.
one issue with low fps is that you get super debt
where you are getting expensive incoming onreps and rpcs
and then you take so long you are already falling behind the next packet
so every frame is just "oh god, more onreps"
so keeping onreps cheap is kind of a must on low end hardware
they are done all on the main thread even in iris
the gameplay code has to be of course but even the dequantization
This was the client sending them to the server. It was silly. Literally GAS breaking itself because reliable rpcs weren't being received.
So synchronisation broke almost instantly. The replications keys failing.
then don't use reliables imo if you can help it
Not much we could do when it was GAS using them.
We don't use GAS any more because of these issues.
unless this was all gas reliables on top of things, yeah...
GAS does a lot of fancy things to make it cheap over the network
but there's only so much it can do
when its sending like dozens of replicated subobjects etc
So do we now. 😛
GAS is a bit confusing with what it sends to sim proxies though, sheesh
part of me wishes that reliables could be sent in distinct channels
We probably do bad things to our network performance with all this tbh.
where you want to make sure it arrives, but don't need other reliables to wait on it playing back
But Mover is still 90% of the traffic, so fuck it.
also fun fact Iris has a way to send rpcs faster to clients
you can send earlier in the frame
free -10 ping basically instantly lol
Nice lol
of course this assumes you can send it back that way
and don't need to rely on a game sim frame
oh yeah, and check out network insights if you are worried about bandwidth
it will show exactly what is huge
it's a bit broken in some ways with how it shows things (some state is not represented well like huge attachments) but it will catch the obvious things
the most common mistake imo is people sending massive floats/doubles when they rarely need to
or just sending things that are sort of self-evident or could be represented as a single thing
I reckon there is an art to knowing what you need and what you dont.
yeah, and what to prioritize and why
if someone were to make some eisenhower matrix version for networking, that could become some revolutionary invention 🤔
you can prioritize object replication already
sure
Hey all I am sending mic data from client to server, at first the client does the rocording and through an RPC call I am sending chunks of data over to the server, where it is reassambled into a .wav.
It works, but I am not sure about the packet size and how frequently I am sending it. Currently I send 10000 byte in a timer event of 0.03 second.
What would be the safer range for bytes to send? Thanks a lot.
Sometimes clients get disconnected from the server, I think it is due to the rate in which we are sending the packets
raising the bandwidth limit in config should help a bit
also consider just compressing it a bit, I don't mean reducing quality either
also you say " I think it is due to the rate in which we are sending the packets"
it should log the actual reason for the disconnect, I don't understand why there is a need to guess here
if the log is ambigious I guess that's fair but you need to at least check that first as a sanity check I think
[2025.05.28-06.35.25:175][600]LogBlueprintUserMessages: [BPC_VR_PlayerCharacter_C_2147482375] Audio Packet Size on Server: 10000 Total Audio Buffer Length: 15041280
[2025.05.28-06.35.25:175][600]LogBlueprintUserMessages: [BPC_VR_PlayerCharacter_C_2147482375] Audio Packet Size on Server: 20000 Total Audio Buffer Length: 15041280
[2025.05.28-06.35.25:176][600]LogBlueprintUserMessages: [BPC_VR_PlayerCharacter_C_2147482375] Audio Packet Size on Server: 30000 Total Audio Buffer Length: 15041280
[2025.05.28-06.35.25:176][600]LogBlueprintUserMessages: [BPC_VR_PlayerCharacter_C_2147482375] Audio Packet Size on Server: 40000 Total Audio Buffer Length: 15041280
[2025.05.28-06.35.25:176][600]LogBlueprintUserMessages: [BPC_VR_PlayerCharacter_C_2147482375] Audio Packet Size on Server: 50000 Total Audio Buffer Length: 15041280
[2025.05.28-06.35.25:177][600]LogBlueprintUserMessages: [BPC_VR_PlayerCharacter_C_2147482375] Audio Packet Size on Server: 60000 Total Audio Buffer Length: 15041280
[2025.05.28-06.35.25:177][600]LogBlueprintUserMessages: [BPC_VR_PlayerCharacter_C_2147482375] Audio Packet Size on Server: 70000 Total Audio Buffer Length: 15041280
[2025.05.28-06.35.25:177][600]LogBlueprintUserMessages: [BPC_VR_PlayerCharacter_C_2147482375] Audio Packet Size on Server: 80000 Total Audio Buffer Length: 15041280
[2025.05.28-06.35.25:178][600]LogBlueprintUserMessages: [BPC_VR_PlayerCharacter_C_2147482375] Audio Packet Size on Server: 90000 Total Audio Buffer Length: 15041280
[2025.05.28-06.35.25:178][600]LogBlueprintUserMessages: [BPC_VR_PlayerCharacter_C_2147482375] Audio Packet Size on Server: 100000 Total Audio Buffer Length: 15041280
This was the last print from server. There was no error about networking. It just stopped sending it.
not even on the server?
This is from the server
so what about the client log?
Client log sadly is not available, as they are on shipping build.
then test without shipping or enable logs in shipping
So sending 10000 bytes, in 0.03 sec is fine? I am only asking because I could not find info on it what is a safe range to send in a RPC call.
what is the configured TotalNetBandwidth in your game ini?
https://forums.unrealengine.com/t/bandwidth-limit-is-10kb-s-irrespective-of-settings/351414/4 see this forum post for how to raise network bandwidth limits
are you just sending raw wav audio?
You really oughta be using some compression library
and yeah like I said it is kind of unreasonable to not at least compress this a bit
No, we are sending bytes to server, and server creates the .wav for us
you can compress into lz4 in like two lines, here
Sure, thanks a lot for the help! 🙂
I mean are you sending raw or compressed audio?
I realize it's all bytes at the end
it is raw mic data
void FBattlementRepSystemState::CompressAndLogForStyle(TArray<uint8>& UnCompressedDataBuffer, const FName CompressionName) {
const size_t OGDataSize = UnCompressedDataBuffer.Num();
TRACE_CPUPROFILER_EVENT_SCOPE(Full state send Compress);
int32 CompressedSizeEstimate = FCompression::CompressMemoryBound(CompressionName, OGDataSize, ECompressionFlags::COMPRESS_BiasSize);
RepBytes.SetNumUninitialized(CompressedSizeEstimate);
int32 RealCompressedSize = CompressedSizeEstimate;
const bool bCompressed = FCompression::CompressMemory(CompressionName,
RepBytes.GetData(),
RealCompressedSize,
UnCompressedDataBuffer.GetData(),
UnCompressedDataBuffer.Num(),
ECompressionFlags::COMPRESS_BiasSize);
const float Pct = (((float)RealCompressedSize / (float)OGDataSize) * 100.f);
BUSTERLOG(LogTemp,
"BattlementStateRecorder size {ogsize} compressed with {name} est: {estSize} result: {actualcompressedsize} ({pct})%",
OGDataSize,
CompressionName,
CompressedSizeEstimate,
RealCompressedSize,
Pct);
RepBytes.SetNum(RealCompressedSize);
OriginalSize = OGDataSize;
}
bool FBattlementRepSystemState::DecompressAndLogForStyle(FName CompressionName, TArray<uint8>& OutResultDataBuffer) const {
if (OriginalSize < 1) {
return false;
}
TRACE_CPUPROFILER_EVENT_SCOPE(Full state send decompress);
//stream?
OutResultDataBuffer.SetNumUninitialized(OriginalSize);
return FCompression::UncompressMemory(CompressionName,
OutResultDataBuffer.GetData(),
OutResultDataBuffer.Num(),
RepBytes.GetData(),
RepBytes.Num(),
ECompressionFlags::COMPRESS_BiasMemory);
}
Yeah you need to not do that
you're basically streaming a CD per player
in my case NAME_LZ4 was the best for size
There is certainly some sort of VOIP built in, I'd use that. IF you need the raw values for gameplay purposes like REPO or Lethal Company, you can extract that
Thanks! The bandwidth was not changed from the default. So we will increase that as well.
the ini settings here are tricky, they expect changes in both game and engine
you can send 1% the bytes
but yeah please compress this either way... this should compress pretty well
game ini
[/Script/Engine.GameNetworkManager]
; Increase from the base bandwidth, numbers need to match ConfiguredInternetSpeed in DefaultEngine
TotalNetBandwidth=200000000
MaxDynamicBandwidth=200000000
MinDynamicBandwidth=200000
engine ini
[/Script/Engine.Player]
; These numbers should match TotalNetBandwidth
ConfiguredInternetSpeed=200000000
ConfiguredLanSpeed=200000000
My numbers here are entirely arbitrary
basically be default unreal divides the total net by the number of players
discord defaults to 64 kbps for audio, you're sending 2640kbps
default is like 32000
I have no idea what scale this is in
I assume bytes but I am not sure
can also set this directly with APlayerController::SetNetSpeed
but idk how well that works in practice
ok changed project config, so I should change the engine as well then?
you need to have a game and engine ini for your project
I don't mean changing the config file in the engine, I mean changing the engine.ini IN YOUR PROJECT
they should look like this
Right got it. Thanks!
it might help to confirm this actually works by breakpointing the net connection creation flow
wat on earth... who is sending this rpc??
ah this is sent post login
it halves it which is funny because... the other player is the server
oh unreal
probably some other case I missed
Yeah, this is why I added custom quantisation and packing to our data!
honestly just not using giant types will get you 90% of the way there
Yup
Movement Replication issue
Hello hello,
I just wanted to ask as I'm getting mixed answers looking this up, when using FFastArraySerializer is item order always preserved between server and cleints?
Nvm a quick search in the discord gave me my answer, it's a no 🙂
Yeah this is steams API, which is a socket, but it's got a limit on the size of the data to send.
ah yeah this would be steam ip
it'd be cool if you could somehow pipe a raw socket through steam's relay servers
maps aren't replicated but you can still use them to store info server side and then get 1 of the 2 parts and send that info back to clients right? you just can't have server set varaibles of a map as a whole and have that fully replicate down to clients, if i understand that correctly
yep
nice , ty
Hi, I'm having bit of trouble with understanding mover2.0. I'm using pawn as player and need for him to be replicated.
I started going through the MoverExampleCharacter in mover plugin and copied his c++ code to my pawn so i got character motion component, because i wasn't sure which part of mover should i use as i didn't found any easy way like just to turn replication on/off.
Now to the troubling part, if i have my custom logic for the flying pawn how should i go about replicating it? Do i need to completely scrap it and remake it with only logic from character motion component(are there any functions which should i specifically use ?) or should i go about it like with rpc that i do my own implementation of movement and then just pass my transform to some function of motion component? I'm bit loss as even in the MoverExampleCharacter the movement is done with NavMoverComponent so not enough for me to comprehend whole logic.
you just put your logic in a method that you bind to mover's PreSimulationTick
that way it'll happen everywhere, on the clients and the server
More in details:
you basically prepare your input values that you want the autonomous proxy to send to the server inside ProduceInput
and on a method that make and bind to PreSimulationTick at BeginPlay, you take the input and use it to perform the actions such as move the character or whatever you wanna do with it .. and it'll happen everywhere on the server as well as on the clients
If i want to make a multiplayer game that is hosted on dedicated server is it nesecarry that i get ue from Source on the github instead of from the launcher?
I want to create multiple movement speeds. I will use a enum to indicate which level I am on. Would I just send a RPC when I want to change speeds?
ok this is a fun race condition
RepNotify to attach Component A to Component B, then set B to simulate physics
if there's any delay between the attachment and the set simulate phyics, A's connection to B breaks
if there's no delay, it's fine
Yeah from more testing, simulate physics first, then attach, is totally fine
but when the attach happens first, setting simulate physics breaks the children's attachment on clients
I hate this fucking engine sometimes
question, im working on a basic scoreboard where players can join in progress and im trying to figure out the best way to handle notifying the HUD that a player has connected. currently, i create the HUD widget, iterate over the player array from the game state and create entries that way to get all the initial players out of the way. then i bind to an event on the HUD itself which fires off when a player state registers itself with it. so on the player states begin play i get my own local player state, make sure it doesnt equal the player state im testing against, then i register that player state on the HUD. this is unreliable since in order to get the hud i need the player controller which means i need to access the player controller from the player state which often times replication has not been received, so on and so forth. the only thing i can think of with this approach is to use UGameplayStatics to get the first player controller and player state which since this would be a listen server game should be fine, but id still like to avoid doing so but it would atleast be able to access my local controller
You don't need the controller. Put a delegate on your GameState that runs whenever a playerstate is created or removed. Make your playerstate call this on Beginplay and Endplay. Alternatively you can also override AddPlayerState and RemovePlayerState in C++ that maintains the actual array.
GameState is available on all machines at beginplay since it is what triggers it, so your UI should have access to that delegate immediately. Bind, and update from the existing list and then handle additions and removals on the delegate broadcast.
that was another thought but i realized i have my hud and such in a separate module but completely forgot i could just put the delegate on an interface in my core module adn throw it on teh game state -_- thank you lol
It's private, and while PostRepNotifies is public, half of what you'd need to access to reimplement it with changes is private. It's annoying.
then disable the replicated property with the macro
also if it is an exported type you should be able to directly write it with a private access template
but I don't think extension is possible without someting even hackier
I'm not trying to say this is easy, it's always frustrating when things are locked down for no reason
It's SceneComponent.Transform
Basically all sorts of shit breaks and needs workarounds if my physically simulating component is NOT replicated, but if it is, then it keeps getting clobbered by the component just directly setting its world transform
I had that too. The code I posted you resolved that though
I also attached in the OnRep, so not only on the server
Also you don't need to tick Replicate Movement on the actor that you attach. It gets moved by the attach parent anyway
The actor got attached and the relative offset is probably 0,0,0 somehow. That's why I set the world transform once more iirc
Which code was that?
I screenshotted you one the other day. Would need to look it up
If I did it with a different combination it ended up like your video
Have you tried set simulate physics after the attachment though?
It's set simulate physics that does it, it seems to clear attachment of children on client, but they still get their "parents" physics replication state
so they sim on their own between replication steps
I only had simulate physics active on the main actor and from the start
Yeah if it's already on it works fine. I mean I can work around it but still it's a pretty major bug. Something somewhere in the onreps is relying on a replicated component when it shouldn't. The child ends up in a weird state where it's not attached but is still along for the ride when its parent recieves updates.
Hello hello,
Is the proper way of serializing a TSubclassOf just Ar << Class? I technically already have it working in a TMap replication NetSerialize (as a key) but just wanted to confirm as I'm not super familiar exactly with how that serialization is done
Another question related to Fast arrays, is the ReplicationID of an item always consistently the same for the client until that item is removed from the array?
yeah
tyvm 🙂 that's super helpful
It kind of wouldn't make sense if it wasn't a stable id.
true yeah, I just had a look at the code etc and that's the unique ID for the item
random Q, does anyone have a take on animating vs transforming when it comes to replicating simple movement/state changes in semi-dynamic objects in world? let's take a simple door, open/closed states, would there be any reason to even debate the differnce or is that really going to come down to preference?
Well, animating would imply a skinned mesh which might not neccesarily be what you want
Really depends on the context. Some doors might be too complex to animate with simple transforms, but others it might be more desirable
yea this is what my instincts leaned toward, and i didn't even consider the skinned mesh for the animation , so in most cases, i wouldn't really want that. i have random things like consoles, mailboxes, that i'd like to make certain transforms for different states, but they are just meshes rn and i was considering if animating them would be the better approach to their state changes vs transforming cause they have more than 1 part needed moved at times, which would be slightly more complicated to manage, but doable
Hey is Non Seamless server travel with command ex "ServerTravel AventinoArena" "ServerTravel mapname" .......
Long question short answer
Does server travel even work in UE4 and UE5 ?
Bots just go frozen
And map just stands there when initiated from client
" the console command "
Long story short answer
Does dedicated server can server travel ?
And if so How to invoke it ?
Also what is the best way to achieve a not seamless server travel or maybe only ?
It really is necessary or the server won't restart and there will be a lot of dead bodies
or the player will have to rejoin all the time
help

Does anyone know if it is possible to create a component and runtime and have it replicated?
I'm wanting to create some UStaticMeshComponents on the server and have them replicated to clients. I know you're thinking just create them on each instance, but I also have GAS-based actors that are attached to these meshes and they need to be created from the server. I can't see a simple way of attaching the GAS-based actors to the mesh component on the client, since I'd have to wait until each of the actors are replicated to each client.
I tried using ReplicateSubobjects to replicate the mesh components, but get an error about the component not supporting networking
This works.
Is the 100 player match limit for Iris hard or soft?
Huh?
For the new Iris Network replication, it said it supports up to 100 players. I don't know if that is a hard limit, or soft and just recommended.
https://dev.epicgames.com/documentation/en-us/unreal-engine/introduction-to-iris-in-unreal-engine It says it supports up to 100 players.
You can have as many Players as you like. However, whether you can support a given number of players is entirely dependent on how performant your game is.
Alright, then it's a soft limit. I imagine it depends much on what is replicated, and how often.
The system builds on Epic's experience with Fortnite Battle Royale, which supports up to 100 players per server instance.
Oh.
Its saying Fortnite supports 100 Players
I mistook it meaning Iris itself.
That's good to know. I think with replication the only thing you need to send every tick is movement. The rest can just be when it gets changed, ya know?
I think you have a lot to learn.
Probably? But, if things aren't changing every frame, I would think that would be the case? Especially if it's a background variable.
One of the worst mistakes you can make as someone new to Multiplayer, is thinking you should make a game with 100 Players.
Start small, learn the ropes.
😬
Multiplayer isn't something you tack on at the end. Generally speaking, you either make a SP game OR an MP game.
I'm asking for the future.
You dont make an SP game and then make it MP later.
Ok.
If you want to support Coop, your game is not SP
Its one or the other.
Not both.
Not SP then MP
Ok. I'm not going over semantics. Thank you for answering my question earlier.
Im not going over semantics either, im being literal
You will rip your hair out trying to turn an SP game into an MP game after the fact
You can make a single player game multiplayer after the fact, but you'll basically be making the entire game again, completely differently, and it probably won't be able to work how you made it to work in single player at all T_T
Just what I was about to say.
Is it possible to replicate a wildcard value in c++?
what exactly is a wildcard value here
you can send instanced structs
and replicate arbitrary objects
A property that accepts anything
Like FVariant
Could be a bool, float, int, fstring
I tried FVariant in the replication event but it wouldn't accept it
You could with Iris and a serialization customisation.
@bitter pine InstancedStructs might be a good place to start.
Thanks i'll look into it
I think it will work!
Way better than...this
an instanced struct would involve sending an entire scriptstruct ptr
you could write a small variant that doesn't even need a custom serializer imo if it just reinterpret casted
with a byte/bits to represent the different kinds of thing
how do you do that
I set it up so I have a system where you can dynamicly add values to a component with a tmap with FName as the key and FVariant as the value and i'm trying to replicate over the key and value through a event
since you decided to mix plain data types and a dynamic type like FString actually I think maybe not
nevermind lol
you would have to forward the value to the fstring serialization scheme
as a string can have an arbitrary amount of data
honestly just stick with FInstancedStruct for now unless you have dozens of these sent a hundred times a frame
FInstancedStruct uses a bit more data and can only send one thing at a time than something hand made but you don't need to get fancy here if it's just for some rpc that only happens periodically
you would still need to choose what to do with it on the other side either way fwiw
I feel like suggesting iris serialization to someone who isn't aware of instanced structs is kind of brutal... that is like just about the most complicated way to solve this I think
that said the option is there of literally just sending exactly what the variant does
/** Holds the type of the variant. */
EVariantTypes Type;
/** Holds the serialized value. */
TArray<uint8> Value;
which does not require any special serializer... you can just use this as is
(EVariant types would probably need to be sent as a byte though of your own type etc)
So when compare sending Instance struct vs instance object, instance object is smaller right.
True 😂
smaller how?
the overall bytes? I am actually not sure exactly how they would compare
an object sent over the network as a replicated object is not just some bytes, but also a shared replicated object they can pass data to later
an instanced struct is just one property
Instance object from data asset should send as path instead of dynamic UObject, If I guess correctly.
I'm curious now how close much extra data a UObject with a single float propert is vs sending TInstancedStruct<Float>
you said instance object, of course if it's a shared network addressable it will send the path
the way the path is sent depends and in iris the path will be sort of negotiated over time as a network export
aka it sends the full path first and then they agree to send it as a smaller id afterwards
The downside of a UObject is that you have to carefully manage it's lifetime and manage it's replication via an Actor if it's not stably named, which is usually why FInstancedStruct is preferable (in some cases, ofc)
But, FInstancedStruct can't do delta replication of it's properties, whereas a UObject can (potentially).
Yeah if it's something long term a true specific replicating property owned by an object seems better
LogHandshake: Server is running an incompatible version of the game IrisReplication vs Generic
So I am having a lobby in which my players connect, after connecting and pressing start game, a server travel will happen into my gameplay map.
(I am running this as standalone game, listen server, 2 players, and I am using AGameMode, not the base version)
The AHud gets initialized for the server but not for the client, the Begin Play of the Hud doesn't get triggered for the client, any help?
Are you setting the hud class in the game mode?
On the game mode of the lobby map?
Or is it the traveled-to map that doesn't get a hud?
Does anyone know if, with UE 5.6, that modular movement component system would be stable enough to run a single ship actor in a 4 player game (with about 20-ish replicated enemies)?
I phrased it that way because I know I read someone that had tried it mentioned in here some time ago (around the release of 5.5) that it was super inefficent (at that time at least).
I have a ship that will land / take off with the players at the start / end of every level and I was thinking maybe I would try to use that new component.
What's the difference between normal UE replication and rollback networking?
If rollback networking is what I think it is, it's comparing different things entirely. UE replications just sends data about updated properties. Rollback networking I think would mean that when the data is received, everything is rolled back to when the data was sent and resimmed to account for it.
E.g. You press jump, the server receives that 40ms later, it rolls everything back 40ms and re-runs the updates from there, including your new jump.
when using the function "event destroyed" is it safe to assume that it won't "destroy" until after the event? like if im pulling from variables that are on that actor that is being destroyed will it still have those variables during that event ?
i changed it so that the fucntions i was calling were just done before destorying, felt like there was a bit of a race condition on some things as i wasn't getting some varaibles back at times but mostly it was working * (mostly working = not working in my case)
yes, thats the whole point of the function, to clean up stuff if needed
but i think that if you run a IsValid check on self if would be false because of potential tags
nice it was nice and convenient so was hoping i could continue to utilize but did change slightly , but think it's for the best in my case
Unreal replication is just a means of making data the same on server and client
It's arbitrary how you use that data
Typically most unreal games use a snapshot replication netcode style where you receive state as-is most recently on the server
But the CMC for example is akin to a small rollback sim on practice as it involves playing input back on the server to validate prediction the client makes
Unreal has some experimental Rollback physics replication but it's still partially snapshot based
True full rollback involves a completely deterministic sim which is very very difficult to do in unreal unless you run your own simulation entirely
But you can use the idea of playing back inputs that you predicted alongside snapshots etc
The CMC on simulated proxies is just snapshots smoothed though, but it does partially sim locally
Netcode is very freeform in practice
Lots of ways to do things with different drawbacks etc
Friday brain. Can somebody help me logic this out.
I want a chest with a persistent state: Open/Closed
I'm thinking I need a RepNotify (isOpen) so that the state is shared with late-joiners. On the transition from Closed to Open, I want to play an anim and scatter loot, but I don't want to trigger the anim each time - only for the initial open.
If I understand RepNotify, then late joiners would see the anim upon entering net relevancy, right? So how would suppress the anim and only show it the first time?
*As I type this, I'm thinking maybe a multi-cast of the anim before the RepNotfy, but is there a better way? *
Struct TimedState
Time TimeOfChange
bool bState
OnRep_TimedState -> if abs(CurrentTime - TimeOfChange) < SomeValue -> do the transition stuff
I think in C++ you might have more options to play with
Would that be better than an MC pre-change? I figure TimeOfChange would be redundant bytes.
does a few bytes every few minutes really matter?
you're already sending thousands per second
Valid. I'll give it a shot, thank you!
My apologies Server travel works for dedicated server in ue4 and ue5
: D
: d
So good
Well wait wiat
this is listen now that I think about it 
nvm
emmmh not sure because the client can do it
too
call the cheat -> server travel
but the host is listen
Soon to check
Oops I got confused
Are you answering to your questions. What's up?!
I'm really struggling with widgets.
I had widget components on each actor as their health bar. This worked perfectly for singleplayer.
Now I've added local multiplayer, the widgets don't work as obviously they are screen space and only show for Player 1.
I've tried a few different approaches, but I can't work out the best way of getting every player to be able to see the health bars on their own screens
Has anybody got any advice?
Have you read the network compendium pinned here? It's important to have a good understanding of the network architecture to diagnose and debug this issues
Is reliable rpc guaranted to arrive in order or that is something that needs to be checked manually?
Like you are in the lobby, travel to the game map and then one player wins. you travel back. where to I save the info about the winner player? and how do I keep track that the right playercontroller is awarded if I only have the index?
Let's say I have an event A called on server and marked as reliable, and an event B called on server and not marked as reliable. If I call event B from within event A, will event B occur reliably or unreliably? I know you are not supposed to call server RPCs from server, however what if there is a difference in this reliability flag?
I think it simply wouldn’t matter because unless your net* relevancy is like super short distance, I feel the anim would be played well before that player even gets to spot where that door is. I have similar functionality for doors via on rep and I’ve never seen the anim play when I get back into relevancy as it most likely already “played” when I was approaching or before I could spot it. If more complex animation/transform or maybe something quite large that can be seen from far then I could see that maybe needing a specific use case but think you’d be ok to use the repnotify to handle it and not worry about it opening
Another option (that may have some issues) is to use a multicast to start an animation/timeline that opens /closes also spawns effects.
Within the multicast, you can set the state locally to whatever it’s supposed to be.
Within the OnRep, you can check if the timeline is already playing, and if not, you can directly set it fully open or fully closed.
I don’t regularly work on netcode, but with a bad enough connection I think it’s possible to see the OnRep open the thing well before a multicast comes through, which will look like it re-opens. If you want, you can check for this within the multicast, then it would just look like the thing suddenly opens.
Edit: ah you did already mention this whoops
Depending on whether players can late join, you may need to send joining clients the server time when they join, for use in calculating relative offsets like this
Within the same actor reliable RPCs will be in order
For persisting data, check the pins on this channel for the Persistent Data Compendium. I believe it has better information on how to track players without relying on the index of the player as well (unique net ids etc)
not guaranteed afaik
really?
awesome thanks a lot for the resources, I thought that order was not reliable
thanks, I´m going to check that out.
For best practice. How would a programmer get around a race condition with the player state and the HUD? (This race condition seems to only happen in multiplayer, singleplayer is fine just FYI)
So for me, I am creating a widget on the HUD Blueprint that needs to read variable data from the Player State. The HUD BP initializes quicker than the Player State. So on my Begin Play on the HUD Blueprint. I am getting Player State NULL references for the first 1 - 2 frames of the game. Yes a simple delay can fix this. But that feels like such a dirty solution programming wise. I am using Blueprint only.
Currently I am doing Event Begin Play > Checking validity of the Player State, if it's not valid, I will delay 0.2 seconds and loop back to check if it's valid yet, and if it is then run an Event that I do on the HUD to read data from the Player State. Is this right? (For best practices here) Lol.
Don't rely on Begin Play for replicated stuff, you should use OnRep from the property you need to make sure it's ready
What I'm doing is, is on the HUD Blueprint. I am creating a Player HUD that has a textblock showing how much cash I have on my player. (Which is saved in the Player State) I have set a default value to 50 for the cash but the thing is, the player state reference in the widget is null upon creation as the HUD is initialized first before the Player State even is. I'm not really replicating it at this point. Just trying to show the default 50 value I have set with the cash variable. Soon enough I will get to the part where the value does change and replicates. But creation is the issue.
Delaying the HUD EBP by 0.2 seconds allows the Player State time to initialize and grab the default value and set correctly firstly. But it's a race condition. and I feel the delay is a dirty solution for the race condition.
I've seen many just do a macro of some sort where they do a Validity check of a reference to something and do a timeout/fail after 10 seconds if the reference continues to be null. Best/Easiest solution I guess.
Player State is replicated, so you still need to rely on the OnRep event if you need the player state for the HUD. This kind of race conditions are common in multiplayer
It's a bad idea although it technically works
There is no On Rep Event in Blueprint for Player State. That is C++ only for that one 😦
Ouch really? I use C++ so I have no clue
Yeup.... Blueprint is really good with what is exposed already but yeah those things hurt a bit 😦
It would be REALLY nice if Blueprint had Events for PlayerState, HUD, etc called OnInitialized or something be default. That way we can technically use that.
While a lot of programmers are against it. Quite honestly there's nothing wrong with waits in UI and you have to get used to it. Due to the async and laggy nature of networking, you can't always rely on things being ready. Even if you find a way to, it's fragile. It's both easier, and nicer to simply put throbbers on widgets, and make them check every frame of every few frames if the state they need is ready like their associated playerstate or pawn being ready and then doing whatever they need to bind to to listen for other changes. Your UI will be a lot more resilient to code changes from gameplay's side.
@kindred widget Appreciate your input on it. I'm one O.C.D freak when it comes to ensuring the right way to doing things. 🙂
Heh. I feel you. But the right way is always subjective to a lot of factors.
This is currently what I'm rolling with, and I mean, it works obviously. But yeah..
that's an interesting take
It's not much different than any other UI with waits. A webpage for example. You open it up and if it needs to request data, you're given a spinner or whatever and you wait til it arrives.
You log into some place and wait for the callback and better UIs have a little spinner thing.
Games shouldn't be any different. You know that the framework always has a PlayerState for the local player eventually. There shouldn't be an issue waiting for it.
You can very easily end up in delegate hell in UI with all of the async nature and waits. And while event driven updates are nice, sometimes it's just not worth the hassle given how spotty the delegate access is in BP where 80% of UI work is done.
With me doing a validity loop check for a Player State for a UI to read some variable data from is definitely from what I'd imagine okay to use what I've made above ^ As @kindred widget said, everyone gets a Player State eventually, it's not a maybe. Just slow sometimes. But for other things that may not ever spawn / be referenced, you'd be doing something quite bad to loop forever like what I've done. It depends on its use case for what you're trying to reference.
This is what I've gathered now haha.
I like this approach. I was mostly thinking from a gameplay code perspective where OnReps are pretty common and clean. But ofc that mostly works in the actor that has the replicated data.
Even then you made me think if a well written system to wait for replicated variables could work in some scenarios at least instead of having lots of OnReps
fwiw, some of this becomes a lot simpler if you do it in C++.
For the question with a Widget and the PlayerState, I would usually have a simple Delegate in my PlayerController that triggers when the PlayerState is valid in its OnRep.
In the Widget I can easily get the PlayerController, cause you usually pass that in as the owner when creating it, and then I either get an already valid PlayerState or I listen to the Delegate.
In some cases, like for example the Pawn, I would listen to the Delegate even if the initial Pawn pointer is valid, cause that one can change throughout the game.
Looping for the PlayerController to be valid is a bit strange depending on where you create that Widget though. That one should be valid.
Showing a throbber until things are valid has nothing really to do with this question, imo. You'd do that either way. But if you don't like the Delay stuff, a Delegate in an OnRep is usually the answer.
So because I am all Blueprint here, I cannot do the On Rep Player State way you mention yeah?
Yop, tons of things are locked behind C++ for Multiplayer. You barely have access to the tip of the iceberg. Multiplayer without C++ is a pain.
For some simple fun gimmic game, you can toy around with Blueprints, but once you want to make something bigger and more worthwhile, you will need C++.
And that's not even about the shitty performance Blueprints have if you need to build a bigger game.
It's a bit sad that Epic never expanded blueprints for multiplayer things like that to give us some more simplicity. Yes I know we should use C++ more so than Blueprint for these sorts of things. But you may as well give us access in Blueprint anyhow.
I would rather have it Blueprints would have less nowadays.
The amount of optimization work our company has to do on projects that started with blueprints is not even funny anymore.
Blueprinting is such a powerful GUI and what it's capable of doing though.
But yeah understandable
Yeah, that's fair, but there should be limits. They turned into quite the mess tbh. They sort of promise that nice visual scripting, but ultimately, if a project grows beyond a given point, they are a trap
And I don't mean to not use them at all.
But Multiplayer needs so much stuff, so many custom types etc. that Blueprints will never get access to, that they will never be viable.
You can't even make a proper inventory system for a multiplayer game, cause the FastArray stuff that is in theory needed is C++ only.
You can't override any of the NetSerialize logic.
Hence why we need to use replicated Structs per slot to save Item data and use Data Tables etc I guess?
And probably 90% of functions and variables that are useful and make life easier are locked behind C++.
It's not even about that. Traditional Array replication replicates the whole damn thing.
FastArray only replicates changes.
Yikes moment. Anyone want some lag lol.
I'm mainly saying people need C++ for Multiplayer, cause of all the functions , types and variables that are locked behind it.
E.g. GameMode gives you PostLogin in Blueprints, but not PreLogin and Login.
BP has no access to ULocalPlayer. No access to AGameSession.
BP has no access to tons of OnReps (we only recently got "OnControllerChanged" in the Pawn exposed to Blueprints.
Absolutely. I knew C++ was always better. I just have always done blueprinting and have been doing it for 8 years now I think. I guess they will focus more on allowing their new Verse language in the future to be capable of everything. Because they obviously don't give two craps about Blueprint support it seems for a Multiplayer perspective as much, sadly. I don't know why they don't just open more up for us in the end.
Epic really did Blueprint dirty with some things. sad lyfe 😦
We have to stick to quirky ways
Also that OnControllerChanged one was nifty as shit. Like come on man. Why they be so lacking now haha.
