#lightyear
1 messages · Page 10 of 1
If you insert a rigidbody, it insert a series of other components
That are already insert via the protocol
Quite redundant I wonder, how one can avoid that
I just got steam networking working, in large parts due to the work by @peak ice with https://github.com/SueHeir/lightyear-menu, so thank you for doing all the hard work! 😄
But it's also surprisingly easy to use with lightyear!
Also somehow even the steamworks crate was really easy to use, requiring absolute no real setup work!
So convenient!
The only annoying thing is that it doesn't support connecting to yourself, but I suppose I can forgive Valve for that 😛
is it due to a collision with the bot while spawning? i can't repro with the bot removed but i might just be getting lucky
Sweet!! Im glad it was helpful!!!
Hmm it shouldn't be because I removed the collision from them, but maybe there is a brief period where it does? I'll give it a try
Oh no wait I did enable collision for them
Ok yeah this is definitely related to the collision with the bot. Hmm, I wonder why it's continuously rolling back though 🤔
Ok now I'm really confused because I moved the bot far away and it still does it. But it does appear to be related to the bot.
possible there's a collision at 0,0,0 for the first tick?
or the bot is honestly mis-sync'd sometimes for some reason
The really odd thing though is it stops rolling back when my own ship finally stops moving, and then the moment I move again it does it
I dont think I understand lightyear enough yet to speculate
Ok so it does appear to be something to do with collision, I commented out the collider and left the bot there, and it appears to be fine
I wonder if I switch the bot to use my Moveable component instead if it would work. Hmm prob not because it still needs a collider.
Ok there is that one comment in there about the position and rotation components needing to be manually added, which I think no longer applies. I removed that, and its not happening anymore
fuck I just got a chain of being lucky I guess, thats not it ^
Question how does one enable lag comp in lightyear?
it is fine it was behind a feature flag
in lightyear avian
I wonder should player that are interpolated in other clients but predicted in current also receive lag compensation history component?
It seens so yes
the things going out of sync are Transform and Movable on the player, according to the logs. i dunno why the bot matters so much 😵💫
maybe we're just reaaally lucky lol. But yeah that's odd
maybe check if the Position of your bot is where you expect. it's interpolated (right?) but it has physics components so maybe it is existing in a funny place in the simulation
you need to add add_prediction in your protocol so that the component gets synced from the Confirmed (which receives replication updates) to the Predicted entity
oop just rebuilt my main and got the same bug as you, I just fixed by moving it via transform. I believe the issue is related to one of the recent commits on main
oh ya? Interesting. So, my player ship is moved via transform, but not the bot 🤔 I'll play around. Good to have this validation though
BTW anyone who wants a simple "move and slide" kinematic movement, I just use Avian's Spatial Query and took a technique from the OG Quake (which is open sourced), it seems to help with determinism quite a bit. Which of course plays nicely with Lightyear
https://github.com/cBournhonesque/sixdof/blob/main/shared/src/moveable.rs
Yeah I dont know whats up, I'm now 100% moving everything via Transform and it still sometimes does it, but only when the bot exists 🤔
If anything at all move via physics
You get a rollback
So a simple appliance of velocity and boom rollback
I'm not even doing that
If there is a single initial rollback that is to be expected. But if they are continous than I have no clue
yeah the initial rollback I figured is fine
I also have this weird thing where the collider on the client is not following the bot at all.
Not sure if networking related
I'm switching things to use Position instead of Transform
Sorry I cannot help more right now on this, I'm a bit sick with some kind of flu + my queue of things to work on are:
- refactor the 'native' inputs
- fix some rollback error that @long marsh raised
- look at sixdof
And yea in general I think it's better to have Position be replicated rather than Transform; I don't really remember why though..
Yeah I think there's something up with it where it:
- doesn't interpolate (the bot jitters when relying off Transform)
- the avian colliders dont follow the transform, only Position/Rotation
maybe thats why
Hmm avian 3d sample is position based and also broken
@pine cape and @misty wyvern @long marsh @viral robin Its not lightyear its the network conditioner!
hewhehheheheh
The conditioner scrambles up the package

They are not arriving in order
it doesn't actually respect ordering!!!
Ok that seems to not completley solve it as rollbacks still happen, but at least thats maybe part of the issue?
isn’t it expected that your average packet does not arrive in order? i would think the default channel is unordered unreliable and we just retransmit unack’d updates until they’re ack’d
Yep after further inspection I think so. We tried to add the conditioner logic after the networking to see if it works, but as far as I can tell lightyear ads the conditioner on a layer where the ordering is handled afterwards.
Shame was hoping it was the reason for the rollbacks, but was most likely a false alarm 😔
The rollback issue does not llurk on your game every single sample (that has physics ) has it right now just utilize an older version of main until fix.
Ya thats a good point, I'll check an older version of main and see if I can find when it happens
I will check what commit exactly broke it. I know for a fact that a week ago my game was working fine with main
lemme know man, good to hear for your case
hey guys i cant use PartialEq with HashMap, is PartialEq necessary ? cause i see the examples using it
Statestype and stateinfo also need to be partialeq
states type have
yes hash map doenst accept partialeq, means i cant use hash map with lightyear?
Oh are you using bevy utils hashmap?
It's partialeq
no
let me check
yes iam
Dang
no, the problem seens StateType
cause it work without StateType as key
but state type have partialeq
You can derive PartialEq for the StatesType btw, you're doing the same thing that the derive would add
i did
What exactly is the error?
I use RustRover, but I don't trust the intellisense sometimes
show us the compiler error :p
Let's continue this in #rust , I don't think it's a lightyear specific issue
I'm new to lightyear, but isn't this a bit of a code smell? If they should both be set to the same value, surely config.replication.send_interval should just not exist?
Is there a way to create the SteamworksClient fallibly? Currently my game crashes if I run it without having Steam running, which is a bit inconvenient, and the constructor for SteamworksClient just unwraps the creation of the inner Client, and the fields are private, so I can't just construct my own.
For now I'll try to just make my own steamworks and check if that works, and hope it doesn't cause any issues that I've created two during the lifespan of the program, but it would be nice to propagate this up.
Should I open a PR for it?
that sounds annoying, but I guess you could also try the suggestion in the doc?
(I'm not very familiar with Steamworks client, so I don't know what the id inside steam_appid.txt should look like)
I'm actually using the other one where I provide the app id directly (since I'm just using 480 for now)
Okayt I found out which commit is breaking everything, it is this guy
@misty wyvern
Check it out this is a dynamic body before him. This is a predicted entity, with interpolated (ignore the gizmos, they are stuttering because I need to play with internals but I am just too lazy)
As you can see no continous rollback
I think moving the Increment rollback tick as last set made it so history update set, didnt update in the correct tick. Just a theory Mr Peri is sick, so I dont know he is the only one who can confirm
Nice I'll check this out this evening and let you know if mine is good too
Yes, in main I only kept the config.shared.server_replication_send_interval
Which commit are you on now?
The one before that
If I use 3748543999b82f9bd74e8ae9b9f27e4404da9ed5 I still get continous rollbacks
Ah shucks, cant you help you brother them unless I see your sample. In this commit avian_3d also functions correect
It’s the main branch, I reference a local lighyear repo (which I rolled back to that commit), so that would need to be modified
ah yours has collisions
mine is just flaoting character and sensors
Ok then it make sense
I just "fixed" the multiple rollbacks when simply moving a dynamical body
thanks; so before that commit you had no rollbacks?
and with that commit, you get continuous rollbacks even with no collisions?
Eh, I'm getting a cash on the commit before it. I think I'm just going to focus on something else for now 🤣 game could use some sound 😈
Continous? No
Yes, if I apply any sort of physics yes. If I just move via transform and other non physical components no. You can check out avian samples they "work" fine in that commit after it, they go banana
thanks i'll take a look
I was reading some issues and thought i heard there was a way to make positions only sync once on specific entities? Like for projectiles
ReplicateOnceComponent::<C>
yeah ReplicateOnceComponent::<Position> is giving me errors
saying expected value, found struct
What happened?
Why don't I have anymore rollbacks?
Why is everything suddenly smooth?
Did anyone else try latest main?
magic probably?
I still have some small rollbacks in the begining (which is expected when everything spawns) , but then it simply is smooth
I replicated the input broadcasting from latest main... but was that the issue?
::default()
ooh I needed ReplicateOnceComponent::<LinearVelocity>::default()
Ok connecting one client seems to be very stable, but when I connect the second client, I get continuous rollbacks again 🤔
Fix came in with new pr, I am guessin
which one?
The merge of input types
Question when doing lag compensation, why must I grab the interpolation delay from the connections entity? Isnt interpolation delay a hard fixed 2 behind ticks, or is it variable?
I haven't looked at the code, but interpolation delay usually varies depending on the ping
And since everyone can have different ping, everyone can have different interpolation delay
exactly, interpolation delay depends on your RTT, so it's varying per client. And even for one client the RTT can vary over time
ok I took a look at the rollback issues, it's not immediately clear for me why https://github.com/cBournhonesque/lightyear/commit/0f51455b0cc38169253dba81038b7f699e5d6340 would cause any issues
However rollbacks are gone with this simple change: https://github.com/cBournhonesque/lightyear/commit/c3a012469c6938075c001eabed30ec3471f39eb1
- transform gets modified too frequently (avian position->transform
sync, transform->global transforms, visual interpolation, etc.) - maybe visual interpolation causes slight numeri...
It's not 100% clear to me why, I suspect it's the interplay between rollbacks and visual interpolation
Ah i know, it's because before we would do:
- PhysicsStep
- SyncStep (Position->Transform)
- UpdatePredictionHistory
And after we do:
- PhysicsStep
- Update PredictionHistory
- SyncStep
So the history for some reason has some invalid Transform component, as the correct value (the one being sent from the server) is the value at PostUpdate, which is after the Position->Transform sync
However we cannot avoid this because we want:
- Correction to happen after UpdateHistory (correction will modify the component so we want the correct value of the component in the history before any correction)
- VisualInterpolation to happen after Sync (because we want to visually interpolate Transform. And transform gets updated only after Sync)
- VisualInterpolation to happen after Correction (correction is a FixedUpdate value, so we need to visually interpolate it to get the correct visual value)
- Sync to happen after Correction (because we want the visual interpolation to run on the corrected Transform)
so this gives us [FixedUpdate] UpdateHistory -> Correction -> Sync -> UpdateVisualInterpolation.
Which is correct in the setup where we replicate Position/Rotation and visually interpolate Transform.
We could have another setup where we replicate Position/Rotation and visually interpolate Position/Rotation, in which case we could:
- [FixedUpdate] UpdateHistory -> Correction -> UpdateVisualInterpolation
- [PostUpdate] VisualInterpolation -> Sync (we sync the visually interpolated Position/Rotation to Transform in PostUpdate)
And another setup could be to only replicate Transform directly. I think I tried it in the past but ran into some issue
Put together a small write up here: https://github.com/cBournhonesque/lightyear/discussions/941
great to have a recommended approach for this. plenty of the examples/ that use gizmos rely on Position to draw the gizmos, so we probably want those using Transform instead (per the recommended option 1)
(anything using a mesh or sprite will be rendering based on transforms already, just an issue for gizmos really)
Correction -> Update history
Sync -> Visual interp
Correction ->visual interp
Correction -> sync
So why not just do correction-> visual interp -> ->sync -> update history why not do it like that ? That way we can still use the transform samples
I guess the reasoning is that the synstep is the one that actually recreates the transform from pos and rot?
With the latest main I observe something peculiar and wanted to know if anyone can replicate it:
- run
server - run
client -c1
-> Rollbacks happen as expected (very few at the start but its stable)
- run
client -c2
Now rollbacks start to happen every frame if I move the second character around.
So with one client connected rollbacks barely happen (even with shooting physics based balls etc. e.g. with collisions)
But as soon as the second client joins rollbacks happen every frame.
Because then the PredictionHistory will have the Corrected value, which is not what we want, we want the raw value pre-Correction in the history
hm i tested the change with multiple clients without issue, but I can test again. I tested with no correction, and with enough input delay to fully cover the latency
Ok will try again, did you also test with the dynamic cubes?
No cubes, only one character
I am guessing the only way to avoid that is to refactor the code logic itself, make it so while correcting you store the incorrect value
Ok only avatars work without rollbacks, only cubes introduce it.
yes because cubes have multiple points of friction with the ground, which causes collision-induced rollbacks
Yes it's possible that there's better ways to organize the code where Correction doesn't modify the component value directly; or where UpdateHistory is aware of the Correction
https://github.com/cBournhonesque/lightyear/issues/940 @pine cape Might i move forward with this. I intend on making it possible to have multiple child colliders considered, instead of jjust one. In lag compensation, also instead of just panicking return a warn where it tell you to insert collider either on parent or child
What is the issue? That you want lag compensation on entities that don't have position/rotation?
I wanted to make it so it was inheritable, for example: I have 8 colliderr attacked to npc
Instead of insert lag compensation in eight I could just set parent
Also dissociate the need for Position, Rotation. As someone may use lag compensation with transform, but in current state could postpone
Yes currently it's tied to avian internals, but maybe it could be more customizable
Feel free to submit PRs
Okay great, I will get on it
Mind mergin this one https://github.com/cBournhonesque/lightyear/pull/938. He is quite volumetric but nothing too serious just taking info spawn from lag compensation and applying rust fmt and global vscode config file
? is the example wrong
you need to import features in avian, the feature in question serde i think it is name not sure
i tought this was auto, anyway thanks
how could i replicate inputs without using the leafwing_input_manager
and this?
is the example old?
cause this is not okie
just import lightyear avian position lerp
it says its private
How has lightyear changed compared to the cheatsheet for adding messages and linear interpolation? 😅
I get a couple errors following it, one not recognizing app.add_message as a method, one I believe to be arithmetic and one unable to find an attribute for message protocol
Sorry if this has been asked before / is a bad question, this isn't a channel I can search in,,
register_message now
seems like the simple_box example is up to date for your issues https://github.com/cBournhonesque/lightyear/blob/main/examples/simple_box/src/protocol.rs#L125
probably just missing these impls for PlayerPosition too https://github.com/cBournhonesque/lightyear/blob/main/examples/simple_box/src/protocol.rs#L50
if that's not sufficient you have to implement Linear trait for your type https://github.com/cBournhonesque/lightyear/blob/c3a012469c6938075c001eabed30ec3471f39eb1/lightyear/src/protocol/component.rs#L283
Its possible to not replicate ALL values from a component?
TY bro, ill try it out
You can add a custom serializer/deserializer for your component when registering it
So i need impl Serializer for It?
And Deserializer
Thanks
well have some examples? cause i think iam doing something wrong, i dont want update applied cause its supposed to client do it on it own and server on it own, but the way i did for some reason server keep forever updating it as false for the client lol
impl Serialize for StatesInfos{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
let state_infos = (self.start,self.duration,self.source.clone(),self.in_cooldown);
state_infos.serialize(serializer)
}
}
impl <'de>Deserialize<'de> for StatesInfos{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>
{
let (start,duration,source,in_cooldown) = Deserialize::deserialize(deserializer)?;
Ok(StatesInfos{
start,
duration,
source,
in_cooldown,
applied: false,
})
}
}
instead do applied: false i want keep the current value that is on client already
but it doenst sent me a self
I don't think you can do that currently, when I receive the bytes I first deserialize them into a Component, and then replace the existing component with the new value
make a support for it on future , not all values from component will need be serializable always
like there is some states i dont want replicate
but i will be forced now lol
You can use replicon which seems to support something like that: https://github.com/projectharmonia/bevy_replicon/blob/master/src/core/replication/command_markers.rs#L112
i would need change my system to use replicon instead
iam fine
but you could do it btw
okie this is a problem now cause server will keep try replicate client_applied = false
anyway i will do some infos locally so will fix the issue
Do you think that the rollback schedules/systems should sit in FixedPreUpdate instead of PreUpdate?
Rollback is closely tied to FixedUpdate (it re-runs FixedUpdate for a certain number of ticks). I'm having some issues that are directly tied to rollback being in PreUpdate, so I'm wondering if this is the move.
I'm also weighting if the general packet receive/send systems shouldn't be in FixedUpdate.
cc @wintry dome @long marsh
I think it's the right move, especially since during rollback check we are checking the confirmed.tick vs the current predicted tick; both are FixedUpdate ticks
@wicked tulip I have a few fixes for correction in this branch: https://github.com/cBournhonesque/lightyear/pull/943
I believe that these completely fix any correction issues. It was mostly due not handling the interaction between Correction and VisualInterpolation when you have 2 FixedUpdate in a row, or 2 Frames in a row
You can try the avian_3d_example and use Q to fire a projectile
With this branch I had some strange things happening:
Also the bullets seemed to not collide with each other
What are the strange things happening? And yes I didn't implement any collisions
Ah, the characters moving into each other is expected?
They are also in different positions on the clients
Looks like the one on the right is offset to the bottom left
Wait
the pink one looks like it might be in the same spot in both, but the green isnt
oh, no, because the shadows arent the same angle
Are the cameras just rotated differently?
hmm weird does anyone have any idea on why my confirmed entity position is not affecting the transform?
oh forgot to add a rigidbody into my interpolated entity
You can also add your own sync function, like in the avian3d example
Hm okay, btw I think I found a bug
Or not a bug but a possible feature, when it comes to the sync mode simple does he consider, insertion and removals of a component?\
In my case I was using a state machine to set my play music and animation logic. But since the state machine usually inserts and removes component continously it seens that the simple component sync mode alignment makes it despawn and never spawn again
It does insert/remove components
Well found what it was, if you have a enum component, and reinsert it into the entity. If it is just a varaint of the enum, it wont detect the change therefore not update it
They had to postpone, the generic types enums fields e.e. Now my logic will be ugly :<
I'm pretty sure the change should be detected, it must be some other reason
When I make it so they are truly different types (instead of enum variants) it changes normally. It matter little to be honest I could just send a message from server with the player state, instead of using sync. If you want I could post the sample code
Here is a sample video
Cant believe the thread is going to die because of this
Weird lightyear doesnt require 0.2.1
Perhaps you are doubling your import
I added the features avian3d and steam
if you already had avian in your Cargo.toml you would need to remove it and do a cargo clean, because lightyear uses an older version of avian than the latest release
if it’s not that, you probably have some other dependency requiring the newer version of avian and you can figure out which one by looking at your lock file
Probably bevy tnua avian3d
yeah might have to use an older release of that or patch the underlying avian version or something
tnua is up to date lightyear is not
I dont know how much changes 0.2.0 to 0.2.1 affected tnua
When are they fixing that?
Is it fixed on the github yet?
1 million dollar question.
you can check that yourself 🙂
thank u for this very good answer
NetConfig is a resource ❤️
hey, i'm still abit confused how hierarchy replication works... does it replicate all the children entities inside the entire hierarchy?
Yes, if recursive=True
For bevy 0.16 I have refactored this to a more performance system
oo ok
What?
glad thats been solved
i fixed it
EventReader<ReceiveMessage<Spawn, Spawn>>
what about NetworkRelevanceMode, does it apply to all children as well? if that's the case do i need to add all of the children to the room for the replication to be correct?
hmm, I dun see the children being replicated in the client, they shud be replicated as children right?
or do i need to add sth special for them to be replicated?
oh... it's only replicated if there's no parent...
wierd, my client still isn't receving it...
Most settings are propagated to children, but I think that for rooms it works correctly
I fixed it for the next version though
i'm still in lightyear 0.16.4 for bevy 0.14 due to some other dependency issues 🤣
DAMM

we love em
I managed to get the children to replicate by adding them to the room manager, however, i noticed the predicted entities are not in a hierarchy, they are separated instead haha
is your game open source? looks awesome
SOME RECOGNITION
it is enough to make a grow men cri
You should see it with it assets it looks way better
it stopped being a few month ago, when we started to have assets produced to it
I was just curious how you organised the project :p (had a quick glimpse at folder structure in your video)
on another note, i've just cloned lightyear (mainline) and i've got 4 failing unit tests, I'm guessing this is expected? I remember briefly seeing some conversation about correction bugs
Ah I'll take a look this weekend
i'm just being a bit nosy
(currently trying to figure out what it might take for lightyear to consume mainline bevy)
I have a branch 'bevy-main' that I use to track bevy main, most of my changes went there
that's really handy, thanks!
for some reason I get this compilation error, and i don't understand why (i'm building bevy-main branch)
I tried cargo clean and rm Cargo.lock to no avail
and I've cleaned registry folder in .cargo
funny enough, lightyear pointing to bevy-main compiles fine when i use it as a dependency, I don't know what cargo is complaining about here (or how I got into this mess)
ok i figured this out (sort of)
lightyear fails to compile after this change went in
https://github.com/bevyengine/bevy/pull/17955
and following the migration guide doesn't help
it's fine if I use a commit just prior to that change (I could compile with 5bc1d68a65d615d4bc107ebb2c3dfc40b455690a with some minor modifications to the code)
So I have an infra question, and I was wondering if this is the correct approach. I have a map made in blender right. I want to fill it up with colliders. Async scenes ones in this case. In this case scenario, what I thought about was, load asset in client -> client replicate child entities with colliders -> pass authority to server -> server replicates for the rest. Is this the correct approach?
Why not load the map in parallel?
Now that I say it out load, I forgot that gltfs. Have the ability to only export meshes
Which mean server can load it quite easily
yeah 😄
Oh you must be experienced in this since you made sixdoof
When it comes to the colliders what did you do to avoid their logic infering with other entities such as player?
Did you use replicate once
Are you using Avian? Then you want to use physics layers
You mean collsiion layers?
err yeah whatever its called
@coral stratus i just updated my bevy-main branch; although i couldn't get it to compile becaues of the errors you linked earlier
I use both std and async_executor features but it doesn't seem to work
yeah it seems like there is an issue in bevy mainline
i had a chat with bushRAT about it in #general earlier
I think he is sleeping rn but I'm creating a github issue for this
I tried to narrow it down myself but it's a little difficult for me 😄 I'm not that familiar with Bevy's codebase
@pine cape I created this issue https://github.com/bevyengine/bevy/issues/18200
I'm using Client Host setup, with a message that implements MapEntities, and after updating to Bevy 0.15 and thus the newest lightyear version I'm getting warnings in the log about being unable to map entities. The actual functionality works fine. I thought would be after some new patch that added logging, but looking at the commit https://github.com/cBournhonesque/lightyear/commit/2011ff894ec08368041437731e29035fb6f003d0 the logging has always been there, which I think means there might be a bug with mapping entities between the client and server on the host (which still ends up working fine because they're actually talking about the same entities)
Upgrading to mainline bevy isn't as easy as I had hoped 😄
I tried working through the compiler errors now that the fix for bevy_utils has gone in, but it's a bit tedious
i've resolved lot's and lot's of errors around tracing::{trace, debug, error, warn} (i think it's tracing anyways)
but this one is killing me lol
I forget the exact syntax, but I believe it's something like requiring A to have the bound A: Component<Mutability = Mutable> instead of just A: Component
ngl I don't understand that syntax (and I don't quite understand bounds)
but i know what needs changing so I'll give it a try
you're a genius
it works...
Looks like https://github.com/bevyengine/bevy/pull/16372 is the PR, and it mentions this in the migration notes, so at least it'll be good for when that's actually released 😋
nice, I tried finding a pr for this change but I gave up 😄
Since I knew what the problem was I just looked at the git blame for the line type Mutability; 😋
I forget what the syntax is called too, which is why I almost forgot how to write it, I could only find the syntax in a ralted rfc hehe https://rust-lang.github.io/rfcs/2289-associated-type-bounds.html
interesting, I mean the migration notes do mention that exact syntax
for this specific situation i'm looking at too :p
Yupp, the joys of working off main 😋 Glad it works though!
now to fix the tests...
Apparently it could've been implemented without any userside changes, but alas associated type defaults is unstable: https://github.com/rust-lang/rust/issues/29661
@fervent karma do you know what a PreSpawnedPlayerObject is? Lot's of tests use it, but it looks like it has been removed
@coral stratus you should probably wait until I fix the branch, I think it would be hard for you to fix it yourself
I think it's a timing issue (for example you're receiving a message about a mapped entity before the entity has been spaw ed), but things should still be working fine
ehhhh, too late lol
https://github.com/cBournhonesque/lightyear/pull/945
I mean, i've fixed it for myself, feel free to do with these changes whatever you like... (i have 0 expectations this is going to get merged)
i've looked through the PR, LGTM! Thanks for the help 🙂
Happy to help 😄
i've pushed another commit that fixes all tests
the other thing i'd like to fix to be ready for the new bevy release is https://github.com/Jondolf/avian/issues/643
Hmm, it's spawned quite a while ago, I'll see if I can get a minimal repro
Is there a way to have certain components be client-authoritative? I would like to be able to do app.register_component::<Component>(ChannelDirection::ClientToServer); and just have the client send the data to the server whenever it updates it's value. However, this doesn't seem to work. Do I need to manually send the updates via a channel?
Yes that's how you do it. Did you add the ReplicateToServer component on the client?
I didn't know there was such a component. I added it just now but it doesn't seem to change anything
It definitely works, I have dozens of unit tests for client to server replication. Can you share more code snippets
guys
this doenst exist anymore like on the example?
cause iam using this
@pine cape its a old example?
i guess this is the new example?
Yes
I currently add this on the client side:
Replicate {
target: ReplicateToServer,
group: REPLICATION_GROUP,
..default()
},
The replication group is just a global one I am currently using for all the character logic
The entity this is attached to correctly gets things replicated from the server.
The entity also has a Rotation component on both the server and client side
This is in the protocol plugin app.register_component::<Rotation>(ChannelDirection::ClientToServer);
Oh wait, did I missunderstand your inital response? Did you mean "Yes" in response to the manually sending via channel?
this LGTM; i would try to see if you're doing anything different from this example: https://github.com/cBournhonesque/lightyear/blob/main/examples/client_replication/src/protocol.rs#L30
its my issue or lightyear issue @pine cape
you didn't provide much detail, i don't know what i'm looking at, and i don't have access to your code. So I can't really tell you anything
bassicaly i press to walk forward
it walks
when i stop pressing
it starts slowing walking back
want see the code on github?
both on client and on server
are you using leafwing inputs or native inputs; are you on the main branch of lightyear?
this happens
leafwin inputs
lightyear = { git = "https://github.com/cBournhonesque/lightyear.git", branch = "main", features = ["avian3d","websocket","leafwing"]}
Probably your issue; I have 2 leafwing+avian based examples that don't have this issue
could you take a small look?the code is small
do you have a link?
iam geting rn
testing. Contribute to Kevenpvp/PowerProject development by creating an account on GitHub.
its very ez to understand the names
combatantsystem.rs on both client and server workspace to see how i make the character
charactercontrollersysem on shared to see how i move for both server and client logic
when the player stops walking, are you sure you reset the linear_velocity to 0?
probably? otherwise if you stop pressing forward the character would keep walking forward indefinitely no?
i mean it would make sense it keep walking forward
but it just moves
backward
back to the spawn point lol
let me try set the linear to 0 to check
I would also try having only 1 input mapped to Move instead of 2
I would check if you're getting rollbacks
I would add logs every tick to confirm the linear-velocity value + the ActionState values to see what they are
but yeah i don't think this is related to lightyear per se
it have just one
how could i?
i mean the weird part is on video the server is moving back too
there's 2
not just the client
iam gonna try
i mean i followed your example
yeah set the lienar velocity to 0 make it stops @pine cape
thanks
@pine cape ?
Did you add some network latency via the LinkConditioner?
nono, i fixed, also i have a question, can i let the rotation be client authorathive? @pine cape
cause i want the player rotate basead on camera
that isnt possible on server since server have no camera kk
the server's Transform could be authoritative, and you just add a Camera component on the client entity that has the replicated Transform
i added
but if i rotate the character on client
i will need send a mesage for server
to rotate it right?
or here i can set biderectional ?
How do you guys handle transferring maps to the clients? I managed to get bevy_ecs_tilemap auto-magically updating by adding a Replicate on the tilemap (which then replicates all the children), but I can't spawn the entire map, since then lightyear tries to replicate every single tile at the same time, leading to overflowing the buffer, which causes lightyear to crash. I wonder if maybe the default behaviour should be to just defer some replication until the next frame, but if that's not desirable I was thinking we could maybe add in a can_be_deferred to replicate, which would allow lightyear to delay it's replication until the next replication instance if it ran out of space in the current one. Does this seem reasonable, or should I maybe not rely on lightyear to magically replicate tiles? I really like how it just works, it even replicates across changes the the tile texture and everything
I wouldnt recommend doing maps via server. As you can see it is truly a heavy thing to do. Unless your games is client host them it is fine
Perhaps, delta encoding would be helpfull
@pine cape Sorry to bother but does replicate hierarchy only work in 0.16?
I think that happens when it's replicated, so once it's up and running it works fine. The only problem is the initial replication
Yeah, I am also having issue with maps. But my problem in this case is simple replicating the hierarchy
Actually since I've just been doing map stuff I can confirm that it replicates the hierarchy by default in 0.15
hmm
What is the issue you're seeing?
Well so I want to replicate the parent entity and the child for a scene, but it simply doesnt receive the child entity in client
fn replicate_maps(
trigger: Trigger<SceneInstanceReady>,
children_query: Query<&Children>,
parent: Query<&Parent>,
mesh_3d: Query<&Mesh3d>,
meshes: Res<Assets<Mesh>>,
mut commands: Commands,
) {
let map = trigger.entity();
for child in children_query.iter_descendants(map) {
if let Ok(Mesh3d(handle)) = mesh_3d.get(child) {
let mesh = meshes.get(handle).unwrap();
// Only replicates worthy entities
if let Some(collider) = Collider::trimesh_from_mesh(mesh) {
let parent = parent.get(child).unwrap().get();
let replicate = ServerReplicate {
// We increase his replication target via lobbies
target: ReplicationTarget {
target: NetworkTarget::All,
},
hierarchy: ReplicateHierarchy {
enabled: true,
recursive: true,
},
// relevance_mode: NetworkRelevanceMode::InterestManagement,
..default()
};
commands.entity(child).insert(collider);
commands.entity(parent).insert(replicate);
info!("Replicating parent {}", parent);
info!("Collider added to map entity {}", child);
} else {
warn!("Info this entity didnt have a mesh {}", child);
}
}
}
}```
One thing you could try is something similar to this example: you can sent a max bandwidth between the server and client: https://github.com/cBournhonesque/lightyear/blob/main/examples/priority/src/main.rs#L32
And then lightyear will use a priority accumulation system to decide which ReplicationGroup to include in each packet. If the max bandwidth is reached, it will put the updates in the next packet. https://github.com/cBournhonesque/lightyear/blob/main/examples/priority/src/server.rs#L49
This only works if you're able to split your updates between multiple ReplicationGroups, because a ReplicationGroup means: "send all updates for this group of entities in one go (i.e. in the same packet)". Would that work?
A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear
A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear
Hierarchy replication should work right now, but it doesn't work well when used with interest management/rooms
In your code you seem to be re-adding Replicate on the parent multiple times, no? I would try to add it only once.
I think this should work; which Schedule are you running this system in?
btw where do i look it?
because iam having this problem rn
again
I dont think so print only runs twice it is an observer so no system, and add to distinct entities
Ah this is exactly what I was looking for I think, I didn't realize it was already implemented! I imagine I can probably do some chunking stuff to put each chunk in a different replication group, and then prioritize the chunks closer to the players highest, but even just for now I'll try adding every tile to its own group for now.
Thank you!
yeah i’m curious if there’s a sane way to handle replication priority based on player proximity? or does that exist already?
same thing for network send rate and proximity tbh
I think I figured out what it is
The map is part of a scene, where other individuals have no replicate hierarchy. If map has replicate and is child from a entity. It simply doesnt replicate his children
If he is not,it replicates normally
So basically, if an entity has no parent it replicates as expected
If it has it doesnt replicate, worth noting parent doesnt even need to have replicate
It's not implemented but I would love to have a demo that implements priority/bandwidth based on distance (some kind of LOD logic)
I see, yes it's possible that the replicate propagation only works when added to the root entity. I think those issues are fixed in the next version
Btw did you know if you create more than 10 plugin, in the same module. The lightyear registering of synchronization types stops ocurring. This is a very crazy bug
For example: I have this protocol file, quite a biggie right. If I create another plugin just to splie the types traits and so on, it doesnt register
Reason god if I know
How would lightyear know anything about your file structure? 🤔
It doesnt but for some reason, if I register another plugin it doesnt work. Registering, wise maybe I am going crazy?
is there an event for client connection failing?
You can try DisconnectError, I think I sometimes emit it if the connection process fails
sometimes?
Two dynamic colliders can collide in server, even in different rooms
Is that expected?
I guess it does make sense
As they are not protocoled components
Yep you would need to add collision layers to match the rooms
thank you!!
So right now I have my projectiles setup like the spaceship example, with collision handling code running on both the server and client, where the client side collision handling writes events that spawn projectile explosions; however, it appears to be random whether or not the explosion happens. i.e. the server is despawning the projectile before the client has the collision handling. Anyone have a more robust way of handling this?
Make it so the explosions are server sided? Perhaps, hmm this is quite a toughie. Perhap never despawn collider on collision, but only on explosion event? From client
I wonder why the rigid body of lag compensated entities is so weridly placed
so the server has athority, so i have to despawn on the server
does lightyear handle server to client events maybe?
you can just hide it on the client as soon as the client predicts the collision, then let the server despawn it and replicate a new entity with the vfx. or something like that anyway
so the problem is that the server despawns before the client predicts the collision
maybe im not understading what you mean tho
yeah maybe im confused? the scenario you’re describing does not sound like a problem to me
it’s a problem because you can’t get the hit effect into the predicted timeline?
so the server despawns the projectile, and the client never gets to collide
but why does the client need to collide
because thats where we spawn the explosion
maybe I could replicate explosions from the server to clients but that leads to more networking
I think I'm gonna try spawning explosions server side and replicating them, unless anyone has a better idea
yeah that’s what i’m saying
i think in some games if the client successfully predicts it spawns a soft / starting vfx and waits for the server to confirm to play the big one
ok cool:) thanks for talking it through with me
Btw why is your pfp so familiar is it from a game?
exactly
oh its a pixel art pictures of me, a friend drew it
oh I tought it was from this game orwell
oh I've heard of that game
Is it normal to get lots of Corrected component was None so couldn't restore: "avian2d::position::Position" in the debug log? I'm getting constant rollbacks and I'm just trying to narrow down the root cause. It seems like if we're doing a rollback, there should be something to restore to right? I get multiple of these logs every rollback
It shouldn't be the case that the server despawns the entity before the projectile collides, because the despawn message take time to travel. I suspect that your projectile gets despawned because the server did not spawn the projectile or there was no prespawn match
If you run with the visualizer feature, there is a plot that shows prespawn mismatches
These logs might happen if your framerate is high, I wouldn't worry about them. You can turn off Correction to help debug the rollback cause.
Note that if you have colliding entities with avian you will get constant rollbacks
Is that for any colliding bodies or just for dynamic?
Dynamic ones I think. It's because the Collisions resource from avian is not replicated
I built my own kinematic controller and it was working well with 0.19. I’ve started to use main and I haven’t been able to get the rollbacks under control yet
The spaceship and avian_physics examples are broken for host-server on main. The host-server player doesn't respond to input but networked client players work. If I add the position_to_transform to the schedule like below, it starts working but with constant rollbacks. Is this expected/known? Are the rollbacks due to the Collisions resources not being replicated?
app.add_systems(
PostUpdate,
position_to_transform
.in_set(PhysicsSet::Sync)
.run_if(|config: Res<avian2d::sync::SyncConfig>| config.position_to_transform),
);
It's possible, I thought I made sure that all examples worked in host-server mode with the input refactor, but maybe something got lost in the merge
Ya the input is being applied because on the spaceship the flames appear but it doesn’t move until I add that code
i think it's a system order missing, because it works half the time
I think i fixed it, but i have another issue. For some reason the server::Replicate component is not added on the host-server's player at the beginning.
I determined via log that it is added, so something must be removing it
https://github.com/cBournhonesque/lightyear/pull/950
It's a bit mysterious: just run cargo run -- host-server in avian-physics. You can see via the inspector-egui that the player doesn't have the Replicate component
ah i'm dumb, Replicate is a bundle, not a component
the ReplicationTarget component is missing though
I have this weird bug when colliding with statics in my game, that does not occur with avian samples. I dont know exactly what am I doing wrong. But the bug goes as follows, there is no rollback on collision when dynamic collides with StaticBody. With sole clients. The moment I spawn a second client, and it has a collision with a the static body. I get continous rollbacks, independently of the force. The rollback just informs me there is a mismatch between server and client position. Sometimes linear velocity differences. My guess is that in a frame, my predicted entity, manage to enter inside the collider. Any ideas on how I can avoid it?
How do you run with a single client?
https://github.com/Sirmadeira/psycho_duel - Here is the repo
You mean how do I move? I just add lin_vel
pub fn physically_apply_movement(
tick_manager: Res<TickManager>,
mut player_action: Query<
(Entity, &ActionState<PlayerInputs>, &mut LinearVelocity),
Or<(With<Predicted>, With<ReplicationTarget>)>,
>,
) {
for (entity, action, mut velocity) in player_action.iter_mut() {
let move_dir = action.axis_pair(&PlayerInputs::Move).clamp_length_max(1.0);
velocity.0 = Vec3::new(-move_dir.x, 0.0, move_dir.y);
debug!(tick = ?tick_manager.tick(), ?velocity, actions = ?action.get_pressed(),?entity, "applying movement to predicted player");
}
}
Oh found a bug in lightyear,
Child entities of predicted entities automatically try to be predicted, even without replication hierarchy on main. Which causes a log spawn, at least that was annoying me. I guess it is because player has a replication group? And replication groups consider thei childs as part of them, even tho the child doesnt have the protocol components
So I've been having some problems running the visualizer with my current setup, My headless server thread crashes when I add the visualizer feature to lightyear.
thread 'Compute Task Pool (1)' panicked at /Users/elizabethsuehr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_egui-0.32.0/src/lib.rs:437:14:
`EguiContexts::ctx_mut` was called for an uninitialized context (primary window), make sure your system is run after [`EguiPreUpdateSet::InitContexts`] (or [`EguiStartupSet::InitContexts`] for startup systems)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `bevy_metrics_dashboard::namespace_tree::NamespaceTreeWindow::draw_all`!
I believe this is because I run a "Headless" bevy which has a window plugin just doesn't display any windows (so some plugins work that don't have a headless mode)
You are correct lightyear doesnt consider headless mode in visualizer
Which makes sense when you think about it because there is nothing to visualize
Oh I figured out what my bug was he was colliding with two colliders in server at same time
Because my layers are ors
Ah fuck that means different positioned maps
is there a way to disable it so my thread doesn't crash?
Are you using workspaces?
If os you can easily make it so visualizer is just client specific
Just add in that workspace depedency
so everything is in one workspace
can i control what server will replicate for client?
i need a system like this for my battlegrounds
-Player press a button like Move (W)
-Player start moving instantly
-Player send a message to server that he pressed W
-Server basead on the delay it took to reach the server will move the player for the position he would be and keep moving the player forward (since its W)
-It also replicated for all clients, sending the direction he is moving, the current position, and a timestamp
-Others clients use this timestamp + the position sent to also move the player for where he should be and keep moving the player on this direction
the problem iam having rn is lightyear is updating myself the position, i dont want, barely i will want the server update my position again
bassicaly the client should move without server interference
instantly
server will calculate the moving direction and update others players, and server will ofc correcrly for the others players in case the player is exploiting
Problematic them, as there is no way of having unique dependencies according to server and client
Everyone is just the same app
One way would be to make server not headless
?? Just make 3 workspaces
Client, Server and Shared
Shared have stuff that client and server can acess
would that work if everything is in one binary?
so I got the visualizer feature compiling, but it doesn't show anything even when people connect, what would I be missing?
as in the metrics dashboard shows up but just has pause and link x axes
Also rollbacks and rollback ticks are happening continuously (found via PredictionMetrics resource, not visualizer), seems like that shouldn't be happening
ok I figured out how to get the visualizer working, and there is prespawn::no_matches every time I fire (sometimes when i fire)
Make It not Just one binary lol
this just sounds like a bug to me
you shouldn't have to restructure your workspace to get that working
when you say add the feature, you mean the Cargo feature right
The real answer is that you need to make a patch to lightyear to allow toggling of the visualizer so you can enable the feature on the crate, but not have it running on your headless server version of your binary
yeah, well, a PR would be better 😛
does lightyear support a network like this? @pine cape https://www.gabrielgambetta.com/client-side-prediction-server-reconciliation.html
and have examples?
cause i just found server authoratives examples
the server authoritative examples are what you want, yes lightyear has prediction and reconciliation
I dont think there is a need for prediction for client authoritiez
yes but the client can move it automaticly? without input delay right
yep
iam making abattlegrounds game
i dont want player press a input
and wait to server tell them what to do
he should start instantly moving
yes this is called prediction and lightyear has it
to feel responsive
tought this example is olf
old
InputConfig doenst exist anymore
you know the replace for it @misty wyvern ?
Don't look at the main version, look at the latest released version (ypu can switch with the dropdown in the top left that says main)
I think all the examples implement prediction and do exactly what this blog post describes
Is child collision supported in lightyears, when it comes to static with dynamic?
It seens most samples break when you add a child collider
Sent the PR request last night!
btw is rebroadcast_inputs need to be true or false?
i see you using false lot of times
rebroadcast inputs means the server that received inputs from one client sends to another client. so do your clients need other clients inputs?
@earnest fog i fixed the issue with host-server in examlpes. There still seems to be rollbacks in spaceships though
Thanks! That’s what I was experiencing when I switched from 0.19 to main with my own project that’s based on the spaceship example.
Ok I almost got things working with 0 rollbacks in spaceships
There is one last system ordering missing, because it only works some of the time
I tried 10 times in separate mode and i couldn't reproduce this, so it must be exclusive to host-server
I'm encountering a bug where confirmed_added_sync() is triggered twice for two different confirmed entities in quick succession. This results in the ComponentRegistry::batch_sync() being called twice before its temp_write_buffer is cleared. This means that temp_write_buffer contains component information for two different confirmed entities which crashes the application later on due to duplicate component entries.
Specifically it crashes in TempWriteBuffer::batch_insert() when trying to call entity_world_mut.insert_by_ids() because self.component_ids contains duplicates
Interesting, that shouldn't be the case because the buffer should be cleared at the time of the insert
https://github.com/cBournhonesque/lightyear/blob/9a348775d0f47f6b59384ecf5a7214b145be8754/lightyear/src/protocol/component.rs#L169-L169
It looks to me that component_ids, component_prts_indices and raw_bytes are all cleared when this function exits
What is the exact error you get? That there are duplicate components in insert_by_ids?
It could be because confirmed_added_sync and added_on_confirmed_sync are called in the same frame
I won't be able to check until tomorrow, sorry! Something came up
Ah I figured it out
If this line returns None then the buffer doesn't get cleared https://github.com/cBournhonesque/lightyear/blob/main/lightyear/src/protocol/component.rs#L621
I'm pre-spawning entities on the client but also "pre despawning" them sometimes (e.g. remove a bullet if it hits a wall). Sometimes it can happen faster than the server can sync those pre-spawned entities to replicated entities on the server. My guess is the client despawned a predicted entity while the client was trying to handle a PredictedSyncEvent.
@earnest fog all input issues should be fixed now
For despawning predicted entities you should use predicted_despawn which hides the entity but keeps it around in case it needs to be reverted if the Server deems that the despawn was incorrect
https://github.com/cBournhonesque/lightyear/blob/main/lightyear/src/client/prediction/despawn.rs#L72
Ah thanks! Is it safe if the server also calls prediction_despawn() or do I need extra logic in my system to ensure that the server calls despawn() and the client calls prediction_despawn()
Based on the examples I do need to add that logic
Looks like the intermittent issue is still there even with prediction_despawn():
fn system(
query: Query<Entity, Or<(With<Replicating>, With<Predicted>)>>,
mut commands: Commands,
identity: NetworkIdentity,
) {
for entity in &query {
if identity.is_server() {
commands.entity(entity).despawn();
} else {
commands.entity(entity).prediction_despawn();
}
}
}
Also, prediction_despawn() sometimes doesn't hide the predicted entity until the next non-fixed tick resulting in the entity sometimes being visible for a single render frame after it should have been despawned. (e.g. Event that a 3d physics collision has occurred is sent, a system reads the event and despawns the predicted entity that collided, the next render frame shows the supposedly despawned predicted entity bouncing away from the collision, and the frame after that shows the entity is gone)
Also seeing this error log sometimes when the prespawned entity gets despawned:
ERROR lightyear::shared::replication::receive: Received despawn for an entity that does not exist
Does the system order ambiguity checker find these?
I figured it out, it seems like I actually need to make the entity fully client authoritative to be able to send things from client to the server? I can't seem to have a mix of server and client authoritative components on the same entity, is that correct?
That's a good point! I'll add a check within that Command so you can use it on both client and server
Are you using Avian?
Hm it might be because Position is disabled but not Transform... or other visual components?
This will be fixed in the next version where I use bevy's new disabled entities features
Hey periwink If i send a message for server before send a input It Will reach in order right?
You're just doing server to client replication right?
No, messages have no strong ordering guarantees currently. Inputs can be used to send data that is read on the same tick on client and server
Yes so this make a problem for me
Ah I should just have used this, you're right. It doesn't give me the exact order being used, which would have been helpful
Btw periwink i wanted to say thanks for that Very well and robust crate
You are Very smart with maths
Currently, I think so. I'm not 100% sure actually
Doing prediction and interpolation seens hard, but you did a Very Nice job
Btw are you planning add a way to not replicate some fields from a struct? Like put a macro NotReplicate on Fields? @pine cape
Iam Still having headcaches with it xd
it's not currently planned
I ser
Well iam gonna need tio manualy send messages for client soo instead make the component replicable
why can it not be 2 components?
?
// instead of this...
struct ComponentAB {
a: ReplicatedThing,
b: NotReplicatedThing
}
// replicate this
struct ComponentA {
a: ReplicatedThing
}
// dont replicate this
struct ComponentB {
b: NotReplicatedThing
}
or am i misunderstanding your problem?
like i had a state machine, i had a applied = false on states, so when a state is added i can know if already appled whatever i need apply on it, like idle i started idle animation, the problem is, server set applie = true, and it replicates to client, so clients wont start the idle animation because the applied got replicated = true for client
Just use a marker component AppliedAnimation instead of the bool
And then don't replicate that component
yeah but than i need make special markers for each state
a applied = true is much more scalable
Do you have a separate bool for each state?
each state have
#[derive(Clone, Debug, PartialEq, Reflect)]
pub struct StatesInfos{
pub start: Option<u128>,
pub duration: f32,
pub source: Source,
pub in_cooldown : bool,
pub applied: bool,
pub values: Option<StatesValues>
}
Is each state its own type?
Just asking because this type doesn't derive Component, so I'm wondering how you use it
My recommendation for this would be to add an on_insert_hook to the StatesInfos Component, and in that component you remove the StateApplied component, then whenever you insert a new state it'll make sure that AnimationApplied is not true
But really you should instead probably just an observer for Trigger<OnAdd, StatesInfos> and do whatever logic you have that sets applied to true in that observer, and then you don't need the applied field at all
Another point of note is that you probably don't really want to replicate entire animations, though I'm not sure how large they are
StateInfos is not a component
#[derive(Clone, Debug, PartialEq, Reflect)]
pub struct StatesInfos{
pub start: Option<u128>,
pub duration: f32,
pub source: Source,
pub in_cooldown : bool,
pub applied: bool,
pub values: Option<StatesValues>
}
#[derive(Component, Clone, Debug, PartialEq, Reflect)]
pub struct StatesMachine{
pub current_states: HashMap<StatesType,StatesInfos>,
}
StatesMachine is
observer?
Okay so what does applied actually mean? Can multiple animations be applied at once? Or can you only have one animation active at a time?
applied means: the state applied_state function got used
like when i apply Jump state for example
it will apply a external force up for example
applied_state function fires when the state is added
Idle state got added? lets applie and set applied = true
Is there a way to guarantee that certain entities are replicated first? I'm currently using a resource to track a list of IDs that I've spawned on the server, but I'm thinking it might be better as entities in the world. The IDs point to assets that are both on the server and the client that describe what kinds of resources other replicated entities will use like colliders and meshes, therefore the list must exist before those entities are spawned.
I'm also wondering if I can utilize prespawned entities for this, but from the book it sounds like they need to be predicted, which would be an unnecessary duplication of each.
I did see that I can use priority, but won't held up entities accumulate priority?
If it's stuff like this you probably want them to be separate components and use an observer to react to when they're added. Instead of having them in a hashmap inside s single component, which is kind of going against the ECS
There's no way to guarantee this currently.
One thing you could do is put all these entities in the same ReplicationGroup. This means that they will only be replicated at once. The entities will be spawned before any components are replicated, so components that point to other entities won't be broken
What about prespawning, Is that limited only to predicted entities?
Yes, prespawning is simply that you spawn an entity with the same system:
- client spawns it first in the predicted timeline
- server spawns it a bit later in their timeline, and replicates it to client
- when the client receives the server entity, it will re-use the existing Prespawned entity as the Predicted entity
Hmm, now that I think about it this might majorly affect how I'm planning on synchronizing the clients when there's already a lot of entities in the world. I was thinking I would essentially save the game, send the save to the newly connected client, and then have them load the save with everything "prespawned" I'd really just want to prepoulate the entitymap at that point.
Almost everything in the world wouldn't be predicted.
I'm not sure I get it; you're saying that instead of the server replicating things to the client directly, the client would be spawning entities using some save file, and then the only thing that needs to be replicated is an entity-map?
Yeah, even the entitymap could be included in the save in that case.
So the server would be persistent? otherwise the entity-map will become invalid
The server could wait in stasis while a player connects. I think that's how Factorio handles it.
If the entity-map is included in the save, you'd be free to populate the ReplicationReceiver's EntityMap manually using that information
@fervent karma https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=ce633730549ecee02b8377c5b5afc092
A browser interface to the Rust compiler to experiment with the language
much better now
this fixes my issue with lightyear
since the StatesApplied wont be replicated
someone can help me ? i don't know how to use this lib, how to structure or how create client/server system ? the docs don't have answers about this
look at the examples in the repo
@pine cape I saw your issue: https://github.com/bevyengine/bevy/issues/18312
And can't you use https://docs.rs/bevy/latest/bevy/ecs/change_detection/struct.Res.html#method.clone
For when you have a &Res? It won't help with World access though, since it gives &R or Ref<R>
It does look like it might be possible to use Ref instead of Res in the system perhaps
That's a great point, I think it would work! You should comment it in the issue
I was scared to comment for fear I was wrong, but I've done so now 😇
actually it doesn't fully work because i still have to re-create all the params needed for the run_condition
ideally i would just do if world.run_condition(is_server)
Has anyone hit this issue before? As soon as the client connects to the server, it crashes with this
// server
Finished `dev-optimized` profile [optimized + debuginfo] target(s) in 0.21s
Running `target/dev-optimized/iron-front-server`
Iron Front Server starting...
thread 'Compute Task Pool (52)' panicked at /home/james/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/lightyear-0.19.0/src/server/connection.rs:553:14:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `lightyear::server::networking::receive_packets`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
// client
2025-03-15T15:59:23.608644Z INFO bevy_winit::system: Creating new window "Iron Front" (0v1#4294967296)
2025-03-15T15:59:23.643746Z INFO bevy_input::gamepad: Gamepad 18v1#4294967314 connected.
2025-03-15T15:59:23.645330Z INFO lightyear::connection::netcode::client: client connecting to server 127.0.0.1:12345 [1/1]
2025-03-15T15:59:23.813639Z INFO lightyear::connection::netcode::client: client connected to server
2025-03-15T15:59:26.814836Z INFO lightyear::connection::netcode::client: client connection timed out
2025-03-15T15:59:26.815316Z INFO lightyear::client::networking: Running OnDisconnect schedule
@pine cape hey is this normal? on client its giving me 2 entities for the player combatant
one have a HistoryBuffer and doenst have transform
is this some new feature on lightyear?
both have CombatantMarker
That is the confirmed entity, and probably your predicted enitty
I've never hit this error before: https://github.com/cBournhonesque/lightyear/blob/0.19.0/lightyear/src/server/connection.rs#L553
@wicked oak did you read through https://cbournhonesque.github.io/lightyear/book/tutorial/advanced_systems.html#client-prediction
hmm. Whats interesting is i just hit the same but on the client side too. Happened when i changed what plugins to load first on the client. Something im doing isn't setup properly, as i've just starting integrating lightyear https://github.com/cBournhonesque/lightyear/blob/0.19.0/lightyear/src/client/connection.rs#L149
Are you starting a dedicated server and client (as opposed to separate / host-server)?
Also the lightyear plugins (ClientPlugins/ServerPlugins) must be added before your shared plugins (protocol)
yeah I have ClientPlugins/ServerPlugins loading before the shared one. Hmm maybe im mixing Seperate and dedicated? Cause I start the server and client on different executables
pub fn shared_config() -> SharedConfig {
SharedConfig {
mode: Mode::Separate,
server_replication_send_interval: SERVER_REPLICATION_INTERVAL,
tick: TickConfig {
tick_duration: Duration::from_secs_f64(1.0 / FIXED_TIMESTEP_HZ),
},
}
}
// server
let io = IoConfig {
transport: ServerTransport::UdpSocket(SERVER_ADDR),
..default()
};
let net_config = NetConfig::Netcode {
config: NetcodeConfig::default()
.with_protocol_id(0)
.with_key([0; PRIVATE_KEY_BYTES]),
io: io,
};
let server_config = ServerConfig {
shared: shared_config(),
net: vec![net_config],
replication: ReplicationConfig {
send_interval: SERVER_REPLICATION_INTERVAL,
..default()
},
..default()
};
let server_plugin = ServerPlugins::new(server_config);
App::new()
.add_plugins((MinimalPlugins, StatesPlugin))
.add_plugins(server_plugin)
.add_plugins(SharedPlugin)
// other stuff
// client
let client_addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 0);
let io_config = IoConfig {
transport: ClientTransport::UdpSocket(client_addr),
..default()
};
let private_key = [0; PRIVATE_KEY_BYTES];
let protocol_id = 0;
let client_id = 0;
let auth = Authentication::Manual {
server_addr: SERVER_ADDR,
client_id: client_id,
private_key: private_key,
protocol_id: protocol_id,
};
let net_config = NetConfig::Netcode {
auth: auth,
config: NetcodeConfig::default(),
io: io_config,
};
let client_config = ClientConfig {
shared: shared_config(),
net: net_config,
..default()
};
let client_plugin = ClientPlugins::new(client_config);
App::new()
.add_plugins((
DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "Iron Front".into(),
//window stuff
..default()
}),
..default()
}),
client_plugin,
))
.add_plugins((
SharedPlugin,
so you're creating the apps in 2 different processes?
I mean it should work, your code looks similar to https://github.com/cBournhonesque/lightyear/blob/832872316a4d21977714cfa025c3b0005c0795ee/examples/simple_setup/src/client.rs#L13-L13
yep cargo run --bin iron-front-server --profile dev-optimized then cargo run --bin iron-front-client --profile dev-optimized
yeah been eyeing these examples to see what i might be missing
From your error, it seems like you somehow create the ConnectionManager without the channels being registered
can you send me a link to your github
oh think it was caused by me using this stuff
app.insert_resource(ChannelRegistry::default());
app.insert_resource(ComponentRegistry::default());
app.insert_resource(MessageRegistry::default());
ok, so I found a bug, and it has to do with children colliders. If you add a sensor collider as a child node to the spaceship example you get constant rollbacks, without the senor I am not getting many rollbacks
the last commit comments out the code causing constant rollbacks
tks
so bassicaly on client i need update stuff for Predicetd entite not for the Confirmed entity?
and the predicted entity will update stuff the Confirmed entity automaticaly?
how i use this lib with wasm ? nothing render when i use
yes exactly; you should never touch Confirmed. Confirmed simply contains the latest replicated state from the server
okie, also the predicted is not having the rigidbody and collider , i need add on it?i just added on confirmed
I think it's generally that lightyear doesn't play well with the Collisions resource from avian, which causes rollback issues.
If you tried to print out Collisions and Position for your entities on the tick of the rollback, I think you would see some differences
yes you need to add them to Predicted, not Confirmed, like here: https://github.com/cBournhonesque/lightyear/blob/main/examples/avian_3d_character/src/client.rs#L83
The Physics components are only added on the Predicted entity
so this explain does glitches
on moving
thanks bro
so i just never should touch on Confirmed
yes
no you would put animations on Predicted
, so what is confirmed for bassicaly?
for receiving replication updates from the server
It would be possible to merge Predicted/Interpolated/Confirmed into one, and rename components as
Predicted<Position>, Confirmed<Position>, etc.
but i thought it was cleaner to keep the entities separate
tks
i dont see Interpolated one entity
anyway i should not touch it right?
Yeah I ran into that issue too, collisions with child colliders attached to static bodies also get rollbacks
look, i see Interpolated if i make predict_all = true, i dont need make Interpolated for for the client itself right? so Interpolated entity will appears for others players, on this case, i also cant touch Interpolated entity right? just predicted
with predict_all = true, we only use Preediction so nothing is interpolated
i see
but if i have interpolation
so for others clients Predicted wont exist right?
just Interpolated
so i touch Interpolated for others clients, and Predicted for the own client
and what is better? predict_all = true or false?
@pine cape fyi ur committing target dirs to git, u need to add
*/target to gitignore i believe
https://github.com/cBournhonesque/sixdof/tree/main
Do you think there is a way to ignore child sensors? What exactly does lightyear do with collisions that gives rollbacks?
My understanding is that PvP games typically predict every player
not necessarily, depends on game type. Shooter are more predict but interpolate to others. Dynamic physical games, such as rocket league are more predict all style of networking
I am confused, sensors do not collide. Collisions from what I know are not handled by default.
a game liek this?
so how is a sensor causing rollbacks?
It is probably not the sensor component itself, but the avian logic behind it
I guess since he is a child of a rigidbody, the transfer to parent transform must be causing a scenario not handled by lightyear.
Maybe i try not having it be a child and updating positions myself
- predict your own controlled character movement
- predict your own controlled character weapons/attacks
- dont predict other characters that you dont control
- dont predict deaths
- dont predict health
that's a good rule of thumb, but the real answer is "it highly depends".
i mean
my question is
for myself i will see predicted / confirmed
yep
and i should just touch on predicted yes
and others you just interpolate
This is absolutely NOT COMPLETE, or even near complete, but we're making headway on this project, this will be a good resource eventually, and maybe even right now:
https://github.com/cBournhonesque/sixdof
this is nice
am i? I dont' see the target dir in here: https://github.com/cBournhonesque/sixdof/pull/26/files
A good idea, although solutionist, you are not actually solving the issue at hand.
also a lot of games just don't do prediction and just interpolate everything. For example league doesn't use prediction; if you have lag your actions are simply delayed
yes
but i think a game like spell break prediction is good
#1124043933886976171 message
@pine cape does this mean i need add transform for the predicted entity?
manually?
or the predicted does not need transform?
@pine cape Do you think that making the collisions resource rollbackable, could fix https://github.com/cBournhonesque/lightyear/issues/961
I wonder how would one rollback, a non networkable resource
Rollback, solely on the given client ? Send collisions as a message, from server to compare with the buffered history
It won't because the resource needs to replicated at exactly the same ticks as the rest of the predicted entities.
Right now resources are replicated via Events, which have no ordering guarantees with replicated components.
I.e. you could be in a situation where your predicted entity is at tick 17, but the Collisions resource is at tick 14.
So if you rollback everything to tick 17, you will get the wrong Collisions resource and you will still get constant rollbacks.
Constant rollbacks are not a problem per se, they just mean that you need to do a lot more work every frame.
One potential solution is to wait for bevy to release resource-as-entities, then it will be easy to replicate the Collisions resource in the same replication-group as other predicted entities, which guarantees that they will get updated on the same tick. I'm not sure that it's ideal though, because Collisions might be a big object to replicate. Maybe it could work with delta-compression
It's already possible to add rollbacks for non-networked resources, I was actually experimenting with it here: https://github.com/cBournhonesque/lightyear/blob/main/lightyear/src/utils/avian2d.rs#L60
However it didn't help because of the reasons I mentioned above.
If we rollback at a given tick T, we need to make sure that the Collisions resource on the client is reverted to what it was on the server at tick T (which is not the case with non_networked_rollback)
Oh thanks, I was about to try that. Just read https://github.com/Sirmadeira/lightyear/blob/b14877613c29f00ad979b71258e8abc5d90529db/lightyear/src/client/prediction/rollback.rs#L541, guess they rollback to it is previous predicted tick similar to components. (Right now resources are replicated via Events, which have no ordering guarantees with replicated components), does that mean even if one were able to make the resource serializable the ordering would still be off?
client/target, server/target
https://github.com/cBournhonesque/sixdof/tree/main/client/target
oh you're right
Resources are already serializable, some examples replicate resources: https://github.com/cBournhonesque/lightyear/blob/main/examples/lobby/src/server.rs#L64
The problem is that for prediction to work with no rollbacks you need all predicted objects to be replicated in the same packet. That's guaranteed for entities/components using ReplicationGroup, but there's no way to do it for resources currently
Ah I see, so one must send the resource with the given group packet. Man that sucks, I cant think of any alternative 😦
Is either resource as entities or extend the api, by a lot I guess
I mean you could implement resource replication via entities instead of messages in lightyear currently
in here: https://github.com/cBournhonesque/lightyear/blob/main/lightyear/src/shared/replication/resources.rs
create a dummy entity that will hold the resource as a component, etc.
but i'd rather wait for resources as entities
Do you know when it will be released?
Hmm I would have to transform it into some sort, of component. Guess it could be easy using world
Probably on bevy 0.17, so around september
Do you know if the issue is open yet? I might as well try to speed up the process
yes it's still open; you can search for it in the bevy gh
i made a InteractNetworkAble component to attach on preditected or interpolated
so i dont need keep checking Or on every query
just With<InteractNetworkAble>
that i put on charcter using Or one time
@misty wyvern
iam having this problem whem i move the model on server
start on 0:23
sorry
the model keeps off form the collider
Seens like the transform is not updated just the body position, like @pine cape stated, and childs move basead on parent transform, causing this issue
I added this extra system to propagate position->transform for non-rigid bodies
okie so i need implement it myself? thanks
wait this is not lighyear i see
couldnt i just update manually the transform on client to where should be basead on position?
well yes that's what the system i shared does
wait you calculating the new transform for the childs too?
iam pretty sure update the ancestor is enought to all childs move automatically
my problem still, and first time i started the character kept floating forever lol
@pine cape that is how i fixed it
fn fix_transform(
mut query: Query<(&mut Transform, &Position, &Rotation), (With<RigidBody>, With<InteractNetworkAble>)>
){
for (mut transform, position, rotation) in query.iter_mut(){
if transform.translation != position.0 {
transform.translation = position.0;
}
if transform.rotation != rotation.0 {
transform.rotation = rotation.0;
}
}
}
gg
the entire code
A browser interface to the Rust compiler to experiment with the language
btw small question guys, when i move the entity on server it does replicate right, but why have this small teleportation when i stop move? since its a local server should have 0 ping right? orrrr, because its every tick and the replication reach the client just on another tick / frame?
is this normal for you guys or just i have this?
honest question btw
it wont happens if i move on client first instead on server first ofc
Hey, wanna ask right that for animated objects, is it better to use interpolation or prediction? interpolation right? (also, when should i choose prediction vs interpolation vs simple? is there a good rule of thumb?)
also for interpolation, will the effect get propagated to the predicted entity?
You will probably have tto animate both, if you have dynamic movement/shooter style of game. Prediction when it needs to be responsive, interpolation when is just something to show like an enemy/npc. Simple when it is a floor, or map like struxture. If you log the animation state in predict and interpolate yes.
I recently made my animation system as follows I have a shooter, predict is animated in client via it is seldom states via a one to many relationzhip. And interpolated is animated via server replication.
@pine cape I was taking a look at the collisions resource from what I could see it is nothing more than a hash struct of contact forces between entities. Perhaps contacts could be treated as components?
Similar to colliding entities
Dont know how hard appliance would be Jondolf would probably be the one to tell
what does "log animation state in predict" means? as in doing the interpolation on my own?
Insert animation state component, it is an component that I utilize to transition from one animation to another, I insert him via protocol and them make a shared logic for server and client
Could be used as a fuzzy animator too but you will have to make a litttle bit of logic
oh
what about spell casting? like skills, i reckon it needs to be triggered from the server right? instead of the client
one of the issue i face with skills is the dash movement, it needs to be server regulated, but the client also needs to feel responsive, and i'm not sure how to achieve both..
Prediction = when you want your own actions to have 0 latency. Generally only your own actions (local player) are predicted.
The predicted timeline is the timeline of the local client. It is in the future compared to the server timeline.
There are some cases where it's possible to also predict other players.
These could be:
- the game has a lot of physics-based interactions with no quick change of directions (RocketLeague, etc.): in this case a player's inputs are replicated to all other players so that every client can predict every other client. If you set an input_delay higher than the RTT, there will be 0 mispredictions related to inputs, but user inputs have a delay. The
avian_physics,spaceships, andavian_3d_characterall showcase this whensettings.predict_all = True. It's also possible to ste an input_delay that is lower than the RTT, and then the remaining time is extrapolated/predicted by the client using the last known user inputs. Usually you can just consider that the remote client kept pressing the same input, and then extrapolate based on this. Thespaceshipsexample does this here: https://github.com/cBournhonesque/lightyear/blob/main/examples/spaceships/src/client.rs#L177 - fighting games (smash bros, tekken, etc.): in these games all client inputs are replicated to all other clients again. However I believe these games do not replicate any state, only inputs, and are deterministic. Also I think the client/server timelines are handled a bit differently, so I cannot really speak confidently about them.
Interpolation = to smooth out replication packets received from the server. Server sends packets regularly (for example every 0.1s) but you want to smooth things out between these packets, so we buffer them locally and then as soon as we have 2 server packets, we interpolate between them.
The interpolated timeline is in the past compared to the server timeline (since we need to receive 2 server packets to interpolate between)
A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear
In general:
- one easy thing to try is simply to interpolate everything. This means that your input will have some latency
- another option is to predict your own controlled characters, and then interpolated everything else
- usually anything that receives regular updates needs to be interpolated (otherwise it will only get updated at the frequency of the server sending packets, which is much lower than your frame rate). You can see the Confirmed entity (which just receives replication packets) in the
simple_boxexample, it looks very chopped
If an entity is Predicted, it shouldn't be Interpolated as well.
Predicted entities are updated in FixedUpdate using your own inputs, Interpolated entities are updated in PostUpdate using the server packets, those are 2 completely different things.
One thing to keep in mind is that Predicted entities usually need some VisualInterpolation (https://github.com/cBournhonesque/lightyear/blob/main/examples/avian_3d_character/src/renderer.rs#L51) because you need to smooth out the FixedUpdate updates for each frame. (since FixedUpdate might run multiple time in a frame, or might not run in some frames)
A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear
thanks alot for the explanations! it defintely gave me some insightsss, I was predicting too much stuff previously haha (which i think causes too many rollbacks and make the game unable to run smoothly on lower end devices)
It's not super clear to me how animations would be handled. I think you have 2 options:
- either the animations can be done entirely client-side. i.e. you can infer what the animation should be based on the position/velocity of the entity. In which case you don't need to replicate any animation state from the server
- either you want to simulate the animation on the server (maybe because animations are important for hitboxes, etc.) and you want the animations on the client to match what it is on the server. In that case you might need to replicate some animation data (for example
animation_id+key_frame) and have a way on the Interpolated entity to interpolate between these values
yeah i was aiming for the second one, tho abit curious what if i do prediction, with Simple mode with a system that "predicts" the animation by forwarding the time itself, will that be a viable solution?
in a FixedUpdate ofc
Yea figuring out what's causing rollbacks is pretty tricky. If you're using avian + lightyear there's a few things to keep in mind. I'm building out a bigger example here: https://github.com/cBournhonesque/sixdof which might be useful.
- I would advise to replicate Position/Rotation but not Transform: https://github.com/cBournhonesque/sixdof/blob/main/shared/src/network/protocol.rs#L109
you will still need those 2 lines to be able to do VisualInterpolation for Transform - This is how I setup physics: https://github.com/cBournhonesque/sixdof/blob/main/shared/src/physics.rs#L27 In particular I disable the SyncPlugin from avian and replace it with these 2 systems . It allows me to sync position->transform for non RigidBody entities (and my Interpolated entities usually don't have RigidBody)
It could work, I guess you want this to avoid doing any rollback checks on animation?
yeahh
it would be wasteful to rollback on animations haha
I think things like this should just be predicted. You have access to the client inputs in the predicted timeline, so you can just make the Predicted entity apply the skill. The server entity will apply the skill on the same tick in the server timeline, and if there's any discrepancy for some reason (for example the character couldn't apply the skill because they were stunned by another player or something), then there will be a rollback
Note - It shouldnt be predicted and interpolated in the same client.
You can also choose a mid-way point: by adding more input-delay you will have less frames to predict. In the extreme where your input_delay is higher than the RTT, there will be nothing to predict. There's some extra settings you can use to balance things out. For example how much latency should be covered via input-delay, and then how much max prediction do we want to apply
I see this one in the example, does the interpolation takes effect on the predicted entity? should i render the predicted entity or the interpolated entity?
There is no interpolation on the predicted entity
oh, so what's the interpolation for?
or is it interpolate others, and predict the current client
Usually you would do what's done here: https://github.com/cBournhonesque/lightyear/blob/main/examples/simple_box/src/client.rs
Predict your own entity, and Interpolate remote entities (entities received from the server)
ahh i seee..
You should run the example; you will quickly see that things look very bad with no interpolation
Remote entities will only move once every 0.1s and things will look choppy
Sure, if it's possible!
thanks!!
It is possible, just acess an entity collisions, via the resource and store as a component on that frame. Problem is how to tell avian to utilize that tick contacts instead of the normal collisions contacts.
Ah that doesnt seen to be hard as all you need to do is to change the contact pairs of that tick, to the ones send by the component.
Easy because you can use collisions itself just to override it is values on that tick
So on_rollback, use my component collision forces instead of the newly calculated forces
Hey @pine cape did you Saw It? It fixes the transform problem Very ez
Someone can answer me this btw?
Question why non networked resource are "rewinded" to only one previous predicted tick?
They are not, they should be rewinded to the rollback tick
Hmm perhaps I should re-read the code, but here is a few findings:
Increasing determinism, via disabling warm collision and increasing sub-step decreases rollbacks to a very a low grade. They are not so continuous before, in 50% of runs they dont occur (system ordering).
If what you say is true (I will recheck the resource functions), add_rollback_resource, should just do the trick
You can try it by uncommenting the line in utils/avian_2d
Okay
@pine cape So avian 2d seens to no have continous collision rollbacks, it does have some weird explosive action when alt tabbing
What I did, increase determinism by adding substeps and disabling warm_collisions
This sample is without the additional deterministic measures
https://github.com/cBournhonesque/lightyear/pull/964 @pine cape Check this pr out, and tell me if you see improvement on your side
In this state I didnt get continous rollbacks
Only on initial collisions I get around 5 and them full stability
@unkempt sedge do you have some rollbacks problems too ?
let me show here
some times when i jump something drag me down
on client
than goes up
iam guessing its because let gravity_force = gravity.0.y * time_fixed.delta().as_secs_f32();
and time_fixed: Res<Time<Fixed>>,is different from server and client?
like on 0:07
its just when iam walking somehow
@pine cape here we go bro, client / server
its jhitteiring a lot lol
its 0 ping this make no sense
mainly when jumps
?
well periwink usually ignores me, so iam cooked
That's normal because avian_physics doens't have many collisions. The real test is avian_3d_character, with the block entities that have full contact with the floor
I will check it out, but I must say there is a very high degrade on rollback amount, which makes sense as the simulation gets more "deterministic"
I would have to check avian code, but if warm_collisions are disabled, the Collisions resource should not matter right? In that case I would expect 0 rollbacks if warm_collisions are disabled
Even a tiny amount of rollback seems like a bug
I mean it wouldnt inherit the interpolation from the previous tick.
Contact data should still be handled, which already is. In my current sample, there is this frame drop rollback which is very weird, where once the frame drops. Due to alt tabbing and so on, there is just a bunch of rollbacks
@pine cape I tested in avian_3d, results are the same, fewer rollbacks. But they still occur
Damm i got ignored
So @pine cape after i analsiy a Lot, i found this, the client start jump First ofc, and when he is on middle of It the server roolbalck he, that is causing the giant amount of roollback on jump
And It have 0 ping, shouldnt have toons of roolbacks
And ik why this happens periwink, the tick from server and client are different when its a dedicated server
That is my case
Making this happens
I would suggest to check the examples, they do exactly what you want
Also lightyear breaks a bit with 0 ping, you should add a link conditioner, even if it's to add 3ms ping
yes but iam doing it
you also aply impulse on examples for jump
i guess order of executions matter right? i changed the order and now seens better
So I switched to replicating transforms instead of positions and I stopped using avain physics velocities, and have managed to remove all constant rollbacks!! (except for characters constantly walking into a wall). All of the prespawned entities find matches; however, I am still getting the bug where sometimes I get an explosions, and sometimes I don't get an explosion.
Im thinking the server is despawning the client's projectile before the client can make the event. I've tried adding 30 milliseconds of Conditioner latency to the client but it doesn't seem to fix the issue.
It is not possible that the server is despawning the client's projectile before the client can show the explosion because the server is running in the past compared to the client. I think it's some system ordering issue on the client between the predicted_despawn and the explosion VFX
Also the game looks great 👍 love the art
So when I log server and client despawning I get the following when I see the explosion
2025-03-18T16:39:37.069151Z INFO bevy_gnomella::networking::shared: server despawn Tick(1282)
2025-03-18T16:39:37.090714Z INFO bevy_gnomella::networking::shared: client despawn Tick(1283)
and I don't get any messages from the client when I don't see the explosion
2025-03-18T16:39:40.684633Z INFO bevy_gnomella::networking::shared: server despawn Tick(1509)
How are you handling despawning + vfx?
I thought you were predicting the collision on the client and adding the vfx on the client.
Or are you instead sending an event/message from the server?
Are you using predicted_despawn?
so its very similar to the spaceship example, I have a shared function to detects collisions, client does predicted_despawn and server does despawn_recursive
both spawn an event, and the events makes the vfx just on the client
But how can you predict the collision on the client if you don't replicate Position?
the collider is following the transform
I think I would need to see your code. Also your logs show that the despawn doesn't happen on the same thing, so something is wrong there. Either some of your logic is not done in FixedUpdate, or the transform<>position sync is not done at the right time, or there's some system ordering issue
yeah I was confused about them not being on the same tick, maybe the server isn't running in the past?
iam having issues too
like this
seens the server is on future here xd
player jumps than get teleported back to server position xd
I'd be willing to share the code with ya if ur willing to look at it :)
iam on same boat as you
The server is running in the past for sure, there must be some logic/order error.
It would be nice to have an editor to more easily debug these things. Sure, you can DM me
Is there currently a bug related between ticks and framerates already open? For some reason, even in transform based controllers I get rollbacks when alt tabbing
you could just disable pausing you're game when not in focus?
I am not pausing it, but I guess somewhere there is if outside window lower fps
Feature in bevy
Yeah I noticed that. When alt tabbing is the game still running in the background? If not, no packets are received, which would cause some issues
Yes it is
I found this post helpful for keeping the game always running, maybe its not exactly the solution you are looking for https://www.reddit.com/r/bevy/s/hHz1aC1Mhz
The colliders were different sizes depending on how the projectile was spawned..........
everything working now lol
Hmm this doesnt fix it, if you simulate frames spikes it breaks lightyear
Oh so things work?
Yep! Getting close to being completely bug free!!!
I think my main problem is lag with large amount of enemies, is 200-300 kb/s a lot for a game to network? Thats when things start breaking down
So 25KB/s for one player? that seems like a lot
how can I let a client know that "this replicated entity that just got created on your end? that's what you should control" ?
You can add the ControlledBycomponent on the server; and then the entity will have the Controlled component on the client.
https://github.com/cBournhonesque/lightyear/blob/main/examples/simple_box/src/server.rs#L52
so that value is present on the entity for the client? e.g. I should look for ControlledBy, or Replicate components on the entity?
ah Controlled, sorry I looked at the code and didn't notice your message on top 😄
something like this: https://github.com/cBournhonesque/lightyear/blob/main/examples/avian_3d_character/src/client.rs#L92
25KB for like 100? enemies
that are all firing projectiles
Hi, I don't know if its normal, but I often get Rollbacks due to missing component on predicted entity with interest management.
What I'm doing is that server spawn enemies on the map/world when the server start with the followings components:
Replicate(prediction: NetworkTarget::All&relevance_mode: NetworkRelevanceMode::InterestManagement)PositionLinearVelocityCharacter(custom component)
And I make my player gain/lose relevance base on distance to enemies (pretty much like its done in the example: https://github.com/cBournhonesque/lightyear/tree/main/examples/interest_management )
The weird thinks is that it does not always trigger a rollback, and when it does, it is not always the same component missing (sometime Position or LinearVelocity or my custom Character component)
Also, all my components are registered like this (prediction full):
app.register_component::<Character>(ChannelDirection::ServerToClient)
.add_prediction(ComponentSyncMode::Full);
I don't know if this behavior happen in the example. Maybe it is, and its unavoidable without prespawning enemies...
I would expect this to happen all the time, because when an entity is not visible it gets despawned. So when it gets visible again there is a rollback to make the newly spawned enemy go to the predicted timeline
But I'm surprised that you're predicting non-controlled enemies, I don't know how that would work
Well yeah I'm trying to make my game kinda deterministic (so for the enemies ai too)
Everything is predicted
Works well so far (and no need to manage predicted vs interpolated collisions)
But yeah, sound normal about the initial rollback when the the new predicted enemy get added/visible
I'm trying to switch over to using leafwing with lightyear and the docs says to add LeafwingInputPlugin but that doesn't exist??
aah feature-flagged, might be good idea to mention that in the guide 😄
hmm but I get the trait `bevy::bevy_app::plugin::sealed::Plugins<_>` is not implemented for `lightyear::client::input::leafwing::LeafwingInputPlugin<PlayerInputAction>
aaah i was missing serialize/deserialize on the actionlike
is it possible to filter which inputs are even sent to the server with leafwing? I only need some to go through
i just use a second ActionState. i broke it up into networked and local inputs
Ah not a bad idea.
how are things that depend on camera/view handled? e.g. mouse movement but logic requires world position out of that. I guess I could handle that as part of local and send in messages
There is an example that updates the Leafwing ActionState using mouse movement. Check the fps example
my use case is world coordinate aim, not movement though. In other words I cannot just send the mouse events over, because the server has 0 knowledge about the viewport of the client
I guess my main conern is with rollback/prediciton, if I'm not handling something as an input but as a message, things won't really work right no?
in my case for example if the player moves a mouse, I have "turrets" that rotate to point to the position the player is pointing at. I'm using (somewhat rounded) coordinates that I send over, but it's not a leafwing input, since I need to handle it with Window/projection first
You can convert the mouse position to world coordinates, which is what I do in the fps example
Ah I see here that's pretty neat
nice, works nicely thanks!
the only other problem I have at this point is that for some reason my child entities work, but seem to only get updates very rarely from replication. The main entity is fine and smooth, but the child entities are like they're on a 1s update schedule. Any idea how I could debug that?
what is the right way to add client/server plugins if the app doesn't know at startup which it will be (HostServer or Client)
I would try turning on debug logs for lightyear::shared::replication::receive to check that you're receiving messages for the child entity correctly
You add both at the same time: https://github.com/cBournhonesque/lightyear/tree/main/examples/lobby
It's fine to have both enabled, and to keep the server turned off when you don't want to be HostServer
configure/add both of the plugins but before you call connect, modify the ServerConfig or ClientConfig resources when you know what values you want
sadly that results in such a deluge that even piped to a file the client is unresponsive
is there a way to hook into server sending replication updates and filter e.g. specific entities for example perhaps? or same on client when receiving those updates. I think if I filtered things just to this one entity it'd be good enough
i did a test and it's definitely something fishy with the children handling:
- making a standalone entity of one of the "misbehaving" children and adding ServerReplicate to it manually, makes that move nice and smooth
- disabling ReplicateHierarchy on the parent and adding ServerReplicate to the child entity manually does not work at all (should this work?)
my replicated components list is very small it's just
app.register_component::<Transform>(ChannelDirection::ServerToClient);
app.register_component::<Ship>(ChannelDirection::ServerToClient);
app.register_component::<Weapon>(ChannelDirection::ServerToClient);
app.register_component::<ShipMounts>(ChannelDirection::ServerToClient);
app.register_component::<Shot>(ChannelDirection::ServerToClient);
In this case the replicated child entity is a Weapon + Transform only
Can someone give me a little bit of feedback on my logic for implementating player look at camera logic:
1 - Transfer already rotated camera yaw via input to server. Vec2 axis
2- Apply the logic, so player physics move according to camera yaw and rotation of player follows along yaw
3- Via protocol reproduce that logic via position
I also see issues with my component's value (Ship in this case) changes. Server sees them ok, but client it almost seems like 99% packet loss but only for those. They come ok initially (e.g. component added) but subsequently no changes are reported for the most part. Occasionally an update seems to arrive.
I'm also seeing 2025-03-20T19:17:04.021392Z INFO lightyear::shared::replication::receive: update for entity that doesn't exist? remote_entity=53v6#25769803829 it's a bit odd because only the server despawns these entities so it's like things came out of order
I need to make errors for this more explicit; are you creating many children that you're then despawning?
How are you replicating the children, did you just add the Replicate bundle on the parent with hierarchy replication enabled?
This makes me think that the parent and child don't use the same ReplicationGroupId, which could cause these kinds of issues
I would try logging the parent and child's ReplicationGroupId
I'm just doing
hierarchy: ReplicateHierarchy {
enabled: true,
recursive: false,
},
..default()
});
On the ship (that's the one that seems not to get some updates). And directly just ServerReplicate::default() on the shots (those are the ones that client logs about being despawned already)
I don't use any channels (don't create my own). Input is done via leafwing and handled on the server. Update duration is 0 on both client and server
sorry to be more clear Ship component doesn't seem to be getting the updates right, as well as Weapon components that belong to the Ship entity as children entities
I didn't do anything to replication groups whatsoever. Is something required for that simple default path?
what is NetConfig::Local(id: <...>) supposed to be set to
using
for event in events.read() {
// the entity on which the component was inserted
let entity = event.entity();
log::warn!("server updated ship: {}", entity);
}
}
I can see that the updates are not coming in on client side 😦
and why does the client need to be started when you are in host_server mode
changing send_updates_mode: SendUpdatesMode::SinceLastSend from last ack seems to "fix" that but I'm not sure why o.O?
it also fixes the children movement, so it looks like the client isn't ACK-ing properly or something? I'm really confused
although only in a lag-free environment, if I do e.g. tc qdisc replace dev lo root netem delay 100ms to simulate 100ms send lag, it behaves very similar to the SinceLastAck setting
in the tutorial here it just says client_id
i feel like that is something that should be assigned by the server :/
what if you get conflicting id's?
You're supposed to get that from an "external source" for auth reasons
so e.g. a master server that hands out client tokens and notifies server instances of expected clients
for testing purposes can I disable authentication
nvm I just set key to 0
Really? i routinely turn on debug/trace logs with multiple clients with no issues. What you want is the "received EntityActions message" and "received EntityUpdates message" logs
Oh also there are messages like https://docs.rs/lightyear/latest/lightyear/client/events/type.ComponentUpdateEvent.html and https://docs.rs/lightyear/latest/lightyear/client/events/type.EntitySpawnEvent.html that you can read to know which component got updated when
Bevy Event emitted on the client when a ComponentUpdate replication message is received
Bevy Event emitted on the client when a EntitySpawn replication message is received
Does the ship have a Parent? I believe the ReplicateHierarchy only works for entities that don't have any parents; this will be fixed for bevy 0.16
You set your own client-id to Local when you're the client that wants to be HostServer. The server will identify the local client through that. You can choose any id
Host-server mode just means that the client and server are running at the same time in the same process.
If the client disconnects you become a dedicated server; if the server stops you become a normal client.
Do you want to share your code example with me? It's hard for me to debug this without a minimum reproducible example
But why do I need the client at all?
Any reason a dedicated server (without client) be a graphical instance?
Perhaps just so single player is the same as multiplayer?
You can always have dedicated servers with no GUI if you want (called headless servers).
Host-server is if you want one of the players of the lobby to host the game for the other players, so that you don't need to provision dedicated servers
And yes it might make things easier for single player
Btw i've done the update to bevy-0.16 in the branch https://github.com/cBournhonesque/lightyear/tree/bevy-main if you want to try it
No parent on the ship
I'm going to play with some of the lightyear examples and see how they behave and if I can figure out where the diff is. If I get completely stuck I'll prep a basic minimum case
what I find most interesting about this is that the Transform of the ship entity is applied nicely and fluid, while the child weapons' Transform and the ship's "main logic component" seems to be staggering on those updates, which is just bizarre
Hmm, I've partially got lightyear working with my app, following the example
My entity and it's TestCube marker component gets replicated on the client
however, the Transform and Name are not getting updates on the client (althought they are registered to)
deleting the cube on the server does delete it on the client