#lightyear
1 messages ¡ Page 11 of 1
NetworkIdentity::is_server() is always false, even though the server is definitely running
I forgot to set shared.mode to HostServer
nope, still broken
also, is there a reason so many of theses structs don't implement Debug?
okay, I finally got it working
just hours of playing around with ServerConfig, ClientConfig etc
can actually get into the interesting stuff now.
just a suggestion: implementing debug + supporting reflection properly so they show up in bevy_editor_pls / bevy_inspector_egui
would have saved me a bunch of time
also, perhaps SharedConfig should be it's own resource, since it needs to be the same. (also, is that really on only thing that needs to be common?)
That is quite an easy pr, perhaps the ones you want to show up can be made so.
I'll give it a shot.
I gave this a try again to see why it floods so much and it's giving a TON of these type of messages: https://gist.github.com/almindor/0bc8a233ce15858c4c8c9983a0d7365a I wonder if there's something wrong
if I comment out the transforms from registered/replicated components, and only include 1 ship and only the ship's "internal" state as replicated (the one that's having the update issues), and remove all else from the world to ensure it's the only updat-able thing. It seems to show that the client gets the update. Checking now to see if it actually translates too since I have no visibility with this setup đ
@pine cape so something is def. odd: I use
fn component_updated(mut events: EventReader<ComponentUpdateEvent<Ship>>) {
for event in events.read() {
// the entity on which the component was inserted
let entity = event.entity();
log::warn!("server updated ship: {}", entity);
}
}
but the logs show this and no warning:
2025-03-21T17:32:13.304254Z DEBUG lightyear::shared::replication::receive: Received replication updates from remote: None remote_tick=Tick(605) EntityUpdatesMessage { group_id: ReplicationGroupId(4294967312), last_action_tick: Some(Tick(439)), updates: [(16v1#4294967312, [b"\0\0\x1aplayer_8938200771922309902\0\0\xc8B\0\0\xc8B\x01"])] }
2025-03-21T17:32:13.304257Z TRACE lightyear::shared::replication::receive: Received UpdateComponent components=[b"\0\0\x1aplayer_8938200771922309902\0\0\xc8B\0\0\xc8B\x01"] remote_entity=16v1#4294967312
my understanding is that it received the component update, but somehow that didn't translate into the world? (the component's data matches here on the "player_...." name) the last x01 value if I'm reading this right is the bool I actually expect to update in the world state. So it seems sending is ok
That's normal, that's all the replication update messages you're receiving
It's possible that the Update events aren't emitted correctly. I've been tweaking some stuff without checking that they work.
Also they aren't really useful so I might remove them entirely
oh wait I'm logging ONLY replication atm. let me fix that
hmm yeah so single replicated Ship component updates. If I re-add replication of the other things it stops (but intermittently can go through)
I wonder if it's a client-side issue, since the server seems to be sending things ok
seems the culprit is Transform
if I don't replicate transform everything picks up (except the actual movement of course)
it also stops complaining about updates received for despawned entities on the client (for the shots) if I don't do the transform. Almost seems like it gets overloaded with the transform updates on the client side or something?
is Transform too expensive to replicate?
Nope
Hmm, any idea how to further debug this? It's literally comment out register_component::<Transform>() and everything else works flawlessly, put it back and movement is fluent but all the others are bad now
I don't have enough information. I don't know if your entities are short-lived, if you're using avian, if you have correction enabled, if you see rollbacks, etc.
I would try adding systems that log Transform at various points
I'm using avian2d, but only on the server. I used to use bevy_replicon so my 1st step was to get the same result with lightyear. I use defaults pretty much everywhere and do not turn on prediction or rollback. Server is standalone CLI only and processed input via leafwing feature, and I only replicate to client with 100% server authoritative ala Quake 3 (fire and wait :D). rollback/prediction were planned as steps once the basics work.
There are only 2 entities, Ship which has a some children which are all long lived together and Shots which are "relatively" short lived. Both are avian2d RigidBody::Dynamic and everything is handled via avian2d on the server (e.g. I never update transforms directly, only velocities)
I did NOT enable the avian feature in lightwing, as my understanding is that it's meant for prediction/rollback in tandem with avian which I'm not attempting yet, but perhaps that's where the issue is?
I do not replicate anything but Transform and my own custom components (e.g. no Position, AnyVelocity etc.)
also a side note, why is avian2d feature locking avian to =0.2.0 ?
ok one more finding if I lower server_replication_interval from 0 to something like 16ms it seems to also improve things (when using sincelastack)
it almost seems like the client gets overwhelmed
yeah setting it to 8ms (on 64hz simulation) seems to do the trick, it stops "dropping" updates, but still stays smooth and seems to work well with some forced lag too
I'd still love to find out what the cause is tho
Can you share your repo privately with me?
There seemed to be some issues with colliders in 0.2.1
Yes, one sec.
https://github.com/cBournhonesque/lightyear/issues/975
saw this issue and it reminded me to ask; when the replication interval is shorter than the tick rate, does lightyear still send a replication update if there hasnât been a FixedUpdate since the last time it sent?
a replication interval of 0 seemed desirable to me because it would ship updates as soon as possible
yes, if ReplicationInterval is 0, lightyear will send replication updates every frame.
- You can set the ReplicationInterval per ReplicationGroup
- I only send updates for components that changed, so if FixedUpdate didn't run there is probably nothing to send
I only send updates for components that changed
oh that should be good enough. is there some kind of "empty" update in this case? or will it not send anything at all
it won't send anything
O well, i Still have the same replications issues, Sad life
This was my issue as well with a headless server. I think the default of 0 should mean "every fixed tick" instead of every frame.
that confuses me / contradicts what Peri said, no? unless you were modifying Transform in Update, it shouldnt have been sending overwhelming amounts of updates...
I wasn't but Avian2d probably does even if it doesn't move anything?
I suspect it derefs which counts for Changed
even with position_to_transform disabled, you think? you're probably right
just seems...weird
Where's position_to_transform from?
avian SyncPlugin
ah I didn't even know about it, whatever is default is what my code uses
app.insert_resource(avian3d::sync::SyncConfig {
transform_to_position: false,
position_to_transform: true,
..default()
});
oh but you aren't gonna disable position to transform
so right now, my code is "blind replication" and it uses transform, I need transforms to update based on avian's values, but not the other way around. Server simulates, client is a dump client it only shows and doesn't even run avian technically
but I do want to transition into position based both-sided simulation with rollbacks and prediction
so essentially I'm on Quake 3 level networking and will work towards modern setups heh đ
silly question bros
what should I be using for dependencies for lightyear? i tried copying what I had before but there's conflicting versions of rustc (1.82.0 v 1.85.0) that makes the example code not work
always use latest rust tooling for anything in the bevy ecosystem
Everything works on latest? I've been getting macro build errors
that is probably just your rust analyzer implodijng
oh word, assumed it was just 'new' cause one of my bevy traits was being weird too
ty KING
i was gonna try and hack together an .io kinda game as a weekend project, but i spent all of the first day just setting up my project. so i pivoted to making a reusable (and slightly opinionated) template for prototypes/jams/repros
https://github.com/Piefayth/lightyear-template
besides the absolute minimum lightyear setup it
- provides a launcher with settings files for both native and wasm
- lets the native client run the server (i.e. there is a "host" button in the client)
- has a simple abstraction for loading and postprocessing groups of assets
if this is something you might use sometime, i would appreciate feedback!
Wow this is super cool and super useful! I have just take a quick look and it seems very clean. Will play around more with it after work!
What kind of .io game are you making?
the reason I started lightyear is that I wanted to make a clone of https://powerline.io/ as a project
powerline.io - Massive multiplayer online snake
I think it uses prediction for the client and interpolation for remote players, but i'm not 100% sure. This is also why my replication_groups example looks similar đ
I added your template to the readme
there was some LLM authored dogfighting io game making the rounds on twitter
surprisingly fun conceptually, but controlled like crap. i was thinking of replicating it but with star fox 64 multiplayer controls
Hmm interesting migrating to crates workspace causes a few rollbacks on init
Is that expected?
anything predicted that wasnât prespawned will have rollbacks when they spawn to fill the prediction history
Ah so I will have to prespawn it to avoid it, lets just say that loading assets and rollbacking is not really cool
that sounds suspicious to me, the rollbacks shouldnât be disruptive in the âspawning a thingâ case
also consider preloading your assets if thatâs causing trouble
I am but the thing is server replixates player the moment client is pre loading assets
Sometimes, although not frequently. The rollback occurs while loading the assets, and since he is quite chonky. It slows down the init margin
I will just make player pre predicted
It is the only predicted entity I have
ah yeah i wait for the assets to load before i spawn the player on the server; i think you're right that prespawn is sufficient for you though
I was meaning to ask, about predicted and interpolated entities. Are those created automatically when types are registered with prediction/interpolation.
I followed the avian example and was suprised not to see any extra entities in my egui
they are created based on the sync field of the Replicate component added to the entity on the server. if you donât specify there that they are predicted/interpolated, they wonât be
Exactly, you either add https://docs.rs/lightyear/latest/lightyear/prelude/server/struct.SyncTarget.html on the server entity as part of Replicate, or you add the ShouldBePredicted/ShouldBeInterpolated components on the client entity
Component that indicates which clients should predict and interpolate the entity
@long marsh I had to run cd crates before running the certificate command, but otherwise everything worked!
thank you iâll fix that!
I like what you did here: https://github.com/Piefayth/lightyear-template/blob/main/crates/mygame-client/src/host.rs#L20
I didn't know this was possible
when you're sending ClientHostRequestShutdown, it just tells the server to stop but it doesn't kill the thread, right?
I should probably use some similar patterns for my examples
yup đ
oh wait DO i need to kill the thread? or does stop server also stop the app? im not re-using the server app đ¤
stopping the app would terminate the thread gracefully
mmm think i have to intentionally exit the server app
the key thing i want to avoid is having to offer a second set of channels so you can talk to the stopped server in the other thread. just easier to throw the whole thing out.
When it comes to timers one should base itself on ticks correct?
It depends on what exactly you need; but yes ticks are guaranteed to be synced between client and server
My case scenarios is implementing a status effect dashed, does tick_manager.tick works even on rollback? The logic is shared and I am little worried about that
Yea the tick manager gives you the correct tick even during rollback
The TimeManager also rollback time so you could use that
Hi I'm trying to upgrade a project from an old bevy/lightyear version (bevy 0.14 / lightyear 0.16.2).
Is using the client and server plugins together in one app, but only starting one of them something that is/was intended to work?
Previously I would add both client and server plugin sets, but only activate the relevant side with start_server or connect_client, which meant users would be able to use in game ui to host or join games.
This almost works in the current version (the main branch on github), but lightyear::server::prediction::handle_pre_predicted consistently panics.
When doing this handle_pre_predicted is running on the client despite not starting the server (but seems to assume it's running on the server only), unless I modify it to check the NetworkIdentityState.
The other issue is that in handle_pre_predicted pre_predicted.confirmed_entity can be None somehow. If I modify it to just skip the None it does seem to work but I don't know if there might be some other consequences of that change?
I see, so the server's handle_pre_predicted is always running instead of only running when the server is started? Yes I think that's a bug.
If you're running in client-only mode, that system should not run at all, which will also fix the panic
Does this fix your issue? https://github.com/cBournhonesque/lightyear/pull/982
I literally just had to fix this as well. Thanks for the fix, I can confirm it's working for me
That fixes the panic from handle_pre_predicted assuming it's running on the server but running on the client.
I think the other issue where I'm getting pre_predicted.confirmed_entity being None in that observer when a client joins is because I'm trying to spawn a pre-predicted player with an camera as a child that doesn't get networked and I think I'm probably doing it wrong.
Is there a way to prevent just one child of a networked entity from being networked? I see that the ReplicateHierarchy component should allow me to disable all the children from being replicated
Could you please open an issue? Then I could add a unit test for the use-case of pre-prediction with a child that is not networked. (if that's indeed the isue)
I think the easiest way is to just wait for the next version. My branch is already on bevy 0.16-rc.2
The new hierarchy plugin is here: https://github.com/cBournhonesque/lightyear/blob/cb/0.20/lightyear/src/shared/replication/hierarchy.rs#L232
You just need to add DisableReplicateHierarchy on the child that you don't want to replicate
Sure. For now I'm just going to switch to spawning the camera on the client after the server has dealt with the pre-predicted entity as that seems to work fine, but I'll try to minimize my code a bit for an example and open an issue at some point soon
I've opened an issue now https://github.com/cBournhonesque/lightyear/issues/984 I've added a fairly minimal example which for me consistently reproduces the issue, but I'm not familiar enough with the lightyear internals to figure it out myself
Deterministic almost fully fledged floating rigid body controller in lightyear
@pine cape I see you've got the steam connection layer working in lightyear; I'm trying to get it working in aeronet right now, and I'm facing a ton of annoying issues with steamworks-rs's networking sockets API:
- can't pass connection option entries otherwise it breaks
- registering callbacks doesn't work
- spurious panics (e.g. when receiving a 0-sized message)
- this actually stems from unsound unsafe code, and is only caught by a std debug assert (!!!)
- probably some unsound bindings somewhere in the API
Do you think it'd be worth it to write a "steam-sockets-rs", a set of rust steamworks API bindings designed specifically around steam sockets, and ironing out the rough edges of steamworks-rs?
Maybe? One issues I think is that I'm not sure if you can have multiple steam clients active at the same time; users might already have a steamworks-rs client active (for friendlists, etc.) which will conflict with your "steam-sockets-rs" client
I'm thinking of not actually exposing the init method from the sockets API - instead, you're expected to depend on steamworks and use that for initialization, then pass in a steamworks::Client into my API, then we do some unsafe shenanigans to get the raw C pointer from that Client, and use that for the socket API.
Is the avian 3d character example supposed to be very easy to desync? It's as if the collisions don't work client side and always depend on the server (which will always be a bit wrong)
And the positions never correct themselves
I can have completely different positions on each client
Nope that's not supposed to happen; the client should detect that the positions are different from the server and rollback to that
Can anyone replicate this? All I did was cargo run server and client like mentioned in the readme
yeah ,the example is a bit broken đ
Does anyone have any examples of lightyear working with rapier3d?
If I have a a shapecast, that is based in what would be the entity future position. Would thjat have a tendency to cause rollbacks? In summary my logic is shared, meaning that the same two shapes casts will be made at server and client?
@pine cape Perhaps you can aid me, is it possible to get easily an entity future tick components?
I would like to avoid repetitive code
What do you mean by a entity future tick components? You could just look at the component values on the Predicted entity, which are the predicted future components
@pine cape How would your world sync work in p2p?
I don't think it would work as P2P, or at least one client needs to be marked as Server for the replication to work
I'm actually planning a pretty big refactor that makes lightyear less tied to a client-server architecture; it might then be possible to enable replication between two peers independently from who is client and who is server
It's still WIP but it's going along well!
I don't think it would have been possible when i first started lightyear, but with RequiredComponents, observers, etc. there's a lot more flexibility around the ECS
You can find it here if you want to take a look: https://github.com/cBournhonesque/lightyear/tree/bevy-main-refactor
Done:
- Link, Transport, Messages, Connection, Netcode, Sync, Serde
Not Done: - Replication, Prediction, Interpolation, Client, Server, Shared,
- specific IOs: Channels, WebSocket, WebTransport, UDP
- inputs
What about custom channels for entity syncing, each of them can disable and enable entity syncing any time as long as the request is sent through that channel?
"unexpected" entities from other channels can be denied and be met with an instant connection closure
It's just that currently the replication plugin is heavily tied to the identities of Client/Server
fresh compiles of lightyear are breaking for me, because lightyear 0.19.0 require wtransport =0.5.0, which requires quinn ^0.11.5. but 0.11.7 introduces a semver breaking change (stream_id.0 is made private), which is fixed in wtransport 0.6.1
Fresh compiles of the released version? I'll release a new patched version
I fixed this in the main branch, but forgot to backport it
Out of curiosity, lets say I want to replicate a collider from server to client, but ONLY for my map entities. How can I make this exclusive logic
(I dont want to just register in protocol, because it seen all confirmed entities get a collider)
I think for now you can add DisableComponent for the other entities where you don't want to replicate
Later I might introduce something like Physics Layers in avian
I did make a physics layer impl, so in your opinion do you think that making the confirmed entity, have a specific layer to itself would be the best approach?
I guess it beats the disable component on everyone else
Yes I was thinking of having some kind of ReplicationLayer, you could make a subset of entities be part of that layer, and for that layer we would pre define a set of components that would be replicated/disabled.
And we would a default ReplicationLayer where all components are replicated
Question, since there is a major refactor branch going on should I open the issue/pr when it comes to child collisions in avian?
Where independently if there is a child collision rollbacks occurs?
I am not sure if it is already fixed or will be fixed
This is not implemented at the moment
is it normal to see WARN bevy_ecs::system::system: System 'lightyear::server::replication::send::add_prediction_interpolation_components' has not run for 3258167296 ticks. Changes older than 3258167295 ticks will not be detected. on a server that had some clients before but none now? No prediction is being used atm. just basic replication (server fully authoritative)
Well yes
You dont have interpolation enabled for more than a few frame
@pine cape Question does replicate resource needs to run only once?
The answer was no
I just found out I was replicating a resource continously lovely
so is this just ignorable?
if i have a predicted entity with DisableRollback, is there any chance that Avian is progressing the state of that entity during rollbacks?
seems like my projectiles teleport forward when something else in the scene rolls back
Yes that's fine. These log messages from bevy are kind of useless
It's possible. But normally DisableRollback just excludes the entity from check_rollback, it should still get rollbacked when one happens
The whole point of DisableRollback for me is to prevent projectiles (whose Positions are ReplicateOnce) from resetting back to their confirmed position at the start of each rollback. Without it, if a 5 tick rollback happened, a projectile that was 100 ticks old would end up at a position 95 ticks in the past. It would be reset to its only confirmed position, then be simulated for the 5 rollback ticks.
It seems like DisableRollback prevents that from happening, so Iâm confused. Until you said that, my theory was that the projectiles were getting resimulated during rollback without getting reset to their confirmed positions first, which sends them even further into the future than the predicted timeline is. This makes sense to me, because if they were getting reset to their confirmed position at all they would teleport backwards, not forwards
đ¤
removing the projectile RigidBody and manually managing the Position fixes it, even when allowing that system to run in rollback, so it's something to do specifically with how avian is integrated. struggling to sort out what exactly though.
edit: i see what you're saying now, DisableRollback just makes rollbacks for that entity use the prediction history as the source of truth. that makes sense.
oh wow, ok. i narrowed it down some. if a rollback happens between the time when my prespawned projectile spawns and the confirmed projectile arrives, the prespawned projectile gets teleported into the future
Hm that's strange, the projectile should get rolledback correctly when in that PreSpawned state
Does this happen only with DisableRollback enabled?
oh wow, ok. i narrowed it down some. if a rollback happens between the time when my prespawned projectile spawns and the confirmed projectile arrives, the prespawned projectile gets teleported into...
actually looks like it's happening either way, i threw some logs that show more of what i'm seeing in the issue
i'll push this project up too in a bit here
pushed, posted w/ links to relevant code
I'm toying with the idea of modifying the replication API so that replication is started for a given entity by triggering an event ReplicateOn instead of simply adding a marker component
Not sure if it's a good or bad idea
what about the ux of that api are you trying to improve? is there some flexibility or boilerplate issue with the component?
I'm completely redesigning lightyear to be more independent from the concepts of client and server.
Everything is now a component, for example have an entity with a UdpTransport to which you can add a ReplicationSender.
However I'm trying to figure out how to specify that an given entity should be replicated on a given ReplicationSender.
I think until bevy supports M:N relationships, I will constrain it so that a given entity can only be replicated on one ReplicationSender
sure, the simplicity of the existing component api is good
whatâs the use case youâre envisioning for one entity being replicated by two different senders? suppose i can think of some but curious what youâre plotting
For example in a P2P setup, you would have connections to several other clients, and you would want your entity to be replicated to all of them
neat, i've been interested in "client-only" p2p lightyear since day 1
a peer owns an entity and can override all changes made to it when it wants
i think the marker component for allowing replication is better
I think the marker component is much more ergonomic. If you make it an event then suddenly you need to add an event writer to every system that spawns entities, which would be quite annoying
The bear is right listen to the bear
I made some more progress in the refactoring, the replication code now compiles! I still don't have a working test though
HELL YEAH burn bright mr peri
Are there any determinism gotchas with web?
Getting web-only rollbacks despite my inputs appearing to be tick-for-tick identical on client/server. 
Calling .normalize() on my Rotation 's Quat was the problem. Can't explain why. Surely that's consistent between platforms if everything else is?
I'm not sure about that; maybe ask on avian? They probably know more
@pine cape do you consider Replicate removal to be permanent entity despawn for everyone else? Or does it work in a different way? https://github.com/cBournhonesque/lightyear/blob/main/lightyear/src/server/clients.rs#L73
Yes, Replicate = entity despawn for everyone if Replicating was on the entity.
To only despawn for a subset you would need to change the ReplicationTarget within Replicate
Got the first replication test working.
I'm trying to think of how a Peer can specify which components they want to replicate. In the previous version each component would specify their ChannelDirection.
But after the refactor it's not good enough since there's no more client or server.
I was thinking that a user could specify a ReplicationLayer, which would contain some pre-defined Receive components and Send components.
Then when a user adds a ReplicationReceiver or ReplicationSender to a given Entity; they can also add the ReplicationLayer to specify which components they want to Receive/Send. We could also provide some pre-defined ReplicationLayers, such as ClientToServer, Bidirectional, etc.
If you're doing a huge re-write of the crate should I wait to dive in? I'm not sure how easy it is to migrate if I start using it in a game right now?
All i have is the registry and a Replicate component đ
I don't think migrations will be that complicated, and the concepts will be similar. I would advise you to dive in now as I don't have a timeline for when the rework will be done
Ah okay, thanks! I've already started. I appreciate your documentation and examples!
conceptually sounds fine to me; i think the ReplicationLayer approach sounds like a general flexibility improvement, besides solving your immediate problem
whatâs the api for a ReplicationLayer gonna look like? guess i wouldnât be excited if it necessitates additional boilerplate
i wonder if you could fold in other per-entity replication settings too. like a set of ReplicateOnceComponents could actually just be a specific ReplicationLayer
and does it have to tie in at all to per-client-per-entity replication settings like interest management (which would want to control entity update rate, for example)? or can those things exist agnostic to ReplicationLayers
Dumb question, is the cargo.toml file supposed to just work out of the box if I copy paste it from the lightyear examples to my project? Looks like I have some non-existent paths to things such as websocket = ["lightyear_examples_common/websocket"]
This is the error I'm getting.
PS C:\Users\tyler\RustroverProjects\celestial> cargo run server
error: failed to parse manifest at `C:\Users\tyler\RustroverProjects\celestial\Cargo.toml`
Caused by:
error inheriting `anyhow` from workspace root manifest's `workspace.dependencies.anyhow`
Caused by:
failed to find a workspace root
I'm using the same cargo.toml as the avian_3d_character example with just the name changed to match my project.
No, the examples have local dependencies that won't work with a simple copy and paste. The error you're getting specifically is related to the cargo workspace structure. You'll need to add anyhow as a dependancy and not a workspace dependancy
Ah okay thank you. Makes sense.
Hmm so I added all the dependencies but now I'm getting this when doing cargo server run. Is this an issue with aws-lc-sys? I thought I needed to add cmake as a dependency in my cargo.toml but that doesn't appear to fix it.
error: failed to run custom build command for `aws-lc-sys v0.28.0`
Caused by:
process didn't exit successfully: `C:\Users\tyler\RustroverProjects\Celestial\target\debug\build\aws-lc-sys-ecaf94aec9668737\build-script-main` (exit code: 101)
--- stdout
cargo:rerun-if-env-changed=AWS_LC_SYS_NO_PREFIX
cargo:rerun-if-env-changed=AWS_LC_SYS_PREGENERATING_BINDINGS
cargo:rerun-if-env-changed=AWS_LC_SYS_EXTERNAL_BINDGEN
cargo:rerun-if-env-changed=AWS_LC_SYS_NO_ASM
cargo:rerun-if-env-changed=AWS_LC_SYS_CFLAGS
cargo:rerun-if-env-changed=AWS_LC_SYS_PREBUILT_NASM
cargo:rerun-if-env-changed=AWS_LC_SYS_C_STD
cargo:rerun-if-env-changed=AWS_LC_SYS_CMAKE_BUILDER
cargo:rerun-if-env-changed=AWS_LC_SYS_NO_PREGENERATED_SRC
cargo:rustc-cfg=x86_64_pc_windows_msvc
cargo:rerun-if-env-changed=AWS_LC_SYS_STATIC
default_for Target: 'x86_64-pc-windows-msvc'
cargo:rerun-if-env-changed=AWS_LC_SYS_STATIC
cargo:rerun-if-env-changed=CMAKE
--- stderr
Missing dependency: cmake
thread 'main' panicked at C:\Users\tyler\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\aws-lc-sys-0.28.0\builder\main.rs:382:40:
called `Result::unwrap()` on an `Err` value: "Required build dependency is missing. Halting build."
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
My cargo.toml for reference.
[package]
name = "celestial"
version = "0.0.0"
authors = ["Charles Bournhonesque <[email protected]>"]
edition = "2021"
publish = false
[dependencies]
bevy = "0.15.3"
avian3d = "0.2.0"
leafwing-input-manager = "0.16.0"
lightyear = { version = "0.19.1", features = ["leafwing", "avian3d"] }
cmake = "0.1.54"
anyhow = "1.0.97"
rand = "0.9.0"
serde = "1.0.219"
metrics-exporter-prometheus = "0.16.2"
lightyear_examples_common = "0.19.1"
tracing-subscriber = "0.3.19"
tracing = "0.1.41"
trying to reuse the shared crate from the examples is going to be difficult i think
maybe try my template? https://github.com/Piefayth/lightyear-template little more involved than the examples, but, unlike the examples it is designed to be run on its own
sure Ill try that. Thanks!
I ended up just cloning it and renaming the folders đ I know you have an in-progress re-work so this idea may not hold water. Maybe the documentation could have better wording? Something like this? Any thoughts?
I could make a PR if you feel this is a worthwhile change?
Getting started
Standalone Template project to get started quickly:
This template is designed to be ran on its own unlike the examples under lightyear.
lightyear-template: opiniated template for a bevy + lightyear starter project
Code Examples
Check out the examples folder in the project.
This is a tutorial[link], which re-creates the simple_box example.
Lightyear Cheatbook
You can also find more information in this WIP book.
ah im not peri, lightyear-template is third party; i also struggled to convert the examples into a standalone project quickly, which is why i made it
Ah my bad haha. I saw your name on the template and got my wires crossed đ
OnInsert does not trigger, when a component that is replicated changes from server to client?
// Spawn map assets according to map informer
fn handle_map_informer(
trigger: Trigger<OnInsert, MapInformer>,
query: Query<&MapInformer>,
children: Query<&Children>,
map_collection: Res<MapCollection>,
gltfs: Res<Assets<Gltf>>,
mut commands: Commands,
) {
// Get file path
let entity = trigger.entity();
let MapInformer(file_path) = query.get(trigger.entity()).unwrap();
info!(?file_path);
// Grab scene
let gltf = map_collection.map.get(file_path.as_str()).unwrap();
let gltf = gltfs.get(gltf).unwrap();
let scene = gltf.scenes[0].clone_weak();
if children.get(entity).is_ok() {
commands
.entity(entity)
.insert(SceneRoot(scene))
.despawn_descendants()
.observe(handle_map_part);
} else {
commands
.entity(entity)
.insert(SceneRoot(scene))
.observe(handle_map_part);
}
info!("Received map informer from server spawning his scene")
}
This function does not get trigger when I mutate my component
Proof video
Egui + Terminal proof
I cri
@pine cape If you tell me why I will give you a meme
OnInsert only triggers on mutation; but when you mutate the component I just mutate the value; i don't re-insert
It's faster to mutate the component than to re-insert a new one because we don't have to check for archetype changes
Ah I see here is your meme
Interesting enough in server I reinsert him does that mean there is a code of yours does counter it?"
Yes, in the replication code I don't reinsert. I could try to make this configurable so that you could choose between mutation vs insertion
Maybe it should modify it, but then emit the OnInsert event directly (if it was inserted on the server, not if the server just modified it)
did you ever figure this out?
looking at doing something similar
might just have each player have authority over their character and have the other players just interpolate
coop game so cheating doesn't really matter that much here
are you having jittering issues? It's been a few months since I worked on this, but I ended up removing bevy_tnua and that ended my jittering problems. I remember not being able to get it it to play nicely with lightyear no matter what I tried. maybe it has improved since then, but I haven't looked into it
I haven't tried it yet tbh, just setting some stuff up for controller stuff
physics with networking is always hard
Are there componentid queries?
What do you mean by that?
Is it expensive to replicate resources?
It's the same cost as replicating a component; it depends on how the resource is serialized
Hey, I do have a question regarding lightyear, that I can't quite wrap my head around.
I want to do the following:
I have an entity (player) that contains components that are networked via client side prediction and server authority. (https://github.com/phaack/pha/blob/8e30b7ceb4f5f1e0626418d965e96afd9cb47611/crates/pha-protocol/src/component.rs#L27) That's all good. But now I would like to have a component ViewDirection that is fully client authoritative (sends updates to server without being rolled-back) and that gets propagated to other clients (except client). Now I understand that lightyear supports that via:
ServerReplicate {
controlled_by: ControlledBy {
target: NetworkTarget::Single(ev.from),
lifetime: Lifetime::SessionBased,
},
sync: SyncTarget {
prediction: NetworkTarget::Single(ev.from),
interpolation: NetworkTarget::AllExceptSingle(ev.from),
},
/// ...
(https://github.com/phaack/pha/blob/8e30b7ceb4f5f1e0626418d965e96afd9cb47611/crates/pha-server/src/replication.rs#L41)
But is that all one has to do? I also register it in the protocol:
app.register_component::<ViewDirection>(ChannelDirection::ClientToServer)
.add_prediction(ComponentSyncMode::Full);
Here's a small demo of what I mean: https://streamable.com/idb8m5
(left: server, right: client)
ViewDirection is not (received?) on the server.
You would need:
- spawn an entity on your client with ReplicateToServer (to start the client->server replication)
- register the component with ChannelDirection::Bidirectional (because a client doesn't replicate directly to other clients, it sends replication updates to the server; then the server sends updates to other clients).
- on the server, you would spawn Replicate with ReplicationTarget::SingleExcept(original_client)
You can see here an example of client->server replication:
- cursor is spawned on the client with
client::Replicatehttps://github.com/cBournhonesque/lightyear/blob/main/examples/client_replication/src/client.rs#L55 - on the server, when the Cursor entity is received, we add
server::Replicateto replicate it to other clients
https://github.com/cBournhonesque/lightyear/blob/main/examples/client_replication/src/server.rs#L131
Some updates on the crate refactor: i've added visibility + per-component replication config (ReplicateOnce, Disable, etc.).
The replication crate is nearly feature complete, I haven't included authority-transfer (i will leave that to the end), or hierarchy replicated (i'm going to work on this now).
After this I will need to update the prediction and interpolation crates, and then there's going to be a lot of testing to check that the new API works in all cases.
Not sure if this is an appropriate venue for this question but..
Has anyone using the lightyear template gotten it to run via rustrover by just pressing the play button? I got it working via the cmd line using cargo run server etc.. but I'm having trouble figuring out how to pass arguments via my startup config in my IDE so I can just press "Play" and have it run a server or client or both.
Here's the error
C:/Users/tyler/.cargo/bin/cargo.exe run --color=always --bin mygame-launcher --profile dev --manifest-path C:\Users\tyler\RustroverProjects\celestial\crates\mygame-launcher\Cargo.toml
Finished `dev` profile [optimized + debuginfo] target(s) in 0.57s
Running `target\debug\mygame-launcher.exe`
error: the following required arguments were not provided:
<MODE>
Below is what my Run config looks like.
Try adding 2 dashes between 'launcher' and 'server'
Didn't work đ˘
Command
run --package mygame-launcher -- --bin mygame-launcher --server
Finished `dev` profile [optimized + debuginfo] target(s) in 0.70s
Running `target\debug\mygame-launcher.exe --bin mygame-launcher --server`
error: unexpected argument '--bin' found
With the previous command that had --server I had this result
error: unexpected argument '--server' found
Usage: cargo.exe build --color <WHEN> --message-format <FMT> --bin [<NAME>]
For more information, try '--help'.
Process finished with exit code 1
server isn't an option/flag, it's an argument, so it needs to be passed directly
server not --server
@barren condor
I was thinking run --package mygame-launcher --bin mygame-launcher -- server
YES this worked! thank you both.
I have a question regarding networked entity hierarchies with different Replication rules.
For example:
on the client
entity (player):
- Position
- NetworkedInput
- ...
- (child) ViewDirection
The player is controlled by the server and locally predicted, whereas the child (ViewDirection) is Replicated ClientToServer.
Now with this in place I see the following hierarchy on the server:
entity (player):
- Position
- Networked Input ...
entity (view Direction):
- ViewDirection ...
I know that ReplicateHierarchy and ParentSync exists, but I'm not sure if my setup is the correct usage.
I also suspect that ParentSync would need the entity (player) and entity (viewDirection) to be in the same ReplicationGroup and I'm not certain that would be feasible. (e.g.: Encountered a panic when applying buffers for system lightyear::shared::replication::hierarchy::HierarchyReceivePlugin<lightyear::server::connection::ConnectionManager>::update_parent)
So the player is ServerToClient and the child is ClientToServer?
The replication groups being the same is mostly to guarantee that that when the ParentSync component is replicated, the parent already exists.
If you're adding the ViewDirection child entity AFTER you've received the parent entity (player), then you probably don't need to put them in the same replication group.
For now I would just disable ReplicateHierarchy on the parent, and manually add ReplicateToServer + ParentSync on the child.
Let me know if this works!
Normally, the flow should look like this:
- server spawns SP and replicates to client
- Client spawns CP (and maintains a SP<>CP mapping)
- You create a child CC and add ReplicateToServer + ParentSync
- when replicating ParentSync to the server, the client should map the entity inside ParentSync using its entity_map (ParentSync(CP) -> ParentSync(SP))
- the server receives ParentSync and should update the hierarchy correctly
Sorry, what does SP, CC, CP and stand for here?
server-parent, client-child, client-parent
Thanks. I think I understand.
Thanks for the help
Sorry, for the questions. I'm running into a bit of weird behavior with big client side prediction errors and unexpected reconciliation/rollback on the AuthorityClient with the following setup.:
I have 1. Networked Input, 2. Server authoritative Position and 3. Client authoratitive LookOrientation.: (https://github.com/phaack/pha/blob/1e424e1f38c48c35b31b10ac84b105ad358d11f0/crates/pha-protocol/src/component.rs#L18)
app.register_component::<LookOrientation>(ChannelDirection::Bidirectional);
app.register_component::<Position>(ChannelDirection::ServerToClient)
.add_prediction(ComponentSyncMode::Full)
.add_interpolation(ComponentSyncMode::Full);
// shortend
The client spawns a LookOrientation (https://github.com/phaack/pha/blob/1e424e1f38c48c35b31b10ac84b105ad358d11f0/crates/pha-client/src/player/client_look_orientation.rs#L25):
.spawn((
LookOrientation::default(),
LocalViewDirection,
ReplicateToServer,
))
server replicates to everyone else but client (https://github.com/phaack/pha/blob/1e424e1f38c48c35b31b10ac84b105ad358d11f0/crates/pha-server/src/player/server_look_orientation.rs#L55):
commands
.entity(view_direction_entity)
.insert(ServerReplicate {
target: ReplicationTarget {
target: NetworkTarget::AllExceptSingle(*client_id),
},
authority: AuthorityPeer::Client(*client_id), // The client has authority over this
sync: SyncTarget {
interpolation: NetworkTarget::AllExceptSingle(*client_id), // Interpolate on other clients
..default()
},
..Default::default()
});
Now comes the interesting part: Based on a (shared!) move_player method that uses only client authoratitive state e.g. Input and LookOrientation, it results in the server prediction something different than the client (on the LookOrientation) and therefore the resulting server authori. Position is send to the local player!
I hope this is not just a huge misconception, but if I understand correctly. As both the Input and LookOrientation are client authoratitive, and the fact that the Position is a function of those Pos <= (input, orientation), the server should never reconsolidate the client's Position.
may i ask why you need specialty client authoritative view direction? seems like you could get away with replicating a TripleAxislike in your inputs
I'm not sure. I'm creating an fps and to me it seemed sensical to network 'where' a player is looking on their client. That's what the LookOrientation is for.
Is that something I could do via Inputs like you mentioned? Your idea is good, if it works for the use case.
Honestly now that I'm thinking about it, that is probably a good idea. Thanks for your curious question. I think I will use Inputs to Network the Mouse Inputs that should be a better solution. Thanks @long marsh
i am not so sure what the ideal design is! but i definitely think it would save you networking headache to get it in the InputMap somehow
https://github.com/Piefayth/spacies-io/blob/main/crates/mygame-client/src/input.rs#L74-L133
I do it with a DualAxislike here - a custom input that derives the Vec2 representing the aim from the MouseMotion. it'd just be a Vec3 for you, and the math'd be different ofc
Can I ask a quick question while you are here. Do you think it would be a bad idea to simply network the delta of the mouse movement and then calculate the yaw, pitch (rotation) that that client wants to perform on the server from the inputs?
depends if their screen resolution matters for your math i suppose
but yeah thatâs probably the ideal way if you can make it work nicely for you. i would make sure that doesnât work before i tried anything else
I can't really think of how this would then look like. I would still want to calculate a view direction for all players and then I supposed for each player I tell the server not to replicate their own view direction back to themselves? Isn't that similar to what I have right now? I just can't have the local camera be influenced by the server (that'd be terrible)
lightyear prediction solves this for you if your player is predicted. just put the input on the map and run the same code on both client and server
itâll just work
just make the camera position on the client derivative, like, itâs just for client display like you say, you can do whatever
Hopefully. đ Thanks for the help đŤś
Yes i would advise to send the world position of the mouse as an input to the server, and use this to control the movement of the player/camera.
camera.viewport_to_world will probably be helpful: https://github.com/cBournhonesque/lightyear/blob/main/examples/fps/src/client.rs#L65
I'm also building an FPS:
- the input is controlled by Leafwing's MouseMove: https://github.com/cBournhonesque/sixdof/blob/main/client/src/player.rs#L62 (I think this might be incorrect and I might need to convert to world positions to account for different mouse sensitivities/screen resolutions), but it roughly gives the right thing
- the input is handled in a shared system between client and server: https://github.com/cBournhonesque/sixdof/blob/main/shared/src/player.rs#L84
- For the 'FPS' view I just add a camera directly on the player entity, which will inherit the player's Transform: https://github.com/cBournhonesque/sixdof/blob/main/renderer/src/player.rs#L129
hey I have a question on ComponentSyncMode::Once if i remove the component, and then insert it again into the entity, will it sync too?
Yes, I think so. A better name would be that inserts/removes are replicated, but not updates
When I spawn cameras on players for my client I'm getting ambiguity. I thought I could just attach cameras to a player and spawn them in. Is there something I'm missing here :/? I'm using the lightyear template btw.
You mean that you're getting rollbacks? I don't think the camera should be contributing to that, it's just an extra client-only non-replicated component
Ah it's more like I'm attaching a 3d camera to my player and when I have one client as the host and another connect it results in this. Yeah I'm trying to figure out why it would be ambigous if I the camera on multiple distinct clients
Camera order ambiguities detected for active cameras with the following priorities: {(0, Some(Window(NormalizedWindowRef(0v1#4294967296))))}. To
fix this, ensure there is exactly one Camera entity spawned with a given order for a given RenderTarget.
Here's the code where I'm spawning it. Yeah, that's what I thought too, the camera shouldn't be replicated. The only other camera I have is a UI camera
fn add_player_gameplay_components(
mut commands: Commands,
q_rendered_player: Query<Entity, (Rendered, Without<RigidBody>, With<Player>)>,
global_assets: Res<GlobalAssets>,
) {
if q_rendered_player.is_empty() {
return;
}
for player_entity in &q_rendered_player {
commands.entity(player_entity).insert((
RigidBody::Kinematic,
Collider::capsule(3.0, 4.0),
SceneRoot(global_assets.character.clone()),
Camera3d::default()
));
}
}
This is my camera I spawn when the game starts, but the order is higher than the default 3d one so that shouldn't be causing issues.
pub fn camera_plugin(app: &mut App) {
app.add_systems(Startup, |mut commands: Commands| {
commands
.spawn(
(
Camera2d::default(),
Camera { order: 1, ..default() },
IsDefaultUiCamera,
Transform::from_xyz(-50.0, 50.0, 50.0).looking_at(Vec3::ZERO, Vec3::Y)
)
);
});
}
edit:
Maybe it's because its going through all the player entities and adding the camera to them again. I can delete this if its cluttering the channel since its more related to the lightyear template? Gonna try a different way of spawning the camera rather than in that loop..
Ah that's just camera ambiguities. Well you should only be spawning cameras once on an app. If you're the host server you shouldn't spawn cameras for other clients
Does lightyear intennd on supporting something similar to bevy enhanced input:
holy schnutzel
Yes, lightyear will have an integration with bevy enhanced input
@pine cape BULLETS
Nice đ
was this moved somewhere else? interested in seeing how you implemented this
nvm im silly use git like its supposed to be used lol
there was something going on that didnt make sense at the time and I said screw it and rewrote it
using dynamic bodies instead
is that working fine with rollback? I'd assume the dynamic bodies would make that much harder
but I heard there was a bug with lightyear that would have fixed it? I cant remember, I could try again soon
Is lightyear scalable for large amounts of units? Like if I want 2000 units replicated? Can I just replicate properties instead of whole components?
It's not possible to replicate properties instead of whole components, but you could write a custom serialization function that only serializes those properties
The scale issue will come from the bandwidth usage rather than lightyear's cpu usage I believe. Is it for an RTS?
similar more mount and blade style
consider a lockstep rts like model if you want thousands of units.. here's how age of empires did it on ancient slow modems: https://www.gamedeveloper.com/programming/1500-archers-on-a-28-8-network-programming-in-age-of-empires-and-beyond
In Age of Empires the time to complete each simulation step varies greatly: the rendering time changes if the user is watching units, scrolling, or sitting over unexplored terrain, and large paths or strategic planning by the AI made the game turn fluctuate fairly wildly. A few quick calculations show that passing even a small set of data about ...
you have to ensure your simulation is deterministic, the difficulty of which depends on what you're building
ah ok thanks!
Look who is back
hello đ i've been doing some non-networking stuff since christmas.. but reckon i'll be back on the networking side of things once 0.16 lands
Hmm nice to hear,
Has anyone used tnua-avian with lightyear? and if so did you register all the Tnua components like TnuaMotor, TnuaRigidBodyTracker etc. in the protocol?
I'm running into some small weird issue where the collider is apparently lagging behind (https://streamable.com/gncypn) on the client (on the right).
I expect that this is due to not having those Tnua components networked (even though the inputs are fully networked and the 'movement' is fully based on that?!), but do you write wrapper types for all these types to implement the partialEq that .register_component needs?
I only register Position and Rotation component for networking.
There is no support for tnua in lightyear
I know for a fact that many tried but failed to make it work with lightyear, I am certain that is not impossible but does require a lot of effor in tnua side
Tnua uses Transform or GlobalTransform internally, so you will have to replicate that instead of Position/Rotation
I'm pretty sure I had a working version in https://github.com/panjeet/networked_cube_test/
Really? I renember a guy coming here and saying he couldnt make it work with predicted entities
IF SO man i went through a lot of pain to making my character flaoty
It probably still had rollbacks
Hmm, question how does map entities handle predicted entities? For example: I wanna send an event that adjusts solely the predicted entity, as it is a render focused event. This event is a message that is usally validated by server. And carries some other information, how can map_entities know that it should grab my predicted entity instead of the confirmed one
i will give you a meme if you answer me, this one is actually good
I can't seem to get it working either. Maybe I'm stupid but replicating Transform or Global Transform doesn't seem to solve the issue either.
Tbh all tnua is, is a floating controller that involves two physical engines, perhaps with two week of work you can make one yourself
With the mechanics that you desirer
I'm already on it xD. I don't know if I will make it work as well as tnua works as I don't have that much idea about how avian (and physics xD) works.
The message is sent by the server to the client?
yes
You would have to map it yourself using the entity_map in PredictionManager, which maps from confirmed to predicted
ah suck
Found out early stage rollbacks cause by workspace, with not pre prediction. Can sometimes due to system ordering cause rollback loop
I made some progress on the refactoring, there are still some rough edges on messaging/connection but i was able to get a simple example compiling with udp!
The example does nothing but have a client and server connect to each other, but it means that a lot of the big pieces are there
The main goals of the refactor are:
- make things more modular by splitting lightyear into multiple crates. The networking layers will be independent, so for example you'll be able to just have an IO layer to send/receive bytes without using any channels; or you could have channels but no MessageRegistry, etc. You could also use WebTransport without Netcode
- move everything from resources to components, to open up more networking topologies. For example an app could have 5 clients and 3 servers running at the same time
- make most of the core logic independent from the concepts of "client" or "server". In particular messaging and replication will just involve a link between 2 peers, so theoretically lightyear could work for p2p usecases
Some things are a bit awkward compared to before (for example an entity specifying on which connections it should be replicated, in the case where there are multiples servers in the app). Hopefully it's going to become easier in the future as N:M relationships and Construct are added
@pine cape i'm not exactly sure what im supposed to put here??
That means I wont have to have all features enabled?
Oh that is cool, very replicon like. Also avoids the whole avian mixture in the main repo
You realocated examples Mr Peri oh my god, finally I dont need to go two layers deep to run them
the examples have always been there lol
you're supposed to provide the ClientId that you want to use, as a u64
Whose clientid though
Of the client that is connecting to the server. You are writing a ClientConfig who is about to connect to the server
Is it ok if i just set it to 0?
yep that's fine. And if you have another client connecting to the same server you will have to pick a different value
sure ill just use a rng number
I now have a simple version of inputs + timeline sync working! I can see cubes moving on the screen (even though prediction seems slightly broken).
It's crazy how much work is necessary to get the simple_box example working
I'm the author of #1173981291801223239, and I know you all hate me because Tnua doesn't work well with Lightyear. This is because Tnua uses dyn objects that can't be synced (or maybe they can - but will require manual implementation of Reflect)
I've started working on a design for a big refactor that switched from dyn to enums. I'd appreciate some input about what's required in order to get it to play nice with Lightyear.
https://github.com/idanarye/bevy-tnua/discussions/97#discussioncomment-12922097
Cool! I'll answer this evening (I can't access discord at work)
heyo, love that idea also love the idea of making tnua friendly to networked games. That way I dont have to handle my weird controller
also love that oh man is all coming together, a tear is going through my eye right now
I'm not super familiar with tnua but I wonder if you've taken a look at bevy_enhanced_inputs? It's supposed to be the future standardized bevy input plugin and it has some ideas that are pretty similar to some things tnua provides.
For example Contexts would be similar to your TnuaScheme.
Ultimately if tnua works by listening to raw inputs and then applying forces from the physics engine, then it should be possible to just run the tnua plugin in both the client/server. Hopefully the plugin is deterministic and would give the same result from raw inputs (which are guaranteed to be the same on client/server).
Or is there additional state that tnua uses? Maybe the "controller"?
I'm not that familiar with multiplayer programming, but from what I understand the issue is syncing between client and server as much as it is syncing between multiple clients (even if that happen inside a server). Ultimately for each player character one client - the client of that player - gets the input first, and all the other clients get it in a few frames delay. So even if the input handling is deterministic, there is no way to guarantee all the inputs are applied on all the machine in the exact same way - not unless you are willing to delay the execution of a player's own input in their own machine.
For other clients, as you said either there is input delay, either the other clients will get the forces/position from the server with a few frames delay and just set their state to that
This won't work, because Tnua does care about its own past state.
Consider a scenario where Alice presses and holds the jump button. Her client syncs that input information to the server - along with the forces/position from the physics engine. After a few frames, Bob's client syncs that data from the server - it gets it while Alice is mid-jump - meaning her character is in the air, not touching the ground.
From Alice's PoV, she is in the middle of a jump. But from Bob''s PoV, Alice has pressed the jump button while in the air. Yes, she already has some upward velocity, but from the TnuaController of her character on his machine - she is in free-fall mode, not in jump mode, because her jump action was rejected (started when she was not on the ground). This will have Tnua handle her status differently behaving in different results on Alice's and Bob's screens - and a visible hiccup on Bob's screen when the next sync from Alice arrives.
Ah I was thinking of the case where a client would be interpolating other clients. In that case the server is computing the forces/positions for Alice and sending that to Bob, which uses it to render Alice on their screen.
For the use-case where we want Bob to predict what Alice is doing (by also having access to Alice's inputs which are forwarded from the server), then yes one option to have 0 mismatches is to add input delay so that Bob has access to all inputs at the correct time
If there is a mismatch and Bob needs to rollback Alice and recompute Alice's position, then Bob would need the corrected TnuaController of Alice's character (+ anything other state used by tnua to compute Alice's position)
I'm just wary of these approaches because that sounds like a lot of state to replicate. I have a similar issue with Avian where avian has some internal state that is not replicated which causes rollbacks. Maybe the solution is to just accept that there will be rollbacks for a few frames until Alice reaches a state that is easily predictable? (Running in a straight line)
@pine cape Sorry but i have to do this, this is a joke btw take your time
aha it's ready; i'm just waiting for avian/leafwing to upgrade
have you tried bevy enhanced input with lightyear yet btw?
nope i haven't tried, i'm still busy with the lightyear refactor.
I just got the simple_box_new example compiling with prediction + interpolation, however things are a bit broken: https://github.com/cBournhonesque/lightyear/tree/bevy-main-refactor
ah yes lots of crates now - i bet it compiles quicker for small changes
how hard has it been finding and carving out boundaries for different crates?
It's still somewhat in flux. One annoying thing is that I'd like lightyear to be client-server agnostic so that it can support any network topology, but that means in a lot of small crates i need to add client and server features to handle special cases for client-server architecture
Actually, if anyone wants to help, the tests compile on this branch: https://github.com/cBournhonesque/lightyear/tree/cb/0.20
but for some reason the 'Connect' button does not work in the examples (you can start an example with cargo run)
is that the bevy 0.16 branch?
i'm in crate upgrade limbo at the mo too
yes that's the 0.16 branch
Are you looking for help getting the connect button to work or something more?
Yes, mostly getting the connect button to work
looks like the Pointer<Click> event fires globally but without a target entity đ¤
Interation component is updated though.. i PRed some tweaks to your branch that i used to verify that with the egui inspector
With global Click events you need to get the target entity via the Pointer, not the Trigger
So trigger.event().target instead of trigger.target()
it doesn't use global events though, the observer is added when the button is spawned
like .spawn(button).observe(|_: Trigger<Pointer<Click>>| info!("CLICCCCCK"))
and although Pointer<Click> fires, it doesn't have a target so that observer doesn't see it
Huh, that should work yeah đ¤ Which code is this exactly?
i just PRed some minor changes to help debugging, it's the cb/0.20 branch
in the client renderer - the connect button
let me find the exact bit..
Ah in common, that makes sense
(i'm testing this with cargo run inside lightyear/examples/simple_box)
feels like the ui picking backend is awol, but i thought that was a default thing
oh maybe we have to opt in to that now, since we're not using defaults presumably.. i think it's bevy_ui_picking_backend
yes, that fixed it
fix is the second commit here: https://github.com/cBournhonesque/lightyear/pull/994
Thanks!!
do you anticipate many user-facing api changes for your lots-of-crates refactor btw?
@pine cape for some reason, the entity is not being replicated/spawned on client, this is the spawning code:
let replicat = Replicate {
target: ReplicationTarget::default(),
authority: AuthorityPeer::Client(v.from),
sync: Default::default(),
relevance_mode: Default::default(),
controlled_by: ControlledBy {
target: NetworkTarget::All,
lifetime: Lifetime::SessionBased
},
group: Default::default(),
hierarchy: Default::default(),
marker: Default::default(),
};
let entity = world.spawn((
Replicating,
replicat,
Transform::from_xyz(45.2, 12.2, 16.6),
RigidBody::Dynamic,
Collider::capsule(0.5, 1.),
TnuaController::default(),
Name::new(username),
)).id();```
Yes there's going to be a lot of api changes; most resources are now components; the replication components will also be different
Are you replicating from server to client? You set AuthorityPeer::Client(v.from), which sounds like you want the client to have authority and to replicate from client to server
yes to both
I think you first to replicate once with the server having the authority. After the entity is replicated you can update the authority to be owned by the client.
i mean the entity does have to be spawned from server first
Only server can update authority right?
correct
and clients with control of their entities?
The server would also be the one changing the authority
it would be cool if a client could "disown" an entity and change the owner to anyone it wanted
I agree! I think the authority system that i have now is a first draft, I want to improve on it.
Something like that: https://docs.coherence.io/manual/authority#orphans
wgat is that
some obscure engine
I have the simple-box example almost working apart from some input/prediction de-syncs:
It's pretty cool networking library for unity
i did a big refactor of my game to better support ai npcs and other bits, and i'm almost done adding gui features and splitting some of the crates to make it work headless. i've not added any networking to it yet. figured i would start on that once all the deps are on 0.16 (probably a couple of weeks away, but đ¤ˇ). i want to re-add the everything-is-predicted and rollback stuff i used before.
could maybe use your refactor branch if you think that would be beneficial? assuming it's in at least a half-working state at that point
seems like both have landed âşď¸
but there's also https://github.com/bonsairobo/bevy_metrics_dashboard, I've posted a PR, hopefully @spare kernel will find a chance to make a new release soon
Yes I think you can try! However I cannot guarantee that input replication or prediction is fully working currently
I don't think avian/leafwing have upgraded
leafwing has, avian hasn't
is the name new? https://crates.io/crates/leafwing-input-manager
Oh, indeed, my bad. I saw the Bevy 0.16 PR merged, but there's no new release yet..
Same with avian
Hm it looks like the text on the button doesn't get updated when the client connects
not sure why
oh it's because the Text is not directly on the button
fixed
ok i have a draft for the release notes as well, just need to wait for deps
@pine cape Sorry to bother you, but I noticed in README.md you mention Replicon in the replication section and then list additional features in the advanced section.
But we actually support things like entity mapping and interest management. Could you restructure those sections? Or maybe just remove the Replicon reference to avoid keeping it up to date đ¤
Oh, sure I can remove it!
@pine cape hmm curious, shouldnt lightyear be independant of such dependencies now that is fully crated?
Well avian/leafwing are currently behing feature flags so it's also somewhat independent, you will only get errors if you enable those features. But yes in the refactor (which is not finished) these will be split into separate crates
ah i see i tought you were going to combo the refactor with 0.16
Struggling to get over the learning hump with this crate. I'm not as skilled as some others here. I see that lightyear_examples_common exists on crates.io. Would it be appropriate or possible to use this crate to reduce the amount of code that I have to write? At least temporarily?
That crate exists mainly to provide a way to run all examples with all possible configuration options.
To start with a simpler usecase, I would try to emulate the simple_setup example
OK. Will do. Thanks!
@pine cape do you have a write-up somewhere for how lightyear does rollback/reconciliation?
I'm thinking about writing my own rollback code from scratch but I'm kinda stuck on the concept of only running a subset of systems for the specific entities that need replication
I don't have a write-up, but basically:
- I maintain for each Predicted entity a history buffer of the past component values that we received from the server
- whenever I receive a new Component value from the server, I check against the history to see if there is a mismatch. All predicted entities are in the same replication group so it is guaranteed that I receive the state for all the predicted entities in the same packet.
- If there is any mismatch, I revert all predicted entities to their past tick, then run the FixedUpdate schedule
rollback_ticktimes.
I also don't have a good solution for only running a subset of systems for specific entities.
Currently, users can use run_conditions to make some systems not re-run during rollback
interesting, I figured that would cause issues with non-replicated systems running more than they need to
I guess I could throw any systems that would cause issues into FixedPreupdate and FixedPostUpdate
I actually run the entire FixedMain schedule again, so it includes FixedPreUpdate, etc.
Some update on the refactor: the replication_groups example seems to run fine!
Remaining things to add:
- IO layers: WebTransport/WebSocket/Steam
- advanced replication stuff: DeltaCompression / Authority (I probably won't include them in the first release)
- HostServer mode: this one is going to be tricky, it usually causes a ton of headaches
- Polishing connection lifecycle: testing that things work fine when a new client connects/disconnects, etc.
- Sending messages to multiple peers
- unit tests: there's a lot of unit tests that I haven't ported over
@wintry dome if you try the new branch (bevy-main-refactor), please let me know about any feedback regarding the new API!
will do! nearly ready to readd the networking
SG, only udp is supported for now, but that should be enough to test
The other main change I want to do is update how I collect replication updates for replication groups. There is nested hashmaps there that cause 95% of perf issues I believe
Is there a general rule of thumb for what systems should go in FixedUpdate and what systems should go in Update ?
For both a client and a server
Simulation in FixedUpdate, visuals in Update is the rough split
For example I do basically all the game logic in FixedUpdate, and in Update I have for example an egui thing to display a scoreboard (but that could also be a UI system that updated based on the value of the scoreboard
Thanks, so should everything on a headless server just run in Update in that case?
Sorry - FixedUpdate
Yeah it likely should
Got it, thank you
I am noticing some cases where client and server get out of sync somehow
I have an AnimationState enum and sometimes it changes on the client and never propagates to server (it is ReplicateToServer)
I know connectivity is fine because other components on the same entity continue to sync/update while the animation state remains out of sync.
ie. I stop walking on the client and on the server the animation keeps playing, but I can still look around on the client and have rotation synced on the server
I haven't ported to 0.16 yet so my lightyear may be somewhat out of date
Are you sure that the component wasn't replicated? Maybe it was but there is some issue on the server. I would try to add extra logs to confirm that the component wasn't synced
I mean I'm looking the inspector
~~Also a quick question, is there a way to have client->server replication also replicate server->other clients ?~~nvm I see in the example
I was able to confirm that the server isn't receiving the update message.
Perhaps a bug where updates are being applied out of order? (possibly related to link conditioner? I am simulate 200ms of latency.)
@pine cape is it possible to restrict the number of messages per second? Like to have the networking run on a fixed tick?
Yes, that's the option called 'server_replication_interval' and 'client_replication_interval' in the SharedConfig
sorry to necrobump.
does it actually need to? couldn't the systems which need TickConfig just use Res<Time<Fixed>> directly
Yes I think that would be possible actually
this is a question a differnt thread mostly, but are there any known issues with bevy_tnua + lightyear
I ask only because I thought I saw a comment to that effect awhile ago and can't find it
I think there are issues because some of the tnua state is not currently serialized so it will cause some rollbacks because the server/client won't simulate inputs using the same tnua state
ah, I'm replicating transform and position instead so think I've sidestepped that
I wonder what order the character controller stuff should run relative to replication though...
probably physics, tnua, lightyear
The character controller is in FixedUpdate, right?
I sure hope so, EDIT: yes, I was in fact in my right mind
I think it should be lightyear::FixedPreUpdate::WriteClientInputs -> tnua -> physics (avian runs in FixedPostUpdate)
I released version 0.20.0 with bevy 0.16 support!
#crates message
I will release a version 0.20.1 when avian upgrades to 0.16
(trying bevy-main-refactor) even after propagating the std feature to the sub crate (lightyear_inputs_leafwing in this case) i'm still getting compile errors where i can't find std. i like the division into multiple crates, but having to set up all the features to propagate is annoying
got it building now. i'll try and fix some of the warnings, they are making it harder to see what's going on
no bevy 0.16 for bevy_metrics_dashboard yet either it looks like
Correct, I've been using RUSTFLAGS=-Awarnings and bevy-metrics-dashboard doesn't support 0.16
I would just try to run with std enabled for now. I think https://github.com/bevyengine/bevy/pull/18822 will help for feature management, but that's only in 0.17
The Bevy 0.16 PR is already merged to bevy-metrics-dashboard, I guess we just need a version bump and a release from @spare kernel
leafwing isn't working on bevy-main-refactor. i think having serialize/deserialize in the trait on that struct is problematic. having trouble getting it to compile
error[E0283]: type annotations needed: cannot satisfy `A: Deserialize<'_>`
--> /Users/rj/src/lightyear-rj/lightyear_inputs_leafwing/src/input_message.rs:17:12
|
17 | pub struct LeafwingSequence<A: LeafwingUserAction> {
(i bumped lwim to 0.17 for bevy 0.16 support)
I just pushed a fix; the priority example works with leafwing
This is done now
How does ReplicateToServer work in HostServer mode
And how does ReplicateHierarchy interact with ParentSync
ReplicateToServer does not send any packets when in HostServer mode. I just directly add a Replicated component
ReplicateHierarchy was removed in the latest version, but it inserts ParentSync automatically on children entities
can't get my server (on refactor branch) to listen.. i'm adding ServerUdpIo, and triggering Start on that entity. but per lsof it isn't listening. is there another step i've missed?
This is how I create my server: https://github.com/cBournhonesque/lightyear/blob/bevy-main-refactor/examples/common_new/src/server.rs#L98
Did you enable netcode?
nope i am using using udp
do i need netcode too?
i copied that but stripped the netcode bits for now
I haven't really tested without netcode yet.
I was planning on separating between:
- raw IO (Udp, websocket, WebTransport)
- connection-layer with persistent ID that is independent from the network socket (steam, netcode)
ok i'll add netcode and see if that helps
To interact with the raw IO you need the Link components (LinkStart Unlink)
To interact with connection you need the Connect/Start components (Connect/Disconnect on client, Start/Stop on server)
oh i suppose i need an IO layer and a connection layer anyway right.. is there any such thing as raw udp lightyear without netcode?
(ultimately i want to just use webtransport)
I was planning on providing a 'pass-through' connection layer that does almost nothing, so that you could just use the raw IO layer if you wanted to
(e.g. just use webtransport/websocket)
but it's not ready yet
alright, i'll add netcode like your example
but you can try triggering LinkStart instead of Start
and see if it works
that's what i listen to: https://github.com/cBournhonesque/lightyear/blob/bevy-main-refactor/lightyear_udp/src/server.rs#L57
ah yep with LinkStart it's bound to the port now
but i need netcode to replicate stuff anyway right?
for now at least
I think so; the main reason being that the entire codebase relies on Trigger<OnAdd, Connected> and that's only added in netcode.
The IO layers only add Linked: https://github.com/cBournhonesque/lightyear/blob/bevy-main-refactor/lightyear_udp/src/server.rs#L200
ok, thanks
Seems like the web_time dependency is missing in Cargo.toml. Can't compile lightyear for wasm:
https://github.com/search?q=repo%3AcBournhonesque%2Flightyear web_time&type=code
it seems that ParentSync::default(), when added to an entity, detaches that entity from its Parent
In HostServer mode
Maybe the issues I'm having are because I'm using replicateToServer in HostServer mode
I had a bug that seemed like some kind of a feedback loop from replicating Transform + Velocity, resulting in erratic rotations that never stabalize
but I stopped doing this, and only attached regular server replication.
and I haven't been able to replicate it since... inconclusive bc it's intermitant
@pine cape is this the issue you had when you tried replicating Transform ?
And does ReplicateToServer actually do anything when in HostServer mode other than add the Replicated Component?
like, could it potentially mess things up by trying to replicate changes from the world to itself?
It doesn't do anything other than add the Replicated component
I really need to enable a CI for all platforms to catch things like that
@stiff quiver will you have time to upgrade WebKeepAlivePlugin to 0.16?
@silent patrol I have this PR up for wasm fixes: https://github.com/cBournhonesque/lightyear/pull/1003
However I still need a new version of https://github.com/Nul-led/bevy_web_keepalive to be released
it might be because you're inserting ParentSync on an entity before it has any replication components
Maybe this helps? https://github.com/cBournhonesque/lightyear/pull/1004
By the way there was a replication bug in 0.20.0, I yanked that version and released 0.20.1
it was inserted with the replication Components.
I should probably port to 0.16 and update lightyear before spending to much time on this.
lightyear_transport::Channel doesn't have a name fn in the refactor, but the derive macro still expects one. not sure if you removed it on purpose or not
Ah I think you don't need to use the derive macro anymore
ah yes it;s fine with just a bare struct now
can i replicate resources on the refactor branch?
nope, not yet
Multiplayer weapon exchange
ignore the offscale and the horrendou uv map
and the fact he lacks arms
nice! is that on the latest version?
Didnt migrate yet waiting for other dependencies
it actually happens on the client as well, not only hostserver
but yes, making sure the replication components are inserted at the same time as ParentSync fixed the issue
In the refactor are we still going to have pre rollbacks if using crates and if server sided prediction?
@pine cape I'm a bit confused by Interpolated and Predicted entities, they seem to work the opposite of what I'd expect, in that components which don't have interpolation or predition get attached to the confirmed entity.
Were-as, it is the interpolated entity which I want to actually see, right?
So if I replicate things like PlayerMarker or whatever loads the mesh etc, these need to not be on the Confirmed entity, but they do need to be on the interpolated one.
What do you mean by pre-rollbacks?
If an entity is predicted but not pre predicted. And if in crate we get mandatory rollbacks
Just wanted to know if that would remain
I think so? The entity is spawned on the 'confirmed/replicated' timeline and you need to bring to the predicted timeline using a rollback
The Confirmed entity simply holds the replicated updates received from the server; the Interpolated entity holds interpolated values between 2 values received from the server (and stored on the confirmed entity). the Predicted entity holds predicted values
Yes usually you want to see the Interpolated or Predicted entities
Hmm might I ask you are a linux user?
No, mac
@pine cape is there anything generic in lightyear for replicating events?
in particular events with a target entity?
if not, do you have any thoughts on it
my first point of doubt is how event bubbling (like how observers work) ought to be handled.
The AB issue is I need a way to have my interactions replicated, like flipping a with a light-switch.
(theres some ambiguity with how events that trigger other events should be handled, to prevent duplicates on the client, but that's an issue for down the road)
Yes you can call register_trigger to replicate and trigger an event on a remote host
is that exported anywhere? it's not on docs.rs
and what is the behavior if the target entity is not replicated?
https://github.com/cBournhonesque/lightyear/blob/main/lightyear/src/protocol/message/trigger.rs#L16
Ah i think i didn't make it public ..
It would trigger on Entity::PLACEHOLDER, I believe
ah, I see. Conveniently I'm working off a fork
is there a good way I could have the entity mapping work off some kind of deterministic ID component
In this case, the Interaction event is triggered on objects in the gltf scene, which is loaded separately on client and server, and doesn't need to be replicated.
Even if it is replicated, I'd need a way of mapping the objects based on some Id, since they are spawned by the sceneloading plumbing on both client and server.
It seems that PreSpawnedPlayerObject needs prediction to be enabled to do anything?
I remember a long time ago when playing around with replicon, it was possible to specify an Id such that replicon would fix the mapping even if the entity had already been replicated.
Yes it is possible to update the mapping manually. I'm out rn but will let you know later
A few other questions.
- Does this automatically network the event when triggered or do I need to call client/server_trigger
- Is there a way to get the server to propagate triggers from client to other clients?
I'm not sure if everything is public (I think remote_entity_map isn't), but you would update the mapping manually like this: https://github.com/cBournhonesque/lightyear/blob/main/lightyear/src/server/prediction.rs#L34
You would call them via https://github.com/cBournhonesque/lightyear/blob/main/lightyear/src/protocol/message/client.rs#L293 (or same thing for server).
There is no way to propagate triggers from one client to other clients; the trigger gets immediately triggered in the remote app.
it's still very unclear to me what the relation between entity mapping and prediction is.
what if I need to map an entity that isn't predicted
or whether this will work at all if the order cannot be guarenteed (whether the client entity is created before or after the server entity is replicated)
I think my usecase is kinda the opposite of PreSpawnPlayerObject, since generally the client will spawn it after the server.
I think i understand the code a little better.
I have kinda a drastic idea, which is to try to add a Uid type to my fork of lightyear, and include it in the trigger message if it exists for the target.
The reason being, I want to be able to trigger events on entities with are not replicated.
And which arguably shouldn't be replicated (because you'd have a race with client side spawn logic adding whatever components happen to be registered for replication. For no benefit)
In my mind there are 3 semi-separate concerns:
- the entity map, which really just implements an abstraction of entities which exist in multiple worlds
- replicating entities, ie spawning, which kinda a special case of a networked command/event/message.
- replicating components, ie inserting/removal and updating. (which are argueably different, but I'd be inclined to think of them as the same.)
:w
The 2/3 are a bit orthogonal and depend on 1, but 1 is useful on it's own
entity mapping is independent from prediction; it's when an entity is A is replicated to a remote peer, the replication_receiver of the remote peer will maintain a mapping from A -> B
I'm also entertaining the idea of host-server fallback, ie. client promotion.
which I think would need some kinda Id's shared between host-server and all clients anyway.
Hm in the refactor i'm getting some errors with prediction/interpolation. I can't replicate what I had before, especially around how the different timelines are synced; it's a bit disheartening đ
I'm struggling to find a time-efficient way to find/fix those issues
@silent patrol wasm support should be fixed
awesome, thank you!
What kind of issue? Perhaps rj, shatur or me could help. Although for me most of what you do is black magic
I'm having rare cases where the prediction completely desyncs, this is whenever the prediction-timeline becomes desynced from the server-timeline and I seem to not be able to recover from this.
Also interpolation doesn't seem as smooth as it was before; I tend to reach cases where the interpolation doesn't have an end value to interpolate towards
you ran into it in lightyear 0.19?
In 0.20.2 too
It is rare usually happens when I leave it on for a long time, no idea why
I think it happens when the timelines get desynced. I emit a 'TickSyncEvent' to update the client ticks to be close to the server ticks again, but this seems to trigger some kind of death spiral
When client is too ahead?
too ahead or too behind
Are you accounting for the time that tick may arrive? Could also be the packett being override or ignored? Or maybe you are sending the same event twice?
I am super duper on the blind here just a debug questions
Do you not slow down/speed up the clock to maintain synchronization?
I do slow down/speed up the clock to maintain sync; I did a pretty big refactor of how I do the sync to make it cleaner. It does 90% of the sync well but I run into some edge cases
It's a really difficult thing to debug, but I'll see if I can help too, is there an example/test that showcases the issue? Or does it just happen to anything eventually?
Yes it's not easy to debug, I'm using the simple_box example on branch https://github.com/cBournhonesque/lightyear/tree/bevy-main-refactor
I run the server with
rm -rf SL && cargo run --no-default-features --features=server,udp,netcode,gui -- server 2>&1 | tee SL
and the client with
rm -rf CL1 && cargo run --no-default-features --features=client,udp,netcode -- client -c 1 2>&1 | tee CL1
Even with only one client I see that there's some issues.
Things to check:
- that the inputs are the same on the client/server for the same tick
- that sync is working correctly -> I think this part is broken. More logs are available with
export RUST_LOG=lightyear_sync::trace
I suspect that everytime a TickSync event is emitted, we enter some kind of death spiral
Like with only one client, I get into a state where I get constant rollbacks. I could try to revert all changes since the last time it worked, but there has been so many code changes that it's not really feasible
Fixing those sync/prediction/interpolation issues is probably the last big blocker for an alpha release.
@pine cape On a unrelated note, do you think that assets in general should be crate exclusive or singled filed. Meaning a single asset folder, for both client and server?
Probably client specific? Unless the server needs to know about something related to the asset (collision box, etx)
Is the simple setup example outdated?
it's possible, i've been a bit busy so i haven't had the time to update all examples properly when releasing 0.20
I just fixed it in the main branch
I don't quite understand what is happening here then
this is my own version but it's identical to the one in the example so I'm so confused on what is happening
You need to enable the udp feature on lightyear
The feature flag std, stands by the fact that udp is still not compatible with no-std?
Or is just std, like hey use this are the standard features
I think i more or less fixed the sync issues!
lightyear itself is no-std, but none of the underlying IO layers are
where was the problem?
i have a commit fixing the run conditions, shall i pr to your refactor branch?
Sure; which run conditions? I was thinking of getting rid of them now that you can have multiple clients per world
The exact issue is not clear; I added more smoothing on the sync logic, and I switched the timelines to update in PreUpdate instead of FixedUpdate
is_server is_client
ah I think they are still good to have, since most of the usecases is still client-server
just rebasing, will pr. it's only small
@pine cape Fyi on version 0.20.2, now my child entities get replicated which is nice they also got predicted which was not very nice (i had a child collider that even tho it is pos/rot is equal to parent, it caused rollbacks)
how do I know what features are available on a rust crate?
I don't know what the feature is called
oh it's just udp nvm
hm yea i don't think there's a way to prevent child entities to get replicated but not predicted. You can just despawn the predicted child for now
deterministic rollback is sounds like such a headache
i'm glad I can get away with just rubber banding, since it's coop anyway
When it comes to replication, is it a lot of overhead to replicate entities from a server to a client that will not change very often?
Not if you define= them correctly in the protocol
Basically controlling how ofter those informations are trnasferred
I was just going to add a Replicate bundle to each entity, but perhaps I'm mistaken?
Got it, I guess that's where I register the replicate-able components? I'm reading this part of the book now: https://cbournhonesque.github.io/lightyear/book/concepts/replication/protocol.html
Also, just for some context -
I'm planning on generating a map on a headless server and replicating map details ("tiles") to all clients. Then I want to get all of the clients to insert a SceneBundle to the replicated entities one they receive these details to render the map...
Before I was replicating a resource with all of the map info, but I'm trying to move away from that to decouple some stuff
No, this works!
@pine cape But I still have to register the components to be replicated, correct?
You can remove the Replicating component afterwards on the server, and the server will stop making replication attempts for these entities
Yes
Got it, thanks!
Is there a way to temporarily change the client-connection timeout? I'm using bevy_mod_scripting both server and client side. I have a script running server-side that is blocking pongs to the client, and thus the Client disconnects.
Nevermind, I increased the client_timeout_secs field in my client::NetcodeConfig đ
So I am trying to update to 0.16, but am getting the follow errors when building lightyear
Compiling lightyear_macros v0.20.2
Compiling lightyear v0.20.2
error[E0425]: cannot find value `DashboardPlugin` in crate `bevy_metrics_dashboard`
--> C:\Users\Elizabeth\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\lightyear-0.20.2\src\shared\plugin.rs:64:54
|
64 | .add_plugins(bevy_metrics_dashboard::DashboardPlugin);
| ^^^^^^^^^^^^^^^ not found in `bevy_metrics_dashboard`
|
note: found an item that was configured out
--> C:\Users\Elizabeth\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\bevy_metrics_dashboard-0.7.1\src\lib.rs:21:27
|
21 | pub use dashboard_plugin::DashboardPlugin;
| ^^^^^^^^^^^^^^^
note: the item is gated behind the `bevy_egui` feature
--> C:\Users\Elizabeth\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\bevy_metrics_dashboard-0.7.1\src\lib.rs:20:7
|
20 | #[cfg(feature = "bevy_egui")]
| ^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared crate or module `bevy_egui`
--> C:\Users\Elizabeth\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\lightyear-0.20.2\src\shared\plugin.rs:61:33
|
61 | app.add_plugins(bevy_egui::EguiPlugin);
| ^^^^^^^^^ use of undeclared crate or module `bevy_egui`
error[E0433]: failed to resolve: use of undeclared crate or module `bevy_egui`
--> C:\Users\Elizabeth\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\lightyear-0.20.2\src\shared\plugin.rs:60:39
|
60 | if !app.is_plugin_added::<bevy_egui::EguiPlugin>() {
| ^^^^^^^^^ use of undeclared crate or module `bevy_egui`
Some errors have detailed explanations: E0425, E0433.
For more information about an error, try `rustc --explain E0425`.
error: could not compile `lightyear` (lib) due to 3 previous errors
note im not building lightyear myself, it just used in my toml file
Hm does it work without the metrics feature?
yes, it does compile without visualizer feature!
What is ReplicationTarget component replaced with?
in 0.16
ReplicateToClient or ReplicateToServer
I feel like I've asked this before, but what is the difference between Message and Inputs? Or at least, a rule of thumb for when to pick between the two
The game I'm making is really similar to Civilization in that it's really just a board game. The client is mostly just clicking things (units, buttons, etcetera), and so far I've been translating these click events into Messages that the server will receive and deal with.
For example, sending a message to the server that contains two points on the map. The server then checks to see if something can move across those two points.
Inputs to me seemed more like real-time stuff, like pressing W/A/S/D on a keyboard for a shooter or something
The main difference is that Inputs are guaranteed to be perfectly tick-synced.
If a client presses a key at tick T, that Input will be 'received' by the server at tick T
Got it, thanks!
Also Inputs are handled correctly for rollbacks (if there is a rollback, your Messages won't be read again, but your Inputs will). But it sounds like you don't need prediction
Right... most of what I want to build amounts to glorified chess đ
Still making progress on the refactor, the timeline seems to work.
I'm not in the very annoying part of debugging prediction/correction issues in the avian examples (I ported all the prediction tests so it should mostly work but I still see some rollback artifacts) and testing input rebroadcast (to be able to predict other clients' actions)
@pine cape What do you think Mr Peri cool right?
Is the final version of my default character
hi, im trying to spawn a tilemap when a match begins, and since certain tiles are interactable i want to add replication to them, but since each client loads the tilemap then spawns it on their own im not sure how id add replication to them, is there something i could use in this situation?
using 0.15 btw
I don't think it makes a lot of sense to add replication to the tilemap/tiles itself. It seems like you'd most likely want some other entity that has replication depending on what type of interaction you're going for
@wintry dome I updated the spaceships demo in my refactor branch.
Things seem to work well! I've ported input-delay and input rebroadcast and things look pretty smooth
The only thing i'm puzzled about is that each bullet fired causes a rollback; it seems that the Confirmed update received from the server has Weapon.last_fired_tick = 0, but in our local PredictionHistory we have Weapon.last_fired_tick = T, which causes a rollback.
I'm not quite sure why the Confirmed version doesn't have its last_fired_tick updated. Maybe it points to some deeper underlying bug?
I merged the bevy-main-refactor branch into the main branch as I think it's now close enough in terms of feature parity!
Examples like spaceships, fps, avian_physics or avian_3d_character work fine with the refactor.
I would like to release soon an alpha version of lightyear-0.21 with the refactor changes.
There is still a lot of work needed on docs, tests, CI improvements + some bug fixes.
I was planning of maybe releasing 0.21 with some missing features (WebSocket, Steam, resource-replication, rebroadcasting-messages, HostServer mode)
hey, so I'm working on a new peer to peer multiplayer game, how do I do the "handshake" thingy with lightyear so that players do not need to leak their ip address all the time when they want to host the game?
You cant without a relay server, but if this is for co-op with friends i dont see the need
If this isnt co op u can switch to steam sockets
In lightyear
oo, yeah the plan is to support both steam and have a relay server for players to play on the server haha
like if possible, players shud be able to just send a join id for the other player to join the game
in bevy 0.16, is it still best practice to use the Replicate bundle, or is there some required components alternative?
You can use ReplicateToClient, which will add all other components via required components
I see, but I still need to add SyncTarget, ControlledBy separately, which makes sense since I need to specify values for those
Yes exactly, you can add extra components to customize the replication behaviour
How do I host such relay server? Any examples? Pointers on how?
Netcode doesnt support relays, so you have to go with steam.
(yet)
(and lets face it any online game made in bevy will be p2p client-server)
I'm not too familiar with that, but look into the matchbox crate. They have a signaling server which might be what you want
But if you're hosting a relay server you might as well host an authoritative server, no?
@pine cape The refactor was merged coolios
Now the true question is can dynamic collisions occur? Wihout continous rollbacks if so my goodness that is cash moneh
If not well at least the new structure seens way easier to mantain
You can greatly reduce the rollbacks by adding a custom is_rollback function for Position/Rotation. For example only rollbacking if they differ by 0.01
Jondolf is working on a change to avian where it doesn't require a cache of past values, which would make it deterministic
Oh
That is nice
Congrats on the rework!
I noticed that with the merge you also restored the Replicon reference in the README. I assume it's by accident due to a merge conflict? đ¤
Ah yes it's probably from a merge conflict! Let me edit it again
Thanks! Now it should be doable to create a lightyear_replicon crate that handles replication/messages as an alternative to the ones I provide
Well relay servers are cheaper. Cuz it only does the handshake haha. Authoritative server neeeds to scale much quicker as it needs to simulate the world xD
Trying to work through some old posts in this channel - what is the best way to get a mapped entity ID? Client is sending a message to the server with a local entity id in the message contents. I'm trying to convert from this ID to the server's equivalent.
Do I need to implement the MapEntities trait for my message? Just tried this and it didn't seem to work. If so I'm definitely messing something up
You need to implement MapEntities for your message, and also call add_map_entities in the protocol, like so: https://github.com/cBournhonesque/lightyear/blob/main/lightyear_tests/src/protocol.rs#L99
Thanks!
lightyear-template updated to bevy 0.16
https://github.com/Piefayth/lightyear-template
Awesome!
I wanted to update the examples in the main branch to add a button on the server that would either spawn a new App, or spawn a new LocalClient, similar to what you did in the templates
That way the example code can remain fairly lean/easy to read, while still having a way to test for client+server mode
Let me know if you need help upgrading it to the 'main' branch, the api is pretty different, and (hopefully) simpler
yeah that's my next task. i was gonna try to do my actual game first. no migration guide or anything yet, right? figured id just feel my way through the examples
Yep, no guide yet, the best place to look at is the examples
my goodness for the first time I have multi dynamic collision with lightyear and it is decent
Today is a good day
With input delay?
Only if latency simulating
Is there a way to replicate an immutable component, like a relation?
register_component requires Mutable, but I think ChildOf is replicated
You can replicate relations by adding the RelationshipSync<R> component!
But yes I should also allow replication of immutable components, it shouldn't be hard to do
Ah, thanks
You might need to add some extra plugins, it's not super ergonomic right now. I can give more pointers when I'm on my computer
I think I need HierarchySendPlugin, and it's pub, but it's in a pub(crate) module, so I can't access it
I can make do without a proper relation, though
You should be able to access it from the prelude
Looks like it's accessible in main, but not 0.20.2
Not a big enough deal to move to main, though
Are you sure? I see it here: https://github.com/cBournhonesque/lightyear/blob/0.20.2/lightyear/src/lib.rs#L231
you need RelationshipSendPlugin and RelationshipReceivePlugin, HierarchySendPlugin is something else
Oh, I see. Thanks.
compared to ReplicateOnce::default().add::<C>() this is pretty painful
could ComponentReplicationOverrides impl Clone?
Yes we can add Clone; and yes I agree that it's not ideal..
Maybe the best would be to add a lot of helper functions. (replicate_once() replicate_once_for(sender_id), etc)
Hey, did you ever solve this? I am struggling with the same issue. when I run avian_physics example in HostServer mode, it seems to be replicating ActionState from host client to the other client just fine. but in my project it isn't working. I've been scouring the code and cannot figure out what I am doing differently
Can't remember, been to long I'm afraid
no worries
yes and yes, i have this in protocol:
app.add_plugins(LeafwingInputPlugin::<PlayerAction> {
config: InputConfig::<PlayerAction> {
rebroadcast_inputs: true,
..default()
},
});
when I have a host server (1) and a second client (2), 2 has the ActionState component on the Predicted entity for 1, but it looks like this:
if I check disabled now, it stays checked until the host server player performs an action, so it seems to be replicating something, I just don't understand how it all works
Can you enable trace logs for lightyear::server::input::native (or leafwing)?
You should see logs for 'prepare_input_message'
sure, how do I enable trace logs?
This system should be running https://github.com/cBournhonesque/lightyear/blob/cb%2F0.20.2/lightyear%2Fsrc%2Fserver%2Finput%2Fnative.rs#L132
It does work in the avian_physics example, right?
yes it works in avian_physics just fine when running in host server mode
Run with RUST_LOG=log_filter cargo run
RUST_LOG=Lightyear::server::input::native=trace
when I run the host server with that, it doesn't produce any extra logs
i got it, it was capital L that was the problem
Maybe you don't have enough input_delay, so the input messages you are sending arrive too late on the client
this is what I get in the logs, seems like it's sending:
2025-05-22T18:18:16.405078Z TRACE lightyear::server::input::leafwing: Preparing host-server input message with buffer: Mut(InputBuffer { start_tick: Some(Tick(1492)), buffer: [Input(ActionState { disabled: false, action_data: {Move: ActionData { disabled: false, kind_data: DualAxis(DualAxisData { pair: Vec2(0.0, 0.0), update_pair: Vec2(0.0, 0.0), fixed_update_pair: Vec2(0.0, 0.0) }) }, Jump: ActionData { disabled: false, kind_data: Button(ButtonData { state: Released, update_state: Released, fixed_update_state: Released, value: 0.0, update_value: 0.0, fixed_update_value: 0.0 }) }, Rotate: ActionData { disabled: false, kind_data: DualAxis(DualAxisData { pair: Vec2(0.0, 0.0), update_pair: Vec2(0.0, 0.0), fixed_update_pair: Vec2(0.0, 0.0) }) }} })] }) tick=Tick(1492) current_tick=Tick(1492) entity=106v1#4294967402
2025-05-22T18:18:16.405111Z TRACE lightyear::server::input::leafwing: Sending host-server input message tick=Tick(1492) current_tick=Tick(1492) InputMessage<"PlayerAction">:
Entity: PrePredictedEntity(106v1#4294967402)
Tick: 1492. StartState: []
interesting, where is that configured?
to expand on the problem: if I run 1 host with 2 additional clients, the 2 clients only sometimes get each other's ActionState, it seems a bit random
i am trying with some input delay ticks, I see 10 is set in avian_physics
using .set_fixed_input_delay_ticks(10) solved the problem, but now that delay is super noticeable. but I can play around with these settings now
thanks for the help
Yep, basically with enough input delay all clients will have access to all other clients' inputs for tick T before running that tick, so there shouldn't be any rollback because all clients will perfectly run the simulation
The InputConfig has multiple levers around input_delay; you can choose to lower the amount of input_delay. This is at the cost that the client might not have perfect input information and will have to predict a few ticks
oh I see. for context, I wanted to use ActionState to control animations (walking, jump, etc) for player models. Maybe this is not the best way to go about this
ActionState is the raw input, the animations probably depend on the input (press jump->start jump animation) but the animations should also depend on other factors (interaction with environment, etc)
yep, for now I am just using the player inputs, later I can add interactions with the environment. but I am just trying to ensure that each client has access to each other client's inputs
Might I ask you does any special logic go into the TickManagerPLugin, or is it in summary, just a counter of fixedupdate ticks?
It's just a counter of fixed update ticks
What ChannelMode is recommended for physics based games? I see that every example uses OrderedReliable. Is that required for something like an FPS?
It depends on the data you want to send
Replication data is using Sequenced Unreliable, for example
Oh I see, so when we add something like:
app.register_component::<LinearVelocity>(ChannelDirection::ServerToClient)
there is some internal Channel in lightyear that it uses? I am confused about what app.add_channel applies to
for context, I added a new component which contains some simple player inputs (updated each frame from ActionState for all players) which the server replicates to all clients (so I can use that to derive animations for other players). When I add that component to the game's protocol, the host player on the second client starts to lag when it moves around. could this be that it is receiving too many packets now from the server or something like that?
Yes, input and replication are handled by some internal channels
Add_channel is for the messages that you want to send
Your component is probably not replicated
Because you don't have ReplicateToServer on your client entity
But inputs need to be replicated differently than normal components, I would your data to the ActionState, or create a second Input struct and register a second InputPlugin
For that extra data
what I have setup seems to be working, just with some lag. I have: ReplicatedInput component which the server builds from each client's ActionState, and replicates to clients. It does seem to be replicated to clients.
I am doing this because relying on ActionState for animations seems to be unreliable. This way, I can guarantee ReplicatedInput is always replicated to clients. I just don't know why the client's predicted entities of other players now lag (their movement is laggy, rest of the game runs fine)
Adding a component as both Input and Component in the protocol will cause issues
I am just registering like this:
app.register_type::<ReplicatedPlayerInput>();
app.register_component::<ReplicatedPlayerInput>(ChannelDirection::ServerToClient)
.add_prediction(ComponentSyncMode::Full);
not using InputPlugin or anything for it.
Just have a system on the server which updates it every frame
It's a component that is modified on the server, should be replicated from server to clients, and is tick-synced?
Lightyear doesn't support that at the moment. The only tick-synced components are client inputs
You cannot make it an Input?
I do not need this component to be reliable. it is just bizzare that adding this affects the performance of things like Position, etc. since this component does not interact with the physics in any way
If it's not reliable, then it's weird, yea
I am not sure what tick-synced means tbh, but I don't need anything fancy for this, compared to replicating Position for instance
i think maybe my approach to these animations might just be not good. all I really need is for clients to be able to figure out what animation to play for other players. I think using other player's inputs is the way to do this, but idk how to make sure clients are receiving inputs from other players reliably. ActionState doesn't seem to work, unless I add lots of input_delay. Not sure what else to try
yes I see 2 options:
- you use interpolation for other players, so they are rendered in the past and you just interpolate between their state
- you keep using prediction. If input_delay is not enough, then you will have a rollback to update the other player's state. Basically it's ok to not have the inputs for other clients in time, it just means that a rollback is triggered, and you will have to determine how you smooth out between the current state to the new state
Thanks, I will probably try interpolation tomorrow when I have more time to work on it. Appreciate all the help
So the refactor is finished no?
I need to add docs. Also host server mode and sending messages from a client to other clients is not currently supported
@pine cape Quick tip
This monster https://github.com/cBournhonesque/lightyear/blob/6867bccab18c582f625dedd4772e03e65db045fb/Cargo.toml#L3, could be avoided if you put your crates under one single crates folder
I guess, I mean it's just a few lines
I will send you a meme if you do it đ
I prefer the current organization
I'm doing something wrong with entity mapping again... server-side I am spawning tiles with struct Neighbors(Vec<Entity>) and replicating to the client. I've confirmed that the neighbors are correctly calculated on the server's end. I implemented MapEntities for this struct but it did not seem to work. Is there a replication setting that I am missing?
Ah... I don't think it shows my cursor, but whenever I click a tile the surrounding tiles should be colored. This is happening about 10 tiles away to the left of where I am clicking.
Goodness... I forgot to add add_map_enities() again when registering the component. I'm getting mapping failures now though with this implementation:
#[derive(Clone, Component, Debug, Deserialize, PartialEq, Reflect, Serialize)]
#[reflect(Component)]
pub struct Neighbors(pub Vec<Entity>);
impl MapEntities for Neighbors {
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
for entity in self.0.iter_mut() {
*entity = entity_mapper.map_entity(*entity);
}
}
}
Also I'm having trouble finding the derive macro for MapEntities, as I'm not confident I'm implementing it correctly. Still on bevy 0.15.3, that might be it?
Got it working after adding all of them to a ReplicationGroup đ
Yep, that's necessary!
@pine cape hi, is the crate-rized version going to be released still on 0.16 or only after 0.17?
is there an example using RelationshipSendPlugin, RelationshipReceiverPlugin and RelationshipSync?
0.16
I might release an alpha or rc version soon
nice
Nope, not yet. It might be easier to wait for the new release as the api for that is easier
hmm
can you tell with a quick glance what i'm missing? the entity already gets replicated, but the relationship uses the server ids
You need to add .add_map_entities to the protocol
And make sure the entities are in the same ReplicationGroup
register_component on the relationship is not possible because it requires a mutable component, and on the relationship target feels weird because it is not the source of truth
@pine cape Cargo.toml on main is using version = 0.19, shouldn't it be 0.21?
Yep, I'll it when cutting a new release
You would be calling register_component on the RelationshipSync<R> component
Hello. Quickly to start, thank you for this incredible crate.
I was quickly trying out the features inspired by this template by Piefayth I saw shared around here and the fps example. I've managed to put the 2 together and have 2 players that can shoot and bots that spawn infinitely. Both the bullets and the bots are predicted on the client. code is available on GitHub
I noticed that very quickly, when you start to have many entities, it behave very strangely, as you can see near the end of the video. And eventually, the server crashes and everything becomes smooth again (until it closes the game). Without any bots spawned, its smooth and bullets are fired and behave as expected.
I was wondering if there is a way to still have this many entities without everything blowing up visually, or if its expected. My knowledge of networking is meagre and I'm not fully aware of the possible limitations. Thank you for your time!
any possibility of register_component working with immutable components?
It's possible, it just needs a little bit of work
Hi, thanks!
Basically I think you can either be CPU bound (too much computation to fit in 1 frames time) or IO bound (too much data to send over the network)
In this case I suspect that you have client-side prediction turned on and the time it takes to resimulate the rollback frames exceeds 1 frame?
I actually haven't dived too much into cases like these, but it would definitely interesting to profile the cpu and network usage to see what the bottleneck is. Tracy might help here
Thank you for your quick response. Yes, both bullets and bots are predicted on the client, bullets being prespawned. I'll look about Tracy to see if we get better data
I ran Tracy while running the game with cargo run --features bevy/trace_tracy client -c 1. It seems to work, but since I never used tracy before, I don't really know what I am looking for.
Most frames seems to look like so:
For the "IO bound" part, is there any tools integrated into lightyear to quickly check sent and received packets size?
Yes there are some Diagnostics that contain the overall bandwidth. Or if you enable the 'visualizer' feature you can get various graphs related to bandwidth
On Tracy I would try to focus on frames that seemed to take an abnormaly long time. You can also try to filter for systems that contain the name 'lightyear'
I tried to add the visualizer and bevy_egui features but I am getting errors :
error[E0423]: expected value, found struct `bevy_egui::EguiPlugin`
--> /Users/klaus/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/lightyear-0.20.2/src/shared/plugin.rs:61:33
|
61 | app.add_plugins(bevy_egui::EguiPlugin);
| ^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `bevy_egui::EguiPlugin { enable_multipass_for_primary_context: val }`
|
::: /Users/klaus/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_egui-0.34.1/src/lib.rs:225:1
|
225 | pub struct EguiPlugin {
| --------------------- `bevy_egui::EguiPlugin` defined here
error[E0425]: cannot find value `DashboardPlugin` in crate `bevy_metrics_dashboard`
--> /Users/klaus/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/lightyear-0.20.2/src/shared/plugin.rs:64:54
|
64 | .add_plugins(bevy_metrics_dashboard::DashboardPlugin);
| ^^^^^^^^^^^^^^^ not found in `bevy_metrics_dashboard`
|
note: found an item that was configured out
--> /Users/klaus/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_metrics_dashboard-0.7.1/src/lib.rs:21:27
|
21 | pub use dashboard_plugin::DashboardPlugin;
| ^^^^^^^^^^^^^^^
note: the item is gated behind the `bevy_egui` feature
--> /Users/klaus/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_metrics_dashboard-0.7.1/src/lib.rs:20:7
|
20 | #[cfg(feature = "bevy_egui")]
| ^^^^^^^^^^^^^^^^^^^^^
ah there must be some incompatibility with the latest egui version... maybe stick to diagnostics for now
I pushed a change in main to do this
fair enough, thank you for your time. For the moment, I've switched the bots to âinterpolationâ, so I can get a lot more before it lags. I'll keep experimenting with prediction in parallel with this project.
Hi! In "host server" mode, where I connect via NetConfig::Local, is it expected behaviour for events not to be sent to the client? eg EntitySpawnEvent and ClientComponentInsertEvent<T>?
Hi, hm I think this might be the case because the replication plugins do not run when running in host server mode. In general I would move away from using these events as they will be deprecated in the next version.
I would use directly: Added<T>, With<Replicated>
thanks for the heads up đ
@pine cape I made some crates that are friendly to the lightyear work environment would you like to give me your opinion oin them ?
Sure!
Question how can i not replicate child entities?
Yay I will show u once i figure that out
Would you perhaps have an example?
I don't, but there is a function in the component registry to register a custom rollback evaluation fn
looking at the current lightyear main.
I like the switch to client/server being an entity.
gives me ideas for modularizing my networking behavior, instead of adding networking components to my Player bundle I could add markers to the server and client which when present enable systems that implement a specific logic for specific things.
something i've been thinking about.
does it really make sense to define what get's replicated at the app level?
the example I ran into is that some entities should replicate position and some transform
likewise, entities might differ in whether updates should be replicated or predition/interpolation applied
I think at least enabling/disabling replication per component per entity is currently possible but idk about swapping out prediction/interpolation
does lightyear need the full list of possibly replicated components to build the protocol? I could see how that might be the case
but does it need interpolation/prediction info? only the client (recieving side) actually needs to know about that right?
with the refactor, can I do Replication::new(ReplicationMode::SingleSender) to automatically choose either Server->Client or Client->Server ?
- Is there a reason you don't split out ReplicationTarget into it's own component. It would make the ReplicationMode enum and Replicate component alot leaner.
there is a move away from leafwing and towards bevy_enhanced_input, is there work to have plugins equivalent to the ones for leafwing, but for bevy_enhanced_input?
That's on the list but I don't have too much bandwidth right now. Also I think bevy enhanced input might not be handling correctly inputs in FixedUpdate (not 100% sure)
I fixed it, we now should support FixedUpdate đ
It's still an issue, but I think LWIM has the same problem. It's when a button pressed and releases less then the update interval.
Oh I see
Hi @pine cape , first off thank you for the awesome crate. I am just getting started reading about it and I was wondering if the book is out of date relative to the repo/examples? I noticed in the tutorial section (e.g. https://cbournhonesque.github.io/lightyear/book/tutorial/build_client_server.html ) the code doesn't match the examples in the repo and many doc links are broken (e.g. https://docs.rs/lightyear/latest/lightyear/client/plugin/struct.ClientPlugin.html ). If so, do you have a recommendation for how to best familiarize myself with the api?
yep both client and server need the full list of components
that's correct, actually the server doesn't get that information. I just put it in the shared protocol for convenience
Nope, because a server will have many ReplicationSenders (the server will spawn one entity per connected client)
Because you could have different ReplicationTarget for prediciton/interpolation/replication
yes the book is out of date currently!
I think the best way is to look at the examples, starting with this one: https://github.com/cBournhonesque/lightyear/tree/main/examples/simple_box
The version from the currently published crate is here: https://github.com/cBournhonesque/lightyear/tree/0.20.2/examples/simple_box
thanks! that was my plan. Might be a good idea not to point to the book in the readme until it's back up to date (granted it does say WIP, but that is pretty different from out of date)
I think tutorial also links to the book which was what I originally clicked on
Would it make sense back porting the register_component for immutable components for 0.20, or is 0.21 just around the corner?
I'll publish a 0.21-rc1 this weekend
Hello, do you know if the lightyear supports DTLS (https://www.rfc-editor.org/rfc/rfc6347) already? Is something we need to contribute to?
DTLS is a web transport feature? lightyear uses https://github.com/BiagioFesta/wtransport/tree/master under the hood for webtransport, I haven't looked to see if that is implemented
released!
any changelog/migration/etc available yet/in progress? (i couldnt find any)
Does lightyear support syncing a subapp world instead of the main apps world?
Nope sorry I didn't have the time, the best would be to look at the examples
I think so? If you add the plugins in the subapp instead of the main app
As I could see it uses HTTP3 under the hood, and it uses QUIC that is encrypted by default. So... I think it is encrypted. I will make some tests later on. Thanks @pine cape
Question, if I have an interpolated entity in other clients, and he is a dynamic body. Predicted locally, how do I handle the dynamic collisions? I cant add a collider to the interpolated entity
How to handle collisions between your local predicted entity and the other clients' interpolated entities?
I think you either predict/extrapolate the other clients, or you do lag compensation (like in my 'fps' example)
I'm stupid, I always forget that an RC is not shown on the front page of the crate
great thanks
https://github.com/bevyengine/bevy/pull/19274 @pine cape Interesting, perhaps tickmanager plugin will be no longer necessary? Or eased up đ¤
Objective
In the past I had custom data structures containing Ticks. I learned that these need to be regularly checked to clamp them. But there was no way to hook into that logic so I abandoned sto...
whats the state of websockets.
example common has an option for it in the client/server Transport enum, but nothing matches on it
It's not added in the latest rc release. Adding it would be very similar to WebTransport, and would involve delegating to aeronet
I'll just try webtransport
with the refactor is hostserver still relevant?
(I never really understood how a hostserver differs from a regular server from lightyear's point of view)
for example, I do need a both a headless server and client-hostserver mode for my game (one for the wasm demo, one for the actual build) but I'd imagine that difference is in my logic, idk why lightyear would need to do anything differently
HostServer is still relevant, but hasn't been ported to the refactor yet
What is the difference, from light-years pov between host server and regular server
Yep, will answer layer when I'm on a laptop
another question is whether the link conditioner can be used on the server, examples don't attach a Link to the server
Not an expert but yes, you can. It seems to only apply to incoming traffic.
seems I have to insert it into the LinkReceiver on the spawned clients.
There's 2 options to have a client act as host:
- either you start a second process on the host machine where you spawn a headless server
- or you you run as HostServer mode, where the clients and server plugins run in the same app. This means that you need to be a bit more careful, you don't want to run the same logic twice for the host client, and you don't want the server to replicate entities to the host client since they are already in the same app
Yes, the LinkServer doesn't actually do much, it's just parent entity for each LinkOf entity: we spawn one entity per client connection.
You can add a conditioner on any link (on the client or the server) to apply it on the traffic received on that link
why have the Client at all? vs having the host have a in process Server and no Client
also, I can't seem to figure out how to add ClientPlugins and ServerPlugins to the same app, without it complaining about duplicate plugins.
the lobby example doesn't even add ClientPlugins, so I'm guessing that's no longer needed?
I think because this would require users to make too many branches/changes in their code to handle host-client vs no host-client.
For example what if other clients want to send a message to the host-client? With your change users would have to send a message to the server in that case
The lobby example is not ready yet, sorry. And I haven't implemented host server in the refactor, so it's possible that the app complains about duplicate plugins
I'll just comment something out somewhere then
The easiest is probably to just start a server in a second process
Even before the refactor, host-server mode can be tricky to get right
it feels like there's two layers of abstraction getting muddled there.
in my head, server vs client is only a detail of network topology
Yes now that things are a bit more unified (every connection is just a Link), it might be possible to implement HostServer mode more easily
my use-case might be a bit odd, since it's almost entirely cooperative and the clients are authoritative over alot of things
and so the server is actually just there to pass data around
it probably should be a mesh network, but it's not worth the hassle
regardless, I've been thinking of the server as the client which happens to be the center of the the network topology
the thing about messages seems like a good reason to spawn a Client on the server, just to give it an ID and existence independent of its circumstantial role as server.
but then, avoiding logic running twice might be pain.
Yep, you need a run condition to avoid systems from running twice
yeah, in process headless server feels like the way to go. (hmm.. but then I'd be doubling the physics compute :/)
I think what you describe should be possible, did you see the authority example in the 0.20 branch?
I looked at it a bit
is webtransport working in main
trigger(Start) doesn't seem to do anything
Yes, the examples work with webtransport
I'll have to take a closer look at the examples. I'm not getting Started on my Server, so something is off
hypothesis: triggering Start in the same system I insert the WebTransportServerIo component causes it to be missed. because Server isn't inserted yet when the Start observer runs
Does the RC have this new API?
Yes
is there a way to rewrite this without it being a command?
app.world_mut()
.commands()
.replicate_resource::<MyRes, CommonChannel>(NetworkTarget::All);
I don't think so, it looks like I don't expose methods on World.
Replicating resource is also not available in the refactor right now. My hope is that in bevy 0.17 resources are entities, so we can just add the Replicate component on them
You should actually go ask for clarification on that, because I remember seeing that referred to as "Resources will be components on a singleton entity", rather than each Resource being their own entity, might well be worth adding this use-case to the pile so that they don't implement something that unusable for this
Thanks, will take a look
my server is started and a client can connect, but neither the Server nor the WebTransportServer get's the Started component
this causes Replicate::to_server insert hook to fail because it can't find the server
this appears to also be because only the netcode module implements the behavior
likewise for connected
it seems like most things are broken if you aren't using netcode
there's got to be some way we could improve the error reporting. I've spent all day on different silent failures and the only reason I could get a clue what was wrong is that I have lightyear forked with dbg stuck all over the place.
admitedly it's tricky since the compositional nature of ECS means anything might not be an error...
anyway. Idk why it didn't occur to me earlier but I copied the default config fromt he simple example for NetCode server and I can actually replicate stuff now
I was under the impression Netcode was a more invasive protocol (requiring a coordination server).
I also was under the impression it used raw UDP, so I didn't think I even could use it with webtransport
based on docstring in lib.rs in lightyear_netcode
Yep, the idea was to distinguish between Link (which was just any io connection) and Connection (where you have a persistent ID, for example provided by netcode or steam).
I wanted to have a PassThroughConnection for links that already give you a connection (like WebTransport) but I haven't gotten around to it
Netcode just wraps packets and adds some security features, it can be used on top of any io
Are you using crates individually instead of using the wrapper lightyear crate?
No I'm using the wrapper
I have this PR: https://github.com/cBournhonesque/lightyear/pull/1018 to separate the PeerId data from the Connected component (mostly because I want to know which PeerId was disconnected), but for some reason it seems to cause very weird behaviour:
- when a client disconnects and reconnects, the Server component gets removed on the server.
I can't even find a single instance ofremove::<Server>in the codebase, so I really don't know why this is happening
Nvm looks like this is also happening in main ..
I have two usecases that require me to deal with entity mapping:
- I need to load a gltf scene on server+clients and have certain children be replicated (ex. items you can pick up)
- I have interactive items that I need to trigger events on (ie. a lightswitch)
my plan for this is to create a Uid component that will be deterministic and the same on clients and server
how does lightyear do entity mapping?
are the entities mapped by the message sender or reciever
can you point me to an example that does custom mapping for entities. I only see the prediction stuff which seems somewhat special case
for example what happens if PreSpawned is added on a client entity when the server has already replicate it? (race condition)
Can you elaborate on the PreSpawn case?
But basically if server sends entity E to client 1, then client 1 maintains an internal mapping of E to E'.
Then if client 1 sends a message containing E' to the server, client 1 will pre-emptively do the mapping from E' to E
can I manually adjust that mapping (ie. the default one for replication)
scene loading: the scene is loaded on client and server via a message or marker trait. The scene contains entites which need to be synced, but must be spawned by the scene loading logic (lightyear doesn't spawn them)
Once the server scene loading loads one of the entitie, it will replicate it to the client
the client may have already spawn it's copy of the entity, or the scene loading may still be running (waiting on disk, etc. timing is unpredictable)
Yes it's available here: https://github.com/cBournhonesque/lightyear/blob/main/lightyear_messages/src/lib.rs#L80
in the former case, the client must use the Uid of the replicated server entity to match the spawned copy (with same Uid) update the mapping and from there replication proceeds as normal
in the latter case, the client must spawn a temporary entity (or buffer the replication message, as replicon does) and when the scene loader spawns a entity with the same Uid, the entities are merged and mapping updated
I take it replication is implemented as a message
yes
anyway, my impression is it would be easier to implement this myself than try to get PreSpawned to work for this usecase
Yes PreSpawn has another meaning that is more closely tied to prediction
yeah, prediction makes the usecase I describe even more confusing
since I think the entity spawned from the gtlf-scene should be the predicted/interpolated entity right
ie. you attach mesh/material/collider etc to the predicted entity
So what is your idea?
- server spawns the scene with E and starts replicating to client
- client might already have spawned E by loading the scene. How do we make sure that client doesn't spawn a new entity for E' but instead of matches it with E?
- client hasn't already spawned E', but instead receives E from replication and spawns E'. How do we make sure that the client doesn't spawn a new entity for E' when loading that part of the scene?
yeah, basically
and my solution is a Uid component, which you just make sure is the same for entities you want mapped
ah I see, that Uid component uniquely identifies the entity within the scene?
yeah. and my solution for that is to give a loaded scene instance a random Uid (assigned by server), and have the children be parent-uid + Name hashes
kinda like egui
I guess the best long-term solution would be for bevy to allow pre-allocating entity ranges
and you specify ahead of time a range of entities that are reserved for networking or scene replication, and you don't need to do any mapping
I have had the thought before that maybe networking should be it's own world / subapp
then interpolation works like extraction
PreSpawn seems fairly similar to what you describe, but just in the context of prediction
maybe I should that capability for replication as well
I was looking into replicon 6 months ago, and it also doen't have anything built in for this
the goal is not to save bandwidth, because the entire scene will still get sent over the network, but rather to make sure that the scene can load fast on the client?
well, the client has to load the scene either way right? you aren't sending mesh handles over the network
I get the sense that what I'm doing is uncommon, which is interesting to me
not too familiar with how scenes/mesh works. Are meshes just an asset handle? so it doesn't make sense to network them?
but then what part of the scene is the server replicating?
i assume you want the server to load the scene so that it has access to colliders, etc.
yes. The server and client both load the scene, which is generally a single gltf file exported from blender.
the gltf file has extra data that is deserialized as bevy components (for colliders, interactivity, replication, etc. )
ex) a scene of a room. there are all sorts of items in the room that can be picked up and thrown around (so they need Transform etc replicated)
re-implementing scene spawning to work entity by entity over the network would require a system for asset handle mapping and idk what else. It would be interesting, but the easy way is to use the same scene loading logic client and server and stitch the entity map after the fact
I see
So currently the replication logic is: (https://github.com/cBournhonesque/lightyear/blob/main/lightyear_replication/src/receive.rs#L717)
- sender sends Spawn(E) to the receiver
- on the receiver, we check if we already have a mapped entity corresponding to E. If we do, we just skip
If latency wasn't a concern, you could wait for the scene to be entirely loaded on the server, then the server sends to the client a message containing all the entity-mappings, which the client inserts inside its entity map. Then the server starts Replicating the scene, but no new entities are spawned because the client already has them in the entity-map
I think I want to make the Uid thing work to make it more data driven
if two entities have the same Uid then they will be mapped, regardless of the spawn order
for that you would need some changes in lightyear, no?
I think I can just write some observers around Uid+Replicate which update the mapping
But you might get extra entities spawned
I guess in the observer, you can check if the entity was already mapped
and if it is the case you can despawn that one
yeah, I merge the two entities components and despawn one,
there's some question of which copy gets priority when merging
but it's probably not super important.
I will want both entities disabled in the first place anyway, and enabled one the scene (or at least that entity) is finished loading on both ends
How to do that is a question. Probably just create a replicated::once NetworkStarting component that requires Disabled, and make sure all the Uid mapped entities have it.
quick question: is there a way to have authority split by component on the same entity?
No, authority is on entity-level currently
I'm having an issue where an entity that was prespawned isn't being rolled back correctly. It's removing a component that was added, but not re-adding a component that was removed, putting it in a bad state. Here's a log that I've annotated
The predicted entity isn't getting HistoryBuffer<Wait> added, so that might be the issue?
Possibly; is the Wait component registered in the protocol? This is lightyear main or 0.20?
Yeah it's registered
app.register_component::<Wait>()
.add_prediction(PredictionMode::Full);
I was on 0.20.2, but I'm moving to main rn
Was Wait added before PreSpawned?
pub(crate) fn add_prediction_history<C: Component>(
trigger: Trigger<OnAdd, C>,
mut commands: Commands,
// TODO: should we also have With<ShouldBePredicted>?
query: Query<
(),
(
Without<PredictionHistory<C>>,
Or<(With<Predicted>, With<PrePredicted>, With<PreSpawned>)>,
),
>,
)
I guess I should also add the History<C> when either of (Predicted, PrePredicted, PreSpawned) is added
I'll fix this and add a test; basically the issue is that i suspect a HistoryBuffer<C> is not added for components C that existed before PreSpawned was added
Yeah, I have a custom entity command that adds the right prediction components for either client or server, which I run after spawning the entity
So it sounds like that's it! Thanks!
Thanks; and let me know if you have any questions regarding moving to main! Is it painful?
I don't have too much docs so some things might be tricky
yes hopefully it's for the better haha
I just fixed the lobby example to work again! (it still doesn't handle HostServer mode, though)
The only broken examples after the refactor should now be delta_compression and distributed_authority
I also updated lightyear_steam to use aeronet, but haven't tested it
My next task will be to try to fix host-server mode
I'm trying to sync (predict) Transform (instead of Position/Rotation) with avian2d, which is working (from the player's point of view) except I'm getting a rollback for every frame. There are no inputs or anything--just trying to get the client to properly sync with the server. I've been trying to work it out but there's so many moving parts. I suspect it is a schedule I need to move around, but not sure which and where. Any ideas?
reproduction: https://github.com/slowchop/lightyear-avian
i suspect it's avian sync to transform, but haven't quite worked out the ordering
In general i would recommend syncing Position/Rotation instead of Transform; is there a reason why you need to sync Transform?
I don't have access to your repo
If you sync Transform I think you will need to use this system order: https://github.com/cBournhonesque/lightyear/blob/main/lightyear_avian/src/plugin.rs#L56