#lightyear

1 messages ¡ Page 11 of 1

autumn furnace
#

Hmm

#

NetworkIdentity::is_server() is always false, even though the server is definitely running

#

I forgot to set shared.mode to HostServer

#

nope, still broken

autumn furnace
#

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.

autumn furnace
#

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?)

unkempt sedge
autumn furnace
#

I'll give it a shot.

marble lava
#

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

pine cape
#

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

marble lava
#

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?

marble lava
#

is Transform too expensive to replicate?

pine cape
marble lava
# pine cape 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

pine cape
#

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

marble lava
# pine cape I don't have enough information. I don't know if your entities are short-lived, ...

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

pine cape
#

Can you share your repo privately with me?

pine cape
marble lava
long marsh
#

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

pine cape
long marsh
pine cape
#

it won't send anything

wicked oak
#

O well, i Still have the same replications issues, Sad life

marble lava
long marsh
#

that confuses me / contradicts what Peri said, no? unless you were modifying Transform in Update, it shouldnt have been sending overwhelming amounts of updates...

marble lava
#

I wasn't but Avian2d probably does even if it doesn't move anything?

#

I suspect it derefs which counts for Changed

long marsh
#

even with position_to_transform disabled, you think? you're probably right

just seems...weird

marble lava
long marsh
marble lava
#

ah I didn't even know about it, whatever is default is what my code uses

long marsh
#
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

marble lava
#

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 😄

sly ibex
#

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

long marsh
sly ibex
unkempt sedge
#

that is probably just your rust analyzer implodijng

sly ibex
#

oh word, assumed it was just 'new' cause one of my bevy traits was being weird too
ty KING

long marsh
#

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!

pine cape
#

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?

#

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

long marsh
# pine cape What kind of .io game are you making?

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

unkempt sedge
#

Hmm interesting migrating to crates workspace causes a few rollbacks on init

#

Is that expected?

long marsh
unkempt sedge
#

Ah so I will have to prespawn it to avoid it, lets just say that loading assets and rollbacking is not really cool

long marsh
#

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

unkempt sedge
#

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

long marsh
autumn furnace
#

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

long marsh
pine cape
#

@long marsh I had to run cd crates before running the certificate command, but otherwise everything worked!

long marsh
pine cape
#

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

long marsh
#

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

long marsh
#

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.

unkempt sedge
#

When it comes to timers one should base itself on ticks correct?

pine cape
#

It depends on what exactly you need; but yes ticks are guaranteed to be synced between client and server

unkempt sedge
#

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

pine cape
#

Yea the tick manager gives you the correct tick even during rollback

#

The TimeManager also rollback time so you could use that

paper sage
#

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?

pine cape
#

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

earnest fog
paper sage
# pine cape Does this fix your issue? https://github.com/cBournhonesque/lightyear/pull/982

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

pine cape
#

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

GitHub

A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear

paper sage
#

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

paper sage
# pine cape Could you please open an issue? Then I could add a unit test for the use-case of...

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

GitHub

Lightyear version: Main branch What I did: Added both the Client and Server plugins to my game, so they can be started based on user choice. Start a Server with a local player, and a Client that co...

unkempt sedge
sonic citrus
#

@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:

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?

pine cape
#

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

sonic citrus
cyan grail
#

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

pine cape
#

Nope that's not supposed to happen; the client should detect that the positions are different from the server and rollback to that

cyan grail
#

Can anyone replicate this? All I did was cargo run server and client like mentioned in the readme

wet kelp
#

yeah ,the example is a bit broken 🙂

cyan grail
#

Does anyone have any examples of lightyear working with rapier3d?

unkempt sedge
#

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

pine cape
#

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

wraith stag
#

@pine cape How would your world sync work in p2p?

pine cape
#

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

pine cape
#

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
GitHub

A networking library to make multiplayer games for the Bevy game engine - GitHub - cBournhonesque/lightyear at bevy-main-refactor

wraith stag
#

"unexpected" entities from other channels can be denied and be met with an instant connection closure

pine cape
#

It's just that currently the replication plugin is heavily tied to the identities of Client/Server

sonic citrus
#

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

pine cape
#

Fresh compiles of the released version? I'll release a new patched version

pine cape
#

I fixed this in the main branch, but forgot to backport it

unkempt sedge
#

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)

pine cape
#

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

unkempt sedge
#

I guess it beats the disable component on everyone else

pine cape
#

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

unkempt sedge
#

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

pine cape
#

This is not implemented at the moment

marble lava
#

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)

unkempt sedge
#

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

marble lava
#

so is this just ignorable?

long marsh
#

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

pine cape
pine cape
long marsh
# pine cape It's possible. But normally DisableRollback just excludes the entity from check_...

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

🤔

long marsh
#

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.

long marsh
#

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

pine cape
#

Hm that's strange, the projectile should get rolledback correctly when in that PreSpawned state

#

Does this happen only with DisableRollback enabled?

long marsh
#

i'll push this project up too in a bit here

long marsh
#

pushed, posted w/ links to relevant code

pine cape
#

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

long marsh
pine cape
#

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

long marsh
#

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

pine cape
#

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

long marsh
#

neat, i've been interested in "client-only" p2p lightyear since day 1

wraith stag
wraith stag
fervent karma
#

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

unkempt sedge
#

The bear is right listen to the bear

pine cape
#

I made some more progress in the refactoring, the replication code now compiles! I still don't have a working test though

unkempt sedge
#

HELL YEAH burn bright mr peri

long marsh
#

Are there any determinism gotchas with web?

Getting web-only rollbacks despite my inputs appearing to be tick-for-tick identical on client/server. thinkfused

long marsh
#

Calling .normalize() on my Rotation 's Quat was the problem. Can't explain why. Surely that's consistent between platforms if everything else is?

pine cape
#

I'm not sure about that; maybe ask on avian? They probably know more

wraith stag
pine cape
#

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

pine cape
#

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.

barren condor
#

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?

wraith stag
pine cape
barren condor
#

Ah okay, thanks! I've already started. I appreciate your documentation and examples!

long marsh
#

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

barren condor
#

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.

earnest fog
barren condor
#

Ah okay thank you. Makes sense.

barren condor
#

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"
long marsh
barren condor
#

sure Ill try that. Thanks!

barren condor
#

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.
long marsh
barren condor
#

Ah my bad haha. I saw your name on the template and got my wires crossed 😄

unkempt sedge
#

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

pine cape
#

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

unkempt sedge
pine cape
#

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

fervent karma
#

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)

inner hill
#

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

river perch
# inner hill did you ever figure this out?

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

inner hill
#

I haven't tried it yet tbh, just setting some stuff up for controller stuff

#

physics with networking is always hard

wraith stag
pine cape
#

What do you mean by that?

unkempt sedge
#

Is it expensive to replicate resources?

pine cape
#

It's the same cost as replicating a component; it depends on how the resource is serialized

split violet
#

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.

pine cape
#

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:

GitHub

A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear

GitHub

A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear

#

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.

barren condor
#

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.

pine cape
#

Try adding 2 dashes between 'launcher' and 'server'

barren condor
#

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
long marsh
#

server isn't an option/flag, it's an argument, so it needs to be passed directly

server not --server

#

@barren condor

pine cape
#

I was thinking run --package mygame-launcher --bin mygame-launcher -- server

barren condor
split violet
#

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)

pine cape
#

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
split violet
pine cape
#

server-parent, client-child, client-parent

split violet
split violet
#

Thanks for the help

split violet
#

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.

long marsh
#

may i ask why you need specialty client authoritative view direction? seems like you could get away with replicating a TripleAxislike in your inputs

split violet
#

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

long marsh
# split violet Honestly now that I'm thinking about it, that is probably a good idea. Thanks fo...

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

split violet
long marsh
#

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

split violet
long marsh
#

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

split violet
pine cape
#

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:

digital cedar
#

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?

pine cape
#

Yes, I think so. A better name would be that inserts/removes are replicated, but not updates

barren condor
#

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.

pine cape
#

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

barren condor
#

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..

pine cape
#

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

unkempt sedge
#

Does lightyear intennd on supporting something similar to bevy enhanced input:

#

holy schnutzel

pine cape
unkempt sedge
pine cape
#

Nice 🙂

inner hill
#

was this moved somewhere else? interested in seeing how you implemented this

#

nvm im silly use git like its supposed to be used lol

misty wyvern
#

using dynamic bodies instead

inner hill
#

is that working fine with rollback? I'd assume the dynamic bodies would make that much harder

misty wyvern
#

but I heard there was a bug with lightyear that would have fixed it? I cant remember, I could try again soon

barren condor
#

Is lightyear scalable for large amounts of units? Like if I want 2000 units replicated? Can I just replicate properties instead of whole components?

pine cape
#

It's not possible to replicate properties instead of whole components, but you could write a custom serialization function that only serializes those properties

pine cape
barren condor
#

similar more mount and blade style

wintry dome
#

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

#

you have to ensure your simulation is deterministic, the difficulty of which depends on what you're building

barren condor
#

ah ok thanks!

wintry dome
# unkempt sedge 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

unkempt sedge
#

Hmm nice to hear,

split violet
#

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.

Watch "Recording 2025-04-17 200911" on Streamable.

▶ Play video
unkempt sedge
#

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

pine cape
#

Tnua uses Transform or GlobalTransform internally, so you will have to replicate that instead of Position/Rotation

unkempt sedge
#

IF SO man i went through a lot of pain to making my character flaoty

pine cape
#

It probably still had rollbacks

unkempt sedge
#

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

unkempt sedge
split violet
unkempt sedge
#

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

split violet
pine cape
unkempt sedge
#

yes

pine cape
#

You would have to map it yourself using the entity_map in PredictionManager, which maps from confirmed to predicted

unkempt sedge
#

Found out early stage rollbacks cause by workspace, with not pre prediction. Can sometimes due to system ordering cause rollback loop

pine cape
#

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

wraith stag
#

@pine cape i'm not exactly sure what im supposed to put here??

unkempt sedge
#

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

pine cape
#

the examples have always been there lol

pine cape
wraith stag
pine cape
#

Of the client that is connecting to the server. You are writing a ClientConfig who is about to connect to the server

wraith stag
pine cape
#

yep that's fine. And if you have another client connecting to the same server you will have to pick a different value

wraith stag
#

sure ill just use a rng number

unkempt sedge
#

they were

pine cape
#

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

opaque wing
#

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

GitHub

Motivation Tnua's basis&action architecture works nicely, but it relies too much on Any. The performance penalty is probably negligible (and swallowed by all the physics queries and calcula...

pine cape
#

Cool! I'll answer this evening (I can't access discord at work)

unkempt sedge
unkempt sedge
pine cape
# opaque wing I'm the author of <#1173981291801223239>, and I know you all hate me because Tnu...

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"?

opaque wing
# pine cape I'm not super familiar with tnua but I wonder if you've taken a look at bevy_enh...

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.

pine cape
#

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

opaque wing
#

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.

pine cape
#

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)

unkempt sedge
#

@pine cape Sorry but i have to do this, this is a joke btw take your time

pine cape
#

aha it's ready; i'm just waiting for avian/leafwing to upgrade

wintry dome
pine cape
wintry dome
#

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?

pine cape
#

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

wintry dome
#

i'm in crate upgrade limbo at the mo too

pine cape
#

yes that's the 0.16 branch

earnest fog
pine cape
#

Yes, mostly getting the connect button to work

wintry dome
#

looks like the Pointer<Click> event fires globally but without a target entity 🤔

wintry dome
#

Interation component is updated though.. i PRed some tweaks to your branch that i used to verify that with the egui inspector

fervent karma
#

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()

wintry dome
#

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

fervent karma
#

Huh, that should work yeah 🤔 Which code is this exactly?

wintry dome
#

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..

fervent karma
#

Ah in common, that makes sense

wintry dome
#

(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

pine cape
#

Thanks!!

wintry dome
#

do you anticipate many user-facing api changes for your lots-of-crates refactor btw?

wraith stag
#

@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();```
pine cape
pine cape
pine cape
#

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.

wraith stag
#

i mean the entity does have to be spawned from server first

wraith stag
pine cape
wraith stag
#

and clients with control of their entities?

pine cape
#

The server would also be the one changing the authority

wraith stag
#

it would be cool if a client could "disown" an entity and change the owner to anyone it wanted

pine cape
wraith stag
#

some obscure engine

pine cape
# wintry dome do you anticipate many user-facing api changes for your lots-of-crates refactor ...

I have the simple-box example almost working apart from some input/prediction de-syncs:

  • Here's how you would spawn a new client
  • Here's how you would handle a new client being connected on the server side
  • Here's how you start replication for a given entity. The API is similar, but a bit different
GitHub

A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear

GitHub

A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear

pine cape
wraith stag
#

I see

#

Btw do you have protection for buffer overflows @pine cape ?

wintry dome
# pine cape I have the simple-box example almost working apart from some input/prediction de...

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

silent patrol
pine cape
pine cape
wintry dome
#

leafwing has, avian hasn't

pine cape
wintry dome
#

oh my bad, i saw 0.16 in that table

#

but confusingly that's the lwim version

silent patrol
#

Oh, indeed, my bad. I saw the Bevy 0.16 PR merged, but there's no new release yet..

#

Same with avian

pine cape
#

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

onyx salmon
#

@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 🤔

pine cape
#

Oh, sure I can remove it!

unkempt sedge
#

@pine cape hmm curious, shouldnt lightyear be independant of such dependencies now that is fully crated?

pine cape
#

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

unkempt sedge
tepid cradle
#

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?

pine cape
#

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

tepid cradle
#

OK. Will do. Thanks!

hallow widget
#

@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

pine cape
#

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_tick times.

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

hallow widget
#

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

pine cape
#

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
pine cape
#

@wintry dome if you try the new branch (bevy-main-refactor), please let me know about any feedback regarding the new API!

wintry dome
#

will do! nearly ready to readd the networking

pine cape
#

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

tropic jackal
#

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

fervent karma
#

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

tropic jackal
#

Thanks, so should everything on a headless server just run in Update in that case?

#

Sorry - FixedUpdate

fervent karma
#

Yeah it likely should

tropic jackal
#

Got it, thank you

autumn furnace
#

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

pine cape
#

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

autumn furnace
#

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

autumn furnace
#

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.)

autumn furnace
#

@pine cape is it possible to restrict the number of messages per second? Like to have the networking run on a fixed tick?

pine cape
#

Yes, that's the option called 'server_replication_interval' and 'client_replication_interval' in the SharedConfig

autumn furnace
#

sorry to necrobump.
does it actually need to? couldn't the systems which need TickConfig just use Res<Time<Fixed>> directly

pine cape
#

Yes I think that would be possible actually

autumn furnace
#

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

pine cape
#

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

autumn furnace
#

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

pine cape
#

The character controller is in FixedUpdate, right?

autumn furnace
#

I sure hope so, EDIT: yes, I was in fact in my right mind

pine cape
#

I think it should be lightyear::FixedPreUpdate::WriteClientInputs -> tnua -> physics (avian runs in FixedPostUpdate)

pine cape
#

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

wintry dome
#

(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

wintry dome
#

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

pine cape
#

Correct, I've been using RUSTFLAGS=-Awarnings and bevy-metrics-dashboard doesn't support 0.16

silent patrol
wintry dome
#

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)

pine cape
#

I just pushed a fix; the priority example works with leafwing

autumn furnace
#

How does ReplicateToServer work in HostServer mode

#

And how does ReplicateHierarchy interact with ParentSync

pine cape
#

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

wintry dome
#

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?

pine cape
#

Did you enable netcode?

wintry dome
#

nope i am using using udp

#

do i need netcode too?

#

i copied that but stripped the netcode bits for now

pine cape
#

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)
wintry dome
#

ok i'll add netcode and see if that helps

pine cape
#

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)

wintry dome
#

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)

pine cape
#

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

wintry dome
#

alright, i'll add netcode like your example

pine cape
#

but you can try triggering LinkStart instead of Start

#

and see if it works

wintry dome
#

ah yep with LinkStart it's bound to the port now

#

but i need netcode to replicate stuff anyway right?

#

for now at least

pine cape
wintry dome
#

ok, thanks

silent patrol
autumn furnace
#

it seems that ParentSync::default(), when added to an entity, detaches that entity from its Parent

#

In HostServer mode

autumn furnace
#

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

autumn furnace
#

and I haven't been able to replicate it since... inconclusive bc it's intermitant

autumn furnace
#

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?

pine cape
pine cape
#

@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

GitHub

add web_time back for wasm
small import fixes

GitHub

Bevy plugins to keep a bevy app running in the browser despite not being visible - Nul-led/bevy_web_keepalive

pine cape
pine cape
#

By the way there was a replication bug in 0.20.0, I yanked that version and released 0.20.1

autumn furnace
wintry dome
#

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

pine cape
#

Ah I think you don't need to use the derive macro anymore

wintry dome
#

ah yes it;s fine with just a bare struct now

#

can i replicate resources on the refactor branch?

pine cape
#

nope, not yet

unkempt sedge
#

ignore the offscale and the horrendou uv map

#

and the fact he lacks arms

pine cape
#

nice! is that on the latest version?

unkempt sedge
autumn furnace
#

but yes, making sure the replication components are inserted at the same time as ParentSync fixed the issue

unkempt sedge
autumn furnace
#

@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.

pine cape
unkempt sedge
#

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

pine cape
#

I think so? The entity is spawned on the 'confirmed/replicated' timeline and you need to bring to the predicted timeline using a rollback

pine cape
#

Yes usually you want to see the Interpolated or Predicted entities

unkempt sedge
pine cape
#

No, mac

autumn furnace
#

@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)

pine cape
#

Yes you can call register_trigger to replicate and trigger an event on a remote host

autumn furnace
#

is that exported anywhere? it's not on docs.rs

#

and what is the behavior if the target entity is not replicated?

pine cape
pine cape
autumn furnace
#

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.

pine cape
#

Yes it is possible to update the mapping manually. I'm out rn but will let you know later

autumn furnace
#

A few other questions.

  1. Does this automatically network the event when triggered or do I need to call client/server_trigger
  2. Is there a way to get the server to propagate triggers from client to other clients?
pine cape
autumn furnace
#

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.

autumn furnace
#

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:

  1. the entity map, which really just implements an abstraction of entities which exist in multiple worlds
  2. replicating entities, ie spawning, which kinda a special case of a networked command/event/message.
  3. 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

pine cape
autumn furnace
#

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.

pine cape
#

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

pine cape
#

@silent patrol wasm support should be fixed

silent patrol
#

awesome, thank you!

unkempt sedge
pine cape
#

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?

unkempt sedge
#

In 0.20.2 too

#

It is rare usually happens when I leave it on for a long time, no idea why

pine cape
#

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

pine cape
#

too ahead or too behind

unkempt sedge
#

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

fervent karma
#

Do you not slow down/speed up the clock to maintain synchronization?

pine cape
#

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

fervent karma
#

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?

pine cape
#

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
GitHub

A networking library to make multiplayer games for the Bevy game engine - GitHub - cBournhonesque/lightyear at bevy-main-refactor

#

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.

unkempt sedge
#

@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?

pine cape
#

Probably client specific? Unless the server needs to know about something related to the asset (collision box, etx)

mighty mason
#

Is the simple setup example outdated?

pine cape
#

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

mighty mason
#

I don't quite understand what is happening here then

mighty mason
#

this is my own version but it's identical to the one in the example so I'm so confused on what is happening

pine cape
#

You need to enable the udp feature on lightyear

unkempt sedge
#

Or is just std, like hey use this are the standard features

pine cape
#

I think i more or less fixed the sync issues!

pine cape
wintry dome
#

i have a commit fixing the run conditions, shall i pr to your refactor branch?

pine cape
#

Sure; which run conditions? I was thinking of getting rid of them now that you can have multiple clients per world

pine cape
# wintry dome where was the problem?

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

pine cape
#

ah I think they are still good to have, since most of the usecases is still client-server

wintry dome
#

just rebasing, will pr. it's only small

unkempt sedge
mighty mason
#

I don't know what the feature is called

#

oh it's just udp nvm

pine cape
autumn furnace
#

deterministic rollback is sounds like such a headache

#

i'm glad I can get away with just rubber banding, since it's coop anyway

tropic jackal
#

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?

unkempt sedge
#

Not if you define= them correctly in the protocol

#

Basically controlling how ofter those informations are trnasferred

tropic jackal
#

I was just going to add a Replicate bundle to each entity, but perhaps I'm mistaken?

unkempt sedge
#

thati s fine

#

You control it via the protocol tho

#

Not via replicate

tropic jackal
#

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

unkempt sedge
#

that book should be exterminated

#

but alas i dont make the calls here

tropic jackal
#

@pine cape But I still have to register the components to be replicated, correct?

pine cape
#

You can remove the Replicating component afterwards on the server, and the server will stop making replication attempts for these entities

#

Yes

tropic jackal
#

Got it, thanks!

tropic jackal
#

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 🙂

peak ice
#

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

pine cape
#

Hm does it work without the metrics feature?

peak ice
#

yes, it does compile without visualizer feature!

#

What is ReplicationTarget component replaced with?

#

in 0.16

pine cape
#

ReplicateToClient or ReplicateToServer

tropic jackal
#

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

pine cape
#

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

tropic jackal
#

Got it, thanks!

pine cape
#

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

tropic jackal
#

Right... most of what I want to build amounts to glorified chess 🙂

pine cape
#

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)

unkempt sedge
#

Is the final version of my default character

lyric badge
#

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

earnest fog
pine cape
#

@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?

pine cape
#

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)

digital cedar
#

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?

wraith stag
#

If this isnt co op u can switch to steam sockets

#

In lightyear

digital cedar
#

like if possible, players shud be able to just send a join id for the other player to join the game

river perch
#

in bevy 0.16, is it still best practice to use the Replicate bundle, or is there some required components alternative?

pine cape
#

You can use ReplicateToClient, which will add all other components via required components

river perch
#

I see, but I still need to add SyncTarget, ControlledBy separately, which makes sense since I need to specify values for those

pine cape
#

Yes exactly, you can add extra components to customize the replication behaviour

digital cedar
wraith stag
#

(yet)

#

(and lets face it any online game made in bevy will be p2p client-server)

pine cape
#

But if you're hosting a relay server you might as well host an authoritative server, no?

unkempt sedge
#

@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

unkempt sedge
#

If not well at least the new structure seens way easier to mantain

pine cape
#

Jondolf is working on a change to avian where it doesn't require a cache of past values, which would make it deterministic

onyx salmon
pine cape
#

Ah yes it's probably from a merge conflict! Let me edit it again

pine cape
digital cedar
tropic jackal
#

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

pine cape
tropic jackal
#

Thanks!

long marsh
pine cape
#

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

pine cape
#

Let me know if you need help upgrading it to the 'main' branch, the api is pretty different, and (hopefully) simpler

long marsh
pine cape
#

Yep, no guide yet, the best place to look at is the examples

unkempt sedge
#

my goodness for the first time I have multi dynamic collision with lightyear and it is decent

#

Today is a good day

pine cape
#

With input delay?

unkempt sedge
#

Only if latency simulating

stone osprey
#

Is there a way to replicate an immutable component, like a relation?

#

register_component requires Mutable, but I think ChildOf is replicated

pine cape
#

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

stone osprey
#

Ah, thanks

pine cape
#

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

stone osprey
#

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

pine cape
#

You should be able to access it from the prelude

stone osprey
#

Looks like it's accessible in main, but not 0.20.2

#

Not a big enough deal to move to main, though

pine cape
#

you need RelationshipSendPlugin and RelationshipReceivePlugin, HierarchySendPlugin is something else

stone osprey
#

Oh, I see. Thanks.

long marsh
long marsh
#

could ComponentReplicationOverrides impl Clone?

pine cape
#

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)

river perch
#

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

pine finch
#

Can't remember, been to long I'm afraid

river perch
#

no worries

pine cape
#

You have rebroadcast_inputs: true in your protocol?

#

And are on 0.20?

river perch
#

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

pine cape
#

Can you enable trace logs for lightyear::server::input::native (or leafwing)?

#

You should see logs for 'prepare_input_message'

river perch
#

sure, how do I enable trace logs?

pine cape
#

It does work in the avian_physics example, right?

river perch
#

yes it works in avian_physics just fine when running in host server mode

pine cape
#

Run with RUST_LOG=log_filter cargo run

#

RUST_LOG=Lightyear::server::input::native=trace

river perch
#

when I run the host server with that, it doesn't produce any extra logs

pine cape
#

You might be missing quotes after rust_log

#

Try with just lightyear::server::input

river perch
#

i got it, it was capital L that was the problem

pine cape
#

Maybe you don't have enough input_delay, so the input messages you are sending arrive too late on the client

river perch
#

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: []
river perch
#

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

pine cape
#

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

river perch
#

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

pine cape
#

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)

river perch
#

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

unkempt sedge
pine cape
#

It's just a counter of fixed update ticks

river perch
#

What ChannelMode is recommended for physics based games? I see that every example uses OrderedReliable. Is that required for something like an FPS?

pine cape
#

It depends on the data you want to send

#

Replication data is using Sequenced Unreliable, for example

river perch
#

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?

pine cape
#

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

river perch
#

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)

pine cape
#

Adding a component as both Input and Component in the protocol will cause issues

river perch
#

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

pine cape
#

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?

river perch
#

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

pine cape
#

If it's not reliable, then it's weird, yea

river perch
#

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

pine cape
#

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
river perch
#

Thanks, I will probably try interpolation tomorrow when I have more time to work on it. Appreciate all the help

unkempt sedge
pine cape
#

I need to add docs. Also host server mode and sending messages from a client to other clients is not currently supported

unkempt sedge
pine cape
#

I guess, I mean it's just a few lines

unkempt sedge
pine cape
#

I prefer the current organization

tropic jackal
#

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.

tropic jackal
#

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?

tropic jackal
#

Got it working after adding all of them to a ReplicationGroup 🙂

feral mirage
#

@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?

pine cape
#

I might release an alpha or rc version soon

feral mirage
#

nice

pine cape
feral mirage
#

hmm

#

can you tell with a quick glance what i'm missing? the entity already gets replicated, but the relationship uses the server ids

pine cape
#

You need to add .add_map_entities to the protocol

#

And make sure the entities are in the same ReplicationGroup

feral mirage
#

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

feral mirage
#

@pine cape Cargo.toml on main is using version = 0.19, shouldn't it be 0.21?

pine cape
#

Yep, I'll it when cutting a new release

pine cape
hot cloud
#

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!

feral mirage
#

any possibility of register_component working with immutable components?

pine cape
pine cape
# hot cloud Hello. Quickly to start, thank you for this incredible crate. I was quickly try...

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

hot cloud
hot cloud
#

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?

pine cape
#

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'

hot cloud
# pine cape Yes there are some Diagnostics that contain the overall bandwidth. Or if you ena...

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")]
   |       ^^^^^^^^^^^^^^^^^^^^^
pine cape
#

ah there must be some incompatibility with the latest egui version... maybe stick to diagnostics for now

pine cape
hot cloud
pure drum
#

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>?

pine cape
#

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>

pure drum
unkempt sedge
#

@pine cape I made some crates that are friendly to the lightyear work environment would you like to give me your opinion oin them ?

pine cape
#

Sure!

unkempt sedge
#

Question how can i not replicate child entities?

unkempt sedge
unkempt sedge
pine cape
#

I don't, but there is a function in the component registry to register a custom rollback evaluation fn

autumn furnace
#

looking at the current lightyear main.
I like the switch to client/server being an entity.

autumn furnace
#

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.

autumn furnace
#

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 ?

#
  1. 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.
feral mirage
#

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?

pine cape
#

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)

onyx salmon
pine cape
#

Even this?

#

#1297361733886677036 message

onyx salmon
pine cape
#

Oh I see

spice rapids
#

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?

pine cape
pine cape
pine cape
pine cape
pine cape
# spice rapids Hi <@263123021336805376> , first off thank you for the awesome crate. I am just ...

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

GitHub

A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear

GitHub

A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear

spice rapids
#

I think tutorial also links to the book which was what I originally clicked on

feral mirage
#

Would it make sense back porting the register_component for immutable components for 0.20, or is 0.21 just around the corner?

pine cape
#

I'll publish a 0.21-rc1 this weekend

woven mortar
pine cape
pine cape
pure drum
#

any changelog/migration/etc available yet/in progress? (i couldnt find any)

worthy rapids
#

Does lightyear support syncing a subapp world instead of the main apps world?

pine cape
pine cape
woven mortar
feral mirage
pine cape
#

I believe it was added to crates.io, do you not find it ther

unkempt sedge
#

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

pine cape
#

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)

feral mirage
unkempt sedge
autumn furnace
#

whats the state of websockets.

#

example common has an option for it in the client/server Transport enum, but nothing matches on it

pine cape
#

It's not added in the latest rc release. Adding it would be very similar to WebTransport, and would involve delegating to aeronet

autumn furnace
#

I'll just try webtransport

autumn furnace
#

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

pine cape
#

HostServer is still relevant, but hasn't been ported to the refactor yet

autumn furnace
#

What is the difference, from light-years pov between host server and regular server

pine cape
#

Yep, will answer layer when I'm on a laptop

autumn furnace
#

another question is whether the link conditioner can be used on the server, examples don't attach a Link to the server

pure drum
autumn furnace
#

seems I have to insert it into the LinkReceiver on the spawned clients.

pine cape
# autumn furnace for example, I do need a both a headless server and client-hostserver mode for m...

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
pine cape
autumn furnace
#

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?

pine cape
pine cape
autumn furnace
#

I'll just comment something out somewhere then

pine cape
#

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

autumn furnace
#

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

pine cape
#

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

autumn furnace
#

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

autumn furnace
#

but then, avoiding logic running twice might be pain.

pine cape
#

Yep, you need a run condition to avoid systems from running twice

autumn furnace
#

yeah, in process headless server feels like the way to go. (hmm.. but then I'd be doubling the physics compute :/)

pine cape
#

I think what you describe should be possible, did you see the authority example in the 0.20 branch?

autumn furnace
#

I looked at it a bit

#

is webtransport working in main

#

trigger(Start) doesn't seem to do anything

pine cape
#

Yes, the examples work with webtransport

autumn furnace
#

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

unique plover
pine cape
#

Yes

feral mirage
#

is there a way to rewrite this without it being a command?

app.world_mut()
    .commands()
    .replicate_resource::<MyRes, CommonChannel>(NetworkTarget::All);
pine cape
#

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

fervent karma
#

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

pine cape
#

Thanks, will take a look

autumn furnace
#

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

autumn furnace
#

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

pine cape
pine cape
#

Are you using crates individually instead of using the wrapper lightyear crate?

autumn furnace
#

No I'm using the wrapper

pine cape
#

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 of remove::<Server> in the codebase, so I really don't know why this is happening
GitHub

Separate Connected from LocalId/RemoteId
We want to do this separation to:

make Link less coupled with the notion of a SocketAddr
be more similat to what aeronet does
be able to access the LocalId...

#

Nvm looks like this is also happening in main ..

autumn furnace
#

I have two usecases that require me to deal with entity mapping:

  1. I need to load a gltf scene on server+clients and have certain children be replicated (ex. items you can pick up)
  2. 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

pine cape
#

Usually by the receiver

#

But it can be done by both, so you won't have any issues

autumn furnace
#

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)

pine cape
#

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

autumn furnace
#

can I manually adjust that mapping (ie. the default one for replication)

autumn furnace
#

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)

pine cape
autumn furnace
#

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

autumn furnace
pine cape
#

yes

autumn furnace
pine cape
#

Yes PreSpawn has another meaning that is more closely tied to prediction

autumn furnace
#

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

pine cape
#

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?
autumn furnace
#

yeah, basically

#

and my solution is a Uid component, which you just make sure is the same for entities you want mapped

pine cape
#

ah I see, that Uid component uniquely identifies the entity within the scene?

autumn furnace
#

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

pine cape
#

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

autumn furnace
#

I have had the thought before that maybe networking should be it's own world / subapp

#

then interpolation works like extraction

pine cape
#

PreSpawn seems fairly similar to what you describe, but just in the context of prediction

#

maybe I should that capability for replication as well

autumn furnace
#

I was looking into replicon 6 months ago, and it also doen't have anything built in for this

pine cape
#

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?

autumn furnace
#

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

pine cape
#

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.

autumn furnace
#

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

pine cape
#

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

GitHub

A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear

autumn furnace
#

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

pine cape
#

for that you would need some changes in lightyear, no?

autumn furnace
#

I think I can just write some observers around Uid+Replicate which update the mapping

pine cape
#

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

autumn furnace
#

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?

pine cape
#

No, authority is on entity-level currently

stone osprey
#

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?

pine cape
#

Possibly; is the Wait component registered in the protocol? This is lightyear main or 0.20?

stone osprey
pine cape
#

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

stone osprey
#

So it sounds like that's it! Thanks!

pine cape
#

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

stone osprey
#

Is it painful?
Yeah haha

#

The changes seem good, though

pine cape
#

yes hopefully it's for the better haha

pine cape
#

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

pure drum
#

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?

#

i suspect it's avian sync to transform, but haven't quite worked out the ordering

pine cape
#

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