#multiplayer
1 messages Β· Page 38 of 1
Are you crashing?
No
Then it's probably not null
I see widget in my windows
Then what's the problem?
C++ Widget creation. π¦
I think I'm getting too spoiled by UIExtensions, and CommonUI
Then I don't understand at all how to debug it, when ScoreWidget is null and when PlayerName not gives me understanding with what Controller I am dealing
Probably. In most of the projects I work on, those aren't used
If it would really be null, then you'd crash on that line
To be fair, they're super new.
Make sure you compile with DebugGame Editor and not Development
2 possibilities.
The class you provide to the createwidget is null or it's not of the type you're casting to.
Oh, Now I worked with Development Debugging
I chose it in the Blueprint of that class
Are you using the BP version of the class?
Yep
Like Cedric said though. If the pointer was actually null, AddToViewport would crash.
Creating a BP subclass won't do anything if you use the c++ class instead.
This sounds super useful. I'll look for some more information for implementation.
Does your BP_PingPongScoreWidget derive from UPingPongScoreWidget ?
Yup
Ok see this is why details are very helpful
Recommend giving these a quick watch for some speedup.
https://www.youtube.com/watch?v=TTB5y-03SnE
https://www.youtube.com/watch?v=uQisYatymjg
https://www.youtube.com/watch?v=u06GAVxyIag
So that simply doesn't work. There are ways to transfer custom structures over the network, but you still need to identify them, like through an enum, otherwise you don't know what you need to parse
Will Choosing the DebugGame Editor help me to Debug?
Honestly just easier and better will be to make arrays of the known structures that you have, like you have FClassDefinition, FItemDefintion, etc... and just transmit those
As a TArray<FItemDefinition> they can't be pointers
It is that I'd learn by passing some cources
Also I call sus on transfering that data from client to server and telling the server what to do!
Add an extra line of code, similar to: c UWidget* Widget = CreateWidget(this, blah); ScoreWidget = Cast<blah>(Widget); ScoreWidget->AddToViewport();
Then debug the value of Widget
Much better if there's a choice involved is to have all of those on the serverside, and the client call tell the server which of the configs you want to play with
Or may need to be UUserWidget*, I'm not sure.
Ok, and about DebugGame Editor
How it can help me?
CreateWidget also has it's own templating. No need for the extra cast verbosity.
I know, but it simplify further actions for me
UUserWidget* SomeWidget = CreateWidget<UUserWidget>(Outer, Class);
Assuming it is a UUserWidget.
I heard in the past epic was working on a way to unify client prediction with GAS and the character movement component to remove a double RPC if you use both, but they canceled it as the guy working on it left.
Does anyone know of the current state of this or if iris will help with this?
Ahh okay, thanks
You should talk to Kaos about that if you catch him around. He's done some RPC batching stuff I think.
Ahh interesting, thanks :)
Do you think tapping into the iris replication may help with the double RPC issue with GAS and CMC?
Don't personally know anything about Iris, but at first thought I'd assume that it has nothing to do with RPCs. I assumed that it was like ReplicationGraph 2.0
Thank you!
How do you debug multiplayer while coding project on c++ (for example, on behalf of which copy some line of code is executed)
Simplify your tests to one item if you can, and check it's role in breakpoints usually.
In Blueprints there are convinient that you see, in which client or server some block is executed
But now I should do that homework from cources on c++
Uff, I remember a twitter post that said something about a param that would help with this
But it's quite vague
Should it help me to understand on which client or server that is performing?
It helps to see on which side the breakpoint happened
Ok, I'll try to use it
xD how, I didn't even post it, cause I can't find it
Is there any function to determine whether the running game instance is a listen server?
Write your logic so that you never have to debug for Multiplayer outside of underlying issues with the engine
Hmm...
If you don't know whether your logic is being executed on the server or on the client you need to go back to the drawing board of the networking basics. That should be second nature, makes the game development of a multiplayer game a ton easier
In BPs you can just check IsServer
In C++ you can also check the NetMode
As all the RPCs are annotated as to where they run
@verbal tendon tbf, if you breakpoint BeginPlay, Tick, or any other function that executes on everyone if an instance exists, it can sometimes be tricky to know who actually caused the breakpoint
The solution is to not use breakpoints! π
I want to make sure that every line is performed by the right side
That is something you ensure by simply writing correct code though
I want to write a game that can be run in both dedicated and listen servers.
A blast occur only in the client or listen server.
I write incomplete code as follows
void AMyProjectile::Destroyed()
{
Super::Destroyed();
if (GetLocalRole() == ROLE_SimulatedProxy)
UGameplayStatics::SpawnEmitterAtLocation(...);
}
It works for a dedicated -- the blast occurs only in clients.
But it does not work for listen server -- the blast does not occurs in listen server.
How to fix this?
Because your Listen Server is both a client and a server
Also .... I would not develop a game that can run both dedicated or listen servers
Make a choice
Duplicating code base is a nightmare to me. π
You're either going to be providing dedicated servers and paying for them, or you let people host with a listen server
This is the only extra info ive found on Iris.
""Why use Iris?
One of the main reasons why one should consider Iris for their project is reduce friction between networking and gameplay code and to get rid of reliable and unreliable RPCs.
Iris replaces many virtual function calls with explicit API calls to achieve this.
One example would be how Relevancy is managed with Iris. The result of IsNetRelevantFor is now controlled by the new Filters that are introduced with Iris.
For RPCs, Iris changes the way when the calls are executed. They are being delayed until after the target of the RPC has had their state data updated.
Therefore the order of execution stays reliable and consistent, removing the need for unreliable RPCs""
There's no duplication of code?
You decide whether your game will be using listen servers or dedicated servers
that's a binary choice with no code duplication involved
Having a multiplayer game logic that caters to both listen&dedis is not a good idea
I will consider it later. π But right now, I want to know whether there is a function to determine the running game instance is in a dedicated server and not a listen server.
if(not_in_dedicated_server())
SpawnBlastingActor();
not_in_dedicated_server() returns true when the code is running in a client or a listen server.
IsRunningDedicatedServer
Dont say later that you weren't warne
warned π
There's nothing particularly wrong with allowing both. There's plenty of games that allow players to host a game while they are playing and also provide the option for players to host their own dedicated servers so they can have it hosted separately and have it always running if desired.
Is it normal when doing a get owner on an actor, the name is different on the server and the client or should they be the same ?
It works also for just a spawned actor that is present on the server and the client
like I have this on the server "BP_DesktopCharWithSkel_C_2147482384" and this on the client "BP_DesktopCharWithSkel_C_2147482215"
you can add {,,UnrealEditor-Engine.dll}GPlayInEditorContextString to your debug watches, when stopped at a breakpoint it'll tell you if you're client 1, client 2, server, etc
Ok, thx
It's normal. Objects aren't always created in same order, or with same names from client to server.
Thanks !
I have an issue with an Actor Component, are they supposed to be able to execute RPC to Owning Client properly ? The Actor Component is added to a Player Character. The strange thing is that I was able to send RPC at some point but not today... I feel like I should use a standard Actor to do that so it doesn't bug so much... I know the question is really not precise but I don't know what to think right now :p
I can see the RPC executed on the server and not on the client
Actually it's a perfect idea. I'm with Datura on that one. There should be no real large scale netcode difference between a Listenserver and Dedicated server. Pretty much none except for the exclusion of visuals which the engine already does for you. Would refer to ARK:SE for a decently sized and successful project that has managed both. The only difference is that ARK:SE forces clients to remain near the server player in Listenserver, so that the server doesn't have to do a lot of extra work. Everything else plays the same. The only honest difference between running dedicated instance versus listenserver is potential client count or cheat prevention for more official gameplay.
I would encourage you to read the static you're calling. If you check through it, down through to CreateParticleSystem. You'll see that it's already gated against creating particles on a dedicated. Your Destroyed code should just call the static and not care about role.
If the actor component is attached to a character that is client owned and the component is marked as replicated then the RPC to the client should succeed. If it's on an AI Controlled character, then there would be no owning client for the Server->Client RPC to execute on.
@sinful tree
The vast majority of games are either never released or are released after having gone over budget, and having been refinanced/delayed. Anything is technically possible, are there a few games that do this? Yes. Just because it's technically possible doesn't mean it's a good idea to do in general. You want to do it because it serves a very well defined and good purpose.
Scope management is one of the most important tools when doing game development or any project really. Adding to scope for no good reason is not a good decision in my book.
If the game doesn't contain a lot of netcode, and is mostly relying on replication, it's not as big of a deal. If you're making a game that doesn't neatly fit into Unreal's pre-defined boxes, or have more complicated net logic, every little piece of extra accounting you need to do when writing and maintaining the net & gameplay logic matters.
I don't see how scope has anything to do with anything here. At the end of the day, there is no real difference between whether a game is running on a dedicated server or running as Listenserver besides having a hosting screen.
Dedicated server hosts the game for you, puts itself on the session list. Listenserver needs a player to do this and travel to the game map.
Beyond this, the netcode is all the same.
All that really needs to be taken into consideration is that there could be a player being the host instead of the server to actually make both. If you define from the beginning that you intend to have both listen & dedicated servers, then you just need to be sure you're not programming anything that wouldn't work in both cases. Like using Has Authority to verify if you're running on a client so you can create some UI is fine if you're programming for a dedicated server, but if it was a listen server then the host wouldn't get that same UI when they perhaps should. So you need to change the logic there and you just need to continually use that same paradigm with everything you code to ensure that dedicated servers don't do what only a client should do, and that listen servers still do what a client should do.
It may be a little bit more work, and a little bit more thought, sure, but it's not a bad idea to do so, if you're aware of what is required in order to get it functioning.
Ehhh, it's not like it is much more work. Just add a dedicated server check after the has auth check. Easy.
That is a very big and understated if. That awareness is not going to be present with someone who hasn't done it before. Again all of these really assume you know what you're doing. For someone who comes here and asks basic networking questions, that is just not going to be the case
Scope control is everything, from large game development to one person projects. In the solo case, if the frustration due to the learning curve wins, then your game never gets finished
If they don't understand basic networking - they don't need dedicated servers. They should learn first.
We have been listening carefully to your suggestion, and we worked toward a fix
- WizardCellβ’οΈ
Now to make it easy for you, I should have definitely said: "servertravel is can be seamless while travel isn't can't"
servertravel can still be non-seamless, you just have to enable seamless traveling as said in the relevant section
Guys, new article about multiplayer procgen w/ Zlo
https://vorixo.github.io/devtricks/procgen/
This will be the last article of the year.
Noooo, why last? 
You're grounded for the end of the year, and you have to publish one post everyday
Hello guys! I want ask easy question. If I wanna make online multiplayer game for Steam in Unreal is there any plugin for it? I know EOS can use steam sessiions but I want have game fully for steam and also publish it there I dont want use epic. Is there any possibility? thank you
I assume if it is integrated with the steam online subsystem, you can just send it to steam through their platform
Gonna check do you think there is also blueprint version of this? for easier usage
(plugin)
Also, hey. I am thinking of creating an external game client for my game, which would be built on html/javascript etc. How would i be able to communicate with game data (fx load player profiles from external database and such.), and create a new session from said client. Just talking about the unreal side of it, and which tools there are to integrate such behaviour.
Atm i simply need a prototype to be able to create sessions to host playtests using NULL online subsystem. Would it be better to just create a session system in a different level in game atm? Or would it be too clunky to transfer later?
Wdym?
You just integrate the online subsystem, and it is almost already ready to go
there are good tutorials on youtube for this
specifically, find one which goes over sessions and how to create them
thankfully these things I know I already did multiplayer for epic with eos π
and implemented also my own Open id login
but wanted start separate project fully for steam
ah i see
maybe you got experience with my problem?
https://partner.steamgames.com/steamdirect
here is how you submit game btw
you wanna create it on clients side ? or dedicated server I Dont understand
I just mean creating my own external UI interface, and how to make it interface with unreal
so client side
I am still not getting what u imagine as client side for me its like menu login etc π
and game.exe which he can run
in pc
imagine league of legends client :)
yes where u can update game etc?
so its like widget imagine launching game and this widget will be launched there u will have play after hit play u will open next widget in game widget with full resolution
nothing special I think
why html
or js
or if you want make it via HTML/JS i believe there is in widget possibility to add like WebView and there u can put this your "page"
but I am newbie in this so rather wait for someone who is smarter than me
What you're refering to is called a "launcher". The ways in which you can interface with this are numerous. The easiest to do is application arugments that you can parse XXX.exe -arg1 -arg2 -arg3 "test" etc...
Your app could query API endpoints to grab JSON or config data from a server
Then why make a launcher?
What does a launcher get you? I frankly find them annoying.
Launcher == $$$ in certain cases
It is owned by a client and the component is marked for replication (as the character) but the client doesn't process the RPC, the server does
Aight thanks
let's say i don't wish to utilize any of the big online subsystems, like epic, steam or such, fx if i have a free-to-play game and it doesn't work nicely with these systems due to monetization.
Then i would need to have my own way to interface with players.
yeah, my point. More $$$ = more marketing = more players = more $$$
If the event says "Run on Owning Client" (assuming blueprints) then it most definitely would be attempting to execute on the client. Are you by chance running as listen server and perhaps the call you're making is on the listen server's character?
Good news! @chrome bay 's FInstancedStruct replication support made it to the engine! π₯³
Thank you James! And thank you Epic (specially to Mikko and co. implied parties..)!
https://github.com/EpicGames/UnrealEngine/commit/1fde898997cc612d467e78fc95e9ce6c59ddb755
I'm in blueprint and it only works on client with multicast but that's not what I want here. I build the server and client before testing on Windows
So I have my character that starts an rpc and at some point send an rpc to the actor component
Inside the AC I then run the rpc on server (as called from the character) then execute an rpc to the client
inside the logs I can see on the server that it runs both RPC on it
and I can't figure out why
like if the owner of the AC is the server
If the server is the owner of the component, even if that component is attached to a character owned by a client, then the Server->Client RPC would execute on the server (assuming here a listen server? not sure if dedicated would do this)
Did you set or otherwise change the owner? Is this component attached by default or is it something spawned by the server then attached?
This is what I have on the server : [2022.12.04-20.14.00:571][293]LogBlueprintUserMessages: [AC_AbilitySelector] BP_DesktopCharWithSkel_C_2147482384.AC_AbilitySelector BeginPlay & Owner = BP_DesktopCharWithSkel_C_2147482384
And this is on the client :
[2022.12.04-20.14.00:585][856]LogBlueprintUserMessages: [AC_AbilitySelector] BP_DesktopCharWithSkel_C_2147482215.AC_AbilitySelector BeginPlay & Owner = BP_DesktopCharWithSkel_C_2147482215
it is attached by default to the character
I don't change the owner but I will check
Also not entirely sure, but I think at this point in your code you're already running on server, so there shouldn't really be a need to have a Run On Server event in the actor component unless you do intend to have clients be able to call the "RPC Add Ability" event in the actor component directly.
This whole thing looks a lot like something that should just be a replicated state with some simple OnReps, specially like the PlayEquipSound.
Yes you are right, I tried to remove the RPC for "RPC_AddAbility" but that didn't change the result
A replicated state ?
This looks like ability equipping code. Abilities should probably be state based. State = Replication.
You 'can' bounce RPCs back and forth like this, but it's not as clean as a simple set on server, let clients do whatever with it when they receive it via onreps. You can also mark is as a owner only replicated struct so that it isn't considered for other players.
This is part of a refactoring (and it certainly is not the perfect way for this) but at the start, the server is handling what ability (an ability is just a spawned actor) is set for the character. Then we ask the server to send it to the character so we can get infos like an icon texture for example). That why there is an rpc that way.
without the client rpc it can't get any info on the client
and there is more infos from the ability that I need the client to be aware of
(I don't do that just for an icon)
Icons shouldn't be sent over network anyhow. That's static data you should be looking up via a key.
the info is stored on a dataasset
but I have other floats and state that I need to link
That isn't really a point here though, the issue is that you're not getting this struct to the client, right? The S_EquippedAbility
the RPC is not run on the client
that one
which is in the actor component
Do you store the abilities in an Array or is it a single ability?
here I just send one ability but In the AC I store it in an array yes
Why not just manage the array on the server, and let it replicate then?
As I understood, when a variable is set to replicate it's data that always transit (event if we can set it to replicate less frequently). I thought a proper way would be to set it once. During a game, we only change abilities in the lobby. Then we can never change it
but yes, it's a solution I will try now to see if it replicates correctly
and maybe use it with a repnotify when it's changed
You get to handle disconnects gracefully too, if you ever allow rejoining. Otherwise you would need to detect a rejoin and send this information again. If you want to go performance happy you can set it's replication time much lower and just call ForceNetUpdate when you set replicated properties.
"You get to handle disconnects gracefully too, if you ever allow rejoining" -> Ah, that's good to know !
Generally speaking, I'd leave RPC bouncing for much later niche performance issues. Unless you're planning on 30+ players at a time on dedicated, or 10+ at a time on listenserver with large maps, you won't have networking issues just using basic replication rules. You'll "usually" end up with a lot less bugs
it's a VR game but with only 6 people for start π
and kinda small map
well thanks for the explainations
I still wonder why the rpc doesn't work but I will check the replication method
That is a little bit odd though. π¦ It definitely should work if it's a default component on the character and the character is possessed or owned by a controller. Technically the component itself doesn't even need to be replicated for those RPCs to work, just the character.
yes it's what I figured
checking replicated component didn't change the RPC being send or not
the worst is that at some point the rpc where sent
π¦
well the repnotify worked
π
It won't as a default component. I found that out the hard way. π You can send RPCs through a non replicated component as long as it's name stable on it's actor.
how do you name it stable on the actor ? Is that on the character I should look for it ?
I don't know how to do it on dynamic components. Haven't cared enough to try. Components that are spawned as part of the actor's class are name stable by default.
OkΓ©, i don't see anything for that on the component from the character
well at least it works with the replication
I have been stuck the whole day for that π¦
thanks again for the tips !
Are you perchance doing this on BeginPlay?
Because in that case it'd be no surprise to show up as running on the server in the logs
I gotta grab some sleep, but if the answer is yes there's your problem
Also I would only use owning client RPCs super selectively, because it's very easy to create out of syncs that way
The first RPC from the character is set on the BeginPlay during the whole character setup
it's used to set a default ability
but even the abilities that are added after that (so without beginplay) have the same issue
Thanks for the info !
I also need to sleep π thanks everybody, I will check this tomorrow
on servertravel, player state gets all variables reset
is there a way to retain the variables information when opening new map?
APlayerState::CopyProperties
@plucky prawn thanks!
hey guys can you help me how to fix this sword it has a glitch if the player leaves the game and the sword stays in place it plz help me guys.
Why this Problem ??
Destroy it when the player leaves, or better destroy it when the character is destroyed
when died the player and when leave if you can help me plz
.
What
when the player died and when he leave
I'm not going to make it for you if that's what you are asking
Override the destroyed event/function on your character
you want from me open a function yes ?
Currently implementing sprinting, climbing, sldiing etc. and was following tutorials that use the 4 custom flags. You mentioned it's the older system, does that mean we shouldn't use them anymore and there's a newer way to handle customizing the Character Movement Component?
Yes, I have a way to identify what struct type it is by using gameplayTag but I dont know what to do with the struct data, which is the void*
The new way involves new functions that let you pack arbitrary data alongside each servermove
Makes it easier to customize custom movement stuff, eventually you will run into something where you need more data than the few flags to replicate movement from the client
Is UpdateFromCompressedFlags() in the CMC called on server or client? I saw someone's code said Client only and another YT video said it's called on the server, so now I'm confused lol
UpdateFromCompressedFlags is only called from MoveAutonomous which appears to be called from both client and server
Ohh I see, but don't you combine them to get up to 256 potential moves?
If your movement options can be described as individual values that never overlap
Once you have something analog that needs to be sent alongside each server move things get harfer
Interesting, do you have an example of this so I can wrap my head around it? E.g I was to make it so you can slide by pressing the crouch button, but only if you're running
Like sending a vector along with the move?
Yep, if you do it a naive way like sending an rpc each time the client wants to change the value, it won't necessarily sync with the received severmove rpcs
Especially if you get into isimportantmove, move combining, corrections, etc
Interesting, I see. Do you know of any resources which cover how to use the new approach so I can try it out?
Honestly best resource is just CharacterMovementComponent.h, im not sure there are good documentation on this since it's optional and was introduced later in 4.X
Okies, thank you! π
Quick question, do box extents replicate?
I have a box component with replication checked, but it doesn't seem to sync up with any joining clients
It occurred to me that extents just simply might not replicate in the first place
Marking a component as replicated doesn't necessarily mean its properties & functions will replicate.
Just that the thing itself can be considered for replication.
I know, that's why I asked if anyone knows if the extents actually replicate
Physics Interpolation!
I still think there should be an out of the box solution for this though
Also still need to fix when it first spawns it doesn't interpolate
Smoothsync plugin was free at some point
Might look into that, thanks
Still surprising that something that seems pretty necessary for any multiplayer games with rigid body sims isn't supported by default, considering otherwise how good unreal is at out-of-the-box multiplayer support
Its hard to believe they don't have something in house for the physics stuff in fortnite
but you are right, it's a weird omission
Does anyone know if 3d widgets are bugged in multiplayer (5.1)? I have an interactable 3d widget and the server can push the buttons fine, but clients cannot interact with them at all
there is an issue with widgets position in general in 5.1... I would need to find the thread on it
Yeah I wish they had at least a little bit of preset prediction/interpolation/whatever for common cases like movement or UI updates.
Or just official tutorials on it would be cool
The solution I ended up with came from the source engine
Source defaults to an interpolation period ('lerp') of 100-milliseconds (cl_interp 0.1); this way, even if one snapshot is lost, there are always two valid snapshots to interpolate between. Take a look at the following figure showing the arrival times of incoming world snapshots: ```
The object will always be 100ms (or whatever value you set) behind the actual received transform, but this gives you 2 points to interpolate between.
So you have a replicated property on your actor that stores position, rotation, velocity, and importantly a timestamp. You can set this every tick and tweak the NetUpdateRate to get something performant. In an OnRep function you add the value into a buffer, and on the client in the tick function you find the correct items to interpolate based on the timestamps and current server time. It's important to have an accurate network clock for this to work well, which I have Vori to thank for π
https://vorixo.github.io/devtricks/non-destructive-synced-net-clock/
Hey @thin stratus This is perfect, thanks so much for your help!
Ngl I barely understood any of that but it's super interesting nonetheless
This also explains why source networking looks great but can have some off moments. (Eg: shooting someone in a pinch and them not dying because they killed you first server-side)
For your buffer are you getting the current transform of the object, or just the delta motion between times? Is your buffer just a single value or an array multiple values and time stamps?
struct FPhysicsState
{
GENERATED_BODY()
UPROPERTY()
float TimeStamp;
UPROPERTY()
FVector Pos;
UPROPERTY()
FVector LinVel;
UPROPERTY()
FVector AngVel;
UPROPERTY()
FRotator Rot;
};```
Then I just have an array of them
TArray<FPhysicsState> ServerPhysicsStates;
I have an actor AMyActor and spawning it as follows:
if (GetLocalRole() == ROLE_Authority)
{
GetWorld()->SpawnActor<AMyActor>(AMyActor::StaticClass(), ...);
}
When bReplicates is set to
true, the actor exists in both clients and server.false, the actor exists only in server.
I should change them to netquantize
Out of curiosity why is there an array? Wouldn't you just want to be interpolating straight to the correct value?
Hey guys, I wanna ask, when creating a photon app id for unreal engine, am i to use PUN or realtime?
You need a lot because of ping variability and because you need at least 2 recent values to get an accurate interpolation. Say you store the 20 most recent physics states every 50ms on average (as source does by default) you can handle pings up to 1 second. You need 2 values either side of the current network synced server time, you find the 2 in the array either side of the networked time - rewindtime (100ms is default in source) using the timestamp values. Then you can calculate an alpha value between these 2 physics states so you can get the interpolated value exactly where the networked server time is.
yep, that's the expected behaviour afaik.
So server time = 1 second, and you would want to find the values in the buffer (usually towards the start for lower ping) at timestamp 0.95 seconds and 1.05 seconds for example, then interpolate between those 2 positions & rotations to get an accurate value.
But wouldn't you just interpolate from the current position anyway? What does interpolating between two positions in the array do?
You could do something really jank like just lerping the position of the actor constantly and forget about any of this, but it wouldn't look like smooth movement. The key is the timestamps, that keeps the flow of motion looking correct.
If you only interpolated to one value in the buffer it would be off anywhere between 0 and 50 ms
But if someone gets behind how do they ever catch up?
with a buffer size of 20*
If they "get behind" it means their ping has exceeded 1 second, in which case they are just kind of fucked.
There's bigger things to worry about then
But if they are always working through that buffer array, aren't they constantly behind?
The buffer is updated everytime the position is replicated, the first value in the array is always the most recent value and everything gets pushed up, then at 20 or whatever size you choose you pop the items
They don't "work through" the array, they're always working with the most recent values
Every tick the client loops through the buffer and interpolates
So you would do up to 20 interpolations in a tick if you were really far behind?
No not at all, the buffer is there because you don't know exactly what the ping of the player will be. If your ping is stable you will always be accessing the same indexes of the buffer
Each item is 50ms apart, from newest at 0 to oldest at 20, which would be 1000ms behind
It's just stored values over a time period of 1 second, then depending on how out of sync the client is he finds the 2 items on either side of that value in milliseconds and interpolates between them to get the accurate value
Yeah
You timestamp the physics state, then you need a synced network clock (which unreal has by default but it isn't entirely accurate)
If I'm behind the server how can I have a synced clock?
You basically have a timer on your player controller that plays ping pong with the server to keep it in sync
As long as your average latency doesn't change too much it's quite accurate
Nothing is perfect though
So is the buffer itself replicated or is it clientside only and updated from an RPC or something?
Based on the experiments vori did, the vanilla clock can be out of sync by up to around 700ms, but using this method it's usually only up to about 30ms
Yeah rpcs
But if the client is out of sync how can they have an accurate buffer?
The circular buffer is just to eliminate outliers, when your ping spike and such
You sync it up by timestamping the rpcs and subtracting the difference
I guess I'm just confused as to how the buffer is trustworthy, and how it solves lag if it's still going to jump between two positions that could be far away
Well if you can't trust it then idk π
Oh I don't mean to question your methods
Hi!
I know my intuition is wrong and am trying to figure out why, lol
After creating a Session do I need to start it or to wait to all the players join it to start it?
Thanks!
I understand, I'm no 150 iq genius so I'm not sure if I'm explaining it correctly
All I know is I played a ton of tf2 so I have a little extra interest in a source-style implementation
I'm just confused on how a clientside history of movement is helpful when the client is the one who is already out of sync
Since their buffer is incomplete from the server
It can be helpful to interpolate between different timestamps (if the divergence is small) so that the client is actually more "in sync"
so if the client is behind for 100ms, and the server sends an update that is 80ms back, we could pick the 100ms ish values to interpolate instad or more recent ones
Ok but if I'm 75ms behind how can I possibly have the data for 50ms?
And why wouldn't I just take the most recent always?
It's like I said earlier, you add 100ms to it (or some other value, 100ms is what source uses) so the object is always 100ms in the past on top of the replicated position.
That gives you the wiggle room for interpolation
You force it into the past a bit
So you are forcing everyone to have the same delay instead of trying to keep up with the server in the first place?
Yes, that's the trade-off for smooth movement
That's wacky
It's not much of a delay either
So I assume it's not ideal in the listen server model
Since the host gets that 50ms advantage
You can also do extrapolation, where you use the velocity of the latest update to predict where it's going, but that's not usually as accurate
At least from what I know. I'm not some expert on this topic, I'm learning same as you
For example I have it set to extrapolate if there's no data available in the buffer within the correct time range
So if I'm way behind what happens in that diagram? I'd be missing stuff in the middle presumably
No you don't miss anything
The only thing that will change is how far in the past you are, which is just your ping
Man I'd be bad at time travel
xD
I think it's a great trade-off, people will notice laggy physics more than a 100ms delay
It's differs depending on the situation for sure
It's interpolation (smoothing) not prediction
So if my ping returns to normal, I fill out my whole buffer and just lerp current position to that value between the latest two?
I'm not sure what you mean exactly
I think I'm having trouble working out what's happening between going from something like 300ms ping to whatever "normal" is
I think if your ping spikes more than 100ms (or whatever the rewind value is) it would be fine for 100ms then stop momentarily because there's no more data.
I'm not sure though
But when it returns to normal what happens
Then it would return to normal at your new baseline, if you go down in ping there should be no noticeable difference
I'm just speculating though, thinking about it in my head. I'd have to test it.
Would that be lerping from the current stopped position to the (100+50)*0.5ms point, or something else?
something else
Then how does catching up work
Because if I need to go through the entire array aren't I stuck way far behind everyone else?
When your ping spikes there's more delay before receiving up to date physics info, so if it jumps too high you would run out for a short amount of time.
The buffer is just map of values for the past 1 second on the server
You wouldn't get stuck anywhere
Either there's data to interpolate or there isn't
If your ping instantly spikes to 1000ms from 0ms, you would have 900ms where there is no information (900 because it's 100ms in the past).
This would apply even without interpolation though
The only cure for that would be prediction, or extrapolation - which is what I currently do when there is no information in the buffer in the correct time range.
Does the buffer actually smooth anything out or is it just keeping everyone in sync more predictably?
In fact interpolation buys you an extra 100ms of ping spike safety because your positions are in the past
Yes it smooths the position
I guess I just don't fundamentally get how
The valve netcode page describes something similar
Yeah that's what I went off
Yeah that's what this is based on
This kind soul has been trying to explain basic network interpolation to my dumbass for the better part of an hour, lol
To make it real simple, you're keeping a history of the last second of positions of the actor, then using timestamps and a synced network clock you can smoothly interpolate between those values, given you are rewinding them to some degree.
You need values either side of the current network time to do interpolation smoothly, which is why you need a delay.
Does an object not still snap to the start of the next interp though?
Or are you doing that buffer in order 100% of the time when possible?
No because it's going off the network clock, which is increasing linearly as a timer.
If there's information in the buffer, it will be smooth
Take a read of this if you're still a bit confused https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
Do you ever skip values in the buffer to get to the latest one?
I'm not doing anything new, I basically just copied what valve did over 10 years ago
No it doesn't work like that
I still don't see how a client can ever catch up to the correct time then
If I can't skip values then if I get 300ms behind I always end up with 300ms of new values in front of me
Even if the intended delay is 100ms then I still have 200ms of values to interp through before I get to that target
And presumably the server continues updating my array during that time.
So how can I ever catch up?
@rotund onyx
{
enum { WithSerializer = true };
};```
First thing you do is use type traits to specify that you want a custom serializer. Then you implement the serialize function on your wrapper type:
```bool FMyWrapperType::Serialize(FArchive& Ar)
{
....
}```
In this function you have an enum switch somewhere that converts what data is inside of your `void*` pointer to a specific `FItemDefition& Instance = *Cast<FItemDefitinion>(ptr);` instance pointer. You then serialize that over the network in your custom serialize function.
The synced server time can "move" anywhere in the buffer depending on ping variability. As long as it's still in the timeframe of the buffer the movement will be smooth. There's no "catching up". If it leaves the buffer, then there will be no information and you will have to rely on an alternative method like extrapolation.
Buffer is newest on the left, new values are insert there at index 0 and everything else is pushed to the right
On top of those timestamps you add the 100ms rewind time to put them in the past
Further right = higher ping
I hope I explained that correctly
So if I'm at t=6.869 because I lagged a bit, what happens?
I want to get to t=6.78 right?
the synced server time is not affected by lag
the only thing that would happen when you lag is newer values would be added later to the buffer
so if you lagged too much, there would be no information left
But current client position would be right?
I gotta go to bed man xD
I appreciate you asking a lot of questions though, I feel like I understand it better myself now
Ya np, I'm learning same as you
If you want to make a competitive game, the latency is the least of your concern. In a listen server model the host can simply cheat, as it is the authoritative game instance
So if you're even thinking to go along that route you need dedicated servers
Based on your restrictions, you can always roll a listen server, but it needs to be backed by peer-approved results generation, instead of the host being authoritative with backend services that support your game, like a ranking system and ladder
Yeah that kind of authority stuff isn't as confusing to me
I was just trying to understand the two most confusing things ever conceived: networking and interpolation
In reality I'll probably just use the nice plugin linked here a bit ago, I wouldn't trust myself to spend weeks trying to do interpolation when that exists.
But it's always nice to at least try to understand what goes on
awwwwh yiss
π
I really hope they merge into 5.1 hotfix but I don't think that's likely π
When non-replicated actors are spawned,
GetLocalRole()returnsROLE_AuthorityandGetRemoteRole()returnsROLE_None
regardless of the type of the game instance whether server or client.
That's correct - you spawned it locally, so you have "authority" over it
When a replicated actor is "torn off" you gain authority over it then too
I tried to do this and I got the module "UnrealEditor-Engine" did not found string in value column
Hi!
Imagine I have a listen server with one player (player1). If another player (player2) joins the server, how does player2 know that there is one player on the server? In other words, who creates player 1 in player 2's client?
Thanks
who destroys the pawn then GM LogOut happens I dotn remmber it
I want to keep my pawn when player leave
The Server tells the Client
This can't be answered without going deep into how the Engine works, which is probably too much as an answer anyway.
But a simple thing is: The Server tells the Client about Replicated Actors so that the Client spawns them in too.
APlayerController::Destroyed() -> APlayerController::PawnLeavingGame() -> GetPawn()->Destroy();
PawnLeavingGame is virtual
thanks , not downlading PDB files of UE5 limited me so bad
Should I choose a different configuration of a project in my VS Studio to make it works?
bUseUnreal = true;
static constexpr const bool bUseUnreal = true;
static_assert(bUseUnreal == true); // why would you even think about it
Why do my VS Studio say that identifier GPlayInEditorContextString isn't defined?
Hello,
I have a quick question. Let's say I spawn replicated actor on server and immediately call reliable RPC executed on the client. Is the RPC guaranteed to execute? Can it happen that the actor arrives at the client later than the RPC and the RPC is not called?
Thanks for any explanation!
How can i achieve getting client notify host about joining session without moving them from Level to next Level? ex. Create lobby (still stays in MainMenu Level), wait for users to join and afterwards move to level? Event Handle Starting New Player is called MainMenu is launched.
Huh?
lmao the error code x'D
Beacons
is it possible in blueprints?
Unfortunately... no :(
So my scenario I cant achieve in blueprints?
But you might be able to do it by just creating an intermediary session
with a custom gamemode and such so it looks like a lobby
But isnt gamemode tied to Level?
no
Can i write u for a sec in dm?
Preffer to keep it here as Im in a train and phone coverage is pretty bad, im sure other fellas will be able to jump in and help
because my internet now is terrible
xDDDD
How do you mean by creating intermediary session?
you have your discoverable lobbies that are sessions that can appear in the session list in your UI
I don't see what a session has to do with that though Vori, if I correctly read it the question is if you can notify a person hosting a game with some kind of message (I assume) from a client that isn't in the lobby. Which without beacons isn't possible right?
and from those "sessions" you can have a minigamemode and UI so that travels to your next gamemode/map by turning discovery off
its a bit more convoluted but whatever...
yes you are right Thom x'D I was thinking of something else
No. I as host create session without moving to next level and I as host wanna get information that someone joined into my session
I was answering about how to fake a lobby in BPs
You just want to get an event for when someone joined the game?
Correct
The gamemode has an event called "PostLogin" with a reference to the player controller that was created.
I tried did printing in PostLogin but didnt print it at all
after client Join Session
Cause its a server only function and maybe u were checking on the client
so
Gamemode is server only
Unless the client that wanted to join failed to join then PostLogin will always get called for someone joining.
yes that's it - oh dear x'D I'm sorry for the "test"
Unforgivable Vori, you shall be banned for this π
π
If you put a print just right after the PostLogin it should work. Either your cast fails or more likely that RPC(?) is the bad guy. Which I'm not sure why you would use in the first place as it only exists on the server.
Thank you π I'll try that
This is just the beginning. You'll need to read up on how to write your own serialization
There's plenty of examples in the engine's source code though, so there's plenty of source material
My question got lost
Hi, anyone knows anything changed for UE 5.0 regarding Steam Sessions?
Not that I know of
Its not working for me anymore
Are you talking about the Advanced Steam Sessions plugin thing?
Yes, i am
It probably needs an update I'd assume. There have been a ton of engine structural changes from 4.27 to 5.
If you have any C++ ability, I'd recommend ditching it in favor of the CommonUser stuff anyhow.
I'm actually trying to find the original forum topic about the plugin.
oh no, you are casting a controller to a widget and then having a client rpc using the gamemode as the target
so... where do we start?
A controller isn't a widget
client RPCs need an owning client, and gamemode doesn't have one... although controllers do
in order for your client rpc to work you need to create it in the controller
and from the gamemode on post login cast to your controller type
and call the client rpc
Is the Unreal Engine Networking System fine for a goal of around 500 slots per server? I've seen a lot of people make their own packet system instead of using the Unreal one with C++.
Not even close, no
You'd be hard pressed to even have an Unreal client running with 500 peers in most contexts, too
You're telling me I can't run 500 players on my raspberry pi? π¦
Also not an expert on this but with 500 players at once that sounds like you need a bit more optimisation than just a custom packet system π
unreal is heading towards better scalability but I think you cannot get that without sacrificing features
or culling logic
ie: not computing skeletal meshes for everything...
It's been widely reported that 100 is a struggle
Am vaguely curious what 500 players would be for. O.o Sounds crowded.
Heating up the house in these cold times π
Hello I am trying to replicate a FName in my player state, from my player controller i call an RPC to the server, but the OnRep never gets called, sorry for all the code pastes, i assume that i am doing something dumb like setting the value on the server and i should set it on the client and then let it replicate
For some reason my server remote procedure call is being executed on the client.
.h file
UFUNCTION(Server, Reliable) void ServerRPCSendHitDetails(FVector BallWorldLocation, FVector BallVelocity, FVector BallAngularVelocity);
.cpp file
void UBallExitUpdatorComponent::OnBallHit(AActor* SelfActor, AActor* OtherActor, FVector NormalImpulse, const FHitResult& Hit)
{
if (!OtherActor->Tags.IsEmpty() && OtherActor->Tags[0] == "Racket")
{
UBallExitUpdatorComponent::ServerRPCSendHitDetails_Implementation(SelfActor->GetActorLocation(), SelfActor->GetVelocity(), UBallExitUpdatorComponent::SphereStaticMesh->GetPhysicsAngularVelocityInDegrees());
}
}void UBallExitUpdatorComponent::ServerRPCSendHitDetails_Implementation(FVector BallWorldLocation, FVector BallVelocity, FVector BallAngularVelocity)
{
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, TEXT("Location: ") + BallWorldLocation.ToString());
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, TEXT("Velocity: ") + BallVelocity.ToString());
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, TEXT("AngularVelocity: ") + BallAngularVelocity.ToString());
}
I am then starting the game as the client and it prints on the screen whenever the ball hits the racket, although it should have only been executed on server.
What am I missing?
You're directly calling the implementation, remove the _Implementation part from the OnBallHit as you're skipping the entire RPC part.
Oh, that makes a lot of sense. I had no idea how it was designed in the background
Thank you
Why do my VS Studio say that identifier GPlayInEditorContextString isn't defined? I am just trying to understand by which side my code lines are executing and someone adviced me to use that in watches: UE4Editor-Engine!GPlayInEditorContextString
https://cdn.discordapp.com/attachments/221799385611239424/1049304832437125181/image.png
Have you implemented/overridden GetLifetimeReplicatedProps for the player state for the OnRep and have you made sure the cast doesn't fail inside the RPC / the RPC arrives?
ah i think i might have done something dumb and just drop a GetLifetimeReplicatedProps in the implementation
sadly that didn't help, and i have a breakpoint, maybe its being optimised away again
Can you show how you implemented it?
yes, sorry ide froze for a few mins
Sorry, not the OnRep it self but the GetLifetimeReplicatedProps π
no problem, nothing out of the ordinary
Then I would kind of assume that one of your if statements fails inside the RPC, the rest seems fine yeah.
Unless inside the OnRep your Pawn cast fails. Also a possibility I guess.
i should still hit a breakpoint i hope
Can you breakpoint your RPC implementation and see if that passes through everything?
even if i run in debug its never called
could it be because i am updated on the server?
whats the oldvalue
by default repnotifies wont fire if value isnt changed on client
can be changed with REPNOTIFY_Always replication condition
What about a dedicated server system but still using the UE Networking? Is it a must to create your own packet system with goals like these?
no, unreal supports dedicated servers just fine
you only need to use source engine version in order to be able to build the server binaries
.
500 players is a problem for much more than networking
if you want to play cards online, 500 is fine
Just not a good fit with an Unreal server
if you want 500 bipeds, you have a problem
that should be a new value, as it was a fresh selection from the UI
In terms of physical server capabilities? It doesn't need to be 500 at the beginning but maybe if my game would grow as I dream of.
yes i can see i changed the value from None to "abc"
Server, client, networking, moderation, gameplay
Not to mention 500 online means you sold like 100k copies
I can't figure out why, I removed the _Implementation part of the call in OnBallBall and the game still prints as client
i can break point the server rpc call, that seems to work just fine, and i can see the code update the player state, I will update the code as you suggested in a minute
could it be because i am playing standalone ?
Guy, did you debug some c++ multiplayer projects? How can I understand by which side my some code lines are executing. Some guy suggested me to add it in watches: UE4Editor-Engine!GPlayInEditorContextString, but for some reason it don't work for me https://cdn.discordapp.com/attachments/221799385611239424/1049304832437125181/image.png
I usually test for authority
I know this function
But how do you understand by which particularly client (client 1, client 2) or maybe server is executing some line of code?
As I know, it is function, that checks, server it is or not
@rotund onyx Btw I think I explained some things incorrectly yesterday, I've been doing further reading and changed my implementation a little.
I tend to look at the callstack. But I have not debugged +2 players so idk how that could be approached
There is some kismeth debug logs that know which client is executing them (they log as in "Client 1: debug text")
maybe you could look at the implementation of those and see how they get the current client etc
hmm, not even this trigger the OnRep function π¦
Do you know something about variable GPlayInEditorContextString in UE4Editor-Engine.dll?
nope
Ok. Or about UE4Editor-Engine.dll in general. Where it is stored or how to work with watches in vs studio and particularly how to add some variables as tracked to watches?
no idea either, what are you trying to accomplish?
I just trying to grasp suggestion of one guy to use watches to my purpose
But if no one knows about this, I'll continue digging in the direction of your suggestion (Kismeth debug logs)
Thx a lot for your advice. I would never have come to this myself
Np, I just happened to use them a couple times
Usually I have enough by testing a single client and the server to debug, but maybe some situation requires more clients
I'm still a beginner and I don't understand many things in ue4
Recently started working with multiplayer
so i can't figure out why OnRep_Chest won't trigger, DOREPLIFETIME_CONDITION_NOTIFY(AAvalonPlayerState, chest, COND_None, REPNOTIFY_Always); i've checked the code to set chest is running on the server, maybe i need to set it on the client?
in that case unless you know it's 100% necessary, take it easy and debug a single client. I'd recommend reading the pinned learning resources, specially the compendiums
In the case of my project, I only have two players
I asked with an eye to the future
No, you need to make sure the OnRep is a UFUNCTION
its a UFUCTION
I tried with and without a parameter
Π‘an you add me for further communication?
could it be related to how i am setting the value PS->chest = characters[character_idx].chest.properties; ?
Maybe because C++ OnReps dont trigger automatically on the server?
isn't that entirely the point of the function, on change you trigger the function
C++: When changing an OnRep variable in the Server, the OnRep behavior will only trigger on the clients when the value of the variable changes. The Server wonβt trigger the OnRep, meaning that we have to call the OnRep behavior explicitly from the Server if we wish to execute it in the Server.
nooo its FName OldChest
the parameter on the onrep gives you the old value
ah so i don't need it
if you need the previous... yeah if you don't, you don't hehe
still doesn't explain why it won't trigger
also, can read what @pale obsidian linked :)
you change the variable on the server
it triggers on client
won't trigger on the server on C++
I assume you've set GetLifetimeReplicatedProps and such
ok so i need to set the value on the client, that will replicate up to the server and then replicate to all other clients?
Usually the server controls state, not the client (to avoid cheating)
nope sorry, I'm busy and I'd rather discuss here in case it is useful for others. If you are beggining, take your time to learn the network part of the framework, the pinned resources are excelent
no, replication goes from server to client
you set the value on the server and it replicates to the client
ok so i was setting it on the server, and the OnRep should have executed on the client
Well, I understand you
perfect that is what i had, the PC set the value on the PS, and i can see the change in VS, but nothing triggers
no the OnRep function never gets called
are you sure you are setting the variable only on the server?
okay i know whats happening
hehe
put a return right below calling ChoseCharacter_Server
lets see, i have tried this a few times
@torpid girder
also what is your onrep doing?
you might have a better time wrapping this in a struct and implementing netserialize for atomicity
FCharacterData
unless u only need to replicate that one variable and u dont want it in a struct
i thought about putting it in a struct too, but its likely that one can change at a time
all i am doing so far
π
so a player could replace their chest clothing,
the only thing i can think of is that i am running
Oh no
haha set it as listen
and put 2 players
π
also Frith!!
remember that onreps dont trigger on the server
u need to call them manually
i just need it on the client
hmm still not working π¦
set it "play as a client"
since i think you are playing as the server
and the server doesn't call onreps by design, as we said
hmm playing as client made the main menu start
Hi, i'm looking at the lobbybeacon code from UE and i don't understand why they use SetNetDriverName ? Why don't they use directly NAME_BeaconDriverNet ?
Mhh is the name different for each connection ?
I understand that I must be the owner of the actor in order to create a RPC call, how do I do that from the code?
ok lets try a different approach, if i am using a playerstate to replicate values to all clients, and then needing to execute a function on each client if that value has changed, another way to do this would be a multicast RPC function i guess
As far as I understand it wants an actor, is it my player actor? what kind of actor does it expect
What's the best way to synchronize clients firing in a fast-moving vehicle?
I currently have a plane dogfighting game where the server spawns the bullet on the client's command, but i'm having trouble with clients having a lot of trouble aiming because the bullets don't appear exactly where they should / pointing the way they should. I'm assuming this is because by the time the server spawns the bullet, the client has moved to a different place already, but i don't know how to go about fixing this
a client owned one, Character/PlayerController/PlayerState that is. But even id you set owner, the RPC will still drop
Because that's not the point in time where it's safe to fire RPCs
So the correct approach is to fire the RPC in the already player owned actor instead
No, multicasts are not stateful. Again you was testing in standalone mode and that's anything but #multiplayer
maybe I have got this totally wrong, its not player state i should be using, i should replicate this values to the character
Has nothing to do with what you was doing tho
Lol all good, would love to talk about it more when I get home
In Standalone or any server netmode, OnReps don't fire automatically. As simple as that
how do you develop multiplayer code? playing in client mode loads up your main menu, i don't think its going to be effectively to navigate my way though the main menu before launching
I read a lot before I try to do #multiplayer
if you can't simulate network rpc calls
How didn't I think of that? π€
can I convert the character to an actor?
SelfActor->SetOwner(UGameplayStatics::GetPlayerCharacter()); wouldn't work because it expects an AActor
so you open the console and connect to a locally running server?
What are we talking about
Because everyone that has a sentence is just throwing it here
so use play as client, "a server will be started behind the scenes" ok great that should do it, so perhaps i can connect to the server using a console command maybe open localhost?
The editor client is already connected to the server on launching.
i didn't see an error in the logs
progress! EncryptionComponent=AESGCMHandlerComponent now i can connect and not get strange confusing behavior π
anyone tried world partition with multipalyer yet ? wondering if dedi's load in the entire map or partition based off where the clients are
is it possible to just start the server with 0 clients?
You can launch a testing dedicated server from command line or a shortcut. If you're doing so and want to test your clients connecting to the server, then you'd need to launch them as standalone in the editor (not as clients).
C:<pathtoueeditor>\UE4Editor.exe "C:<path to your project><projectname>.uproject" <map name server should launch> -server -log -port=<portnumber>
<pathtoueeditor> should be something like C:\UE4.27\Engine\Binaries\Win64
Every player controls a single pixel and can turn it on or off. Together they can draw stuff. There you go that's a multiplayer game with 500 players running on a raspberry pi.
thanks! that is useful, it can be hard to see what is generating an error with both starting!
for multiplayer it is totally
Hey! I'm trying to replicate a cable and setting it's attach end point doesn't seem to replicate properly. Any tips?
Hello guys I have dedicated server where I am creating sessions for my game. ItΒ΄s working like that, I have register session class inside where I am creating session right after I run packaged server. But what in case I wanna have different map in session how I will change it? Create new map and use same game mode or ? how
Anybody mind helping me with some RPC connection stuff?
I'm trying to have a RPC from the Server to a specific client connection on an actor that is owned by the GameState without using a Multicast or an OnRep...
So say I have actor ACube that was spawned by the GameState and it exists on all clients now too and Im trying to RPC from the Authority only to Client 1's instance of ACube but not Client 2's without using a Multicast.... how would I do this?
There's two ways I've been thinking of as possible solutions:
- Similar to how player states replicate but switching its owner at runtime between gamestate and a player controller
- Manually sending RPC's with the owning client's net connection which is VERY on the fence to me...
Yeah Server owns the game state, so by definition you can't send a client RPC because the server owns the stuff the GS owns too
Switching owner will have issues because if the RPC arrives before the owner change replicates, the client won't execute it
So you'll need to route it via an actor the player does own - like controller, player state etc.
E.g. AMyController::ClientDoSomethingToCube(ACube*)
I have a level script actor only with
void AMyLevelScriptActor::BeginPlay()
{
Super::BeginPlay();
GEngine->AddOnScreenDebugMessage(-1, 600.f, FColor::Blue, Values, true, FVector2d(2.f));
}
I set the Number of Players to 2 players.
When Net Mode is set to Plays as Client, each window shows Hello 3 times.
When Net Mode is set to Play as Listen Server, each window shows Hello 2 times.
QUESTION: Why does each window show Hello more than once?
Because every instance executes it - and when you choose Play As Client a dedicated server is spooled up in the background
Play as Client = 2 client players + 1 server
Play as Listen Server = 2 players, 1 is the server
OK. But when bReplicates of the script actor is changed to false. No thing changes. I got the same result. How can an actor spawned in a game instance affect other game instances?
Here's the kicker... what if its in a plugin that doesn't have a player controller? Like Im well aware of this pattern... but its not allowed with my requirements...
Level Script exists everywhere, it has no network functionality.
Not really anyway around it
To call a Client RPC it has to be an actor the client owns
unless I start overriding stuff
Can't be overridden AFAIK - but even if it could, you still need to rely on the ownership change reaching the client before the RPC - which you can't garauntee
Its actually for a prediction model so the client connection is actually figured out ahead of time lol
If the owner is set long before the RPC is called, should be fine
sweet thanks for the confirmation(please don't take that as an insult, don't have many people around me that understand the networking stack that well to answer my questions so I really did appreciate bouncing it back and forth with you)!
You could always add a component to the player controller to provide an interface, if you don't want an actual controller actor
Modular and "safe" then π
Ahh - classic James. One of the kings of #multiplayer
In the CMC, why does MOVE_Walking not set a MaxWalkSpeed in this switch case? How is the MaxWalkSpeed set for the walking mode?
float UCharacterMovementComponent::GetMaxSpeed() const
{
switch(MovementMode)
{
case MOVE_Walking:
case MOVE_NavWalking:
return IsCrouching() ? MaxWalkSpeedCrouched : MaxWalkSpeed;
case MOVE_Falling:
return MaxWalkSpeed;
case MOVE_Swimming:
return MaxSwimSpeed;
case MOVE_Flying:
return MaxFlySpeed;
case MOVE_Custom:
return MaxCustomMovementSpeed;
case MOVE_None:
default:
return 0.f;
}
Does anyone know if its necessary that ALevelScriptActor be set to Replicate?
It contains no replicated properties and makes no RPCs but is set to Replicate and Always Relevant?
MOVE_Walking "falls through" to MOVE_NavWalking. It's apart of the switch logic.
ohhh interesting, thank you. I'm new to switch cases, is that a switch case syntax thing?
Pretty much, MOVE_Walking & MOVE_NavWalking evaluate to the same thing in this case.
Yeah. Pretty standard as well. So any google result about switches will most likely cover it.
ahh perfect, tysm!!
makes sense
To my knowledge - it doesn't have networking π€. It is the Level script if I recall correctly.
Im doing Server optimization and noticing that levels still cost the Server time to process (although a tiny amount of time) that is unnecessary.
Huh - interesting.
Im gonna advocate for replication graph in that case(I have said my peace, wont bring it back up)...
I've literally always thought it didn't support networking stuff (even though it is an actor) π€
What happens if you turn off replication on it btw?
My guess is nothing, I would have to override it in some way to do it properly.
Huh - well I'll be. Looks like the event graph at least supports it π€
Try it out? Worst you can do is stop playing and turn it back on lol Β―_(γ)_/Β―
Does it? Looks like the networking stuff is exposed in the event graph and as DevilsD found, bReplicates & bAlwaysRelevant is true.
ctor
At least it can't be damaged though π
Just an example
A few sub levels still costing time on the Server
Even though not doing anything
Ah I think actually it might have replication support thinking about it, but it's probably stably-named so not spawned like a normal replicated actor
Just wanted to know if anyone had any idea if it was network relevant for other systems or not.
Time to create a new one and just turn that stuff off I guess
I might just go ahead and override it and stop it being relevant and see what happens
Was going to
Please post the findings π
@fathom aspen You might be interested in this kind of information π
Yeah @fathom aspen scroll up a little bit, theres some good convos ^^^^
Level Script has a really odd lifetime IIRC
Ahhh wait, no - I think LevelScript actor is serialized into the level - so it makes sense it would be stably named
So turning replication off really shouldn't matter
Base ALevelScriptActor does nothing with networking
Wait what? LevelScriptActor replicates?? Since when heh?
Yeah - so why set these values to true and cost precious time π
That means my hated level BP has always been replicating, darn
Yeah, at a cost of, seemingly like .0016
I guess if you do want to replicate something level-specific maybe
That's right, but why does it need to replicate 
So setting bNetLoadOnClient to false seems to supress functions from running on client, so yeah that explains that
yeah makes sense
Time to figure out why it replicates, brb
I think it might be so you can call RemoteEvent?
Was looking into that, "Remote" triggers me, but I don't think that has to do with replication
I expect a very detailed blog post on the matter
You mean a blog post that's one line long saying that was a legacy decision?
Apparently its safe to turn off according to the Coalition...
Oh for sure, just didn't know if it has one of those propagating effects
Funny enough, I'm seeing the input stuff (yes that brought me back to your notGDC presentation) but neither that it's explaining the replication part
Yeah everywhere else its used is WITH level streaming and sub level stuff but not any replication purposes... so might be a good PSA to tell people "TURN IT OFF"
Yeah not that it's being spawned at runtime or something. The only place I see it being spawned is if you changed the level BP and compile
But that's not runtime 
Good that you guys brought this up tho, will keep this in mind in case I notice something interesting
Hello,
I am trying to find the best way to give player controllers a number so I can assign spawn points on the map.
Currently, when a player logs in I call their respective controller and I assign them a number based on the order they login. However, this does not work when the map needs to be generated first.
One Map I have is preset with all the rooms and spawn points. Another map is generated at the start and then the players spawn once the map loads by checking if βPlayer Startβ Actors can be found.
Everything works on the Preset map but not the generated one.
Is there a better way to accomplish this goal that im not seeing?
Image details: This is called on the Event OnPostLogin after validating that the logged on player did not go over the player cap of the session. The update Player num is a function on the controller that just updates a variable on the player to what order they logged in.
physical animation crashes client on servertravel
has this happen to anyone else?
I think there is definitely a lack of updated multiplayer tutorials (atleast everything that is pinned), I also am confused on how every single video is from an hour to a couple of hours, simple multiplayer couldn't be that advanced I imagine if you understand the engine? I understand the different type of multiplayers that you can host but know nothing about how you actually measure replicatable events and really just looking for a basic tutorial to introduce me to it
better read the pinned guides, specially the compendiums
"simple multiplayer couldn't be that advanced I imagine if you understand the engine" ... well it is kinda tricky. You need to understand how it works at engine level plus all the challenges and difficulties that come with real time multiplayer games
I see.
I don't really think multiplayer is simple by any means
Having a base is just easier to grasp things in general, atleast in my experience
From what perspective? A simple game like chequers is very simple.
Yeah, I refered to real time multiplayer
Good idea actually, I only thought printstrings were client sided though so good info to know
Any game that involves a world you move around in will be hard, by definition.
You can have real time chequers! π
Lol
In my head I consider an achievable goal to learn like in the next month or 2 is to be able to make a simple fps where 2 clients can shoot at eachother and there's HP and you can die
i believe in u, Soldier
Just be wary the road to network programming ends in a dark place
most ppl cant handle it and end up tapping out and writing Golang instead
but if you endure it, you will be a Titan
Isn't that just "start new project -> fps template" ?
Or Lyra?
like Lord Vori
Does that actually have built in replication?
Also the goal would be I want to be able to do this myself without looking anything up
Also the goal would be I want to be able to do this myself without looking anything up
π€¨
I was reading the level script actor replication thing, interesting oversight -
Then you can probably get the OSS Null to work and you're done.
load up ue5 and print strings over raw udp socket to send data between clietns
that's bold
To be fair, UE5 does have a udp transport layer you can just use out of the box.
(not related to connecting to srevers)
π³
π§ββοΈ
π
Wondering what other oversights we have lurking out there
the never-ending story
I noticed that GEngine->AddOnScreenDebugMessage() invoked in one game instance will also be displayed in other game instances.
For example, if I set Number of Players to 2, then:
- there will be 3 messages shown in each game instance when
Net ModeisPlay As Client - there will be 2 messages shown in each game instance when
Net ModeisPlay As Listen Server
GEngine->AddOnScreenDebugMessage() is shared among game instances.
By design?
It's because you're running both under the same process.
There's an option to disable this in the advanced settings.
Hehehe. Thanks!
Hey π
I have a general question about whether or not UE5 would be a good fit for the type of game I want to build. The main thing is that there's only one map and I want players to really quickly switch servers they're connected to. For example, imagine players are randomly matched up into servers after every death. I want them to spawn into the new server as seamlessly as possible, ideally without unloading the single map (but obviously resetting some other minor game state). How baked into UE5 is unloading / reloading the map as part of connecting to a server? Any help appreciated.
Pretty baked in there
It seems like the ClientTravelInternal RPC takes a MapPackageGuid, but it doesn't seem to do anything with it
If I call ClientTravel with a server IP that's on the same map, is the game going to unload the map from memory anyway? Or is UE smart enough to keep it in memory because it's going to the same map?
And it seems like seamless travel is very specifically about changing levels on the same server
Is it possible to make an instanced actor that I drag from C++ class onto the level get spawned only in clients?
the objects would be lost but the map would still be in memory.....so loading the same level you are already in will always be very fast on your RAM
I really don't think you're describing a reasonable setup anyway though, collaborating ecosystems of servers are a bitch to setup you'd be better off just loading streaming levels and having a single server moving people around within it
besides, it sounds like what you're describing is a game with rounds, so a 2-3 second loading screen between rounds wouldn't be jarring if you're really set on jumping between servers
Besides the networking compendium, are there any resources/videos you guys recommend for understanding network replication better? I need to transition from needing tutorials for specific implementation, to understanding the principles on a deep enough level to implement my own systems faster.
Just practice
No real secret
Build very small games
Like, exceptionally small
Then build up from there.
I've thought about this but I wouldn't be able to get away with a single server for example. This would always put some hard limit on how many sessions could be going on at once. I assume this cap would be less than one hundred, but I am basing that solely on external experience playing multiplayer games and not building them. The core of the concept is that any player can be matched with any other player at any time. I definitely think I'll end up pooling multiple 1-on-1 sessions within the same server, but I'll also need to be able to move players between servers and have those two things be as similar as possible in terms of experience. 2-3 seconds would definitely be fine for this I think. I just wanted to make sure the whole map wouldn't be unloaded from memory when changing servers.
The orchestration element I feel more confident with. I come from a web background where I have to deal with those kinds of problems regularly. Game servers won't need to communicate between each other, just with a central matchmaking server.
When you say the objects would be lost, I assume you mean like all the Actors and everything in game state, right? I think all that's fine.
@low helm Thanks for the consideration. I need to just get to the prototype phase at this point and see how dumb this idea is I think.
The way memory works is that assets you haven't used in a while are gradually loaded out of memory over the span of like.....5-60 seconds, roughly speaking
So reloading the map you already have up doesn't take very long
this also depends on what your map looks like
how much terrain you are using
how many assets
Anyone know, how does actor channel know, which actor channel is responsible for updating and which actor channel is receiving.
So NetDriver basically works from Server to Clients, where server calls ServerReplicateActors, which basically updates the actors channel inside the NetConnection, and then these actor channel is sent to ClientNetConnection.
I am creating this netDriver in such way that, i can add Actors for replication from Server and Clients both, and both side will call NetDriver::ServerReplicateActors(). as both will be sending so i need to understand how actor channels can distinguish who will send for which actor and who will recieve.
I hope this makes sense.
Kind of
You could place a wrapper object in the level, that has logic to only spawn the real object on the client during execution
Though highly dubious as to why you would do that
Probably best to state the problem you're trying to solve
Hi!
I'm having an access violation here: ```void ASessionTestCharacter::BeginPlay()
{
Super::BeginPlay();
if (GEngine->GetNetMode(GetWorld()) == NM_Client)
{
USessionTestGameInstance* MyGameInstance =
Cast<USessionTestGameInstance>(UGameplayStatics::GetGameInstance(GetWorld()));
if (MyGameInstance)
{
Server_SetPlayerName_Implementation(
MyGameInstance->GetPlayerName(),
false);
}
}
}```
const FString& NewPlayerName,
bool bNameChange)
{
AGameModeBase* GM = UGameplayStatics::GetGameMode(GetWorld());
GM->ChangeName(GetController(), NewPlayerName, bNameChange);
}```
And I don't understand why. Yes, I know the problem is with the GameMode and I think that should run on the server. Or probably there is another error.
Thanks.
The error is: GM is nullptr.
maybe this is a dumb question but are the apply and take damage events make by epic replicated by default
you dont call _Implementation functions directly, just Server_SetPlayerName(MyGameInstance->GetPlayerName(), false); should be fine
Oh, thank you.
as for your issue, if ASessionTestCharacter is ACharacter, you can just do AGameModeBase* GM = GetWorld()->GetAuthGameMode()
Yes, it's an ACharacter.
Think about it like this, the XXX_Implementation part is your logic that gets called on the server the base XXX function that gets called executes the logic that gets you there
Thanks. I'm new on this.
Now, I'm getting this: LogNet: Warning: UNetDriver::ProcessRemoteFunction: No owning connection for actor BP_ThirdPersonCharacter_C_1. Function Server_SetPlayerName will not be processed..
Is it because I'm making the RPC call too soon?
Thanks!
maybe. when are you doing it?
ACharacter::BeginPlay
ye thats probably too early
This is the log that I get:
LogTemp: Warning: [ ASessionTestCharacter::BeginPlay - Sever]
LogTemp: Warning: [ ASessionTestGameModeBase::PostLogin ]
LogNet: Join succeeded: Melnibone-C3C47F184F
LogTemp: Warning: [ ASessionTestPlayerState::OnRep_PlayerName ] Server Player
LogTemp: Warning: [ ASessionTestCharacter::BeginPlay - Client]
LogTemp: Warning: [ ASessionTestCharacter::BeginPlay - Client]
LogNet: Warning: UNetDriver::ProcessRemoteFunction: No owning connection for actor BP_ThirdPersonCharacter_C_1. Function Server_SetPlayerName will not be processed.
LogTemp: Warning: [ ASessionTestPlayerState::OnRep_PlayerName ] Melnibone-C3C47F184F
LogTemp: Warning: [ ASessionTestCharacter::Server_SetPlayerName_Implementation ]
LogTemp: Warning: [ ASessionTestPlayerState::OnRep_PlayerName ] Client Name
LogTemp: Warning: [ ASessionTestCharacter::MulticastRPCShowPlayerName_Implementation Init]
LogTemp: Warning: [ ASessionTestCharacter::MulticastRPCShowPlayerName_Implementation End - Client Name]
LogTemp: Warning: [ ASessionTestPlayerState::OnRep_PlayerName ] Client Name
LogTemp: Warning: [ ASessionTestCharacter::MulticastRPCShowPlayerName_Implementation Init]
LogTemp: Warning: [ ASessionTestCharacter::MulticastRPCShowPlayerName_Implementation End - Client Name]
LogTemp: Warning: [ ASessionTestCharacter::MulticastRPCShowPlayerName_Implementation Init]
LogTemp: Warning: [ ASessionTestCharacter::MulticastRPCShowPlayerName_Implementation End - Client Name]
LogTemp: Warning: [ ASessionTestCharacter::MulticastRPCShowPlayerName_Implementation Init]
LogTemp: Warning: [ ASessionTestCharacter::MulticastRPCShowPlayerName_Implementation End - Client Name]```
There are two players: one as the listen server, and the other as a client BP_ThirdPersonCharacter_C_1.
I'm going to ask it in the Unreal Forums to share all the code.
I have to go now. Thanks a lot.
Hi everyone, I have a strange behaviour with what I have done and I'm not sure I did it the right way (if there is such a thing!). I have an actor component add to a player controlled character. The AC spawn some actor only on client (I use a dedicated server). The builds on windows (client and server) doesn't give me any warnings but with Android (as client), the server have those warnings :
Warning: UPackageMapClient::InternalLoadObject: Unable to resolve default guid from client: PathName: B_MainSelector_C_2147482002, ObjOuter:
I use the Has Authority from the Player controller to ensure they are spawned only for the client (as you can see in the picture). Is this the right way to do that ?
getOwner->Has authority ()
avoid using getplayercontroller(0)
since it will grab the first player controller existing in the world, which wont match in client/server
@meager raptor
OK. I will think of if later.
Now I am confused in determining the correct way to spawn replicated actors.
Most people do the following:
if (GetLocalRole()==ROLE_Authority)
{
// Spawning...
}
QUESTION:
As replicated actors should be spawned only in servers, why don't we do the following?
ENetMode NM = GetNetMode();
if (NM == NM_DedicatedServer || NM == NM_ListenServer)
{
// Spawning...
}
the snippet i wrote will give you execution flow in the server and autonomous proxy (false) - in the case of a component in a controller. If you want to spawn something local only u can do
getowner->cast to controller -> is local controller
Because the server has authority over your gameplay actors unless u spawn something explicitly on the client, in which the client will have authority over it
You can use the netmode to ensure your spawning context, but checking role is faster
also the role system gives you more information
you can filter based on simulated proxies, autonomous proxies...
Thanks ! Will try that
and you have the remote role, also useful
@meager raptor
Yes I just saw
ok
This will be cleaner
π
Ok, I just checked the whole code and we used a lot of time Get Player Controller
strange it didn't break before
OK. Thanks.
Spawning replicated actors without if guard (making them get spawned in both server and clients) does not make sense, right? Or is there any practical usage for this case?
there is a very niche practical use case for this but you'll need to go to C++
the niche use case can be procedural generation
it's kind of an advanced topic
In the clients there will be 2 actors spawned. One is obtained from replicating the server version and the other one is locally spawned actor. It does not make sense to me. π
no if you do it properly and create net startup actors
if you are ready to learn about the topic I can send you an article I just wrote but it's a bit hard to digest if you are still learning the basics
In general there are two distinct use cases ( not niche ) for spawning actors
But for the general use case if you dont spawn on authority (assuming you have double exec flow), yes you will suffer that issue.
One is for replicated actors on the server, one is for client local only actors ( this requires more care )
Rogers he means spawning the same actor in server and client
while its replicated
and the only use case in which that is valid is simulating a net startup actor
quite niche if you ask me
OK. Thank you!!!
Ofc you can spawn local actors - ie: not replicated debrii when you destroy something that you don't care about replication
and regarding the proc-gen article, you can read about it hwre
it also covers the net startup actors bit
Ah this is you ! On one of my readings I came across this articles of yours https://vorixo.github.io/devtricks/shootergame-vulnerability/
Thanks for all of this π
@chrome bay found it! I only documented his findings and gave an explanation with the code + how to fix it
Some of my articles are community's efforts
The fun part of it is cross-referencing resources, while getting a solid piece of information out there
writing together the synced clock article, with Laura, Zlo, Adriel and co - was a really fun thing. We got something usable after some iterations
I just finished making my learning note about replication.
Why would an object spawned on the client have a remote role of simulated?
It is based on my experiment. Rechecking...
How do you even spawn a replicated actor... On a client?
Without some serious replication hacking.
@pallid mesa Yes this looks really cool :). Sorry I was just reading https://vorixo.github.io/devtricks/stateful-events-multiplayer/ this is what was explained to me on sunday here :). I'm starting to understand a lot more of the correct way of doing networking. I'm glad for that
Also at the top right, why do you have 2 entries for client-server?
read the article about procgen i sent above
the tldr: make it net startup in runtime
Because there will be 2 actors in the clients. One is from locally spawned and the other one is replicated version of the server.
In a listen server?
I will check again.
spawning without if guard.
in a place where there's client/server exec flow
Ah.
also simulated cannot be replaced for autonomous :c
Okay that makes more sense. When I read spawn location, I'm thinking instance, not code checked location.
For the third case:
if (GetLocalRole() == ROLE_SimulatedProxy && GetRemoteRole() == ROLE_Authority) // Client
{
// spawning...
}
The result is confirmed.
I spawned the replicated actors from AMyLevelScriptActor::BeginPlay().
The first case is also correct.
Each client has 2 actors. Tested with Play as Client and Play as Listen Server
The server has 1 actor. It can only be seen when using Play as Listen Server. No server window for Play as Client.
hi all, for my mp shooter I'm just replicating player trigger state for firing high rof weapons, so rpcs per shot dont clog bandwidth. How might i replicate cam shake in this situation? e.g. player controller direction is replicated, but not local cam shake, so client will have shots land differently than others
Yeah, don't worry about what I was saying, I was just confused about what your second column meant.
Hi!
I'm getting this warning LogNet: Warning: UNetDriver::ProcessRemoteFunction: No owning connection for actor BP_ThirdPersonCharacter_C_1. Function Server_SetPlayerName will not be processed. in ACharacter::BeginPlay because BP_ThirdPersonCharacter_C_1 doesn't have a PlayerController yet.
How can I fix this problem?
Thanks.
You'll have to run the function after possessing the character.
Is there an event to notify that?
OnPossessed or something maybe? Idk
PossessedBy
Called when this Pawn is possessed. Only called on the server (or in standalone).
Hi! I'm trying to spawn a bunch of assets (buildings with logic, etc) procedurally in network sessions. I've been doing this with replicated actors on authority, but now that we start to have more complexity the layout of making interesting actors with many SM, lights, logic, etc, it is really tedious inside one single BP.
So we are considering moving to load level instances.
However, network-wise, I assume that level instances have to be called both in server and client, since they are not replicated, however, what happens with all the actors within the level instance? any specific workflow to load level instances in multiplayer?
Perhaps someone with more experience in replication than me can help me here. I got my lobby working, and a client can create a lobby and it updates based on how many players are connected, however the clients cannot see how many players are in the lobby π
It seems that the "update players" function i have in my widget, which updates the player list, is called only on the server?
client on the right is acting as listen server
It's a bit difficult for anyone to figure out what the issue is without showing anything π
What have you tried so far? What do you have in terms of code/blueprints? Have you tried looking at whether or not it indeed only gets called on the server?
Well. I'm not good at replication, in fact i don't fully understand it, but i can show some code π hang on
also, i love your pfp
So this is my game mode, which (in my mind) adds a player to a connected players list and tells each player connected to update their list, when a new player joins
This is my player controller, which then fires an event on owning client
That then fires a change player event in the widget. (The hidden pin is just the created widget reference)
And this is the code in the widget
the hidden code is just adding it to the list
@twilit radish Makes sense?
What I would recommend is track down where in the execution line it doesn't work, it's a bit much for me to just guess where it can go wrong π . Put down some breakpoints or/and print out some messages showing if certain parts work. My suspicion is the implementation of "Change Players" being the issue because it calls a RPC when already on the client to the client(?). But I'm not entirely sure I must say. So yeah, debug / print some messages and see at what part it doesn't work any more π
(RPC being replicated event btw).
well, at first i created it to be without any replication, and saw how much of it worked. Then after added the "Run on owning client" events π
but okay, i will try
just not exactly sure how to debug multiplayer
Either put a breakpoint in the blueprints or just add a node between other nodes that print messages. Start at PostLogin and see how far it goes when actually playing the game or how many messages get printed.
If you see in the widget, i get it to print the "Player" 2 times when the second player logs in, however it says "Server: Player"
i guess this means the server executes it?
But i don't understand why, since it is set as "run on owning client"
how does unreal multiplayer support compare to unity's multiplayer support?
Unreal has a built in multiplayer system that has been used for many years by many projects, Unity's stuff is rather new. But I would argue Unity is generally simpler.
Well - for starters, UE actually has one that is supported. It's a roll of the die if Unity will continue supporting their new stuff.
If I'm honest I would rethink how you want to do this. It's a bit all over the place along with having delay nodes (which you really do not want to use unless you have to) and I also have no idea what is going on with it in general π
What I would recommend is creating a replicated variable in the game state with the data you want and use a replication callback ("OnRep") to know when your data has been replicated from server -> to clients. Then from there hook into your UI. https://docs.unrealengine.com/4.27/en-US/Resources/ContentExamples/Networking/1_4/
I used the delay because of some problems with the widget not being created before it was called to update and such π
But thank you, i will try
i don't understand how such a big engine could not have multiplayer functionality
Is listen server only for localhost?
Is PlayerID in PlayerState consistent across ServerTravel?
A listen server is having a game client act as the server for other to connect to, essentially, it allows a player to play the game while also accepting external connections to their game for others to play with them.
but anything replicated to clients will also be replicated to the listen server, yeah? Like, if i told all clients to update their UI, the listen server would also?
The host is both a client and the server