#multiplayer
1 messages ยท Page 243 of 1
yes, however this doesn't answer why we need two actors
if I needed some replicated value that isn't seen by other players, I could always put it in the player state and set it to only replicate to the owner
I def dont have the answer to why they do it - I just know how they are different. Personally I don't use player states at all really, so you can avoid them. Just remember to not expect player B to be able to read Player A's controller type thing
I understand
looking at the classes, it seems like the distinction stems from over-ooping programming practices
yea it could just be an extra bucket so to speak to help organize code and give a general direction on how to set things up
it seems like they started with the controller because they needed to get connections and inputs working, but then they added the game framework and decided to add a game framework 'controller equivalent' class in an attempt to abstract the game layer from the.. 'engine' layer...?
anyways it feels like the consequences of that decision are a pretty big setback that just adds extra development drag when having to plan game systems
i think this single function just speaks to the mess that's created
im on a development build
Are you using a windows shortcut? My target is "C:\folderpath\RuinsOfTearynClient.exe" -log
sorry i do not understand what you are asking
Yea it really comes down to your preference, I've built dedicated server online games and I ignore the player state as I found player controller, player character, game mode and game state are enough
Right click your .exe, create windows shortcut
Than right click the short cut and add -log to the end of the target path
oh you are asking if im running my game from a shortcut ? no i use the .project file
that is to start the game project in unreal engine, to use -log you need to package the game
Is getting Player State > Get Owner (Player Controller), reliable way to look for target PlayerController in multiplayer?
relative to what?
is there a documentation // article about input buffers being implemented for multiplayer
do they have to be implemented in a certain manner or do we handle this locally?
Depends on what you mean by input buffers
That can mean different things in different contexts
i wanna save input , like when a player presses 1 and then 2 instantly to switch weapons, i wanna let one action be saved and qeue itself later.
same but for movement where if player wants to jump but right after a slide then save that input and do the action right after
You can do it either way depending on your game's needs
Having the buffer only on the server is easiest to implement and most reliable one, but latency will be noticable
But the best way is to probably have the buffer on both the clients and the server. The clients wouldn't wait for the server to do the action, and the server would just validate it.
You'd have to deal with interpolation on that one though, but it's worth it
Hi friends,
I still have this question related to server Meshing ,
If I sync the player location and current server id to database ,
how i can make shards map render for all players ?
i see, is there any documentation around this?
but i guess i understand this, this is just like client side prediction atleast what it sounds like
the movement code
Yeah it is
aight imma try this and see if i can make it work
Dont know any docs about it
okay, i was concerned since i wanted to implement curves into my movement, so each state feels gradual and i thought that + this might make latency a lot more visible or just break the movement
hello, I have a replicated array of bools, I have a problem where the client doesn't receive the correct value of all indices, so it's out of sync. I suspect this is due to arrays being replicated everytime one of its indices value is changed, and since I'm modifying the array of bools on a loop, I think it tries to replicate on every loop index...
is there a way to not replicate the array until it's fully modified after the for loop? I'm thinking of creating a temporary array, modify it, then assign it to the array so it becomes replicated once, but I wonder if there is already a built-in way to help the engine decide when exactly should it replicate?
I don't think changing the value of an element in the array triggers an update in the first place
Only if you modify the array, (adding or removing elements) it'd register a change to replicate
oh yeah as far as i know the order of an array is not garunteed to be the same on client and server
I've only tested it with an OnRep function, in an array of structs, if a struct member's value is modified, it'll replicate at least.
you could make a struct where you store a bool and a server index value, you can set the server index on server and use that as your index
the order is more likely a problem of a fast array I've heard, or is it also the case for TArrays?
im using fast arrays yes as for TArray i cant recall any exact moment i faced an issue cause i ran stuff on server
use a buncha print strings to check?
if not then just do the struct thing where you use your own int packed in as the actual index
For regular arrays the order is maintained
oh then just use print strings and see whats the client returning and server doing
I'm right now trying a method, which is creating a temporary array, modify it on the loop, then assign it back to the array so it only replicates once
didn't work unfortunately, I'll try yours
It already doesn't replicate multiple times, modifying the contents of the array doesn't register a change for the array
can they set the array to itself to make it replicate?
or someway to mark it dirty for replication
yeah so apparently if it receives multiple calls for replication in a short amount of time, it only replicates the latest call
which is totally fine, it'll still replicate the server's version of the array so it's synced
I'll keep debugging this problem, I've been stuck on it for some time now
this is incredible, logging the array being modified shows that it's working as intended, but when I check the array on the client (client's world, not the server), it's out of sync.
if I force the array to be re-created on the OnRep function, then it's fine, it becomes synced, but I wanna know why is it out of sync in the first place..
what I notice is that, if the index [1] and [2] were true, and became false, then setting them back to true won't replicate it to the client, but the Index [3] will replicate because it hasn't been modified recently
Found the issue, the client modifying the array, before the server does so, causes the array to be out of sync, which is totally normal and expected, but when the server, shortly after, modifies it, the client doesn't receive the final replicated array from the server to become synced again, welp that's it.
It does not. If you're doing a loop on the game thread it won't replicate part way through.
Player state at index 0 should be the server/host for all players be it client or listen server, correct?
Because as far as the comment on the node, that's how it's supposed to be. I am kinda getting a different result however and can't wrap my head around why
I want to display the host in a lobby for all players and for the host itself, it works. For the first client joining, it's also displayed correctly, but from then on the players joining see themselves as the host
Although I just check if the player state is == player state at index 0
Easiest solution is to have a replicated bool on the player state
Host sets it to true for themselves
In theory, yes. In practice - don't rely on it. Those static getters have a way to get the actual one typically speaking. Such as getting the controller or getting the pawn or getting the player state. There is also the PlayerArray in the gamestate.
Also, what Cyn said (and what I'd do personally)
The only "guarantee" I know of is for player controllers (0 being you)
Since player states can be moved in and out of the active player array I doubt order is guaranteed
Oh that's actually a really good idea, I think I was too blinded by doing it with what's at hand with these static nodes lol
Thanks guys, and I will keep that explanation in mind when something weird occurs next time with these nodes xD
You might want to check the pinned multiplayer compendium
(Cedric's and WizardCell ones)
Thanks, yea I actually did plenty of times and know my stuff usually but here I was thinking that I am using the node wrongly as the comment on it states that it should be the same on server and client ๐ซ
when I playtest in the editor with 2 client windows, is there a way to quit/close one of them without it ending the whole session? need to test quit messages
try the disconnect command on the client you want to disconnect
ah thanks, weird how that doesnt show up in the autocomplete
Does anyone know at what point on the CLIENT with Real/Emulated Network lag, it is save to access both PlayerController / Player State for a Given Possesed Character for the purposes of binding to UI Data,
OnPosessed by and OnRep_PlayerState both do not seem to be reliable candidates. or is one of these for the CLIENT supposed to be reliably safe to access both of these.
BeginPlay of these
Check if they belong to you
incase its not clear if the server dies and respawn, the code works fine. But when the client dies and respawns they come back still in the death animation/montage.
Im pretty sure that runs BEFORE the other functions and isn't guaranteed to have a valid player state yet on client am i wrong?
Hey I'm curious if anyone is experienced with overriding movement physics / inheriting the movement component with multiplayer
I'm running into an issue where it seems like the server-side client actor's input vector is 0 (that makes sense), but it's causing some logic in my movement to fire incorrectly on the server which is causing the client to rubber band a ton because it's auto-correcting to the server's wrong calcs
Is there some other value I can check on the server that would equate to input? I tried getting the acceleration direction but that seemed very error prone because acceleration does not always equal input
You need to send the inputs from client to the server
The server won't know client's inputs since they are local
Yeah I guess actually I don't even know if I should be doing movement logic if I'm on the server, I'm not sure why this logic is firing on the server because I see at some point the logic in the native movement component diverges if not locally controlled
BeginPlay of your playerstate
And you can wait for the PC to BeginPlay too
Alright yeah thanks for the help, I think I just need to figure out the difference between what should be firing on the server vs the client, anything related to input could maybe be moved higher in the call stack as to not fire when the server updates movement
Ill try this but:
Isn't it possible that the ON Begin Play runs but it hasn't Possesed or Replicated fully to the client or the controller isn't full initialized yet.?
I need three things, Player State Valid, PlayerController Valid and Character or Pawn Valid, is there anything that for CLIENTS is reliably a sync point for these classes?
You can just put a check loop
Check every frame if it's valid, if not wait a frame and check again, repeat until it's valid
Pretty much guarantees there won't be any timing related problems
If you check how Lyra uses the IGameFrameworkInitStateInterface, it's essentially to solve this problem here. Because it's not reliable when it's safe to access certain things, essentially every 'important' component/actor implements this interface and when each of they load in they broadcast to all other components to check if they are ready yet, and at some point everything loads in and everything is ready
I don't think I described that very well, to put it another way for any given actor/component that has dependencies on other things being initializied, you make those depenendies broadcast when they're initialized, and the actor/component that you care about basically subscribes to those updates and each time one comes in it checks if everything it needs is initialized yet, if not then it keeps waiting, but if so it can run its logic
That makes sense ill take a look at how that is implemented in Lyra, thanks for pointing me in that direction. hope its what im looking for!
Any classes you know as an entry point that utilize it?
I'll also add that it might look complicated / like a lot of work at first glance, but you can copy paste most of the code lol and you realize where it's used outside of those classes is really infrequently just to broadcast those updates
Hm let me check
I think the main class for this is the LyraPawnExtensionComponent, it's kind of like the manager for it
Also check out the LyraHeroComponent, and I think it shows up in the player state as well
If you search for IGameFrameworkInitStateInterface you'll see which classes implement it, and there's only a few functions that they implement
Alright will do thanks again.
Hey everyone, Do you guys think its worth using GASP character for my multiplayer game? Its already replicated in 5.5, but i cant be sure if its already ready for usage since its the first patch. Or i can also use ALS, but not sure if its replicated already.
I'm personally not a fan of getting these assets. Mainly cause you'd need to go through it and decide if it's actually well implemented and potentially resolve bad design decisions.
Especially for beginners and intermediate level peeps it's potentially better to try and create this yourself.
Other than that you'd need to ask in their respective communities if no one answers here.
That's my perspective on ALS as well.
End up rolling my own very bare bone animation bp.
FYI ALS community version already replicates what ever in it atm..
But saying oh this system is already replicate doesn't magically make anything you build on top of it replicated. Replication just mean a process of communication between different machine. So if you want to add anything on top, it will be your job to ensure that the data is send and received appropriately.
And that's kinda difficult imo, especially as beginner. You have more to gain doing it from the ground up and understand what information need to be send across network when it comes to animation.
since default CMC is replicated, so when Client_ApplyGroundMovement is called by server the movement will be replicated back to server as well or it will just be limited to the targeted instigator client?
void RequestMoveForward(const float Value);
void HandleGroundMovement(const float Value);
UFUNCTION(Server, Reliable, WithValidation)
void ServerHandleGroundMovement(const float Value);
void ServerHandleGroundMovement_Implementation(const float Value);
bool ServerHandleGroundMovement_Validate(const float Value);
UFUNCTION(Client, Reliable)
void Client_ApplyGroundMovement(const float Value);
in short: will the character be moving on server and on client? --> because default CMC is replicated
if you move a pawn thats using CMC outside of the CMC, most cases it will just rubberband back
I sure hope you aren't calling those RPCs on Tick :D
Or on anything that calls every frame.
And if you use the CMC then you shouldn't run any additional RPCs for movement.
It should all go through the default ServerMove RPC
Thank U for clarifying it and Ofcourse not callilng it on tick
Where are you calling it then?
Sure looks like a method called via Input. And Input is processed every frame
At least axis input. Simple pressed/released would only call "once" I guess
quick sanity check. AIController only exist on the server right?
want to throw away the authority check if not needed.
Sorry to interrupt the ongoing convo.
const bool bCanExecuteInputRPC = (Value != 0) ? 1 : 0;
if(bCanExecuteInputRPC){HandleGroundMovement(Value);}
And value is what? :D you are still not sharing where this is calling from
void RequestMoveForward(const float Value){
const bool bCanExecuteInputRPC = (Value != 0) ? 1 : 0;
if(bCanExecuteInputRPC){HandleGroundMovement(Value);}
}
Finally finished my inventory, now its time to replication. One thing really scares me to use add impulse on multiplayer. I drop my items from inventory with mouse, and add impulse. Would it be bad for multiplayer performance? We will only make it work when dropping item. But still it needs to have a physics. Maybe i can change its collision profile after 2 secs etc.
Can my items that is dropped simulate physics? Would it be a disaster? ๐ Because I am really afraid of using phsyics in multiplayer, in some video, it was really not intuitive to use phyis.cs ๐
I wouldn't use Physics. There is a nice workaround for this: ProjectileMovementComponent.
If you have that a root component with collision and then a mesh component as the child, you can set the mesh component as the InterpolatedComponent (function you call on the ProjectileMovementComponent on e.g. BeginPlay or Construction Script or similar in C++ of your Actor).
It can do a variety of physics-like things, like bounces.
It's not reaaaally Client Authoritive, (only the CMC really has Client prediction), but if you set the (Start)Velocity on Server and local Client you can get a relatively smooth result, especially if you set up that InterpolatedComponent.
You could of course use Physics if you really wanted, but there is no prediction AND no smoothing built into it.
So to sync it you'd blindly replicated Movement on the Actor, and that might cause a lot of rubberbanding on the Actor.
Hmmm. I like that suggestion actually! I can simply fake it. It doesnt really matter that much.
Maybe i should add i projectile movement component to tem when dropping, and simulate it.
There is also the option to split the item and the drop in terms of classes. The drop can reference the item and take parts of it, like the mesh. Doesn't need the whole item to be spawned. Then the drop actor can have the component by default
Physics replication is also quite bandwidth heavy
You mean in theory?
Cause what would "Physics Replication" even be? There is no button for that, despite enabling Physics and replicating the Actor and its Movement, potentially including the Component that simulates Physics (and that might be redundant if there is nothing replicating in it).
I don't think there is any builtin Physics data replication going on in UE, or?
ah yea i guess it'd be more accurate to say the replicated movement of a simulated object is bandwidth heavy lol
Hiii! I am running into an issue when calling a Server RPC from a client. This function used to work properly, but when rewriting part of the UI of the game, I encapsulated the calling into a lambda:
UIData.OnLeftClick.AddLambda([ProductionComponent, ProducibleUnit]
{
if (IsValid(ProducibleUnit) && IsValid(ProductionComponent))
{
AsyncTask(ENamedThreads::Type::GameThread, [ProductionComponent, ProducibleUnit]
{
ProductionComponent->AddToQueue(ProducibleUnit);
});
}
});
Initially I did not have the AsyncTask call, but I was getting an assertion about calling RPC from non-game thread, so I thought to wrap it in the AsyncTask to see if that helped (I didn't think Lambdas would get called from non-gamethread anyway).
Now I don't get the assertion anymore, but the client gets disconnected and I find this in the logs LogNetTraffic: Error: Received corrupted packet data with SequenceId: 2086 from client 127.0.0.1. Disconnecting, so I suspect that the AsyncTask wrapping is also not a good solution.
Probably I should just avoid calling the RPC from the Lambda, but I wanted to ask here and seek a bit of clarification ๐
if something expects to be in the gamethread a task not on the game thread is the exact opposite of what it wants e: im dumb, it's game thread
Yeah but the task specifies game thread ๐
lambdas do not magically change how rps work afaik... this is probably capturing something incorrectly
when in the frame is this called exactly?
can you show the callstacak of it without the async task?
The binding on the lambda happens on tick, and the execution comes from pressing a UMG button
let me check the callstack
Callstack for the binding
Callstack for the code inside the lambda just before the error)
is it on the game thread?
I assume yes
I am actually not sure why it would complain here as this should just be inside of slate drawing
Yeah same
I would say for starters you should bindweaklambda with an owner pointer
also I have no idea if this capture makes sense
Oki, I'll look into that. Or maybe just bind a function from the object instead of a lambda
just in case something funky is going on
ok I'll try and let you know how it goes
doing my head in i have been trying to setup a dedicated server but i am unable to connect to it. I have done a source code build of ue5 and added the server and client builds the server loads and logs that it is running but it never shows up in the search box? anyone else have this what am i missing i opened up the 7777 UDC TCP on my firewall but im running server on the same pc anyways. if i create a server in game i can find it though
What might be the reason of my drag and drop is not working when 2 person exists, this only happens in server., client can drag and drop in UI. Server cant simply drag and drop, UI is not working for the Server, Client can drag and drop.
If I start 1 player stand alone, it all works fine.
On the left which is a client, i can simply drag from my inventory.
"Its not replicated btw." But it happens on multi side.
On right, i am unable to drag items.
which is occuring on the server.. Generally things bug out in te client side. ๐
Its not printing that event on the server. But in client.
Also checked for locally controlled, to create widgets, initilizce player etc. This is my UIComponent assigned in player controller.
If I start Number of Players as 1, it works fine on the server. But as soon as 2>, it stops working for the server, but it works in client.
How can i Debug this?
I think this is happenning because on the server, there is two UI opening at the same time, or client one.. IDK. Can it be opening the clients UI in his own screen?!
What I found is, When other client connects, It also spawns Widget in my server's screen. IDK why though. I already check for
is locally controlled
, Here in server, it logged 2 times
I solved it with that way, in UI Component class.. But still. MEH. I didnt like it, is this a good way of solving it, are there any checks?
So when I print BeginPlay in Player Controller, If it says SERVER, It's the guy who spawned in my Spawned Character right? So in client's my version, it will send the print as Client right?
So Server has all of the Player Controllers, for that reason, it logs 1 Client, and 2 server, when client connected to game. Client doesnt log 2 times client, because CLIENT has only ONE Player controller, and my CLIENT version in the client instance, is not printing.
I understood that part now. But why this logged as true in the server 2 TIMES?
use is server and is locally controlled targetting self inside pawn
Here is the relationship between the server and client
Yeah, checked out this in compendium, but I cant to seem to understand the table here. Player Controller exists in Server, and the clients. Is this mean since the server is also client in Listen Server, meaning duplciate?
Its my UI Component which is inside the Player Controller.
then the UI component is only seen by the server and the owner of that client
To be clear, the controller is only seen by the owner of that client and the server has a copy of that. So client 1 and client 2 know nothing about each others controllers
Yeah, but server has all of them right? Thats why everyime I player connected, server's Player controllers begin play works,which mean duplicated UI widgets in my case.
Your screenshot would be typical for 2 clients
But how to check to spawn on only owning client without RPC? Since the connected client is also Server in my instance, and controlled locally on his instance
There isn't a separate client for a listen server host
Hmm. So if 2 player, server has 2 player controllers.
Yes, its own and the remote player
Server runs on each controller. Each player runs there own controller also
so 3 prints in your case
Not sure what you mean by duplicates tho. The server should be doing that unless you dont want the server to know about your UI component for some reason
You'd get 4 messages in dedicated server mode
In my case, If I check IsServer, and locally controlled, it will still spawn 2 widgets? Since when the client connected, it is the server in my instance, and is locally controlled? No its not.
Instead of checking IsServer, i was checking switch has authority.
Maybe that was the issue.
I thought IsServer and Has Authority would be same.
Not strictly true if a client spawns an actor on their client
If its not server, i would simply spawn widget, since clients have no other player controllers in their instance tright?
GetPlayerController(0) and GetPlayerCharacter(0) is almost always wrong in a networked game
Hmm, its time to check compendium again for Switch Authority & IsServer. I am not sure how to handle those stuffs in components. Since I call it in Even Begin Play in the component, it might not be possessed yet. But h ow to handle that in components, which events should on that we initialize?
If you use IsServer as blocking logic for the server for your UI component whatever you do or dont do would just happen on owning clients if thats what you want
Well, I have simple Inventory UI that i spawn in Begin Play, in the UI Manager component, which owned by Player Controller. That was causing spawning 2 widgets on the server, which blocks my "Drag n drop system."
So for local stuffs on players, what checks I should be sure to do in the Server, in player controller
Make it spawn on possess
If you want the UI to be local only just put IsServer before the event. both client 1 and 0 will run the code, but server will not add a "duplicate".
If its server do nothing.
If its not server do UI thing.
You are right.. Why i am even checking for server.
But then Server wouldnt have a UI, in the server Instance?
No the "listen client" would have the UI
the server just wouldnt double run the code
But my Server Instance would have UI?
Okay look. Server is not exactly tied to your listen client
What does that Player controller returns in the server instances? Since we have 2 Player in the server Instance,
you can skip a call from the server, but still have it run on your listen client
Hmm
Sorry, i was supposed to do that.
Wrong screenshot.
So is the right Server Instance, is listen client?
So you know how we call a player that is the "host" of a game?
Thats still an client
but they have the server running on their machine too
So, you can exclude that server from running on specific code
that doesnt mean the code wont be ran
it just wont be ran on the server additionally for a total of 3 times
Hmm, What i didnt understand when I play in Listen Server, and check !IsServer, would it still return true? Since server is also a client?
And thats whats confusing me.
My bad. I got another hello print. It printed only one, in the client, which is the second player.
But should I be spawning those UI in !IsServer check only?
Because I might be playing alone which i am the host, and it wont get spawn UI
Im almost there. I got understood all the stuffs in RPC, RepNotify, etc. And now trying to understand, what is what. and how to check conditions.
ah my mistake. Yes you will need to spawn on server as well
listen doesnt seem to act as a client and server at the same time
thought that was what you were having issues with
yeah so it shouldnt be running twice then. Show me your code
I will create smth. like this.
If It is server, and locally controlled, spawn Widget.
If it is not server, just spawn widget, on client. which is already doesnt have multiple instnace of player controller.
You can just check is locally controlled on everyone
it doesn't matter if it runs on the server or the client
So when player connects as a second player in my server instance, it wont log "Is Locally Controlled" right? But how do i check this in Begin Play, I dont think it would return right value.
Its my compoonent in player controller.
Get Player Controller -> Is Local Controller, is the way i check?
No wait
If you call get player controller it will always return the local controller
Unless you call get controller on a pawn
Its a UIManager component that inside of the Player Controller
is locally controlled is what you want to use to have it run locally only
I think thats all you want right?
Yes, but i can only get it from Character as it seems. And in begin play of my component, it might not be ready.
Ok then simply ''is local controller'' node will work
Are there any better ways for components to get Player Character, like in Character's OnPossessed method.
In your component Get Owner -> Cast to player controller -> Is local controller
Assuming you have that component only on controllers
Yes, UI component is just a wrapper, to not hold all the UI stuffs in Player Controller.
Thanks guys. Its helpful. Now its time to learn IsServer vs. HasAuthority. difference.
Thank you guys. Its much more clear for me.
After you cast the owner to player controller you can save that reference, then you can simply call Get Controlled Pawn on it
And is Get Player Controller is fast look-up? It is searching or smth? I am afraid it would be smth. like FindObjects In Scene, and return.. which is expensivbe.
Yes, would I be doing that inside Event Play?
What do you mean?
It gets the zero index for player controllers, which like you said its local one. But is it expensive to call that node?
The pinned messages, on this channel
It's not that it's expensive, but it's better to avoid using Get Player Controller (0) to get the local player whenever you can
It's not bad to use it, but it's not a good habit
I had to break that habit once
yes,
I want to do that before I get my hands dirty with them. I will check the pins and check for alternatives then!
The alternative is to treat it like any other actor, keep references to it when needed.
Hmm, so you mean locally. I got it.
For example in the player character you can call Get Controller instead of Get Player Controller (0)
Alright, now i should be more familiar with those checks like IsServer & Has Authority. I cant seem the difference though.
Yes, That's what i was doing in single projects actually. I feel like its searching the whole scene or smth. ๐ like FindObjectOfType in Unity, which searches for all objects in scene then returns it. ๐
The problem with this is it locks you in to a certain structure. If you decide later to add split-screen for example, you'd need to refactor every single code that uses Get Player Controller (0)
If the game was singleplayer and you decide to add multiplayer later, it creates a problem as you'd once again need to go back and clean them up
But if you used the ownership chain to access the controller instead of Get Player Controller (0), you never have that problem
But that is if it is the dedicated server right* if changing to multiplayer.
Thats what i am doing for my interaction & inventory. ๐
In Listen Server, it would still return local.
You can still use it in multiplayer if you have no plans on adding split-screen. But where you use it matters
Thank you guys. โค๏ธ Now its time to create sessions. I already setup for Steam Sessions, can we still test with my friend from remote, can we use steam lobbies for testing purposes just by building and giving the build to my friend?
It usually doesn't matter if it's a dedicated server or not
Yes
Why that might still logs 2 times? In Server and in Client, I see log 2 times.
I thought that would print only one, But as soon as the other client connects, it also prints Hello From Server.
Get Player Controller (0) will always return the local controller, so that branch always returns True
I think it still didnt click on me.
Ah, I see, so when the second client connects, in my Server Instance, it gets Player Controller which is local, and it still returns as is local.. Hmm.
God, I just want to spawn ONE UI in my server instance.
๐
Is this in the component inside the controller?
Yes, UI Component inside the Player controller.
Inside Controller or Pawn?
Controller
So the screenshot above is in the PlayerController?
You can either call Get Owner == Get Player Controller (0)
or
Get Owner - Cast to Player Controller - Is Local Controller
Ah, so it's a Component on the PlayerController.
No it is the UI Component iside
Yeah then you'd do what Spynora wrote
I handle UI & widgets.
Whats this different then Get Player Controller?
As I see, IT gets owner and cast to player controller, then check if its local
would it still return local?
Yes, I want Inventory UI just for players.
Since it duplicates, I cant drag and drop.
Owner is the Actor the Component sits on.
Aha, I understood now.
If this is ListenServer + 1 Client
Then Client has 1 PlayerController instance, so one Component.
ListenServer ahs 2 PlayerController instances, so two Components.
One for its own PC
When we check Is Player Controller, it checks its local, but its already local for that server instance.
One for the Client's
But when we check our Owner, and check if its player controller, its not the local one.
So if you do GetOwner -> Cast -> IsLocal, on the LisnteServer it checks it once for the Server's and once for the Client's.
And on the Client it checks it once for the Client.
So you get:
- Server
- Server's PC -> IsLocalController: True
- Client's PC -> IsLocalController: False
- Client
- Client's PC -> IsLocalController: True
Do I need IsServer check before that? OR its redundant now?
You don't need to check if it's a server or not
You only need to know if the controller is local
Alright, so we simply check if our Owner is the local, not the Player Controller in Get Player Controller.
IsServer would only be needed if you don't want the Client to have the UI.
Yeah cause, GetPlayerController0 returns the first entry in the LocalPlayer Array of the GameInstance in C++.
So this is always the ListenServer's PC on the Server.
Get Player Controller returns the local controller regardless of where you're calling it from.
Get Owner will return the specific controller that Component is in
Alright, I was confused about, I thought my "PC" is calling Begin Play when other client connected for a while IDK why. When the other player connects, The second instance in my server, calls the begin Play. And if it checks Is Local directly, ofc it is, because its player controller is local for the instance.
But when checking for owner, its not the local one. IT says! Hey, you are the second one!
Well you basically pick the same PC for both checks
Yeah, I meant my Character's "Controller", sorry.
Thats good to know.
Thank you guys. It clicked for me.
Now i can see WHY Get Player Controller is such a headache if you dont know what you are doing.
That's exactly why you need to be careful on using it
I finally understood Print strings for multiplayer. For example, I print Hello in Player Controllers begin play. I can see my both instances send Hello like Server:Hello.
But how can i detect which one it was as it best? For example the second instance sent it. I log Controller display name but i cant really understand it
Is there anyway to understand who is exactly sending, For example Server's second instance. (which is the server version of the client pawn)
is local controller does that
if it's not the local controller it has to be the clien'ts controller running on the server
Clients only have their own controllers
Server has everyone's controllers
including his, right. I was confused before about If Player is both server and client, I thought for 2 player game, it would exist 3 player controllers. ๐
Revising it.
I can see now why its bugged.
But what about Player Character now? Would I be getting it from player controller too? Hotbar and Inventory component is in my Character blueprint.
Would it be accessing right character
Is this same for Get Character, like in Get Player Controller.
Get Player Character is the same thing with Get Player Controller, but for characters
And same rules for Multiplayer right?
It would work, since we need the local character. WE already checked for owner local.
Yes, thats what i will convert. But that would still work i think?
Since we already check local player controller, it will get the local character here and get values from there.
Get Player Character (0) does this:
Get Player Controller (0) - Get Controlled Pawn - Cast to Character
So you're still getting the Local Player Controller's pawn when you call Get Player Character
Not the one the component is in
Understood, but since its already returning local character, and we already checked for Get Owner's Is Local Controller, it would still get our right character. Because we already know its locally controlled now.
I am asking to understand it completely. ๐
Yeah true it would return the correct character
Because for the second client in our server instance, it wont get inside the if loop
Our main server instance will get in if loop, and get its own local character.
But as for best practise, i would do your way! โค๏ธ
Its better we just get it by chain.
Thanks. I can finally drag and drop my items.. Not duplicated hotbars and inventory.. ๐
For local components, ITs really great practice to know that. Thank you guys, this was really irritating topic for me.
Its much more clear.
An overview of the essential concepts for writing multiplayer game code in Unreal, in under 25
minutes or your money back.
Sample project: https://github.com/awforsythe/Repsi/
Patreon: https://patreon.com/alexforsythe
Twitter: https://twitter.com/alexforsythe
00:00 - Introduction
01:24 - Net Mode
03:33 - Replication System Basics
05:13 - Acto...
I want to add a left/right lean to my character for looking around walls. I want it to have multiple angles. So instead of just leaning and it going to a full 35 degrees, I want to have maybe 2 other positions in between. So for example, 0, 12, 24, and 35 degrees. My question is what would be the best way to handle limiting the rate at which this can be triggered? For example if they were leaning and rotating through all of these angles rapidly it would cause a lot of RPCs to be sent. Instead, should I set some sort of delay between the change? I was thinking once they lean, they wouldn't be able to change the lean angle until the lean was completed.
Watch this and it will make it much easier to understand
Yeah, I already watched it 3 times, and read Compendium for 6 times, I still need much more practice. I need to get those difficulties so that i can solve.
You have to send the client input one way or another
Instead of sending an rpc each time they lean at a specific angle you can just send the inputs and handle lean angles locally on both the clients and the server
If the lean angle is changed it would need to be updated
How do players change the lean angle?
keyboard
Yeah but like is it by holding the button? Pressing it multiple times?
Not sure yet but I think it will be something like lean and while holding the lean button you would scroll or use the up or down arrows
You'd need to send a server rpc each time the player presses a button or uses their scroll wheel, there is no getting around that
For the angle you can use a rep notify variable with skip owner condition to update the lean angle to other players
Yeah that should work
in terms of optimizations which version is fine? A or B
A
MoveForwardKey(short int Value)
{
RPC_RequestSimulateMovement(1, Value);
}
MoveRightKey(short int Value)
{
RPC_RequestSimulateMovement(2, Value);
}
RPC_RequestSimulateMovement(const uint8 bDirection, const short int Value)
{
const float VelocitySize = GetCharacterMovement()->Velocity.Size() + 10.0f; // Smoothness to movement since we don't use float for input Axis
GetCharacterMovement()->MaxWalkSpeed = (VelocitySize <= MaxMovementSpeed) ? VelocitySize : MaxMovementSpeed;
FVector Direction = FRotationMatrix(FRotator(0, PC->GetCustomControlRotation().Yaw, 0)).GetUnitAxis((bDirection == 1) ? EAxis::X : EAxis::Y);
AddMovementInput(Direction, Value);
}
B
MoveForwardKey(short int Value)
{
RPC_RequestSimulateForwardMovement(Value);
}
RPC_RequestSimulateForwardMovement(const short int Value)
{
const float VelocitySize = GetCharacterMovement()->Velocity.Size() + 10.0f; // Smoothness to movement since we don't use float for input Axis
GetCharacterMovement()->MaxWalkSpeed = (VelocitySize <= MaxMovementSpeed) ? VelocitySize : MaxMovementSpeed;
AddMovementInput(FRotationMatrix(FRotator(0, PC->GetCustomControlRotation().Yaw, 0)).GetUnitAxis(EAxis::X), Value);
}
MoveRightKey(short int Value)
{
RPC_RequestSimulateRightMovement(Value);
}
RPC_RequestSimulateRightMovement(const short int Value)
{
const float VelocitySize = GetCharacterMovement()->Velocity.Size() + 10.0f; // Smoothness to movement since we don't use float for input Axis
GetCharacterMovement()->MaxWalkSpeed = (VelocitySize <= MaxMovementSpeed) ? VelocitySize : MaxMovementSpeed;
AddMovementInput(FRotationMatrix(FRotator(0, PC->GetCustomControlRotation().Yaw, 0)).GetUnitAxis(EAxis::Y), Value);
}
I don't think making a new function for each direction is very clean
You can probably get away with using a negative value for left and a positive for right instead
No need to use a new variable to decide direction
Wait nvm i misread the entirity of this
Tbh there is only 1 byte difference between A and B
I don't think that's worth duplicating code
If you absolutely need those bytes consider using int8 instead of short int
mostly i am afraid of spamming computations on tick like (bDirection == 1)
FVector Direction = FRotationMatrix(FRotator(0, PC->GetCustomControlRotation().Yaw, 0)).GetUnitAxis((bDirection == 1) ? EAxis::X : EAxis::Y);
Why not send inputs only when they change?
The movement code can still run on tick
You don't have to worry about a simple bool check (You can have hundreds of those every frame with no real impact)
That way you're not spamming RPCs every tick
hmm, if i block input like say if(value == 0){return;}
then i will need a new function on release movement input to reset the velocities else it will not pass 0 to the rpc
You can store the last input
then compare the new input value, if it has changed send the rpc
when it changes set the last input to current input
a replicated global value?
that's the point, its all server authorotative... nothing is accessible from local clent unless server don't set it for them
The local player will always have access to their own inputs
You can't make that server authorititive
They are inputting on their own pc lol
they are inputting on their own pc yes and server reads and validate and set a new val for them and notify
their local val not possible to use for mov inputs
Yes, I don't think you understood what I was suggesting
can u show an example, my eng is bad sorry ๐
Pseudo Code:
Vec2 LastInput = Vec2(0,0)
# Will run on Client
MoveForward(value){
if(value == LastInput.x){return}
RPC_MoveInput(1,value)
LastInput.x = value
}
RPC_MoveInput(dir, value){
if(dir == 1){
LastInput.x = value
return
}
LastInput.y = value
}
HandleMovement(){
#move the player using LastInput values
#will only run on server
}
Tick(){
if(!isServer){return}
HandleMovement()
}
Something like that
You could also bundle the forward and right values into a single variable first before sending them to the server, instead of sending forward and right individually
that's perfect, now I got it thanks ๐
Hello. I have this widget in my game. The players can interact with is using the "Widget Interaction" component.
This widget is contained inside a blueprint actor who has a "SpawnIngredient" function. This function is bound to an event called from the widget when an item is pressed.
The problem is that I am not able to make this a server replicated function because the client who presses the button does not own the blueprint actor that the menu is created on.
How would I fix this?
Hello, any ideas on how to attach actor to an actor before client joins, so that the client would see it attached after joining?
post your current code, if you are using multicast to attach, consider using onrep
As long as both actors are replicated attachments replicate by themselves
If not use a repnotify
I have a server rpc that sets rep notify variable. In on rep function I do the attachment. When client joins, the rep notify variable is invalid for him
code
waiting for you
https://blueprintue.com/
or post screen shot if code is small and can fit in an image
you should have a bool, when you interact and attach an item set the repnotify bool to true
else set it to false when deattach
You'd have to rework your interaction system so everything is called from an owned actor
this works perfectly, just compiled and tested
I dont know where to set the bool though. No matter where I set it, when client spawns ,he sees the bools default value. Or am I missing something?
new joining client will see the new value of the bool
My understanding is that all widgets are client only?
How would you make a widget ever be able to call a server rpc on anything?
@full vapor
For example, you could have a replicated actor component on the character for handling interactions.
The widget could send a message to this interaction component when you press a button, and would pass a value like an integer, representing the selected item.
The Interaction Component would then run a Server RPC with that value on itself.
The server would then pass the value to the target actor and it would spawn the ingredient as if it's the server that's interacting with the actor
That's only one way of doing it
it should work like:
InteractOnServer -> bAttached = true
then the repnotify function will be called
then you check:
if(bAttached)
{
//here do your attachment
}
else
{
//here do your detachment
}
every one will be notified for these changes, no matter current players or later joining players
this is just for listen server setup.
dedicated server setup will need you call the repnotify function manually right after when you change the bool.
Ok, thank you for the explanation!
Yeah I now right. Can I be missing something in actors settings? I have it replicated and thats it
if your actor is set to replicated, you are missing nothing
Okay well thanks for clarification though
So I've been doing some more research and testing into this issue, starting with removing the delegates/lambas from the equation to ensure that the actor component that was calling the function could do so, I also removed the parameters in case I was passing non net-addressable data - and I still keep getting disconnect from the player, so I think that the problem lies somewhere else.
I think that the most likely reason would be a missunderstanding (on my part) of server RPCs and connection ownership:
- The component calling the server RPC is attached to an actor. This actor is owned by another actor (let's call it manager), who in turn is owned by the player controller. All these actors are spawned in the server, so authority is on the server.
- If I call an RPC from the actor that owns the component, the RPC is dropped but client doesn't disconnect
However it is not clear for me, who "owns" this net connection - if the net connection is owned by the server, then according to the docs the RPC will be dropped.
Are you sure this is what is producing the drop out at all? Have you tried to breakpoint the drop code to see how it got there?
If you comment out the call to the RPC, does it still result in a drop out?
Yep, if I breakpoint when the actor calls the RPC, I see the ServerRPC being called but not executed.
And if I remove the RPC call from the component, then there is no drop out at all.
I would breakpoint just before the RPC is called by the Client and verify that the Owner chain indeed does roll back to a PlayerController.
yeah, that makes sense. How do you check it exactly? I think I can just call GetOwner kind of recursively and double check
If you breakpoint on ProductionComponent->AddToQueue(ProducibleUnit); you should be able to inspect ProductionComponent and follow its Outer chain until you see a PlayerController.
If you dont, then you are probably falling into the last row of that table you posted.
true, excellent. On it then, let's see
Yeah, tbh since it's an RTS game the net setup for actors is a little more convoluted, if anything, because there are many hehe. Thanks for the support, I'll research and see if I can figure it out ๐
I had a similar issue before, which eventually got solved, so probs it's some silly thing in the ownership chain
Not sure how it being an RTS changes anything really ๐คท
It doesn't actually, but maybe there are more actors involved, which makes my debugging more confusing. But that's probably me hehe
void AMyCharacter::MoveForward(float InAxis)
{
AddMovementInput(RootComponent->GetForwardVector(), InAxis);
TempMoveForward = InAxis;
}
ServerSyncRot(FRotator(GetControlRotation()), TempMoveRight, TempMoveForward, TempBoneOffset , TempLeanAlpha, TempTurn,TempLookup);
void AMyCharacter::ServerSyncRot_Implementation(FRotator InRot, float InRightAxis, float InForwardAxis, FRotator InTempBoneOffset, float InLeanAlpha, float InTurn, float InLookUp)
{
UE_LOG(LogTemp, Warning, TEXT("ServerSyncRot Called! RightAxis: %f, ForwardAxis: %f, Turn: %f, LookUp: %f"),
InRightAxis, InForwardAxis, InTurn, InLookUp);
ServerSyncRotation = InRot;
RightAxis = InRightAxis;
ForwardAxis = InForwardAxis;
CalcTurn();
LeanBoneOffset = InTempBoneOffset;
LeanAlpha = InLeanAlpha;
if (IsDriver)
{
MouseTurn = InTurn;
MouseUp = InLookUp;
}
}```
Guys im trynna replicate the axis values however for some reason the value doesnt seem to get replicated to the client.
am i doing something wrong here?
serversyncrot is called on event tick
What do you mean it doesn't replicate? Like the RPC doesn't reach the server or value is 0?
its honestly confusing me, the server keeps setting the value to the axis value then instantly sets it to 0?
as my logs read
LogTemp: Warning: ServerSyncRot Called! RightAxis: -1.000000, ForwardAxis: 0.000000, Turn: 0.000000, LookUp: 0.000000
LogTemp: Warning: ServerSyncRot Called! RightAxis: 0.000000, ForwardAxis: 0.000000, Turn: 0.000000, LookUp: 0.000000
LogBlueprintUserMessages: [Alpha_C_0] Client 1: 0.0```
however my client doesnt even get that fluctuation of -1. it just has 0 all the time
The value changing to 0 instantly could be because (if I remember correctly) the Axis events fire always even when the InAxis value is 0. So that could override your data.
so if i keep my axis held shouldnt it set to the value im holding at?
previously i used to call the server event in the MoveForward() but then i thought why call so many individual RPCs and try to reduce those to 1.
it worked fine if icalled the server event in MoveForward but not when i shift it to event tick
I think so, shouldn't be hard to check.
im printing the val on tick but client always prints 0
I see the print is in BP is that in tick?
ye
and the log is in the cpp
LogTemp: Warning: ServerSyncRot Called! RightAxis: 0.000000, ForwardAxis: 0.000000, Turn: 0.000000, LookUp: 0.000000
LogBlueprintUserMessages: [Alpha_C_0] Client 1: 0.0
LogTemp: Warning: ServerSyncRot Called! RightAxis: 0.000000, ForwardAxis: 0.000000, Turn: 0.000000, LookUp: 0.000000
LogBlueprintUserMessages: [Alpha_C_0] Client 1: 0.0
LogTemp: Warning: ServerSyncRot Called! RightAxis: -1.000000, ForwardAxis: 0.000000, Turn: 0.000000, LookUp: 0.000000
LogTemp: Warning: ServerSyncRot Called! RightAxis: 0.000000, ForwardAxis: 0.000000, Turn: 0.000000, LookUp: 0.000000
LogBlueprintUserMessages: [Alpha_C_0] Client 1: 0.0
also weird pattern in log, sometimes it gets called twice
How ServerSync... declaration looks like?
void ServerSyncRot(FRotator InRot, float InRightAxis, float InForwardAxis, FRotator InTempBoneOffset ,float InLeanAlpha, float InTurn, float InLookUp);```
maybe because the packets are unreliable server drops them?
Could you share tick function?
the event tick that calls this?
yup
void AMyCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
ServerSyncRot(FRotator(GetControlRotation()), TempMoveRight, TempMoveForward, TempBoneOffset , TempLeanAlpha, TempTurn,TempLookup);
}
So I know what's with the double call, your ServerSync runs on client and server
is event tick client and server?
then just HasAuthority() check right?
i knew about begin play, constructors but not tick
because you want to call it on clients
what would you get if you'd print the value of the input insted of calling rpc?
one input is enough, need to make sure the values are actully different from 0 on client
so print value on the axis event?
maybe in the tick and axis to be sure
oh okay let me try
Btw you may want to take a look at this:
https://dev.epicgames.com/documentation/en-us/unreal-engine/understanding-networked-movement-in-the-character-movement-component-for-unreal-engine
Somewhere in there should be described how CharacterMovementComponent replicates movement, it's similar enough to your idea so should help you.
LogTemp: Warning: Event Tick ForwardAxis: 1.000000
LogTemp: Warning: Event Tick ForwardAxis: 0.000000
LogTemp: Warning: ForwardAxis: 1.000000
its setting itself to 0 again for some reason
yheah cus server wouldnt know about temp vars
is it cause im not setting the temp var to be a UProperty?
shouldnt be imo but idek now
nah that shouldn't be the problem
LogTemp: Warning: Event Tick ForwardAxis: -1.000000
LogTemp: Warning: ForwardAxis: -1.000000
this is right
on !hasauthority
so now the client has correct values all the time?
the temp var which i was parsing in was correct all along
so i need to figure out the desync
Just to make sure, if you hold the input for like 5 seconds the server will start receiving only correct input?
let me try that
because you need to remember that RPCs are not guaranteed to reach in the same order they were send
weird, server prints 0 and so does client
in BPs
oh i dont think its calling the func
it randomly stopped calling the function
i think ill rebuild my project first haha
did you uncomment it in tick?
your character is rubber banding?
sometimes my entire replication thing breaks and that rubberbanding happens then i rebuild and it fixes, it wasnt rubberbanding right now but i dont know whats wrong so might aswell rebuild to see
Do you use hot reload?
better not to do that
please dont tell me thats the reason why my project works like this
If you're not using live coding that means your editor doesn't refresh after changes you make
yeah so the rebuilding didnt fix it
you did close the editor when rebuilding right?
yes yes
i closed it, deleted dervied data cache, generated new sln files and rebuilt
i think ill try the very same code in BPs and see quickly
I usually close editor everytime I recompile project after changing cpp files, just for safety.
damn i guess ill follow that
thanks for the time by the way. i appreciate it.
if you figure this out you can share what was not working.
i will, i might have to hit the hay now since 0 sleep and its 8 am haha
but i gotta submit this project in college soon so ill figure and share
@trim onyx it works when i hook it to the actual axis event but not to event tick
and the same thing of making a temp value wont work
it has to go out from the actual axis event
hmm, I'll have to test this on my own. I'm curious why tick doesn't work.
You get your input from your enhanced input, what on tick do you even pass
It will just be 0
Regardless you need to pass the input values
Check the value before you think about rpc
we did, we checked the values on the tick too the ones before passing, it weirds out after the RPC
i just remade the same thing in BPs, it doesnt go as a seperate var, i have to connect it to the actual axis event
this worked.
why do you have a client rpc here
just tick -> if locally controlled -> send whatever you want to server
and it should be unreliable
yeah i tried that, it didnt work. let me try again
doesnt work
What are you actually trying to do here?
replicate the input axis
From where to where
i have vehicles and i dont possess them so i wanna take the input axis and then use those to control these vehicles
taking the clients input and replicating the float
Tick -> locally controlled? -> yes -> send value to server
Get value -> set replicated value
Also what class is this code in?
the player character, making it unreliable and showing
thats all there is to it, making it unreliable in cpp and building
You can just get inputaxis Forward, no need for the axis value 0 variable
where is the other end of server sync rot?
wdym the other end? the function?
thats a cpp function that i sent above all it does is set the value to the rep variable, everything after is just a timeline that runs for the lean
and you're sure it works?
.
yeah im very sure
uh its for a lean function
why is it on tick though
You presumably want to play it when you lean, unless you're trying to lean 60x per second
the fact that it might "work" here is just lucky, a timeline does not belong here.
Anyway, have you debugged? Where does the chain break down if it's not working?
the chain doesnt breakdown, it all works fine but only when i directly plug it in an axis event or the owning client thing calling this event
also ill remove the timeline, didnt know but thanks
Then either tick doesn't happen, or the branch isn't being taken
let me print something on true and check
or the value is being overwritten somewhere else.
it works for one client but not the other
they both return true however client1 gets 0 and client2 gets the replicated var
afaik the issue stems from get control rotation. If you dont replicate that in some way the rot is always 0, 0, 0
not sure if you are using that tho
yeah but the forward axis im trying to pass in even as a var doesnt get replicated. and yeah im using that too
if you are using get control rotation and multiplying it by the forward axis or anything obv it would be 0
idk how you are using it tho
im not multiplying
It's me again, because I've found out that you're using ListenServer, here is what I think is happening:
- You insert input on ListenServer.
- The ListenServer tick runs, but because your RPC is sever only it is not send to the other Client. (Using NetMulticast should solve that, and that's too the reason why using client RPC makes it work)
- The logs run for both Client and ListenSever, so you're seeing confusing data. (Use UKismetSystemLibrary::PrintString it will show you where the logs come from)
so @quiet yarrow has the very same system for one var
and hes got a listen server
is locally controlled thing works for him but not for me
idk if thats got to do with engine version
@daring gorge what does is locally controlled do in your words?
Just making sure you used it correctly.
And i failed to see why do you even have to use is locally controlled.
Inputs are local.
Your computer won't know if I press e on my keyboard.
Because if not you'll just attempt to send 0, might still "work" but it's pretty gross to spam RPCs that won't go anywhere.
I didn't read the entire convo just the part where it's about sending input and how is locally controlled work for others but not for him.
Why do we need that check for sending input.
because it's sending on tick and not on input event
Oh..
tick happens on 3 machines but there's only good input on one of them
Make sense.
and the bad input will usually come last. so it overwrites the good data
I have created a dedicated server and my search isnt finding it but when i direct connect to it. i can connect straight away. why cant my find sessions wont pick it up
- Where is the Server hosted?
- What OnlineSubsystem are you using?
how would you update your UI on a replicated value change?
I know of RepNotify and binding from the UI Widget to the variable.
is one better than the other? Is there another way I dont know of?
e.g. I have a AC_Health with Health on it and now i do Server_GetDamaged(20) and now Health is changed from 100 to 80. Now the server knows(if only replicated) that it is 80, replicates it down to the client to 80 to, but obviously the UI has no not updated yet?
whats best practice here?
a onHealthChanged delegate can be fired when the repnotify function gets called
The widget would bind to that delegate and update whenever the health value changes
So actually use RepNotify? (i know of the delegates)
Yes why not
The best and simplest practice by far is to tick the UI and query that value
haha sry wasnt a "why not" question,more of a whats best practice ๐
People go too hard in the paint with "event driven" UI and they don't need to
๐
I'm not joking btw
There isn't a set in stone way, it's mostly up to preference
To be honest on my personal projects I just bind the value directly and not care if it's ticking or not
But if you're concerned about the best practice you can make it event driven
There is zero benefit to doing that from an event and in some cases it could cost you more. If that widget is off-screen, you're still updating it and invalidating layout. Ticking the UI and updating simple properties that way means that it only updates if it's on screen (ticking != bindings btw)
binding still ticks
ye but tick doesnt tick if it aint "active" i think thats what he means
bindings can potentially invalidate more than they need to. Literally anything is better than a binding usually, but bindings are ofc very convenient
e.g. you could tick a widget that shows your health that is turned on/off like a "player stats screen"
A widget will tick only if it's painted and not culled, tick is really just "OnPainted" tbh..
But obvs there are layout considerations to make as well, since tick is post layout, so it really depends what you're doing
ye, given that it is a healthbar +its value(current +max) ill go with the rep notify and delegate ๐ thanks for your help though โค๏ธ
Is there a way to RepNotify 2 different variables to the same RepNotify function?
e.g. i wanna be lazy and do RepNotifyHealth either time CurrentHealth and MaximumHealth has changed?
you can make both repnotify functions call another function like HealthUpdate or something
yeah,i know that, but i want them both to call the same RepNotify"initial" function ๐ if it doesnt work,ill do your way... ๐
i wanted to avoid this: both literally being the same just for 2 variables
I hoped there was a way to :
HealthCurrent ->On_RepHealh
HealthMaximum->On_RepHealth
repnotifies are tied to the variables so no you cant make them call the same function
but can call a shared function instead like that
aight np, was just outa lazyness and curiosity...this way works,so imma use it ๐
I'm curious what happens if this is made in cpp though ๐ค can we legally give the same function to different ReplicatedUsing specifiers?
ye in c# it would be "Getter and Setter" there you can just specify whatever function u wanna have called. but i got no clue about c++...havent looked into it yet, still getting the basics of MP in UE down first ๐
Well OnRep/RepNotify functions and c# properties are kind of different concepts though
might worth a try to see what happens
I couldn't trust to use it even if it seems to work properly
UE gave me so many trust issues
yeah, I dont think they ever intended it to be used with multiple variables
A shared function works just fine lol
i can't immediately think of a reason as to why that wouldn't work
You can yeah, though if you're passing PrevValue and the types are different it won't work
Probably makes more sense to just pack them into a struct though
That's neat
I recently rewrote some "dynamic" widgets exactly like that. Otherwise it becomes a nightmare to keep track of the data changes and you end up needing so many events just for a simple property
Is it normal for the PlayerState->GetUniqueId().GetUniqueNetId() to be nullptr on the client (several seconds after launching PIE)? I'm using the Redpoint EOS subsystem. This is in the editor, haven't confirmed in packaged build yet
Using the Dev Auth Tool
FIGURED IT OUT
I had to hit "Login before play in editor"
On the Big screen as you can see, The Player 1 flshlight is flashing up to the ceiling, but on player 2, he sees player 1 flashes on the wall.
Control rotation is local
Use an rpc to send the pitch to the server, which then can be replicated to everyone else with a replicated variable
Yaw is already handled by rotating the character
yeah
do i have to delete them all?
No not at all
im kinda new into this, i just watched a yt tutorial about it, and theres only 1 vid of them
haha nice drawing
If you're new to multiplayer then watch this
An overview of the essential concepts for writing multiplayer game code in Unreal, in under 25
minutes or your money back.
Sample project: https://github.com/awforsythe/Repsi/
Patreon: https://patreon.com/alexforsythe
Twitter: https://twitter.com/alexforsythe
00:00 - Introduction
01:24 - Net Mode
03:33 - Replication System Basics
05:13 - Acto...
Replication logic might get confusing when you're new to it
what about repnotify?
You don't need repnotify for replicating the pitch angle as it's going to update the rotation every tick anyway
You can also interpolate the rotation instead of setting it directly, that way the flashlight won't look choppy to others when you look around even if there is high ping & packet loss
WHen I join a session it fails. how can i debug this?
That already exists, GetBaseAimRotation
Does it replicate?
Yes
[2025.03.10-20.08.32:306][290]LogBlueprintUserMessages: [GameInstanceinfo_C_0] GI: JoinSession Failure```
Could it be the cause
SO I'm using lobby. DO I disable UsePesence
Hey guys, can we test our game with a friend that has the project already for multiplayer? I setup Steam & Advanced Steam sessions.
Seems like I cant see my friends session.
Or would it work, if my friend also "package" the game himself? And I do? I dont want to build and and upload to my friend as everytime. My friend has the project already.
How do you check that during joining a session? I don't see a way to extract that info from blueprint session result struct
I have what I think is a dumb question: I have an android game that I want to connect to a dedicated server running on my windows machine. I've been told that this is possible and that I need to package as a windows server and as an android client, and the two should be able to connect. Is that actually the case? I'm running over LAN if that matters
why should the rotation applying part in my code not working? ๐
it's already an hour i can't figure it out!
void ASurvivalCharacter::RequestFlyForward(const float Value)
{
HandleFlyingMovement(1, Value);
}
void ASurvivalCharacter::RequestFlyRight(const float Value)
{
HandleFlyingMovement(0, Value);
}
void ASurvivalCharacter::HandleFlyingMovement(const uint8 bForward, const float Value)
{
if (!HasAuthority())
{
ServerHandleFlyingMovement(bForward, Value);
}
}
void ASurvivalCharacter::ServerHandleFlyingMovement_Implementation(const uint8 bForward, const float Value)
{
Multicast_HandleFlyingMovement(bForward, Value);
}
void ASurvivalCharacter::Multicast_HandleFlyingMovement_Implementation(const uint8 bForward, const float Value)
{
if (bForward)
{
if(!HasAuthority()){
AddMovementInput(GetActorForwardVector(), Value);
}
}
else
{
if(!HasAuthority()){
AddMovementInput(GetActorRightVector(), Value);
}
if (Value < 0.0f)
{
const FRotator ActorRotation = GetActorRotation();
if (!(ActorRoll < -20.0f))
{
ActorRoll = ActorRotation.Roll;
SetActorRotation(FRotator(ActorRotation.Pitch, ActorRotation.Yaw, ActorRoll - 1));
}
SetActorRotation(FRotator(ActorRotation.Pitch, ActorRotation.Yaw - 1, ActorRotation.Roll));
}
else if(Value > 0.0f)
{
const FRotator ActorRotation = GetActorRotation();
if (!(ActorRoll > 20.0f))
{
ActorRoll = ActorRotation.Roll;
SetActorRotation(FRotator(ActorRotation.Pitch, ActorRotation.Yaw, ActorRoll + 1));
}
SetActorRotation(FRotator(ActorRotation.Pitch, ActorRotation.Yaw + 1, ActorRotation.Roll));
}
}
}
Did you ever solve this? I'm running into the same problem ๐
guessing i catched that bug: basically applying the old ActorRotation.Roll so the changes seems unseen ๐
this new version should work, testing it now
if (Value < 0.0f)
{
const FRotator ActorRotation = GetActorRotation();
if (!(ActorRoll < -20.0f))
{
ActorRoll = ActorRotation.Roll - 1;
}
SetActorRotation(FRotator(ActorRotation.Pitch, ActorRotation.Yaw - 1, ActorRoll));
}
else if(Value > 0.0f)
{
const FRotator ActorRotation = GetActorRotation();
if (!(ActorRoll > 20.0f))
{
ActorRoll = ActorRotation.Roll + 1;
}
SetActorRotation(FRotator(ActorRotation.Pitch, ActorRotation.Yaw + 1, ActorRoll));
}
That also didnt work. Maybe we should have the same ZIP.
you don't need to upload the whole game everytime, just the shipping.exe folder need to share with them @remote tusk
but if you change assets in content folder like adding new animations, mesh etc then yes you need to rebuild the whole and reshare
hi, making a truck kinda loading sequence to a game and i want the truck to drive off but when i interp the movement to the clinets from the server it's really choppy and I feel like it's not the best way to turn net update frequency up rly high to interp smooth, is there a better way?
Is it entirely cosmetic?
yeah there's no gameplay purpose
As in, like a Cinematic sequence?
yes
wont they be out of sync? should i be making sure they are synced or does it just not matter?
Is the Truck drivable by the Player?
Then as long as the "start" of the sequence is in sync, the rest of it should be fine.
When you say this, are the Players locked in place, doing nothing?
They are just passively viewing the sequence?
thank you :)
Im guessing you are using BP?
You will be pretty limited in the types of solutions you can utilize then.
Multiplayer in BP only is not ideal.
But while you are learning it should be fine.
If you are serious about learning to develop Multiplayer games, you will want to eventually learn C++
Get your feet in BP first though ,you can certainly learn a lot of the basics in BP only.
What could this warning be? 'ue5 LogNetPlayerMovement: Warning: ServerMove: TimeStamp expired:' when I'm moving with 2 clients.
Suddenly is like I have 200 ping. It's not a stuttering, because even the environment is starting to 'stop moving',
If I play with 1 client/or standalone everything works smooth.
that ServerMove is from dcmc or your own method?
What dcmc means?
I'm using character movement. I didn't made any server movements/predictions
I've seen that and as I understood, the server is behind with the prediction/or client?
But, it's not the movement. Everything. Even the ui (damage indicator is not moving anymore) and I think this is why it's throwing the server move warning.
I've tested an older backup and it's working perfect.
This, current project, I made it yesterday, after I migrated from an older project to clean it up.
And it's going to 3 fps when this is happening
this oftenly happenes when you eject from one client window to another since the new window becomes active and windows will flag the second client window not focused, but not sure if this is your case
I've also tested with built client version and server. The same.
And, just saw now. It's also throwing a warning with 'Video Memory has been exhausted'.
online subsystem is null in the enginedefault.ini
the server is hosted on the same computer. i opened the ports for it as well
Are sublevels automatically like for multiplayer too?
Not solving any specific problem, but I'm curious why first person shooters don't use a GGPO style network model for games with small player counts. Is there something about a UT-style FPS that makes GGPO a no go?
Quoting from Glenn Fiedler's great article:
GGPO style deterministic lockstep
All the benefits of deterministic lockstep without the lag. Each client frame process frames with inputs from the relay server up to most recent server time. Then, copy the game state (fork it) and simulate the copy forward with local inputs to present (predicted) client time. Continue predicting the fork until the next update arrives from the network, then discard the predicted fork, rinse and repeat.
When to consider:
You are making a fighting game.When to exclude:
Don't use for physics heavy games because they are CPU bound, although as a con for this advice, Little Big Planet was networked using something similar to this approach, but one of their team members was the author of the physics engine!Pros:
Can predict ahead using local inputs to hide lag. All the benefits of deterministic lockstep.Cons:
It can be difficult to make sure your game code keeps track of visual effects and sounds considering all the rollback that is going on. In practice some amount of input delay needs to be used (eg. 2-3 frames @ 60HZ), otherwise rollbacks can be very disruptive to players. If the game is CPU bound, you can get into a spiral of death where the simulation can't keep up with all the invisible resimulations. Only suitable for games with low player counts. I would recommend 4-8 being maximum but perhaps it can be pushed up to 32.
https://mas-bandwidth.com/choosing-the-right-network-model-for-your-multiplayer-game/
Can anyone confirm if a FNetworkGUID, specifically the FNetworkGUID.ObjectID, is the same for a given replicated object on every client? Since FNetworkGUID can't be a UProperty I'd like to pass around the ObjectID int64 knowing it will refer to the corresponding UObject.
I you mean GGPO "style" netcode, with rollbacks. They do!
The difference is they don't even try for full client side determinism. They use server authoritative corrections when things go too far out of sync.
think about it this way... what happens when you rollback a first person game?
if rollbacks happen a lot from interaction from other players it would basically shake your view around for example
but yeah the CMC is basically a tiny mini rollbacking game sim
it predicts input +state and sends a combination of input + some raw state to the server
and if the client is too far off they get bonked to rubberband back into place
it isn't one single holy chain of inputs as it includes state as well but its very similar
and yeah imagine input delay in an fps game lol
I am trying something similar but for view rotation 3 16ms frames of input delay seems insanely bad
so I always let clients change view rotation to whatever
Ports aren't relevant for same computer.
Make sure your dedicated server is creating a LAN session.
Hey, is there an opposite to Event Network Error. Like Event Connection Established to know if for example if the user is online again?
what's a cheap way to get closest player to an actor?
unreal engine expert AI is telling me to:
Get All Player Characters
Use Get All Actors of Class with Character or Pawn as the class.
Loop Through Players & Check Distance
Iterate through the players and find the one with the smallest distance.
Does that sound reasonable? or is there obvious better solutions?
also imagine this at scale. I will have hundreds of these. Perhaps all checking at the same time in rare cases.
expert AI? lol?
chatgpt guy lol
do you need to check for actors that are miles away
if not just do a sphere overlap and iterate over the overlapped actors.
imagine this. I have a stack of hundred balls. My character drives through the pile. On wake events fires for each ball: I want to check the closest player (usually just will be the player who woke them) to those balls then do an event
If your player-count wont change during runtime you can store references to the players so you dont have to query them everytime
then just check for the squared distance and compare them I guess
You probably want to register the ball to a manager so you don't have all hundreds of balls ticking
also does the ball really need to know players that are far away?
you can cull based on that data already
no probably not
also ball manager sounds good. Just havnt even tried managers yet. They sound intimidating lol
you just have a manager class that references all the balls and while it's ticking handles all their logic, instead of having all hundred balls ticking on their own
I need an example of what a manger can do, bcus I always here people say manager but Idk how it behaves and interacts with my actors
Actor tick can accumualte and butcher performance
instead all hundreds of balls ticking
so you are saying the manager would tick, but apply that tick to all of the balls instead of each ball doing its own tick. thats sweet!
you pass all the ball references to an actor
however I dont use tick on them for that very reason lol
and that actor alone can tick and loop through all the balls.
but its good to know I can
So you end up with 1 tick instead of 100 ticks
1 tick to rule them all type
you can also slice
so instead of doing everything in one loop when there are too many balls, you can slice it to multiple frames.
large loops in bp is performance killer.
just do it in cpp, for some casses the difference can be 100X or more
I had a loop for all trees
it turned into a hitch each time I chopped a tree down lol
looping over large data in bp is kinda gross imo.
for sure
I will likely move over the heavy parts as I get closer to shipping
but im kinda poo poo at cpp
anyways thanks for the ideas guys. im gonna get some sleep
cheers
I have a concept question:
How would you go about carrying replicatable data across multiple levels, data that is NOT tied to a specific player but rather to the general state of the game? E.G. some sort of overall score, collected items, defeated bosses, something along those lines.
The natural answer would be the GameState, right? Since it's replicated and every player has access to it, but the issue is that the GameState is not carried over between level changes.
The other possibility would be the GameInstance, but the GameInstance is not replicated, and I need the clients to be able to access that data.
So I guess my approach would be to keep the data in the GameInstance, and have the GameState react to changes in the data and copy those values over to itself, so it can then be replicated down to the clients who can use the data.
Is this a good approach? Are there obvious other solutions to this problem that I'm not seeing? This feels like something that might already have a built-in unreal solution, if so please let me know.
I'm far from a multiplayer expert but I would for sure use the GameState, and the server can copy the data to the game instance and back to game state on level changes. The simpler the solution the better, I found that having duplicated data in multiplayer tends to bring problems
Is there a treshold settings I can adjust to stop correction on client? Preferably I don't want correction if the delta is just a tiny bit.
but shouldnt it still work. not being lan?
You are searching on the same PC. So it's LAN.
SubsystemNULL has no Online Sessions.
LAN or direct IP connection is all you get.
I guess that makes sense. I would just like to avoid copying the data around everytime I change levels
After a bit of research, there is a way to persist actors across seamless travel, so maybe I can create a replicated AInfo and carry that object with me across levels. For anyone trying to persist data across level changes:
https://dev.epicgames.com/documentation/en-us/unreal-engine/travelling-in-multiplayer-in-unreal-engine
Unless it is an obscene amount of data, I would rather keep the code simple and copy a single time every level change, than doing something more complex. Because then in my experience replication times can be inconsistent and the data might not be ready and race conditions happen etc. Just being pessimistic hehe
I have no idea how that works, but sounds promising
Yeah I appreciate the help
Hi!, Adding mapping Context for a player need to happen serverside ?
noop
hmm
input management is all local
hi, any luck getting mover working with Iris in 5.5.3 release? Or any one else that might have figured out a way to get them working together
dunno not tried it but doubt it, they havenโt added the net serializers for NPP, itโs not mover or iris that is the issue itโs NPP
if you swap to the chaos prediction liason then likely it will actually work on iris
Pretty sure we have Iris running with NPP and Mover. But nothing I can share of course ๐
Wow, some pointers will be appreciated
You mean on the packaged build? Only the .exe file of my packaged build ?
Are there any cool tutorials about doing timers for multiplayer, optimized way
yes if you changed only the code and rebuild
Can you explain the workflow? My friend has already the packaged build, and I changed some stuff in blueprint, then re-package (idk if its same with rebuild),
send send him the .KB exe
c++ timers don't need any optimizations they are lite weight
FTimerHandle BombTimer;
GetWorldTimerManager().SetTimer(BombTimer, this, &AMyCharacter::ExecuteBomb, Delta, false);
you packaged the game once, shared the full game with your friend.
later when you change something in code/blueprints, you just rebuild and share the new .exe with him
he will replace it in his old client build and run the game
Uh no
If you modify Blueprints this will modify assets
Unless you only modify C++ files, you shouldn't ever only send the .exes
codes in blueprints
That will still modify assets
i can confirm, i did changed the code in the UI widget and just shared my new .exe with the friend and he got new updates and was everyting working fine
If you modify a Blueprint, you're modifying an asset which isn't packed in a .exe file
Whatever you did isn't this
so it was a magic then ๐
@remote tusk If possible I would get the project on Steam so you'll only upload changes between builds
I have a Steam app for development I just use for whatever project I'm working on, for that reason
Otherwise, you'll be better off compressing the built game and sending it all that way
Less error prone
Yeah, After prototyping, i am going to do that actually
Do I rebuild or package? I also saw option like rebuilding, so wanna be %100 sure
package is when you want to share a publishing copy with friend, he can't change anything
rebuild is when you just apply new changes
only to code as said before
so you can share updated .exe as a patch with your friend
changing bp code effects changes in .pak files?
Thanks mate! I am relieved.. I didnt want to to upload 1.5 gb for small changes.
yes
You mean even with deltaTime?
you're modifying a .uasset
but changes will still be compiled in .exe?
i think this is why it was working when i changed the code in widget in blueprints
yes delta time is just a game tick
no
you can't avoid it, you can just slow it down @remote tusk
oh, then where the bp code compiled?
Unless you're in an older Unreal version
with blueprint nativization
might actually be what happened to you
I sadly can't share anything
So, I should share my whole game? ๐ข
Trying to understand prints in blueprint, is this mean My client is also seeing timer replicated? Since he sees the log?
No.
Editor just prints in every window.
The word in front of it is the important thing
Hmmm, So it should have written "Client:" if client had those.
What DO I miss here? ITs my game state class. I check authorty and start timer, Maybe I should send Server RPC right?
I thought since the Countdown is replicated, it would automatically do that, but i still need to send server RPC and edit it, even if i am sure it started in Server right?
Since I check here the authority, I became sure its the server changing value, but we still need to send Server RPC?
So like that.
Thats good to know. I was confused thanks
I have changed my Cooldown to RepNotify, and print string like this.
I thought Server is also calling RepNotify's response event, but it seems like only the client is calling
Finally looking into this client authority stuff now
So to recap, the client is reverting it's location to the location sent by the server (which is it's own location in the past due to the given authority). From TickComponent() if ClientData->bUpdatePosition is true, it will enter ClientUpdatePositionAfterServerUpdate(). If I set ClientData->bUpdatePosition to false when we have client authority then nothing else updates either (compressed flags, move data, etc). I need to stop it using the received location while still doing everything else. The problem in a nutshell is that it isn't using the received location anywhere I can see.
ClientUpdatePositionAfterServerUpdate() iterates the ClientData->SavedMoves and calls MoveAutonomous(CurrentMove->TimeStamp, CurrentMove->DeltaTime, CurrentMove->GetCompressedFlags(), CurrentMove->Acceleration) on them. This is what reverts the location. If I comment out the call to MoveAutonomous() the location stops reverting.
The problem is, nothing actually reverts the location. Ever. Anywhere. ClientTimeStamp is not used at all. Nothing reverts the location before iterating.
Except something does, I just can't find it. I've gone over it in detail. I must be missing it.
I get the feeling that commenting out MoveAutonomous() isn't preventing it from reverting somewhere, it only applies the reversion, i.e. the actual reversion must occur elsewhere.
Found out Decrement / Increment is not changing for server or smth like that. I have used set notify, and it works both for them.
Yeah this is a really annoying thing with Blueprints.
OnRep, in C++, is an actual "Hey this value replicated and changed (optionally even when not changing)."
In Blueprints this is more like a PropertyChanged notifier, but not so much tied to replication.
That's why it also calls for the Server. It calls for generally changing the property.
Now, one would think that this really calls for any change, but there are a lot of nodes that don't trigger it.
Decrement/Increment apparently don't. I'm also sure a lot of Array functions that modify the array won't cause it to call.
At least not on the Server.
The only thing that usually always calls is if you use the "SET w/ Notify" nodes.
helloo, I have a question about bServerAcceptClientAuthoritativePosition, If I enable this on CharacterMovement -forListenServer coop example- will it effect itself or I need to make some special things to do with it? All project has base project multiplayer movement.
ListenServer is a special case. It doesn't get affected by that. It's already the authority.
In case that's your question.
Oh.. Thats.. Interesting.
ACharacter?
Hmm, so we should re-set the array completely to notify?
Don't understand the question ๐
whoops, i meant to edit the message, deleted instead
oh so bServerAcceptClientAuthoritativePosition not effects in Listen servers. Ok thanx
Well, AActor replicates and applies Transform based on bReplicatedMovement.
Maybe this already happens through that? Can't recall.
At least if you notice that it doesn't trigger otherwise. It will trigger on the Client, cause the replication changes the property, so this is mostly on the Server I guess.
Yeah, maybe Server already knows where it changes the value, maybe i can update the UI directly in Server RPC for server, and inside OnRep for client, if some cases happen like this, like incrementing etc. where we dont use Notify set.
Since I understand PRINTS better, i can debug easily. Thanks sir!
This is where MY Timer ends, in the server RPC. Should I RPC here to inform finish (game state) so that others can react to that. OR should I have a "RepNotify" boolean like IsFinished, and react to that? Which one is more scaleable for that case?
Or i can simply check on OnRep_Cooldown, and check Cooldown <= 0.
Commented that out but still happening so don't think that's it
Wrong place
Only sim proxy (or physics) getting that
Have confirmed its not getting called at all for local
Yeah, makes sense.
@grand kestrel Are you sure CMC doesn't update the location? How are you checking for that?
The only calls to MoveComponent or MoveUpdatedComponent or SafeMoveUpdatedComponent originate from MoveAlongFloor, nowhere else in my test level
Why would it use those methods?
Because it calls MoveAutonomous > PerformMovement > StartNewPhysics > PhysWalking > MoveAlongFloor
Pretty sure it will just set the Location without Sweep on the UpdatedComponent directly.
But aren't you saying you can't find where the Client applies the Location the Server sent?
Maybe I misread
Correct
Yeah, that's in ClientAdjustPosition_Implementation
It doesn't appear to do that anywhere but the MoveAutonomous call (and rest of what it calls) results in the location being reverted on the client
I commented that out entirely and it still happens
Let me test again
Like, that's what overrides the Loc and Rot, then sets the bUpdatedPosition, which then leads to the saved moves being re-applied
Wtf I know I commented that out before
I thought it would be there and specifically checked
I overrode the function and didn't call Super
But maybe I didn't reload properly or something because it IS there ๐
Lemme know if that solves your problem. I'm back to watching random animes.
Is it possible to create a component on server only? Like, from the constructor? Or would I have to wait to do it at begin play?
Hmm it doesn't
The calls to set the location and/or rotation are inconsequential
The only thing that actually matters is this line at the very end, taking that out stops it de-syncing, but probably definitely stops it updating other stuff too
But all that does is control the replaying of the saved moves orn ot?
Well, I need them to replay
Everything except the location...
I don't see where why or how its replaying the location, as far as I can tell, it isn't, except... it is
Okay I think I'm just misunderstanding. I thought you were against the Client accepting the Server location.
You also don't want it to replay the location?
I guess that makes sense
Cause that would cause the Client to run off
@grand kestrel
As far as I'm aware, all it does is:
- Ack SavedMove based on Timestamp (throw all old ones away)
- Apply Location from Server.
- For each SavedMove
- MoveAutonomous for current SavedMove
- PostUpdate current SavedMove (updates the SavedLocation to the new one from MoveAutonomous)
That SavedLocation is also barely used for anything important.
I'm not sure if applying the location from the server even does anything
Its replaying the moves (via MoveAutonomous) that screws up the location
I just don't see where/how that is happening in MoveAutonomous
Why wouldn't it do anything? If it wouldn't do that it would apply the moves again onto the current location of the Client.
Commenting it out isn't showing a big difference. But yeah the issue is in move autonomous
It should show a big difference though. Strange.
Like, if you imagine there to be a 1 second delay, so the Client performs 1 second worth of movement predictively.
And then the correction comes in, if it were to replay those 1 second worth of moves, it would be 2 seconds ahead in location.
Yeah. I think so too. But nonetheless :/
It#s of course the combination of the two. First it resets to the last ack Move and then it replays all moves that are still predicted to get back to the location the client was at.
Oh wait I might be overwriting it to use the client's location lol, because it has authority
MoveAutonomous performs the move the same way it would have done when predicting. So it will run through the StartNewPhysics etc.
Where does it reset to that move, esp. the location?
It shouldn't.
I need it to quit doing that when it has client auth
Gimme a sec
But that shouldn't rewind anything t here.
Client accepts the new Location in ClientAdjustPosition_Implementation.
At that point, the Client got teleported back to the Location of the move that the Server deemed wrong.
So if nothing happens afterwards, the Client would now stand a few meters back.
It then acks the move based on the Timestamp, which kicks all SavedMoves that are older out, so only the ones that aren't replicated back yet will remain.
At this point the Client is still in the Location a few meters back.
Then it starts replaying the SavedMoves that are still predicted. Replaying here means that it takes the information about the "Input" of the player and simply performs the movement again.
Only that this time it originates from the corrected location. After all the SavedMoves are replayed, the Client will be more or less at the location it was before the correction. Just +- the corrected distance.
Replaying of the moves shouldn't reset the location at all. Quite the opposite.
If you comment out the MoveAutonomous you would cause it to not replay any of the movement it still has predicted.
It would just teleport the Client to the auth Location and that's it.
@grand kestrel I just scrolled to the original message of yours and I already wrote all of this once :D
Yeah that makes sense. Sorry I was away from it so long I forgot it, I did read up but maybe not enough. I need to think this over. I'm probably doing something backwards then
What was the original issue again?
It's probably simulating ahead by not reverting the location because I'm overwriting it
And thus snaps
Yop, that will also lead to a second correction then in theory.
Yeah I'll play a bit with that in mind
Cause the next move after the replay will be based on the wrongly replayed location
Yeah
@thin stratus this snaps to server location
This doesn't (but it also doesn't apply anything in saved moves besides location, such as stamina etc)
This means I've stopped it from applying server location yet its still doing it as a result of MoveAutonomous called for the SavedMoves
I guess it must be applying the saved move's location somewhere
This isn't making any sense to me
What it comes down to is when simulating my saved moves I need to be applying the client authority right? Because I have no idea where I'd do that
I really hate that CMC pretends it can grant client location authority
But it can't do that at all, it can only provide complete authority where it can no longer receive/apply server moves
ServerShouldUseAuthoritativePosition() and bServerAcceptClientAuthoritativePosition are not specific to position at all
Without bUpdatePosition I can't receive stamina or any other changes from the server
With bUpdatePosition I can't not receive location from the server
I have commented out ClientAdjustPosition_Implementation to no avail, so long as bUpdatePosition = true then it will overwrite the client's location, seemingly nowhere at all -- nothing ever queries this let alone sets it
But yeah. I'm not doing anything backwards. It isn't simulating from the wrong point and then simulating ahead. I'm not applying anything anymore. All I'm doing is toggling bUpdatePosition. MoveAutonomous doesn't even use the ClientTimeStamp. Nothing reverts to server location. Except, its reverting to server location. It occurs when using MoveAutonomous to resimulate saved moves. Except, it doesn't occur there. I've been through everything it touches.
Without reading the stuff below the picture, that would also disable the Move Ack and potentially more if you comment out Super.
Ah I'll put that back in
