#lightyear

1 messages · Page 13 of 1

pine cape
#

I'm wondering why you're running into all these issues where they didn't happen before for host-client examples. Do you have a code example?

earnest fog
#

I only have issues with host-client mode in that example. All the other examples and modes work fine

unkempt sedge
#

@pine cape This ack message is a little too loud, I think it is triggering everytime a packet becomes too chonki

pine cape
#

This is fixed in main

unkempt sedge
feral mirage
#

the fact that Confirmed can be added after some components is a bit annoying, gotta study a way to make the ordering of the components being added a bit more strict, maybe do something like this when receiving a replication message

commands.spawn((Confirmed, <other lightyyear control components>)).insert((<replicated components>));
#
(
  Without<Confirmed>,
  Without<ShouldBePredicted>,
  Without<ShouldBeInterpolated>,
)

this works now

earnest fog
tranquil granite
#

Hi, im trying to replicate my clients input on the server.

this is my protocol enum

#[protocol(
Event = "MyEvent",
Input = "PlayerInput",
Component = "MyComponent",
Message = "MyMessage"
)]
pub enum MyProtocol {
// Input messages
#[message(Instant)]
PlayerInput(PlayerInput),

// Replicated components
#[component(Sync)]
Player(Player),
#[component(Sync)]
Transform(Transform),

#[message(Channel = "Channel1")]
Message1(Message1),

}

But the compiler cant find the macros in any crate.
Is this the right way to do it?

feral mirage
#

i've never seen those attributes

tranquil granite
#

yeah I looked through the repo and I couldnt find them either. Full disclosure I got them from Gemini...
I've been trying to get it done for a few days...

pine cape
#

This is from a very old version of lightyear, I would advise you to use the latest version and check the tutorial

pine cape
#

@earnest fog I think i'll revert this commit: https://github.com/cBournhonesque/lightyear/pull/1135
I'm a bit hesitant of masking errors like this if it can be avoided.
In practice, we don't need to add the ChecksumSend plugin on the HostClient since the app is also a server, so what i'll do instead is not add the ChecksumSend plugin if the server feature is enabled. It's not a perfect solution since it means that non-host client will have to run with the server feature disabled, but then no changes are required on the registry

GitHub

Ignore duplicate registered messages. Problematic for host-client mode.
Follow up to #1130

#

The deterministic-replication example now runs in host-client mode

#

Interestingly, inputs from the host-client work fine, but inputs from the remote client cause a checksum mismatch

#

which points to a bug as to how inputs are handled for host-client mode

#

Probably something with input-delay, or with the delay-buffer

#

I don't have the bandwidth to debug this now, but i'll open an issue

earnest fog
#

I can look into over the next few days. Thanks for getting the example working again

pine cape
#

thanks; might be hard to debug though :p
I guess the first step would be to print the input buffer at every tick and see where is the mismatch

amber oracle
#

Hey,

thanks for all of the work already put into this crate!

I am wondering if there is already a way to get notified about a certain component replication update using observers.

Something similar like Trigger<OnReplicated, COMPONENT>

pine cape
#

I would use OnAdd<C> and add a With<Replicated> filter

old skiff
#

Is there a minimal example for using this crate? I tried copying the simple box example to a standalone project but it has so many dependencies that it feels like too much work trying to get it to work.

pine cape
#

The simple_setup example

old skiff
#

I guess this has already been asked before but why is the client receiving packets so long after the server on a local connection? It looks like a few hundred ms. The server doesn't have any noticeable lag.

amber oracle
pine cape
pine cape
earnest fog
# pine cape <@272616132505108480> I think i'll revert this commit: https://github.com/cBourn...

I've been thinking about the message registration and new limitation with host-client mode. I've got 2 ideas:

  1. Add a check to the ChecksumReceivePlugin to check if ChecksumSendPlugin is already registered. If true, don't register the ChecksumMessage again.
  2. Add a new ChecksumPlugin that does the ChecksumMessage registration and does the hacky is_unique Plugin workaround to make sure it's not run twice.
    Thoughts?
pine cape
#

I think 2. works; but what about just having a if !register.is_registered::<M>() { register }

earnest fog
#

Good point. That should work as well

#

Probably more obvious what that one means

amber oracle
old skiff
pine cape
molten dagger
#

How do i add an InputBuffer to my character? The component isnt automatically added, but the examples uses it without doing any setup, so how do i add it? (leafwing input)

pine cape
#

Everything is added for you when you add an InputMap component on the entity you want to control

molten dagger
#

my character contains an InputMap, but doesn't have an InputBuffer

#

InputPlugin is added on both the server and client

pine cape
#

I see InputBuffer in your screenshot

peak ice
#

In regards to: https://github.com/cBournhonesque/lightyear/issues/1124
steam and crossbeam do not work together right now. I'm thinking I like option 1 for now, if you point me in the right direction I can try to make a pullrequest this weekend

GitHub

Incase this is not intended, currently, to get a Steam connection to work for ConnectTarget::Peer, you must also add a RemoteId component to the client entity; otherwise, you will experience crashe...

pine cape
#

Hm actually no because we still want Netcode to be enabled for non-steam clients.

#

Yeah i think option 1 (one server entity that has multiple ServerIo components is probably easier)

peak ice
#

Ok we got it working, sent a pr last night!

#

So I’m at the point where I need to debug latency issues. Over steam I get about 60 ms of latency and the rollbacks are crazy. Adding a conditioner with 60 ms of latency does not replicate these rollbacks over udp

pine cape
#

what is your real latency? you can get it with debug logs in lightyear_sync i believe

#

or by adding the diagnostics

peak ice
#

It is “lightyear_sync=debug” or lightyear::sync?

pine cape
#

lightyear_sync=debug

peak ice
#

its telling me a delta of -12 ticks, no latency print out

#

ill try diagnostics feature

#

although I am getting a lot of printouts saying rollbacks over 200 ticks

pine cape
#

You can also add

    #[cfg(feature = "visualizer")]
    {
        app.add_plugins(bevy_metrics_dashboard::RegistryPlugin::default());
        app.add_plugins(bevy_metrics_dashboard::DashboardPlugin);
        app.add_systems(Startup, |mut commands: Commands| {
            commands.spawn(bevy_metrics_dashboard::DashboardWindow::new("Metrics"));
        });
    }

and enable the metrics feature of lightyear

#

to add the metrics dashboard

peak ice
#

ooh, where in the namespace is latency?

pine cape
#

ah is it not there? damn

peak ice
#

so i held move_left and the let it go

pine cape
#

Looks like it says 60ms still; are you using steam locally?

peak ice
#

yeah its between my mac and windows computer, one is on wifi.

#

wouldn't steam connections always not be local because they use a server to get past port forwarding?

pine cape
#

Probably; 60ms is pretty low and shouldn't cause any issues.
You're doing something similar to simple_box? state-replication with prediction?
You disabled the link conditioner?

earnest fog
autumn furnace
#

I'm playing with messages and I've got it going host-client -> client but not the other way around. It's registered bidirectionally.

#

Do I need to do something in the on_new_client handler. I thought may I have to manually add MessageReciever<MyMessage> to the Connected but I don't see that in the examples.
Actually it seems to be auto added. I'm guessing its a logic error in my code.

autumn furnace
#

actually it seems it's something about how host-client works.

#
        pub(crate) fn receive(
            mut receiver: Query<
                &mut lightyear::prelude::MessageReceiver<InteractionMessage>,
                With<Client>,
            >,
            mut commands: Commands,
        ) {
            for message in receiver.single_mut().unwrap().receive() {
                // THIS does not
                info!("Client received message: {:?}", message);
                ...
            }
        }

        app.add_systems(
            Update,
            receive
                .in_set(lightyear::prelude::MessageSet::Receive)
        );

        pub(crate) fn server_receive_and_send(
            receiver: Query<(
                &mut lightyear::prelude::RemoteId,
                &mut lightyear::prelude::MessageReceiver<InteractionMessage>,
            )>,
            mut sender: ServerMultiMessageSender,
            server: Single<&lightyear::prelude::Server>,
        ) -> Result {
            for (remote_id, mut receiver) in receiver {
                for message in receiver.receive() {
                    // THIS runs
                    info!("Server received message: {:?}", message);

                    // I expect this to send to the local client (when remote id is remote client)
                    sender.send::<_, ActionsChannel>(
                        &message,
                        &*server,
                        &NetworkTarget::AllExceptSingle(remote_id.0),
                    )?;
                }
            }

            Ok(())
        }

        app.add_systems(
            Update,
            server_receive_and_send
                .in_set(lightyear::prelude::MessageSet::Receive)
                .run_if(is_server),
        );
#

client sends a message to host-client, and it is recieved by server_receive_and_send but the resend there is not received by the local client.

#

expected?

pine cape
#

Let's say you have HC (host-client) and C (remote client).
You're saying that C sends a message to the server; then the server sends a message to all clients (HC and C), but HC doesn't receive it?

autumn furnace
#

okay, I will look at that and dig deeper

pine cape
#

I notice that in my test i'm using

            sender
                .send::<_, Channel1>(&send_message_clone, unsafe {
                    UniqueEntityArray::from_array_unchecked([client_of_0, host_client])
                })
                .ok();
#

it's possible that there's a bug when using NetworkTarget

#

Can you confirm that your HC has a MessageManager and Transport components?

#

hm you're right I think there is a bug

autumn furnace
#

and MessageReceiver<InteractionMessage>

autumn furnace
#

Oh, I was meaning to ask about reconnects also. client reconnect results in this on server side for me
2025-08-04T03:31:37.911313Z WARN lightyear_netcode::error: Netcode error: Packet(TokenExpired)

pine cape
pine cape
#

I have a server_app with a HostClient entity + a ClientOf entity (remote client).
I send a message from the server to both of them using the ServerMultiMessageSender, and both clients receive it.

#

Hm one thing that is different is that you send the messages in Update, i do outside of the app updating

#

that could cause an issue

autumn furnace
#

hmm my debugger does not understand how to show Entity

#

so I'm recompiling with some dbgs in send_with_priority to see what its doing

pine cape
#

no, still works if i send in Update

#

basically it's suboptimal, but we serialize the bytes and buffer them in the Transport of the host-client entity in MultiMessageSender::send
and then in Plugin::recv, we deserialize the bytes and insert them into the MessageReceiver of the host-client entity

autumn furnace
#

I don't get that log

pine cape
#

You should try to confirm that the message is being written to the Transport by the ServerMultiMessageSender

autumn furnace
#

This line runs, and sender= entity id of the Client

#

could it be that I'm using the ActionsChannel?

autumn furnace
#

looks like I missed this

#

and that fixes it

#

🎉

#
2025-08-04T04:54:35.970400Z TRACE lightyear_messages::receive: Received message "lightyear_sync::ping::message::Ping" on channel ChannelKind(TypeId(0xe2e202f912727d2cda9e6c573a3cc731))
2025-08-04T04:54:35.970406Z TRACE lightyear_messages::receive: Received message (id:None) from peer Netcode(17434101101550735348) on channel ChannelKind(TypeId(0xe2e202f912727d2cda9e6c573a3cc731)). 364v1#4294967660
2025-08-04T04:54:35.970411Z TRACE lightyear_messages::receive: Received message "lightyear_sync::ping::message::Pong" on channel ChannelKind(TypeId(0xe2e202f912727d2cda9e6c573a3cc731))
2025-08-04T04:54:35.970414Z TRACE lightyear_messages::receive: Received message (id:None) from peer Netcode(17434101101550735348) on channel ChannelKind(TypeId(0xa47bc931a4d47c60a39abfa8be5b5093)). 364v1#4294967660
#

I am curious what the id: None message is, and whether it's possible to reduce the rate of ping and pong.

#

setting keepalive_packet_send_rate: 1 doesn't seem to reduce freq, I am assuming that's a different layer.

autumn furnace
autumn furnace
#
thread 'tokio-runtime-worker' panicked at /home/user/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/wtransport-0.6.1/src/error.rs:122:18:
QUIC connection is still alive on close-cast
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
2025-08-04T05:22:49.351476Z  INFO lightyear_netcode::client: client connecting to server 127.0.0.1:42217 [1/1]
2025-08-04T05:22:49.351501Z  WARN lightyear_webtransport::client: Connecting with no certificate validation
2025-08-04T05:22:53.697418Z ERROR lightyear_netcode::client: client ignored packet: invalid packet: sequence 4611686018427387905 already received
... (^^repeats ~100 times)
2025-08-04T05:22:54.918083Z ERROR lightyear_netcode::client: client ignored packet: invalid packet: sequence 4611686018427388014 already received
2025-08-04T05:22:54.934796Z  INFO lightyear_netcode::client_plugin: Client Netcode(1885806082525081831) connected
2025-08-04T05:23:19.926165Z ERROR lightyear_netcode::client: client ignored packet: invalid packet: sequence 4611686018427388271 already received
#

another reconnect issue is I get this on client when the server is killed+restarted and client reconnects

pine cape
pine cape
pine cape
autumn furnace
#

it has to get through a lot of those invalid packet messages

#

the amount of them seems related to how long the server was down for

#

and so sometimes it just keeps printing that error, on the order of 10 times per second, sometimes for a long time

marble wyvern
#

Are there any actual simple self-contained examples for lightyear?
All the examples in the github repository use lightyear_examples_common

autumn furnace
#

No, I've wanted that before as well

#

I wonder if some stuff from lightyear_examples_common could be moved into a lightyear crate for general use.

marble wyvern
#

probably

#

it contains fully set up servers and clients that seem reusable

marble wyvern
pine cape
marble wyvern
#

shows the missing parts

marble wyvern
#

i am following the examples and the input buffering does not work
the if let block does't run, when unwrapping the error it claims there are no entities

#

i have registered the type and plugin and i am running it in the correct system

#

is there something i've forgotten?

pine cape
#

You have add an InputMarker component to your predicted entitu

marble wyvern
#

is a predicted entity needed to send input to the server?

#

inserting it into the server entity does nothing

#

the movement method now logs movement but still does not receive input

marble wyvern
#

ive tried to add prediction and interpolation and the entities dont appear
and the red square is still visible, so it seems to not have the Confirmed component

the Added predicition info is displayed but the if let block is not ran

pine cape
#

You're inserting InputMarker on the server, but you need to insert it on entities that are on the client app

#

Basically the client needs to know among all replicated client entities, which one is the only they control

pine cape
marble wyvern
marble wyvern
pine cape
#

Looks like your movement system is not actually modifying the position?

marble wyvern
#

im surprised it showed no errors

feral mirage
#

@pine cape i added .add_map_entities to a trigger, but using both the Entity of the predicted and confirmed entities fail

#

on the server the Entity is still the client Entity

#

fixed

#

missed #[entities] on the MapEntities derive

peak ice
#

its a little more complex than a simple example, and I wrote it so the code smells bad, but its self contained

marble wyvern
feral mirage
#

@pine cape moving ChannelSettings and ChannelMode to lightyear_core possible?

feral mirage
#

more like, does it make sense?

pine cape
#

What would be the reason? I'd prefer to keep it in lightyear_transport unless there's a good reason

dusk adder
#

@pine cape is it possible to change the InterpolationConfig externally?

I saw you have a TODO to move it to InterpolationManager but I'm struggling to find a way to set it

pine cape
#

Hm you could disable the interpolation feature from lightyear, and the InterpolationPlugin directly from lightyear_interpolation
but yeah i think the correct solution is to move the InterpolationConfig to the InterpolationManager

#

hm looking at the code; it looks like there's multiple InterpolationConfigs?

#

One thing you could is simply update the InterpolationConfig in the InterpolationTimeline component before you connect the client.

fn set_config(timeline: Single<&mut InterpolationTimeline>) {
    timeline.interpolation_config = ...
}
dusk forum
#

Anyone figured out how to do replication with the new BEI api yet? ive been putting off having a crack at it because the only idea ive got is to replicate the actual action entities.

pine cape
#

I tried to implement with that approach (spawning the Action entities on the server when they receive an InputMessage component) but i've had trouble making it fit into my shared lightyear_inputs framework that abstracts over BEI, leafwing and native

#

primarily because the new BEI uses 4 components instead of 1 to represent the ActionState

peak ice
#

Anyone know how to get your bandwidth usage to show up in the lightyear egui metrics panel?

#

Also has anyone done any live tests with 5+ people yet?

pine cape
unkempt sedge
#

@pine cape Hey sorry to bother u nice to see you again mr peri, anyways i am doing lag compensation for my player entity, an entity that is predicted on it is client and interpolated on other. WIll lagcompensation history work normally in that scenario? Just curious

pine cape
peak ice
pine cape
#

yep, everything worked 🙂

unkempt sedge
pine cape
marble wyvern
#

How should i despawn an interpolated (non player) entity?

#

without this

unkempt sedge
#

@pine cape Removed vscode file and made it gitignore future ones (if that is okay by you), btw would you mind releasing a new version. This fix is kinda really important for me.

pine cape
#

I need to wait for a new release of bevy-enhanced-input since i want the next lightyear release to be compatible with it. In the meantime you can just use the main branch of lightyear, no?

#

@dusk forum I got the latest BEI working, will release a new version once BEI publish a new version with a couple necessary changes

pine cape
# marble wyvern without this

It looks like you are despawning an Interpolated entity that doesn't have a corresponding Confirmed entity with a Replicated component; is that intended?

marble wyvern
unkempt sedge
pine cape
peak ice
#

So i am randomly getting these errors

thread 'Compute Task Pool (15)' panicked at C:\Users\Elizabeth\.cargo\git\checkouts\lightyear-16a1ca81dacb5ed5\2711a08\lightyear_inputs\src\input_buffer.rs:153:37:
attempt to subtract with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `lightyear_inputs::server::receive_input_message<lightyear_inputs_leafwing::input_message::LeafwingSequence<bevy_code_gnome::networking::protocol::PlayerActions>>`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!

Do you think its something I did in my code or should we check the subract here?

pine cape
peak ice
#

Also started getting this with steam:

2025-08-11T03:56:02.049649Z  WARN aeronet_io::packet: 17854v3 has 1 received packets which have not been consumed - this indicates a bug in code above the IO layer

unkempt sedge
#

@pine cape Mr Peri my game is reaching the point where well, we are getting oom issues. Of course I can try to diminish the main offenders, but I think is about time we deploy a server. Any ideas on cheap ways to do so?

dusk adder
feral rock
feral rock
dusk adder
#

that's fair, depends on the workload for a demo it's not very expensive to pay 3$/m for a shared 2cpu which in my case could handle multiple dozens of users

unkempt sedge
#

Perhaps i can use them

pine cape
#

There are plenty of providers that give you 1month of free credit (kamatera, digital ocean, hertzner, etc.) That's usually what I do

peak ice
#

Might be a setup issue, might be the 3 ms latency causing the problem

pine cape
#

Are you using the latest version? I think it's because some filters are missing in the crossbar systems so some packets intended for steam are getting stolen by crossbeam

peak ice
#

yeah its the latest version, so you think crossbeamIO needs it's own "this is a crossbeamIO link" component?

#

it seems like crossbeam has that already, every function is filtered by CrossbeamIO

peak ice
#

ohh this error is from aeronet not lightyear, i see

17854v1 has 1 received packets which have not been consumed - this indicates a bug in code above the IO layer
peak ice
#

ok this is crazy, steam works when I use my gui-server, and does not work when I use my no gui server

#

these errors started showing up when I rewrote stuff to run servers without bevy_render

pine cape
#

It's because without gui the frame rate is super high

#

So you're sending more packets and there's a higher chance of the error appearing

earnest fog
dusk forum
dusk adder
# dusk forum ive been toying around with the idea of implementing a version of dynamic server...

I've been generally happy with it. I hosted some web services with them for a while now and I've had no issues. As for lightyear, I've only been toying with the library for the past week and wanted to test something hosted and it's just so easy to have this deployed in seconds so that's mainly why I used them. As someone else said before they can be expensive so for scaling or doing more advanced stuff prob look if this is a dealbreaker & they have a note about MTUs which I'm really not sure if this is even relevant for lightyear but useful to be mindful of I guess?

Fly

Documentation and guides from the team at Fly.io.

peak ice
dusk forum
pine cape
#

Also does this happen when clients are connected? or around connection/disconnection?

pine cape
peak ice
pure drum
#

@peak ice long shot, but i had the same error. I dont know why this fixed it for me ☝️ i havent seen that error since.. very strange bug at least the way i was triggering it

peak ice
pure drum
#

it started with observers with inputs for me.. maybe not related then?

pine cape
#

enchanted 😂 can you please open an issue so we don't lose track of this?

peak ice
#

lol

peak ice
pine cape
#

#crates message

silent patrol
#

What's the modern alternative for DisabledComponents? Can't find it in the vew versions

#

Actually, I even need the opposite. I have the following config:

.with_replication_config(ComponentReplicationConfig {
                disable: true,
                ..default()
            });

and I want to be able to enable replication for a specific component per entity. Is it possible in the latest lightyear version?

#

ah, I think I found it: ComponentReplicationOverrides

pine cape
#

Yep that's it!

autumn furnace
#

is it possible in theory to reuse the web-transport connection for another stream.

#

and could that stream be accessed in realtime (outside the main bevy loop)

#

I am thinking about how to implement voice chat.

#

my intution is that 1 is possible (but perhaps not in a way lightyear exposes), and that 2 is harder

pine cape
#

What do you mean by stream? A quic stream?

autumn furnace
#

yes

pine cape
molten dagger
#

How do i manually update an ActionState and have it replicate that change?

#

When i try to manually update an axis value, it gets reset to 0

pine cape
#

Did you make the change in the correct system set? I think it's something like ClientInputs::WriteInputs

molten dagger
#

Ok i tried adding it to the InputSet::WriteClientInputs systemset, same issue
It says the user should emit InputEvents, but i cant seem to find such a thing in the docs?

#

(sorry, also forgot to mention, using leafwing)

pine cape
#

This example uses leafwing and manually updates the ActionState

molten dagger
#

Hmm, seems like it only works in Fixed(Pre)Update
Is it possible to do in the Update schedule?

#

It's for an orbit cam, so yeah this is required for my use case

#

(Or should i maybe send these updates to be applied in a FixedUpdate system?)

pine cape
#

I'm not on a laptop right now, but AFAIK this won't be possible. Leafwing updates the action-state in PreUpdate, and lightyear populates the InputBuffer in FixedUpdate. The message is then sent in PostUpdate.

You could manually update the buffer in Update, but that seems dangerous.

What is your usecase exactly? You want the server to have a replicated cam of the client's POV?

#

Yeah I would just apply the updates in FixedUpdate (for replication), and then also do the updates in Update (so that the camera is smooth on the client)

molten dagger
#

I'm just trying to rotate the character whenever the orbit camera's yaw changes

pine cape
#

Yea I would do that in fixedupdate

earnest fog
#

@pine cape why is a Predicted entity a requirement for BEI? I was hoping to use BEI with deterministic replication but because the entities aren't predicted, the ActionWraper/InputMarkers aren't setup on the replicated clients

pine cape
#

It's not a requirement; that's Option<Predicted>

#

But yeah i might have to also handle DeterministicPredicted and PrePredicted

#

haven't had the opportunity to test all situations

earnest fog
#

Oh I see. Hmm, for some reason this isn't firing

#

I'll dig in some more. Thanks

pine cape
#

probably you didn't have a ReplicationSender on your client, and ReplicationReceiver on your server

#

that's unfortunately required if using the new BEI

#

since the client needs to replicate the Actions entities to the server

#

I think you can also just spawn the Actions entities on the server and replicate them to the client, if you want to avoid that

earnest fog
#

I have a ReplicationSender and ReplicationReceiver on both the client and the server and I'm replicating the input component. For some reason the client doesn't get the input setup

earnest fog
#

So the setup is working right (it was how I was spawning the local players) but the input doesn't seem to be mapped to the local entities. Still trying to figure out where that mapping happens

pine cape
#

The context entity is spawned on the server and replicated to the client?

peak ice
#

So right now I'm trying to get projectiles to not be networked once the server replicates the projectile to the client, so on the server I use ComponentReplicationOverrides to set replication once to true, and on the client I add DeterministicPredicted and DisableRollbacks. This seems to work but there is this bug where when you fire a projectile all other projectiles jump forward a little bit, its not bad in this video but can get worst with real time connections. Anyone have any thoughts on what is causing it?

feral rock
#

Is websocket gone?

peak ice
#

I'm sure it's still there!

peak ice
pine cape
pine cape
# peak ice So right now I'm trying to get projectiles to not be networked once the server r...

The reason is because you added DisableRollbacks. This completely excludes the projectiles from rollback, so whenever you have a rollback, the projectiles keep moving forward during the rollback frame.
When you replicate a projectile it triggers a rollback so your other projectiles move forward.

You can:

  • use projectiles pre-spawning so that no rollback is triggered for new projectiles
  • remove DisableRollbacks on spawned projectiles
feral rock
unkempt sedge
#

@pine cape Question, what causes this? It seens lightyear is trying to map child entities when I have the component disable replicate hierarchy

pine cape
pine cape
# pine cape The reason is because you added DisableRollbacks. This completely excludes the p...

In general it's annoying that you would need to still do rollbacks for projectiles after they were replicated. Ideally they could be completely excluded from rollbacks, meaning that their systems don't run during the RollbackSchedule.
I think there are several ways to do this:

  • find a way to only run systems for Predicted entities during rollback. Maybe a separate World that only holds predicted entities?
  • maybe a disabled marker on entities that we don't want to rollback. We would add the marker before the Rollback schedule runs, and remove it afterwards
pine cape
unkempt sedge
peak ice
pine cape
peak ice
#

but when you rerun the entire FixedUpdate set for rollbacks don't all entities experience it?

pine cape
# peak ice but when you rerun the entire FixedUpdate set for rollbacks don't all entities e...
  • DeterministicPredicted: we don't check for rollbacks on that entity
  • DisableRollback: we don't rollback to the previous confirmed state, but the entity will still be affected by re-running FixedUpdate
    What we're missing is a way to have entities be completely ignored during rollback, so that in your case your projectiles wouldn't need to get rolled back at all, and wouldn't advance during rollbacks.

You can still achieve this by only having DeterministicPredicted, but it's more expensive

peak ice
#

so something in the DeterministicPredicted is deleted the physics of my projectiles

unkempt sedge
#

We used to do it via ActionMock but it seens that does not get replicated anymore

pine cape
pine cape
unkempt sedge
#

I will try to make a reproducible example

fn buffer_rotation(
    q_camera: Query<(&Transform, &CameraMode)>,
    mut players: Query<Entity, With<Action<RotateInput>>>,
    mut commands: Commands,
) {
    let (transform, camera_mode) = q_camera.single().expect("Camera to have a transform");
    // Only do this if in tps mode
    if camera_mode.ne(&CameraMode::Tps) {
        return;
    }

    let (yaw, pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
    for player in players.iter_mut() {
        // This creates a pseudo-action, that continouslys gets fired every state
        let action_mock =
            ActionMock::new(ActionState::Fired, Vec2::new(yaw, pitch), MockSpan::Manual);
        commands.entity(player).insert(action_mock);
    }
}```
#
app.add_systems(
            FixedPreUpdate,
            buffer_rotation
                .before(InputSet::BufferClientInputs)
                .after(EnhancedInputSet::Update),
        );```
#

perhaps i need to change the context entity?

pine cape
#

Try to enable debug or trace lightyear_inputs::client=debug logs and check if the InputBuffers gets updated with the values you expect

unkempt sedge
#

2025-08-17T14:23:23.270473Z DEBUG lightyear_inputs::client: sending input message for "psycho_core::player::PlayerInputs": InputMessage { interpolation_delay: None, end_tick: Tick(2544), inputs: [PerTargetData { target: ActionEntity(272v4#17179869456), states: BEIStateSequence { states: [Input(ActionsMessage { state: None, value: Axis2D(Vec2(0.0, 0.0)), time: ActionTime { elapsed_secs: 0.0, fired_secs: 0.0 }, events: ActionEvents(0) }), SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent] } }, PerTargetData { target: ActionEntity(371v2#8589934963), states: BEIStateSequence { states: [Input(ActionsMessage { state: None, value: Bool(false), time: ActionTime { elapsed_secs: 0.0, fired_secs: 0.0 }

#

Are thos the buffered entities?

pine cape
#

Basically you keep sending

{ state: None, value: Axis2D(Vec2(0.0, 0.0)), time: ActionTime { elapsed_secs: 0.0, fired_secs: 0.0 }, events: ActionEvents(0) }
unkempt sedge
#

@pine cape 2025-08-17T14:33:26.960139Z TRACE bevy_enhanced_input::context: updating psycho_core::player::RotateInput from Mut(ActionMock { state: Fired, value: Axis2D(Vec2(1.0209994, -0.31257823)), span: Manual, enabled: true }) seens to be running fine

#

Directly changing ActionValue on the action entity also did not work

#

@pine cape Found out what it is, I need to bind it to something

#

If the action is just empty it wont send the message

#

So

#

(Action::<RotateInput>::new(),ActionMock::new(ActionState::Fired, Vec2::ZERO, MockSpan::Manual)), this wont work

#

(Action::<RotateInput>::new(),ActionMock::new(ActionState::Fired, Vec2::ZERO, MockSpan::Manual),Bindings::spawn((
Spawn((Binding::mouse_motion(), Scale::splat(0.1), Negate::all())),
Axial::right_stick().with((Scale::splat(2.0), Negate::x())),
)),), this will

#

my guess is you require a component associated to Bindings

pine cape
#

Oh; you can also just add an InputMarker component on the entity I believe

stray sinew
#

I'm having trouble getting a message with an entity to work.

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, MapEntities, Reflect)]
pub struct RequestTarget(#[entities] pub Entity);

app.add_channel::<Channel1>(ChannelSettings {
    mode: ChannelMode::OrderedReliable(ReliableSettings::default()),
    ..default()
}).add_direction(NetworkDirection::Bidirectional);

app.add_message::<RequestTarget>()
    .add_map_entities()
    .add_direction(NetworkDirection::Bidirectional);

On the client:

if let EWButton::Select(i) = ew_button {
    let Ok(ew_pointer) = q_pointer.get(child_of.0) else {
        return
    };

    let Some(ew_entity) = ew_pointer.0 else {
        return
    };

    request_spawn_sender.send::<Channel1>(RequestTarget(ew_entity));

    info!("Selected target {}", ew_entity);
}

On the server

pub fn handle_request_target(
    mut receiver: Query<(Entity, &RemoteId, &mut MessageReceiver<RequestTarget>)>,
    mut q_character: Query<&mut Target>,
    peer_metadata: Res<PeerMetadata>,
    q_name: Query<&Name>,
    q_controlled: Query<(Entity, &ControlledBy), With<CharacterMarker>>,
) {
    for (client_entity, remote_id, mut message_receiver) in receiver.iter_mut() {
        message_receiver.receive().for_each(|message| {
            let conn_entity = peer_metadata.mapping.get(&remote_id.0).unwrap();

            // Find the controlled character
            let controlled_entity = q_controlled
                .iter()
                .find(|(_, controlled_by)| controlled_by.owner == *conn_entity)
                .map(|(entity, _)| entity);

            if let Some(controlled) = controlled_entity {
                let mut target = q_character.get_mut(controlled).unwrap();

                info!("Setting target entity: {}, for: {}", message.0, controlled);

                target.0 = Some(message.0);
            }
        })
    }
}

Entity 197v1 is a predicted entity.

pine cape
#

entity mapping for messages is only done automatically between the Replicating and Replicated entity.
In your case you will have to first map from the Predicted to the Replicated entity manually on the client side:

fn send_with_map(
  component_registry: Res<ComponentRegistry>,
  manager: Single<&PredictionManager>,
) {
  // map from predicted to replicated
  let _ = manager.map_entities(&mut component, component_registry.as_ref());
}
stray sinew
#

I tried doing it manually and got this:

thread 'Compute Task Pool (3)' panicked at workspace/deep_field/src/renderer/ui/early_warning_system.rs:234:141:
called `Result::unwrap()` on an `Err` value: MissingSerializationFns
pine cape
#

hm that's weird if the component was registered

#

will make it pub

stray sinew
feral mirage
#

yeah, it seams that only the confirmed entity is mapped between server and client

#

since there is not 2 distinct entities on the server

peak ice
#

I just had a playtest using a host server with 8 players, and it went super smooth, steam peer-to-peer seems to only handle 3-4 players, do ya'll think steam peer-to-peer is designed to handle more than 3-4 players?

pine cape
#

It can handle more than that for sure. Did you try with 8 players and no steam to compare?

peak ice
#

yeah we tried 8 players with steam p2p and it was poop, then we switched to a hosted server and it was very smooth, so I'm thinking its steam and not the game

#

but i don't know anything about how p2p works vs udp

pine cape
#

Steam relay also uses udp

#

I'm not too familiar with the internals, but maybe some configuration is messing things up

unkempt sedge
#

@pine cape Why doesnt lightyear utilize the native interpolation library in avian?

pine cape
#

Mostly because I published my version first, + mine is more general purpose, it's not only for Transform/Position

#

The avian one has HermiteEasing which seems interesting

unkempt sedge
pine cape
#

Yes, after frame interpolation

unkempt sedge
pine cape
#

PhysicsSet::Sync runs in FixedPostUpdate

#

The latest system is TransformPropagate so I would order against that

#

You can see the order I use in lightyear_avian

unkempt sedge
#

Or any scenario whatsoever?

#

Because the moment I remove it, everything looks smoother on my side

pine cape
#

it's to smooth components that are updated in FixedUpdate (like Position, Rotation, etc.) so that they get interpolated in the Update schedule

#

how are you using FrameInterpolation?
Currently I think using FrameInterpolation on Transform doesn't work, because of the way it interacts with Correction

#

you would have to use FrameInterpolation on Position/Rotation

unkempt sedge
unkempt sedge
#

@pine cape I ran into an interesting bug the moment I add my lag compensation history to my player. He teleports to what I think it is the MAX value of f32. Here is the log.

#

I have no idea what is causing it, because in your logic it seens you create a child entity and keeps recreating the collider according to it

#

It seens the logic is making my collider extra chonki

unkempt sedge
#

Okay I will refactor the lightyear s lag comp to check if I can get my collision information . @pine cape is that okay by you instead of relying on spatial query casts make it so we check colliding colliders history and adjust as needed

#

I am gonna make a draft to explain what I mean

pine cape
#

not sure what you mean, you can open an issue

unkempt sedge
# pine cape not sure what you mean, you can open an issue

If I fire a bullet that is a ball it hits a player head, and I want to get the collision details force of impact and so on how would I do that with the current api?
There is also this annoying bug but i think it should be an easy fiix

peak ice
#

@pine cape My github isn't working for some reason rn. I tried to replicated the steam not working in headless and you're examples work with p2p connections, so you can close the issue. Idk whats going on there

peak ice
#

maybe it has something to do with making the client entity before setup?

pine cape
#

On the server, do you trigger on Connected vs on Linked? It's important to trigger on Linked

peak ice
#

i trigger clientOf to add the replicationsender, and connected to add the players

peak ice
#

should connected be switched to Linked?

pine cape
#

Just do what I do in the example

unkempt sedge
#

@pine cape Issue opened will work in this PR on saturday if you give the go ahead

pine cape
#

Sg for point 1 and 2, but I'd like to keep the code in lightyear_avian

feral mirage
#

the lag compensation problem is mostly due to teleportation, what should be done when the server teleports an entity? clear the history?

pine cape
#

Yeah there probably should be some special case if the change of position is too big

feral mirage
#

added a video to the issue

unkempt sedge
pine cape
#

I use RustRover, works well

hybrid fractal
#

hi @pine cape , after stopping my WebTransport server (using the Stop event), I want to be able to stop the underlying IO too. I have an observer that triggers Unlink when the server reaches Stopped state, and I see the following logging:

2025-08-20T17:12:49.115135Z TRACE lightyear_connection::server: Stopped added: removing Started/Starting 2025-08-20T17:12:49.115194Z TRACE lightyear_aeronet: Unlink triggered on Link entity 164v2#8589934756 (reason: ""). Closing/Disconnecting AeronetLink entity 168v1#4294967464 2025-08-20T17:12:49.115257Z TRACE lightyear_aeronet::server: AeronetServer closed for 164v2#8589934756. Adding unlinked on Server

...however I can see my application is still listening on the port number I used for the server, which prevents the application from starting a new server with the same port number later on ("Address already in use (os error 98)").

Is this expected? (Is there currently a reliable way to fully pull down the server without restarting the application?)

Many thanks!

pine cape
unkempt sedge
#

@pine cape I am making it so lag compensation also handles multiple child colliders

unkempt sedge
#

2025-08-20T19:44:44.052757Z DEBUG psycho_lag_compensation: collider=ColliderAabb { min: Vec3(inf, inf, inf), max: Vec3(-inf, -inf, -inf) } @pine cape Found out the cause of the chonki colliders, avian for a single frame returns a infinity collider aabb

unkempt sedge
#

@pine cape There is two impls of the same thing in history buffer

pine cape
#

one is for &HistoryBuffer

unkempt sedge
#

oh silly me

silent patrol
unkempt sedge
silent patrol
pine cape
# silent patrol hi folks! I've just published a draft of my first Bevy blog post, and it happens...

The post seems great to me!
The factory approach is interesting.
And for delta-compression you are very right to mention that this wouldn't work for components where the diff is expensive to compute.
I actually had an issue open: https://github.com/cBournhonesque/lightyear/issues/1045 where I wanted to implement a separate kind of DeltaCompression where instead of computing the diff manually between 2 component values, the user specifies the diffs that should be applied

GitHub

The current delta-compression implementation works fine for cases where your component is small, but the diff can be optimized. For example your component is a Position/f32, and the diffs between t...

#

I guess it would be nice to see a picture/video of the result

silent patrol
slow kernel
#

I'm noticing occasional desync from the server on the interpolated clients with BEI. It seems to get corrected once I start moving again which leaves me to believe maybe it's packet loss or something, but it made me wonder if it will resend unacked replications on the interval even without any changes or if there's a way for me to do that?

#

It could be something else entirely, but it made me realize I don't fully know how it behaves

pine cape
#

You observer this when testing locally or in real conditions? Packet loss is normally very small.
But yes we resend replication packets for Insertions/Removals/etc. to make sure they are acked, but not for Updates, so it's possible that the client didn't receive the last packet and is temporarily stuck in a different state than the server.

#

The logic is here: https://github.com/cBournhonesque/lightyear/blob/cbcb42825de980430a12dfa56c49f34faea03473/lightyear_interpolation/src/interpolate.rs#L133 but probably needs to be refactored, the current implementation is a bit confusing.
Basically the interpolation timeline progress smoothly (tick keeps increasing), and we record the ticks at which we received server updates.
Then we compute the fraction between two consecutive start_tick and end_tick that we are interpolating between.
Normally we should have been interpolating all the way to the last received update.

GitHub

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

unkempt sedge
#

@pine cape Rough draft of what the lag comensatio api will look like

#

I am curious thos, what is the point of that slerp lerp in the ray cast? If a player is hit you want us to return to where he was in server?

slow kernel
slow kernel
#

Are send_intervals closer to the tick rate problematic?

slow kernel
#

Digging through sender is clearing up a lot of my questions I think

slow kernel
#

I guess I basically want ChannelMode::UnorderedReliable with different ReliableSettings

slow kernel
#

Or maybe I'm thinking about it wrong and I should just do periodic updates or something 😅

pine cape
pine cape
pine cape
silent patrol
#

to save on the network traffic, I actually need ComponentReplicationConfig::replicate_once

#

for some reason I assumed that if both interpolation and prediction is set to Once (or disabled), it would also affect replication itself

unique plover
#

Is it possible to predict other player's inputs with BEI? I'm using rebroadcast_inputs, but I think I need to set up replication for the actions manually?

#

Actions are replicated to the server, but it doesn't look like actions get replicated back down to other players.

pine cape
unique plover
#

The context component was properly replicated to the predicted entity BTW.

unique plover
# pine cape I haven't tested rebroadcasting with BEI, I'm in the process of setting an examp...
2025-08-23T17:12:42.626906Z ERROR lightyear_serde::entity_map: Failed to map entity 341v2#8589934933
2025-08-23T17:12:42.626932Z ERROR lightyear_serde::entity_map: Failed to map entity 330v2#8589934922
2025-08-23T17:12:42.626938Z ERROR lightyear_serde::entity_map: Failed to map entity 327v2#8589934919
2025-08-23T17:12:42.627006Z ERROR lightyear_inputs::client: received input message for unrecognized entity entity=PLACEHOLDER target_data.states=BEIStateSequ
ence { states: [Input(ActionsMessage { state: None, value: Axis2D(Vec2(0.0, -0.0)), time: ActionTime { elapsed_secs: 0.0, fired_secs: 0.0 }, events: ActionEv
ents(0) }), SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPre
cedent] } end_tick=Tick(48554)
2025-08-23T17:12:42.627029Z ERROR lightyear_inputs::client: received input message for unrecognized entity entity=PLACEHOLDER target_data.states=BEIStateSequ
ence { states: [Input(ActionsMessage { state: None, value: Bool(false), time: ActionTime { elapsed_secs: 0.0, fired_secs: 0.0 }, events: ActionEvents(0) }),
SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent] } en
d_tick=Tick(48554)
2025-08-23T17:12:42.627039Z ERROR lightyear_inputs::client: received input message for unrecognized entity entity=PLACEHOLDER target_data.states=BEIStateSequ
ence { states: [Input(ActionsMessage { state: None, value: Bool(false), time: ActionTime { elapsed_secs: 0.0, fired_secs: 0.0 }, events: ActionEvents(0) }),
SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent] } en
d_tick=Tick(48554)

The only major difference between this version and the interpolated one is the addition of rebroadcast_inputs, is there something else I should be adding to the replicated entity or protocol differences?

pine cape
#

Ah yes I guess it makes sense that rebroadcast doesn't work because the Action entities of client 1 are not replicated to client 2. You would have to manually add Replicate on the action entities on the server to make sure they are rebroadcasted to other clients. Maybe this can be done automatically by adding HierarchySendPlugin<ActionOf> (so that the Replicate gets propagated automatically from the Context entity to the Action entity on the server), but it needs to be tested

feral rock
#

Randomly unable to build with wasm clientside

error[E0599]: no function or associated item named `builder` found for struct `lightyear::prelude::client::ClientConfig` in the current scope
  --> modules/core/networking/src/network_client.rs:51:43
   |
51 |                     config: ClientConfig::builder().with_no_cert_validation(),
   |                                           ^^^^^^^ function or associated item not found in `lightyear::prelude::client::ClientConfig`
#

building non-wasm works fine lol

unique plover
feral rock
pine cape
#

Can you post this in the aeronet channel? I'm using aeronet_webtransport and they would probably know more

earnest fog
pine cape
#

yep i'm working on an example for projectiles replication using BEI; i will have to rebroadcast BEI inputs for it so i'll be looking into that

unique plover
#

FYI another issue I had with the BEI refactor was that I was manually setting an input for leafwing like in the FPS example to sync the camera position and that didn't immediatly work for me.

The issue is that I wasn't doing any bindings to the Action, so lightyear didn't add the InputMarker component

The fix was just to add the InputMarker component manually to the Action. This is our Action:

context.spawn((
    Action::<CameraForwardAction>::new(),
    LocalActionComponent,
    // no bindings since this is mocked
    // Added to help lightyear pick up this action since it doesn't have bindings
    InputMarker::<NetworkInputComponent>::default(),
));

Also if you're wondering the BEI equivalent of set_axis_pair and friends from leafwing is, it's done through mocking. Here's the system we use:

fn third_person_camera_input_system(
    transform: Single<&Transform, With<ThirdPersonCameraComponent>>,
    action: Single<Entity, (With<Action<CameraForwardAction>>, With<LocalActionComponent>)>,
    mut commands: Commands,
) {
    commands.entity(*action).insert(
        ActionMock::new(ActionState::Fired, transform.forward().as_vec3(), MockSpan::Manual)
    );
}
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

#

I also recommend setting networked actions and local only actions with different context components. Otherwise I saw a lot of warnings. I'm assuming it was trying to replicate the whole relationship, and not just the actions that are defined in the protocol.

#

Both contexts can exist on the same entity. We literally attach them at the same time.

fn add_local_input_observer(
    trigger: Trigger<OnAdd, LocalInputComponent>,
    mut commands: Commands,
) {
    commands.entity(trigger.target()).insert((
        Actions::<NetworkInputComponent>::spawn(SpawnWith(|context: &mut ActionSpawner<_>| {
            // Networked actions
        })),

        Actions::<LocalInputComponent>::spawn(SpawnWith(|context: &mut ActionSpawner<_>| {
            // Local actions
        })),
    ));
}
pine cape
#

Yes I ran into this as well, I'll probably also add the InputMarker automatically if ActionMock is added on the action entity.

Another thing I need is to be able to have actions that are unaffected by rollback (for example global actions like pausing the game). I did it right now by adding DisableRollback on the Action entity, but I think I also want to allow users to add BEI Contexts that are evaluated in PreUpdate

stray sinew
#

Does anyone know why RustRover is not able to find Tick? It doesn't work through lightyear::prelude, and importing lightyear_core directly does not work either. I already have org.rust.macros.proc enabled and Expand Macros enabled in the rust settings.

pale sequoia
#

I tested the deterministic_replication example and noticed that it is very easy to become out of sync, is there any good solution to correct the state at some points?
I also made both the client and server crash quite a few times because of some panic unwrap calls.

unique plover
stray sinew
#

Still not working, I'll try vscode next

unique plover
pale sequoia
stray sinew
pale sequoia
stray sinew
#

Yep, no issue with VScode. Seems to be a RustRover specific issue

pine cape
pine cape
stray sinew
pine cape
#

Maybe try File -> InvalidateCaches

stray sinew
#

I already tried that and it didn't work. I suspect its related to nightly builds because the issue showed up after I switched from the nightly compiler to 1.89 but I'm not sure since I had a lot of other changes too

pine cape
#

For some reason the examples don't work if the server is spawned with only the server and netcode features; the client cannot connect.
It works if the server also has the client feature; can't figure out why

pine cape
stray sinew
#

There seems to be a bug when updating ChildOf with PredictionMode::Simple.

On the server:

commands.entity(character_entity).insert((
    ChildOf(parent_parent_entity),
));

// Registered like this on both
app.register_component::<ChildOf>()
    .add_immutable_prediction(PredictionMode::Simple);

Crash on the client:

thread 'Compute Task Pool (0)' panicked at /Users/rherv/.cargo/git/checkouts/lightyear-16a1ca81dacb5ed5/82026f6/lightyear_prediction/src/predicted_history.rs:133:13:
assertion `left == right` failed
  left: Once
 right: Simple
stack backtrace:
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Encountered a panic in system `lightyear_prediction::predicted_history::apply_immutable_confirmed_update<bevy_ecs::hierarchy::ChildOf>`!
pine cape
#

hm yes it's probably this

#

i can update them to Simple for now; as it seems more flexible

pale sequoia
pale sequoia
pine cape
#

@lime jungle for #networking message:
Lightyear works with 2 layers:

  • IO for how to send bytes (crossbeam, udp, websocket, webtransport). This is the Linked, Linking, Unlinked components
  • 'connection' layer for auth + establishing a 'session' (a more long-term ID on top of the raw link)

I provide 2 implementations of the connection layer, which both give you a long-term id: Steam or Netcode.
But you're free to implement your own, the only requirements are that:

Let me know if that makes sense or if you need help with that

GitHub

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

lime jungle
#

it seems i will be accepting byte messages over websocket, feed those into crossbeam channels and then implement the connection layer myself. i will look into it and then reply to your message, thanks!

unkempt sedge
#

@pine cape Does the replicatelike component also follows up adjustements in rooms?

pine cape
#

That was actually the main reason why I introduced ReplicateLike (to avoid copying the room information on children)

unkempt sedge
#

@pine cape To replciate somewhat a relationship all I need to do is implement entitymapper on both target and targeted?

pine cape
#

you can just add HierarchySendPlugin<Relationship> and you just need MapEntities on the relationship component

#

(ChildOf and not Children)

pale sequoia
#

Has anyone made a stable version with lightyear and bevy-tnua?

pine cape
#

I don't think so

unkempt sedge
pine cape
#

@earnest fog @unique plover it's not cleaned up but I think you should be able to use branch cb/projectile-demo-interpolation-sync for BEI input rebroadcast

pale sequoia
unkempt sedge
#

Not needed

#

Depends on your character to be honest

#

Is it pred or interpolated?

pale sequoia
# unkempt sedge Is it pred or interpolated?

I was thinking of trying optimistic prediction on the local characters with server authoritative position. I am not happy with the results, and quite unsure exactly how I want it to work smoothly.

unkempt sedge
unkempt sedge
#

@pine cape Correct I am mistaken but the hierarchy replication is in summary a handy way of ensuring that a related entity follows the replication logic from root. It does that how tho? Cant seem to find the logic of the ReplicateLike component (only the insertion and remotion logic) on the plugin

#

And in my case scenario which is the following:
I have a root entity, with related entities. I just need the information of those releated entities to be replicated (no need for interpolation or prediction). It also needs to follow the NetworkVisiblity of the root entity. So I was thinking of doing the following, add ReplicateLike to related entities. Remove the prediction and interpolation component and be cheerios. Would that work?

#

Also this wouldnt work, because well R is not necessarily ChildOf

earnest fog
pine cape
pine cape
# unkempt sedge And in my case scenario which is the following: I have a root entity, with rela...

I actually needed that recently in my branch cb/projectile-demo-interpolation-sync
You can do this: https://github.com/cBournhonesque/lightyear/pull/1183/files#diff-3f085b5b6de1bf196399b8bb71ace7922da59752295a4afd5e4620a777ebeaa6R143
ReplicateLike uses the same replication behaviour of the root entity, but you can still override the replication components to customize the replication

unkempt sedge
#

although this is way better

pale sequoia
unkempt sedge
#

Probably having rollbacks on jumping

pine cape
#

yeah probably rollbacks that are mispredicted on jumping

pale sequoia
#

I tried to turn off that and it just works slightly better

pine cape
#

@unkempt sedge did you make progress on your lag compensation code?

unkempt sedge
#

@pine cape I finished it but i did not handle the slerp scenarios yet

#

I still need to handle the diagonal movmemnet too

pine cape
#

I've got rebroadcasted inputs for BEI working + i have a bunch of fixes on correction/prediction, so i was thinking of making a new release

pine cape
unkempt sedge
#

well dashing diagonally for some reason is kinda bad

unique plover
#

@pine cape FYI the cb/projectile-demo-interpolation-sync branch has a dependency of ../bevy_enhanced_input so I'm unable to test it with my setup.

#

I mean I could, but I would have to change the scope of my nix flake.

pine cape
unique plover
#

Cool, I think I'll wait unitl that's merged then. Thanks!

unkempt sedge
#

@pine cape A weapon with a state machine should be predicted correct?

pine cape
#

I'm experiment with weapon/projectile replication rn

#

I think weapon should stay responsive so you should predict it, yes

unkempt sedge
slow kernel
#

ya I imagine firing and reloading can be predicted, just probably wouldn't predict damage/death for anything hit. Some of the hit vfx and sfx are probably good to predict to help smooth over the delay before confirmation although can sometimes be misleading in a rollback

pure drum
empty wave
#

is it possible to connect a custom io layer to lightyear? if so is there anywhere i could look to see how to do it

pine cape
# empty wave is it possible to connect a custom io layer to lightyear? if so is there anywher...

Sure you can look at existing IOs like crossbeam: https://github.com/cBournhonesque/lightyear/blob/main/lightyear_crossbeam/src/lib.rs
You mainly need a receive and send system + reacting to events like LinkStart, Linked, Unlinked, etc.

GitHub

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

empty wave
#

quick question. does lightyear itself handle reliable sending or is that delegated to the io layer being used?

pine cape
#

lightyear handles it; so the io can be unreliable

slow kernel
#

Just want to say the projectiles example looks amazing! The thoroughness is appreciated, especially as another BEI example

#

helps answer so many questions with the different options and the readme

pine cape
#

Thanks! Funnily enough the readme and the example were initially entirely generated by chatGPT. I was surprised to see that the implementation worked so well.
It's still heavily WIP though, i'm working on making the examples work with 2 weapons only (hitscan and linear bullets)

slow kernel
#

Haha I assumed the readme was but ya that's surprising for the implementation

pine cape
unkempt sedge
# pine cape

On my pr lag compensation is now a one to one relationship

#

It seens you also ran into the diagonal movement clunkiness

pine cape
#

Quick peek at the new example; the goal is to have a sandbox where we can try many different ways of replicating projectile to see what 'feels' best.
I was working on a FPS project but it was very hard for me to decide on an approach for replicating projectiles because there are many different ways to do things and it's very time-consuming to test all of them. So hopefully using this we'll be able to explore the trade-offs between the various approaches.

On the right is the server, which spawns 6 differents entities for each player. We use interest management via Rooms to make sure that clients only receive updates about entities that correspond to one of the 6 modes:

  • AllPredicted: entity is predicted by all players, hit detection is done server-side with no lag compensation. This should favor the target since the shooter has an imperfect view of their position. This also allows testing that remote entity prediction works well with BEI, which is now the case.
  • ClientPredicted (No lag Comp): the 'default' setting of predicting the client and interpolating other players. Hit detection is done server-side; since there is no lag compensation, even if you seemingly hit the target on the client's screen it won't be registered as a hit on the server because the client has a delayed view of other clients
  • ClientPredicted (Lag Comp): same as above but this time we use lag compensation on the server. The white boxes on the server are the collider occupied by each player in the last few frames. If the projectile collides with that (broad-phase), we check if there was an actual collision on the client's screen using the narrow-phase lag compensation query. It's interesting to see how the boxes grow after any diagonal movement, but I think that's expected (it's just for broad-detection)
#
  • ClientSideHitDetection: same as above, but hit detection is done on the client. This should give good results + saves a lot of server-CPU (since server doesn't need to do any hit-detection), but cheaters are free to send fake 'I hit that target' packets
  • AllInterpolated: this time the local client is also interpolated, so each of their movement will be felt after a delay. That's a tradeoff to make in exchange for having all entities in the same timeline, which removes the need for lag compensation. Note that interpolation seems somewhat clunky because we interpolate between infrequent states without having a full view of the history of each component. I'm planning of maybe adding a mode where the full history of the component is replicated, for better interpolation.
  • OnlyInputsReplicated: this time the server does basically nothing except acting as a proxy that exchanges inputs between players. The simulation should be deterministic and run on each client. If there is enough input-delay (for example in lockstep), each client has a perfect view of other clients and there is 0 prediction. Otherwise the client has to predict other players, which can make things tricky. How do we handle mispredicting that a target was shot? How do we handle receiving a late input telling us that a remote client shot a bullet?
#

The example also uses a fake 'bot' client that acts exactly like another client but runs in a headless app and communicates with the server using crossbeam channels. This is useful for testing to be able to see how remote clients work without having to manually spawn 2 clients.

pine cape
#

I'll post this in #showcase ; I think this is already quite a lot of progress 🙂
It was a lot of work to even get to this stage

unkempt sedge
#

mine feels clunky, we actively jump and so on he becomes too big

#

i am guessing is due to the cuboid shape

pine cape
#

The broadphase collider is simply to have a cheap way to check if there was a chance that the projectile collided with the lag compensation history. So we include the biggest AABB bounding box that contained the collider during the history.
If and only if there is a match with that broadphase collider, then we check for the actual lag compensation collision with the exact position of the collider lag_compensation_delay ago

unkempt sedge
#

it is not like it is gonna be expensive

pine cape
#

Feel free to open an issue about benchmarking this; we could test it and see if it's worth it or not

unkempt sedge
pine cape
#

my implementation seems very similar to what's described in those blog posts. However i'm storing ColliderAABB instead of more complex Colliders in the LagCompensationHistory because I know nothing about animation.
We might want to handle complex colliders, yes

unkempt sedge
#

since avian utilizes parry beneath, it is quite easy to store the constructing shapes and reconstruct from there in a cheap way?

#

okay i am hyped this will be fun

stray sinew
#

New commit working great. I also switched from leafwing to BEI and its running so smoothly with no rollbacks

unique plover
#

@pine cape Still trying to get the cb/projectile-demo-interpolation-sync branch working in my project.

I noticed when trying to launch my dedicated server instead to rule out HostClient that this like should probably be behind a client feature?
https://github.com/cBournhonesque/lightyear/blob/cb/projectile-demo-interpolation-sync/lightyear_inputs_bei/src/plugin.rs#L21

GitHub

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

pine cape
#

Yes probably

unique plover
#

That error is very strange because I defintely get an entity with both Server and Started before that.

#

Also only happens on my DS, not in HostClient mode.

unique plover
#

Nvm, it looks like that isn't related to this branch.

unique plover
#

Still having DS troubles, but I was able to get further with HostClient. The actions for remote clients seems to work, but the HostClient's actions do not seem to get replicated.

pine cape
#

I haven't tested with host client, I'd be surprised if it worked

#

I think I'm missing some HostClient/HostServer bounds in lightyear_inputs_bei/setup.rs

unkempt sedge
#

@pine cape Found a interesting nuisance, if you replicate an entity that has a relationship,the ordering of the relationship is not cool 🙁

#

So lets say relationship is a vector duel, katana, shotgun

#

Confirmed has duel, shotgun, katana,

#

but predicted has katana,shotgun,duel

#

Or whatever in da hell comes first

unkempt sedge
#

The fix: Replicate the target component to confirmed, than reformulate the relationship on the client end

pine cape
#

Hm, that's unfortunate

#

We could detect if one of the replicate componend is a RelationshipTarget; in which case we could re-order the entities that are replicated to be in the smae order

unkempt sedge
#

hahahhaa

#

besides identify via trait

#

For example: When do I know that the entity will be first replicated?

pine cape
unkempt sedge
#
fn reorder_relationship(
    query: Query<(Entity, &WeaponCarrier), With<PlayerMarker>>,
    weapon_slot: Query<&WeaponSlot>,
    mut commands: Commands,
) {
    for (carrier, weapon_carrier) in query.iter() {
        let mut vec = vec![];
        for (correct_slot, weapon) in weapon_carrier.iter().enumerate() {
            let slot = weapon_slot.get(weapon).unwrap();

            if slot.0 as usize != correct_slot {
                vec.push((slot.0, weapon));
                debug!("WRONG {}", slot.0);
            }
        }

        vec.sort_by_key(|(slot, _)| *slot);

        for (ordered_slot, entity) in vec.into_iter() {
            commands.entity(entity).insert(WeaponOf(carrier));
        }
    }
}
#

I dont want this code on me prettyy api

unkempt sedge
#

my goodness rollback logs now are pretty chonky and prettyy

amber oracle
#

Hey there,

I used the space ship example and have added a static rigid body circle obstacle.

Does somebody know why the client ship clips into the obstacle when colliding?
The collider exists on the client and on the server(rendering is done using the collider shape like in the space ship example)

I suspect that there might be some kind of prediction/collision setting I am missing.

You can see the issue in the video.

I am very grateful for any help.

pine cape
#

That probably means that the collision is not being predicted.

You are predicting that you are passing through the obstacle, but the server sends a correction about the collision.
Did you add the collider components on the Predicted entity?

amber oracle
#

Yes I do but now I see that I forgot to add the static rigidbody.😆
(Yup it works when I add it.)

Thanks for the quick response😄

glacial kernel
#

Heya!

I'm currently trying to grok lightyear, and I am making progress. Currently I'm trying to see how I could achieve the following:

  • n players, each with m cards in their hands

I have a hierarchy of [Player] -> [Hand] -> m x [Card]

Each Card has components that specify what the Card does etc... Now, I would like to replicate the entities, but not their components, unless they are the given Player's Hand. Basically so you can't see what others have.

I already found NetworkVisibility, but that seems to be wholly on/off. Is there a way to disable component replication without disabling entity replication for specific clients?

pine cape
#

Yes, look up ComponentReplicationOverride! You can also grep it in the examples

#

You can also in the protocol set the ReplicationConfig to not replicate the component by default, in which case you would use the ComponentReplicationOverride to enable the component (instead of disable)

glacial kernel
#

Okay, so I'd add this to every entity I don't want to replicate, as the default is to replicate?

Does this follow the hierarchy? So I could just set it in the Hand once for example 🤔 (There is no mechanic of looking at other peoples hands)

pine cape
#

The default is to replicate, in which case you would do something like ComponentReplicationOverride::default().disable_all()

But you can also register the component as being disabled by default (.with_replication_config) in which case you would use the override to enable replication

glacial kernel
#

Alright, awesome! Thank you for the infos :3

unkempt sedge
#

@pine cape My crate has a implementation of lag compensation pretty much done here is the link for it advantages when campared to your.

  • It is a little more precise (it listens to collision event of where the would be of the collider)
  • It support multiplo colliders/hitboxes.
  • It is very easily capable of handling animation
#

If you want to have a test drive I will link to ya, if not i can convert and open the pr

pine cape
#

can you open a PR? I'm on holiday for 10 days but I can take a look after

unkempt sedge
#

you know mr peri we have a picture of you in our wall of images, yet we know so little about our lord and saviour

pine cape
#

I'm from France!

strong barn
#

I'm having an issue with Lightyear I think is an issue of the crate.

I get consistent RTT / Jitter sitting idle in my game, on web or native:

#

As soon as I start to move (use inputs) the RTT skyrockets on web, and becomes unplayable and goes into a death spiral @pine cape

#

I remember having a very similar issue a while back, and the solution was (I think) to reduce the input replication rate on web. I am using bevy_enhanced_inputs.

Is this still the recommended approach? It really feels like something is fundamentally wrong, idk.

stray sinew
#

Sounds similar to numerous rollback loop errors I’ve had previously. Sometimes a poorly coded system wont fully resolve a client server mismatch with a rollback. Using delta time will sometimes cause this and relying on predicted components getting inserted and removed can trigger it too.

strong barn
#

I am basically adding a physics bundle (LinearVelocity, Position, Rotation) to each player in the screenshot. When players use inputs, this adds speed to the LinearVelocity component.

I've noticed many weird behaviors, and really cannot for the life of me pinpoint exactly wtf is going on, it's so frustrating.

  • Sometimes my player inputs get stuck (I press things and the player stutters momentarily).
  • On web I get a lag spike when the RTT spikes when inputs are sent by the local player (as shown in the screenshot)
  • Sometimes the player does an initial stutter in location when the first physics interactions happens, or when I start moving the first time.
strong barn
#

I am disabling the SyncPlugin, SleepingPlugin, and PhysicsInterpolationPlugin from the PhysicsPlugins by avian2d since lightyear is supposed to handle those things.

strong barn
#

This is what I mean by input just randomly locks up. The terminal is the server printing whenever it receives a Trigger<PlayerMovement>. The server is seeing constant inputs from the broken client, while the other works just fine. It's super inconsistent, happens 20% of the time, and only witnessed when there are multiple clients connected.

#

update: it seems that input is some type of system ordering issue.

If I close the bad client and open it again, there's a chance the new client works fine, able to send inputs to the server.

stray sinew
stray sinew
pine cape
#

Is the server headless? I noticed that there are issues caused by running the server with a GUI. I would test with the server running in headless mode

#

It is possible there is some unexpected input bug with multiple clients

stray sinew
strong barn
#

I encounter this and my server is headless and indeed I am using MacOS as well

#

@stray sinew Your game looks super cool, too!

pine cape
#

Do you also encounter this in the examples? The inputs_bei example or the projectile example

strong barn
#

Is there an example that uses the combination of BEI + Avian2d?

#

@stray sinew is your network tick rate the same as your replication rate? I am using 10Hz for both and wondering if there's some type of timing issue

#

I think the inputs are sent on the replication interval, right? @pine cape

pine cape
#

Inputs are sent every frame

pine cape
#

It's still kind of a wip example, but it should be enough to test the input issue.

strong barn
pine cape
#

I believe you can override the replication frequency of the InputChannel if you want to change this

strong barn
# stray sinew After some testing I was never able reproduce the error on my Windows PC running...

By the way, I printed out whenever input is triggered when this lockup happens. The server never gets input packets but the client is saying it is sending to the server. I don't understand why the client stutters position though, if it's a Predicted entity. It's not getting rolled back either, since I print out when a rollback occurs. Is there a system that cancels or rollsback the input on Predicted entities to your knowledge @pine cape ?

My only guess is that there could be a system ordering bug where queueing and sending the inputs are ambiguous systems, because sometimes the server gets them for half a minute, then stops. It just happens, randomly.

#

--

#

I know you're on vacation, Periwink, but if you ever want to DM a screen share when you come back, I can reproduce this issue.

pine cape
stray sinew
stray sinew
#

I haven't been able to recreate it in the BEI example.

slow kernel
#

I'm not sure if they're the same ones you're seeing

#

actually pretty sure they're not, the issue I saw was just related to interpolation I think (multiple clients)

spice rapids
#

Hi, I've been working on trying to understand lightyear, particularly for 3d. Looking at the avian_3d_character example, it seems like the client prediction isn't working - inputs are reflected on the server before the client character moves. Am I missing something? The readme for that example makes it sound like client movement prediction should be enabled in that demo
Also the client movement is jittery - seems like it's moving in step with the network for controlled entities. Remote entities don't have that so ironically Client 1 looks better on Client 2's screen than on their own

pine cape
pine cape
spice rapids
pine cape
spice rapids
#

let me see if I can find it

#

@pine cape I think I found the commit you're talking about. It doesn't seem to have any impact on the issue. Take a look - you can see the server moves before the client does:

#

That commit does fix overcorrection mention in the issue though

#

just not the input lag / lack of client prediction

strong barn
# pine cape Also try using the main branch from lightyear, it fixes some input related bugs

If I upgrade to main I get this panic on load:

thread 'main' panicked at /Users/simbleau/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_ecs-0.16.1/src/error/handler.rs:141:1:
Encountered an error in system `lightyear_frame_interpolation::visual_interpolation<avian2d::position::Position>`: Parameter `Res<InterpolationRegistry>` failed validation: Resource does not exist

Any ideas?

#

I have interpolation activate, not sure why I would get this.

        app.register_component::<Position>()
            .add_prediction(PredictionMode::Full)
            .add_interpolation(InterpolationMode::Full)
            .add_should_rollback(position_should_rollback)
            .add_linear_interpolation_fn()
            .add_linear_correction_fn();
pale sequoia
unkempt sedge
#

All frames unless you simulate high ping, which I dont know if that example has

glacial kernel
#

Does someone have an example of using both a crossbeam as well as netcode server + client?

I am not sure how they interact, and how things are meant to work together.

I get that Link is the 'logical' connection, into which you can feed from any source.

But looking at CrossbeamIo it says that new_pair is for testing? So I assume that for non-testing, one should assemble it oneself. But is there a specific reason?

I also assume that Client is the same thing basically?

hot cloud
glacial kernel
#

Thanks! I will take a look :3

strong barn
#

@pine cape @stray sinew I get the client input lockup on main as well, and two new issues:

Issue 1: Bad Input spam in terminal if I turn on rebroadcast_inputs: true (screenshot attached)
Issue 2: Interpolation registry missing error (I had a message above with it). Turning off visual interpolation still has the input lockup, so it is not related to visual interpolation.

strong barn
#

Note: Tinkering with the send rates did not help. Input lockup still occurs with both homogenous and heterogenous intervals.


/// How often inputs are sent.
pub const INPUT_SEND_INTERVAL: Duration = Duration::from_millis(1000 / 60);

/// How often replication takes place.
pub const REPLICATION_SEND_INTERVAL: Duration = Duration::from_millis(1000 / 60);

/// How often the networking ticks.
pub const NETWORK_TICK_RATE: Duration = Duration::from_millis(1000 / 15);
spice rapids
spice rapids
pale sequoia
strong barn
#

I have a video that shows 3 issues.

  1. Triggering input on WASM causes a death spiral
  2. Input lockup (we've talked about this one)
  3. Inputs when I'm not even pressing anything!

Sometimes, input continues to spam even when I have nothing pressed or not on the window anymore. No clue why.

As soon as I press inputs, usually either the RTT goes into a death spiral, or it locks up and refuses to work. And finally, when I am on another window, or no longer focusing the same tab, RTT recovers. There must be some correlation between inactive window focus and correctly networking. Maybe the WebKeepAlivePlugin is doing something really good?

#

@stray sinew have you encountered all of those 3 issues or just the input lockup?

spice rapids
#

Ok, i guess it is something else. I just ran the test with 100ms network lag in Clumsy and the prediction seems to work. Maybe it's just the character controller causing it to be stuttery/slightly lagged?

stray sinew
pale sequoia
spice rapids
pine cape
pine cape
pine cape
# strong barn I have a video that shows 3 issues. 1) Triggering input on WASM causes a death s...

Does your input lockup issue only happen when you test using wasm? I haven't tested wasm for months and I never ran into that issue.
Also just a reminder that enabling GUI on the server slows down the server frame rate and can cause issues.

When you switch to another tab, we manually (via WebKeepAlivePlugin) call app.update every 100ms on the client. Maybe the slow send rate helps things recover.

  1. This is normal; currently we keep sending inputs even when you're not pressing anything. (to distinguish between inputs not being received, and empty inputs)
pine cape
#

I just tried running the projectiles example in wasm (with branch cb/projectile-demo-interpolation-sync) and I cannot reproduce the issue.
I used rm -rf SL && cargo run --no-default-features --features=server,netcode,client -- server 2>&1 | tee SL to start the server, and
bevy run --no-default-features --features=client,netcode,gui web --open to start the client.

I can't reproduce

  1. death spiral if inputs are pressed
  2. inputs lockup (server stops receiving inputs from client)

I can't help much if we can't reproduce this in an example

glacial kernel
# pine cape You can also look at the tests: https://github.com/cBournhonesque/lightyear/blob...

Oh wait, am I getting this right, that one should not mix multiple Transport on a single entity?

I can't seem to get it to work, as when I do, it spams:

2025-09-09T16:12:58.048185Z DEBUG lightyear_netcode::client: client sending connection request packet to server
2025-09-09T16:12:58.064921Z ERROR lightyear_transport::plugin: Error processing packet: PacketError(ChannelNotFound)

My code:

pub fn start_hosted_server(trigger: Trigger<StartLobby>, mut commands: Commands) {
    let StartLobby {
        name: _,
        socket_addr,
    } = trigger.event();

    let (server_conn, client_conn) = CrossbeamIo::new_pair();

    let server = commands
        .spawn((
            NetcodeServer::new(NetcodeConfig::default()),
            LocalAddr(socket_addr.parse().unwrap()),
            ServerUdpIo::default(),
            server_conn,
            ReplicationReceiver::default(),
            ReplicationSender::default(),
        ))
        .id();

    commands.trigger_targets(Start, server);

    let client = commands
        .spawn((
            NetcodeClient::new(
                lightyear::prelude::Authentication::Manual {
                    server_addr: std::net::SocketAddr::new(
                        std::net::IpAddr::V4(std::net::Ipv4Addr::LOCALHOST),
                        12312,
                    ),
                    client_id: 0,
                    private_key: lightyear::netcode::Key::default(),
                    protocol_id: 0,
                },
                lightyear::prelude::client::NetcodeConfig::default(),
            )
            .unwrap(),
            PeerAddr(std::net::SocketAddr::new(
                std::net::IpAddr::V4(std::net::Ipv4Addr::LOCALHOST),
                1,
            )),
            ReplicationReceiver::default(),
            ReplicationSender::default(),
            lightyear::prelude::Client::default(),
            client_conn,
        ))
        .id();

    commands.trigger_targets(Connect, client);
}
pine cape
#

The server_conn should be added on a ClientOf entity, not on the server entity itself

unkempt sedge
#

Delay gives the impression that is a small buffer between interpolated and predicted so it doesnt well interpolated to agressively

#

I also would like to say I am about finished with my code just writing a lot of test for multiple differents scenarios (20 bullets at once), one sole bullet, bullets with dynamic bodies

#

Multiple collider

glacial kernel
# pine cape The `server_conn` should be added on a ClientOf entity, not on the server entity...

Oooh, that makes sense now. It's the "server-side" part of a connection!!

Thank you, that's the piece I was missing

Trying it out, I think I am still plugging it together wrong 🙈

My first thought was that ClientOf is just part of the puzzle, as it doesn't have any way to relate back to the Server. So I was thinking that was the job of LinkOf!

And it does work now, but it's currently spamming on top:
https://github.com/cBournhonesque/lightyear/blob/14365d2b9c7fe134c8d8fc035d56447bd83fbb40/lightyear_udp/src/server.rs#L112

The comment above makes me think this is benign? I can filter it out for now if I can ignore it.

GitHub

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

pine cape
#

Yes you can probably ignore it

strong barn
strong barn
#

If by lightyear plugins you mean lightyear::prelude::ClientPlugins

#

Here are all my features:

lightyear = { version = "0.23.0", features = [
  "webtransport",
  "netcode",
  "interpolation",
  "prediction",
  "replication",
  "input_bei",
  "avian2d",
] }
lightyear_frame_interpolation = { version = "0.23.0" }
avian2d = { version = "0.3.1", features = [
  "2d",
  "f32",
  "parry-f32",
  "parallel",
  "serialize",
  "enhanced-determinism",
] }
#

does anything there seem odd?

#

Here is how I am adding frame interpolation:


fn add_visual_player_interpolation(
    trigger: Trigger<OnAdd, Position>,
    filter: Query<(), With<Predicted>>,
    mut commands: Commands,
) {
    let entity = trigger.target();
    if filter.get(entity).is_ok() {
        info!("Added visual intepolation to {entity}");
        commands
            .entity(trigger.target())
            .insert(FrameInterpolate::<Position> {
                // We must trigger change detection on visual interpolation
                // to make sure that child entities (sprites, meshes, text)
                // are also interpolated
                trigger_change_detection: true,
                ..default()
            });
    }
}
strong barn
pine cape
#

I am on mac M2

amber oracle
#

Is local to remote entity mapping supported for crossbeam channels?

I have a "client" command that is sent via a crossbeam channel and i would like to include a vec of entities that the server should see as its remote entities and use for an action a client would like to do.

afaik add_map_entities only exists for MessageRegistration.
However, crossbeam_channel does not expose this when constructing a new channel.

So now I am wondering what the recommended way to support automatic local to remote entity mapping is when using crossbeam channel messages or if the "solution" is: do not use them for this case and regular message channels instead.

Thanks for any response in advance🙂

pine cape
#

Yes entity mapping is independent from the IO used. It's also independent from the channel, it's purely a property of the Message

feral mirage
#

@pine cape could you map the Client entity and the ClientOf entity? i want to have some "client information" that stays on the Client/ClientOf entity

unkempt sedge
#

Adding ClientServerStepper , will automatically simulate a scenario where I have n clients connected to a server in a dissociated app?

unkempt sedge
strong barn
#

If anyone finds out the issue with 1/2/3 please remember to let me know

unborn sedge
#

hey does anybody can explain what i'm doing wrong?
when trying to run or build the example i get a cmake error, but i've installed the c++ build tools and can run other bevy projects without any problems. Does anybody have an idea?

feral mirage
#

you need the cmake application

unborn sedge
spice rapids
unborn sedge
glacial kernel
#

The books and issues mention being able to replicate Resources 🤔 Is this (still) a feature? I can't seem to find anything pertaining to it in the current version/main branch.

Not a biggie if not, but if its around but renamed I'd just use that 😄

pine cape
glacial kernel
#

Well, time to not use Resources then alright!

#

I feel I'm also running a bit against a misdesign of my app.

What I am trying to do is keep a 'Lobby' entity where each Player gets an Entity that contains public info, like name, ping, if they are host etc... that gets replicated to each client.

My 'problem' right now is what would be the best way to find a specific child entity of that again? There is the ControlledBy and its Target, but they don't expose the list (unlike Children). So I can't easily iterate the controlled entities of a given connected Peer.

I am currently iterating the Lobby entity for its children, but that is n^2 if they all update and that irks me lol

#

So I have

Lobby -Children-> [Player1, Player2]

Server -Server-> [Peer1, Peer2]

Peer1 -ControlledByRemote-> [Player1]

And when I receive a Message through Peer1 I currently have to iterate Lobby for its Children and match the PeerId to find the correct entity, which seems not how it should go?

pine cape
#

You could add the components directly on the Peer entities

#

Or you can store the mapping in a resource

hot cloud
#

Hi! I am using lightyear from the main branch of the git repo. For context, I am trying to make a first person character controller for a co-op game. For simplicity and quick prototyping, I wanted to transfer authority of the spawned character controller to the connecting client. The book and the distributed_authority example mention the method "transfer_authority()", but it doesn't seem to exist anymore?

I tried to run the distributed_authority example and got a bunch of errors:

// Many more errors above, but this one is about the missing method.

error[E0599]: no method named `transfer_authority` found for struct `EntityCommands` in the current scope
   --> examples/distributed_authority/src/server.rs:118:22
    |
116 | /                 commands
117 | |                     .entity(ball_entity)
118 | |                     .transfer_authority(PeerId::Client(player_id.0));
    | |                     -^^^^^^^^^^^^^^^^^^ method not found in `EntityCommands<'_>`
    | |_____________________|
    |

Is there anything I'm missing, a new way of achieving the same behavior or even a workaround that I could use in the meantime?

hot cloud
#

What led me to try making the character controller client-side is an issue with rollback and "bouncing" on my character controller, and I couldn’t find a way to fix it. I ran the avian_3d_character example, and it works as expected with cargo run -- host-client -c 0. However, when running a server and a client separately (cargo run -- server & cargo run -- client -c 1), I see the same effect as in my project: (in the video, I move left twice, then right twice, and each time the capsule rolls back when I stop pressing the keys. Tried with the lightyear 0.23.0 from crates.io and the problem was already there.).

spice rapids
#

@hot cloud can't help you any further but just an fyi that the book is quite out of date in most areas

glacial kernel
#

What would cause only some entities to be replicated?

I have an Entity with Replicate and NetworkTarget::all. The idea being that it gets transitively given to all its Children.
When something gets the LinkOf, it gets a ReplicationSender and once its connected they do receive some of the entities. But not all? Most notably, on my client host I see all three entities, but then on all other connected clients I only see the ClientHost entity. Which does get replicated. If I change something on it, it gets updated for the others

#

The server has 3 and the other clients all only get 1 🤔

#

I do get a lot spam like this in the console I just noticed setting to debug, but I can't tell what this means?

#

Adding a Replicate to all entities seems to do it, but this is very counterintuitive? Why would only some entities get replicated in the first case? Especially it looked like the whole hierarchy would get replicated.

Aka, if I had replicate to the parent, its child and a grandchild got replicated.

And if I add it to all children recursively it all works.

I'd expect in the first case then only the entity itself gets replicated?

glacial kernel
glacial kernel
#

Yeah that fixes it! Will write some tests and send a PR

glacial kernel
pine cape
pine cape
pine cape
glacial kernel
#

So it couldn’t see ReplicateLike

pine cape
glacial kernel
#

Yeah but if you insert deeper into the hierarchy the root never gets notified

#

So

E -> E1 -> E2

If you add a Child to E1 or E2, E will never have its Children changed, and so the root_query will not return it and thus children_query will not be used

slow kernel
#

how do you handle networking fps player/camera rotation inputs when cursor grab is active? can you get the BEI mouse motion value before a mock is evaluated that same frame? I basically just want to send the server the player rotation (yaw, pitch) after the mouse motion instead of the mouse delta to prevent any need for correction.

Edit: got this working through separate context schedules

unkempt sedge
unkempt sedge
#

@pine cape Any ideas on how I can map the entities inside a trigger message? Like this one , note when I add_map_entities to it, it only seens to affects the target entities the ones i point to in trigger_targets and not to the ones inside the message

#[derive(Event, Clone, Copy, Deserialize, Serialize, MapEntities)]
pub struct ChallengeSent {
    /// The entity who sent the challenge
    pub from: Entity,
    /// The entity who receives it
    pub to: Entity,
    /// The amount betted
    pub bet_amount: BetAmount,
}```
#

I can just check RemoteEntityMap and go for there, but I was wonmdering if I am missing something in the api

pine cape
#

Just deriving MapEntities and then calling add_map_entities in the protocol should work

#

When deriving MapEntities, you need to add the #[entities] to the fields that you want mapped. You should check the docs for MapEntities

pine cape
#

I'm wondering if it would not be easier to just merge the Interpolated, Predicted, Confirmed entities into one.

My main motivation would be to remove the need to have complicated entity mapping logic when a client sends a message to the server that mentions an interpolated or predicted entity.

Some possible questions:

  • how to handle despawns? What if the entity is predicted to be despawned?
    -> we already handle this by not actually despawning the entity but instead we temporarily disable it.
  • how do we distinguish between the confirmed and the predicted value of the component?
    -> I would say that in the immense majority of cases the user is interested in the Interpolated or Predicted value of the component and not the confirmed one. I think it's also extremely rare to need to have an entity be both Predicted and Interpolated at the same time. Therefore we could change the 'confirmed' value to be Confirmed<C> and the predicted/interpolated component to be simply C
#

Of course it would also be a massive breaking change, but it might make things easier in the long run

unkempt sedge
# pine cape I'm wondering if it would not be easier to just merge the `Interpolated`, `Predi...

The pointer components are very handy (predicted/interpolate), perhaps you should just make it so they are relationships?
For me it makes a lot sense to have distinct entities with their own components. For example: If i want interpolated transform i just query interpolated, how would i do that with this API I think it would be a little more dirty.
I also dont like the idea of centralization, but that is just my opinion.
The mapping used to be a pain in the ass but nowadays I wrapped my mind around it

pine cape
#

We would still keep the Interpolated, Predicted, Replicated marker components

#

so you can still query Query<&Position, With<Predicted>>

#

querying the confirmed component becomes harder, because you would do Query<&Confirmed<Position>>; but querying confirmed components seems to be pretty rare. I don't need it in any of the examples

unkempt sedge
#

Ah so the predicted entity/interpolated becomes the central point?

pine cape
#

Yes, basically. The confirmed components get added as special Confirmed<C> and the predicted or interpolated component value is just C (+ we add a Predicted or Interpolated marker)

unkempt sedge
#

not gonna lie

unkempt sedge
#

As currently it goes something like: predicted entity needs new visual -> send message to server -> mutate component -> from confirmed to predicted listen to mutations, do not create visuals for confirmed

pine cape
#

When you send message to server, you need to convert from predicted to confirmed, no?

#

Also we wouldn't need PredictionMode::Once or PredictionMode::Simple; maybe for those modes the component can be replicated directly as C instead of Confirmed<C>. Only for PredictionMode::Full or InterpolationMode::Full do we care about distinguishing between Confirmed<C> and C

unkempt sedge
unkempt sedge
pine cape
#

I can try to implement this in a branch and see what it looks like

pine cape
#

I published a new version 0.24.2 that contains recent bug fixes; it will be the last version before bevy 0.17

feral mirage
#

ah, for the BEI one only

#

no, wait, all subcrates are 0.24.2, but the metacrate (lightyear proper) and the workspace are on 0.24.0?

feral mirage
#
thread 'main' panicked at /home/hukasu/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/hashbrown-0.15.5/src/raw/mod.rs:797:9:
assertion failed: index < self.buckets()
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `lightyear_replication::receive::ReplicationReceivePlugin::apply_world`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
corrupted size vs. prev_size in fastbins

on 0.24

feral mirage
pine cape
#

Yes replicating the ClientOf or Client itself is not allowed rn

feral mirage
#

that worked on 0.23

#

it just created a new entity on the client

pine cape
#

Which shouldn't be the case, since Client and ClientOf are mapped

#

Maybe you're adding Replicate too early, before the mapping is done?

feral mirage
#

that is on 0.23

#

i'm adding OnAdd, Connected

pine cape
#

So you're replicating ClientOf, which creates a new entity on the client (in addition to the Client entity)

feral mirage
#

yes, the replicate-able components go into a distinct entity

#

on 0.23, 0.24 crashs

pine cape
#

In 0.24, the Client and ClientOf entity are already mapped. Can you try doing this after 1 second? To make sure the mapping is done

feral mirage
#

i was having an issue were 1 of the components would intermitently not replicate, after adding the Replicate earlier i haven't seen it happen

feral mirage
#

@pine cape is there anything that i can query to wait for the entity mapping?

pine cape
#

Right now, no, but we should add something

strong barn
#

@pine cape Interesting development:

Upgrading to the latest lightyear version almost** solves the input lockup. Here's what I'm noticing now:

Input no longer locks up for a long time, but now I am seeing 1-2 seconds at most of delayed input handling. Basically for half a second I see my player move based on very recent past inputs.

#

You can see there are some lockup stutters, but they are short-lived now.

It seems like the input is being handled later than when the input was sent, do you know why that would be the case?

#

im attaching a BEI input map to the Predicted player

feral mirage
pine cape
feral mirage
#

i'm having a problem now that i am replicating a relationship, but it arrives on the client before the entity that maps to the relationship is received

2025-09-17T14:01:45.911927Z ERROR lightyear_serde::entity_map: Failed to map entity 587v2#8589935179

so i would say the same thing about the ClientOf, only have the Replicating component added after the mapping is established

#

i added an arbritary 5 second delay on creating the relationship and it still failed to map, so there is something else on my ordering

feral mirage
#

@pine cape i saw on the ComponentReplicationConfig that you can have a compontent be registered, but not automatically replicated, so can you have a component on an entity with Replicate::new(NetworkTarget::All) but that one component be Replicate::new(NetworkTarget::Single(...))?

pine cape
unkempt sedge
#

@pine cape Is there a good trigger to check when server can start replicating an entity?

#

or can i just start replicating entities on startup?

#

Ah i found the started component

pine cape
#

I believe you can start replicating at startup, the server will start replicating only after Connected is added

pine cape
#

I'm working on adding some opiniated network UI to help debug

#

it's loosely based on the one from avian right now, but I want to improve it

unkempt sedge
pine cape
#

What performance egui? Bevy_metrics_dashboard?

unkempt sedge
#

yup

#

i do not vibe with that guy

feral mirage
#

iyes_perf_ui is kinda extensable, no?

pine cape
#

I'm using metrics and not Diagnostics, so I think it's easier to roll out my own

feral mirage
#

@pine cape are you sure that there is a mapping on the client between the ClientOf (on the server) and the Client (on the client)

#

this log is on the client

2025-09-18T15:47:09.603285Z ERROR lightyear_serde::entity_map: Failed to map entity 598v2#8589935190
2025-09-18T15:47:09.603469Z  WARN bevy_ecs::relationship: The psycho_core::player::PlayerOfClient(PLACEHOLDER) relationship on entity 450v2#8589935042 relates to an entity that does not exist. The invalid psycho_core::player::PlayerOfClient relationship has been removed.
#

598v2 is the id of the ClientOf on the server, and it does not exist on the client

pine cape
#

Yes; you can add logs in the system receive_sender_metadata to confirm

feral mirage
#

ah, yes, updating to 0.24 fixed

#

@pine cape after upgrading to 0.24 i started getting this crash on Netcode(0) only

thread 'Compute Task Pool (8)' panicked at /home/hukasu/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/hashbrown-0.15.5/src/raw/mod.rs:85:9:
Went past end of probe sequence
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `ReplicationSendPlugin::replicate`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
free(): double free detected in tcache 2
thread 'main' panicked at /home/hukasu/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/hashbrown-0.15.5/src/raw/mod.rs:85:9:
Went past end of probe sequence
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `lightyear_replication::receive::ReplicationReceivePlugin::apply_world`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
double free or corruption (!prev)
sonic citrus
#

if so I might ditch egui_plot for aeronet/visualizer

pine cape
pine cape
sonic citrus
#

Might switch to it in the future then. I'm kinda annoyed with bevy_egui

pine cape
feral mirage
#

@pine cape has anyone complained about a stack overflow on the server?

#
thread '<unknown>' has overflowed its stack
fatal runtime error: stack overflow, aborting
pine cape
#

Yes there is an issue open. Related to inputs?

feral mirage
#

the only difference between the previous commit and the current is bumping the version of lightyear to 0.24 and bei to 0.18

#

the server was open with just one client connected, and i was afk

pine cape
#

But where did it overflow, what is the stack trace

feral mirage
#

#1189344685546811564 message that is all that gets logged

#

i saw an issue about subtract with overflow, but not stack overflow

feral mirage
#

even with RUST_BACKTRACE=full the only log is those 2 lines

pine cape
#

Ah, I've never seen that stack overflow

split violet
#

How do you properly Replicate Components with Entities inside again? I couldn't find it inside the docs or examples. A hint do an example or docs would be sufficient 🙂. I can't find any myself. Do you map the entities manually via some external id? I thought I read something about some built-in map in lightyear somewhere before

pine cape
#

You just need that + your component must implement MapEntities

split violet
peak ice
#

Hey @pine cape I updated to the latest version of lightyear and my enemies are now 1) invisible when i spawn into the map 2) Show up when I walk into them 3) seem to have their positions between the server and client desynced because they are firing projectiles not from where they are at. Any ideas what changes would have caused this? (Enemies are interpolated)

pine cape
#

That's from 0.23 to 0.24?

peak ice
#

from 0.22

#

ive been gone for a while:(

pine cape
#
  1. seems expected; you probably make the enemy spawn a projectile as soon as the message is received, but instead the projectile should be delay-spawned to be on the interpolated timeline
#
  1. and 2) seem to be related to the visibility systems?
peak ice
#

Ok:) thanks for the help!

pine cape
#

Merged a first version of the debug UI

#

Each section is collapsible + you can filter by send or receive

slow kernel
#

nice that will be really helpful

unkempt sedge
hot cloud
#

Hello! I wanted to add an "Attack Hitbox" to my players to test the collisions of close combat weapons with enemies. Using the "avian_3d_ character" example, I added a child entity to the Character entity:

    // Edit of the `avian_3d_character` example.
    commands
        .spawn((
            Name::new("Character"),
            ActionState::<CharacterAction>::default(),
            Position(Vec3::new(0.0, 1.0, 0.0)),
            Transform::default(),
            Replicate::to_clients(NetworkTarget::All),
            PredictionTarget::to_clients(NetworkTarget::All),
            ControlledBy {
                owner: trigger.target(),
                lifetime: Default::default(),
            },
            CharacterPhysicsBundle::default(),
            ColorComponent(color.into()),
            CharacterMarker,
        ))
        // Attack Hitbox collider
        .with_children(|commands| {
            commands.spawn((
                Name::new("Character Attack Hitbox"),
                Transform::from_xyz(0.0, 1.0, 1.0), // offset in front of entity
                ColorComponent(RED.into()),
                AttackHitbox,
            ));
        });

    // Shared observer system to add Sensor and Collider:
    pub fn on_add_attack_hitbox(trigger: Trigger<OnAdd, AttackHitbox>, mut commands: Commands) {
        commands
            .entity(trigger.target())
            .insert((Sensor, Collider::cuboid(0.5, 1.0, 1.0)));
    }

However, the Hitbox Collider entity doesn't follow when the Character entity moves. I tried the same setup with Avian's character controller example (From Avian's github), and the Hitbox Collider followed its parent as I wanted.
Is this a difference in behavior due to how Lightyear handles things around Avian internally? Am I missing something obvious?

pine cape
#

I would try with self.update_syncs_manually=True to see if that works

pine cape
#

I made some progress on the projectiles example; I got linear-bullets shot by the current player working.
Next steps:

  • make sure that shots fired by remote players are replicated properly
  • bullets are currently Replicated individual entities. That's very expensive in terms of bandwidth, instead we want to just replicate the initial direction
stray sinew
#

I found this bug when I changed my entity hierarchy from using Prediction to using Interpolation.

Description:
ChildOf sync will fail randomly when adding interpolated entities to interpolated hierarchies. Some entities in both the Confirmed and Interpolated hierarchy will not have a ChildOf component while others will.

How to reproduce:

  • I did not register ChildOf in my protocol because it is already registered here:
    https://github.com/cBournhonesque/lightyear/blob/e86c042f497707a730480fac66298e20fd9f1041/lightyear_interpolation/src/plugin.rs#L173
  • In the StartUp schedule I made a "4 deep" hierarchy of entities that are interpolated to the client. (the client receives these correctly 100% of the time)
  • In a system that runs right after in the Update schedule, 16 new interpolated entities are added to the hierarchy and replicated to the client.
  • In the most recent test only 5 of those entities had a ChildOf component while the other 11 entities from both the Confirmed and Interpolated hierarchies are left orphaned for a total of 22 orphaned entities. This number seems to vary with the exact same build sometimes only 2 new entities had their ChildOf component.
GitHub

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

#

Relevant logs:

#

Just a guess, but maybe a child entity is replicated to the client before it's parent entity, making it's ChildOf component invalid and thus removed?

#

When I was making this with a Predicted hierarchy I would get the "Failed to map entity" errors but the ChildOf components were never removed.

pine cape
#

You're using InterpolationMode::Full?

#

Components are not synced from the Confirmed entity to the Interpolated entity right away, only when they have received 2 confirmed updates

#

ah my bad; it's mode Simple

#

Are you replicating all these entities in the same ReplicationGroup?

#

If not there is no guarantee that they will be replicated together, so the entity_map will fail for some of them

stray sinew
pine cape
#

aha yea i also always forget

unkempt sedge
#

@pine cape Mr Peri, how expensive would be to replicate 32 entities. That are not predicted or interpolated?

#

But all would have the component inserted into them immediatelly

#

guess i can find out here

pine cape
#

Cheap

unkempt sedge
stray sinew
#

When I spawn a predicted entity as a child of an interpolated entity, it gets placed in the confirmed hierarchy instead of the interpolated hierarchy. Is there a way to put predicted entities inside the interpolated hierarchy?

unkempt sedge
#

why would you make a predicted entity, a child to interpolated? Cant you just make a relationship

stray sinew
# unkempt sedge why would you make a predicted entity, a child to interpolated? Cant you just ma...

I making a solar system simulation, the planets are interpolated, and the child moons that orbit it are also interpolated. I want to spawn a predicted character as a child of the moon entity. The confirmed character is spawned correctly, but the predicted character is also in the confirmed hierarchy. I was wondering if there was a way to do this or if I should just implement my own system to set the parent.

unkempt sedge
#

Unless you want character to not inherit the moon transform

stray sinew
unkempt sedge
#

Hmm, i guess then all you need to do is move the ChilfOf component to the predicted entity

stray sinew
# unkempt sedge Hmm, i guess then all you need to do is move the ChilfOf component to the predic...

I already made a system that just swaps it to the interpolated hierarchy from the confirmed. I noticed this issue: https://github.com/cBournhonesque/lightyear/issues/1208 which would probably solve all of this so I'll just wait for it to be implemented.

GitHub

Currently we have the Confirmed entity (which is replicated from the remote peer) and then potentially 2 other entities: the Interpolated entity the Predicted entity I had separated these entities ...

pine cape
pine cape
pine cape
#

I've tried implementing the 1-entity solution. It removes so much code and complexity that i think i'm going to go ahead with it.

unkempt sedge
pine cape
#

we'll find another way 🙂

silent patrol
#

hi! I'm trying to debug why my server deployed to GCP suddenly stops responding to connect token requests. It lives for about 12h (sometimes less, sometimes more), and then incoming requests just time out during the TLS handshake:

curl -v https://gameserver.minecrawler.pp.ua:5001
* Host gameserver.minecrawler.pp.ua:5001 was resolved.
* IPv6: (none)
* IPv4: 35.208.181.89
*   Trying 35.208.181.89:5001...
* Connected to gameserver.minecrawler.pp.ua (35.208.181.89) port 5001
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* SSL connection timeout
* Closing connection
curl: (28) SSL connection timeout

On the server end, I can't see any error/warning logs, the process is still alive (though I just thought I need a another confirmation of that), but the timeout error suggests that the socket is still open at least (otherwise it would be a connection refused error).

This is not a lightyear specific issue, so apologies if is this off-topic, but I figured that some people in this channel go through this kind of setup and might be able to notice a problem in my code.

this is my gist of the code that serves http requests via hyper (I'm also using tokio_rustls here and executing tasks via Bevy's IoTaskPool through the async_compat layer), assume that the tls feature is enabled:
https://gist.github.com/vladbat00/6cac156f98c9dabe3706b7dceb9b2ca6

Any help or ideas would be much appreciated!

vagrant moth
#

Hello all 🙂

I hope it's the right place to ask questions, I'm trying to understand multiplayer in general and I'm trying to do a simple capsule FPS template (really basic).

https://github.com/ierezell/yolo

It works fine, player spawn, fall down a bit but when it collides with the ground, the capsule starts slight infinite boucing.
I've tried to add_should_rollback, damping etc... but nothing do.. I guess it's a problem of sync.

If anyone have any indsights, thanks a lot ! 🙂

stray sinew
vagrant moth
# stray sinew Also make sure you're only adding visuals to predicted entities here: https://gi...

For walls, floor etc.. yes it's only visual (meshes) on client side.
The functions are shared, so server will add it in non-headless/"visualization mode".

But from what I've read (and oh boy it's more complex than I thought), I could have client interpolating and server being authoritative for all the physics but it brings more input lag.

So what I'm trying here (if i'm correct...) is to also have the client run physics (so I'm adding my PlayerPhysicBundle in the client).

I've tried adding PredictionMode::Once and double checked the visuals but still, the capsule is bouncing (and so is the camera).
Server side, the position is stable everytick, but on the client Y is bouncing.

Thanks a lot for the fast answer and the feedback !
Edit: I'm pushing the comments as fast as I can so the repo is up to date

silent patrol
pine cape
vagrant moth
#

Thanks a lot for the help! I'm a bit less noon now

slow kernel
#

I'm trying to enable replication for a bunch of level entities that are spawned separately on client/server from a gltf scene at different times. I tried adding prespawned with a custom hash after it's loaded and have had partial success depending on ordering/timing, but it seems like it's not meant to be used the way I want. I'm basically trying to load the level on the server when it starts, but then let each client load it on their end when they connect and then map some of the entities for future changes. Can I just manually add the mappings on the client and have it replicate from then on or would it cause issues?

pine cape
#

Yes you can add the mappings on the client or on the server directly and it would work; but i'm also I'm modifying Prespawning so that it would work like you intended.
(i.e. you can add Prespawned on both the client and server entity, and then when you try to replicate it will just re-use the existing Prespawned entity instead of spawning a new one)

earnest fog
#

I'm getting an error I think because this line was removed in 0.24. Encountered an error in system <bevy_app::app::App as lightyear_steam::SteamAppExt>::add_steam_resources::{{closure}}: Parameter NonSend<SteamworksClient> failed validation: Non-send resource does not exist nvm. it's working on main

slow kernel
earnest fog
#

What's the best way to debug why a component is not replicated when it's set to PredictionMode::Once and InterpolationMode::Once? I don't ever see any logs on the server from lightyear_replication::send::sender when I create an entity with the replicated component

silent patrol
#

Oh, and I also wanted to trace-log what's happening on the hyper end. Because, effectively, it never writes the last response, and then the whole thing deadlocks somehow

silent patrol
#

My guess is that the auth example in the repo is also affected by the issue (haven't checked it though)

silent patrol
#

How does replicate_once work for immutable components? Will replaced components (i.e. inserted more than once) will also get replicated?

earnest fog
pine cape
unkempt sedge
#

@pine cape You know something that would be great for the api

#

Making it so rooms have native entity map, as I think that would avoid the whole lobby shenanigans.

pine cape
#

Can you elaborate?

unkempt sedge
#

honhon

pine cape
#

but what was your pain point?

split violet
#

I've been running into a weird issue in a setup with a fully server authoritative setup without any client side prediction etc. (only replicating to clients) everything works fine. Then I switch over to a HostClient setup (working fine) but then switching to a HostClient setup with a custom scheduler (using godot-bevy, which manually triggers FixedUpdate and Update based on external (godot) schedules) and then all of a sudden after a few seconds, it would seem like the replication on the <Replicated> entities break.

I've done extensive logging and it seems like this might be related:
15:11:25.443 D Setting the latest_tick Tick(172) to tick Tick(28388) because there hasn't been any new updates in a while @ src/receive.rs:
This happens right where the sync happens (the Replicated component gets stuck at the value) other events/messages still function (like despawning).

Now my question: I suspect that this is related to the Scheduling of replication and the TImeline, but in the host client mode both the server and client are using the same FixedUpdate (/Update) schedules, so I don't get why it would matter who often or when they are called (- as godot is controlling them).

My suspicion is that lightyear uses some other schedule internally for some replication tasks or timeline progression, which is not working correctly.

I understand that this might a bit vague but if someone has some insight it would be greatly appreciated as I spent a lot of time debugging this issue.

pine cape
#

Does custom-scheduler without HostClient work?

split violet
#

Yes, when I run the client through godot-bevy (which simply manually calls Update and FixedUpdate) and the server is using Bevy default scheduler, then it works. Even though this is the opposite of what I expected.

pine cape
#

Ok, and could you clarify exactly what is broken?
If I understand correctly you're using: Host-Client App that has a Server and a Client and uses godot-bevy + remote Client using godot-bevy.
And an entity is being modified on the Host-Client App but the updates are not replicated to the remote client?

split violet
#

No, it's simply a single client that also acts as a server. No other client. I'll make it little clearer:
I have:

- shared // this contains all server side systems and these act on FixedUpdate (or sometimes Update)
// the systems here only operate on entities Without<Replicated> to avoid running on Replicated entities in a HostClient scenario

- server // this wrapper that simply spawns a server entity and starts it, while using shared to authoratively control entities.

- client // the client contains 1. a godot-bevy version and 2. pure bevy version. The 2. version simply doesn't render anything.

Now when running in a server + client setup: both versions work. Server + Godot-Bevy Client (1.) and Server + Bevy Client (2.)

When running as HostClient, :

  • the server systems simply run inside the same bevy app as the client.
  • BUT: the pure bevy HostClient version works, while the godot-bevy HostClient version stops replicating some components after a seemingly random time.

I attached videos.
The server + client setup with both clients: -- This works fine
(bottom is server, top is client)
https://streamable.com/3286k7

Now HostClient:
The first start using cargo r is the pure bevy version
The second start using cd .. && godot is the godot-bevy version which breaks.
https://streamable.com/o3cab3

What to look for:
(here it breaks:)

// desync example in HostClient with godot-bevy version.
GODOT transform  : [336.74863, 212.15329, 0] // this is always coming from the client
new position in pathing: [471.8, 207.9] // this comes from the server

The client logs by quering for With<Replicated> entities and then logging the position.

#

Sorry if this is still messy.

split violet
#

I suspect that Setting the latest_tick Tick(172) to tick Tick(28388) because there hasn't been any new updates in a while @ src/receive.rs: might be a symptom as it seems to happen exactly when replication stops happening.

pine cape
#

So in your host-client setup, you only have a single App? You're not testing that updates are being replicated to another app?

#

Because in a host-client setup, there is no replication from the Server to the HostClient since they are both in the same app. I just add a Replicated filter for convenience, but it should be the same entity

split violet
pine cape
#

Yes, in a HostClient setup, if you add Replicate to an entity that is meant to be replicated to the HostClient, I just add Replicated on it since the server and the client are in the same App. There is no replication messages to be sent.

#

So should there be an entity with With<Replicated> and With<Replicate> at the same time, then?
Yes exactly

#

That's why i'm a bit confused that your Godot Transform doesn't match exactly the position in your host-client log

split violet
#

Wow, that's useful. But that makes my issue even more confusing to me.
I see this log:

GODOT transform  : [336.74863, 212.15329, 0] // this is always coming from the client
new position in pathing: [471.8, 207.9] // this comes from the server

Both are from the same entity 🙂 How can that be haha, I'm flabbergasted

pine cape
#

It is possible that I actually forgot to disable replication messages being sent from the HostClient Sender to the HostClient Receiver (which are the same entity, because a HostClient is a entity that has both Client and ClientOf)

split violet
#

But weirdly, my issue only appears after a while. It doesn't immediately break. (at least it seems that way)

pine cape
#

Should I clone the repo and add that filter locally and test again?

Sure, I would first enable lightyear_replication::receive=trace logs and check if you're receiving replication UpdatesMessage

split violet
#

like 15:11:25.416 T Received message "lightyear_replication::message::UpdatesMessage" on channel ChannelKind(TypeId(0xc099382d27579fd2a33001d7d7139452)) @ src/receive.rs:147
?

pine cape
#

yes

split violet
#

Yes, I do receive that.

pine cape
#

Is GodotTransform an equivalent of the bevy Transform? Is there a system that converts from your position to a GodotTransform? In which system set does it run

#

Still trying to understand how they could be out-of-sync when it's the same entity

split violet
#

I'm genuinely impressed by you @pine cape . That seems to solve the issue. HostClient and Client + Server both seem to work after testing the previously failing behavior successfully a couple of times.

#

It only cost me 2 days 🙂 , but as long as that solves it, I'm incredibly happy. Will you add those changes?

pine cape
#

aha well i'm pretty familiar with the code base; glad I could help!
I also tihs is pretty important since before we were wasting CPU time to write/read all these replication messages for the host-client

#

I will add these changes for bevy 0.17, if that's ok

split violet
#

Thanks again.

pine cape
#

Hm there will be one other big change; which I think will simplify things in the long run: the Confirmed/Predicted entities and Confirmed/Interpolated entities are now merged together

stray sinew
#

I have a question about deterministic prediction.
In the projectiles example, a bullet is spawned on the server with DeterministicPredicted and without Replicate.

Q1. If a bullet is spawned and then a second client joins later, wouldn’t that client not receive that bullet? My game has long-lived projectiles/entities, so late-join visibility matters.

Q2. In my setup, adding Replicate on the server gave me errors, so I switched to “no client spawning; server spawns with both Replicate and DeterministicPredicted,” which seems to work (though I'm not sure if there's desync with this). Is this the correct approach for long-lived projectiles? If not, what’s the recommended pattern (including for late joiners)?

pine cape
pine cape
#

Q1. OnlyInputsReplicated clients only exchange inputs and run the simulation deterministically based on that.

When a client joins late you have 2 options:

  • the new client receives a history of all inputs sent by all clients since the start of the game, and replays them. (in which case they would simulate the long-lived projectile that was shot before they joined). The issue is that it may take a while to simulate that
  • the server sends a one-time snapshot of the world, and then continues with input-only replication

I haven't tried any of those, but I guess what I could do is that when the client joins, the server would replicate to them all existing long-lived projectiles. (For that, you would have to also run the simulation on the server, which is possible since they receive all inputs)

Q2.What kind of errors did you get? I don't really understand what you meant by “no client spawning; server spawns with both Replicate and DeterministicPredicted,” .

split violet
stray sinew
# pine cape Q1. `OnlyInputsReplicated` clients only exchange inputs and run the simulation d...

Yes I was referring to OnlyInputsReplicated, sorry for not clarifying.

The error I was referring to happend when doing something like:

  • server: spawn(Replicate, DeterministicPredicted, missile_bundle)
  • client: spawn(DeterministicPredicted, missile_bundle)
    But the error was due to another part of my code.

For Q1, would doing something like:

app.register_component::<Position>()
    .add_prediction(PredictionMode::Full)
    .add_interpolation_fn(Position::lerp)
    .with_replication_config(ComponentReplicationConfig {
        replicate_once: true,
        disable: false,
        delta_compression: false,
    });
add_non_networked_rollback_systems::<Position>(app); // not sure if this is needed

Work as the server sending a snapshot of the current world?

#

So instead of having fully non-networked components you'd just have replicate_once and then its inputs only from there. I just tried it and it seems to be working.

unique plover
#

@pine cape got a strange one for you. I get a panic on the client when connecting if the server has somewhere between 467 and 471 total entities.

thread 'main' (612209) panicked at /home/brain/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/hashbrown-0.15.5/src/raw/mod.rs:85:9:
Went past end of probe sequence
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `lightyear_replication::receive::ReplicationReceivePlugin::apply_world`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
corrupted size vs. prev_size in fastbins

Debugging the stack seems to point to this line as the potential culprit:
https://github.com/cBournhonesque/lightyear/blob/0.24.0/lightyear_replication/src/receive.rs#L779
In my case these were the values that function was called with:
local_entity: 344v1
group_id: 4294967764

Running version 0.24.2

pine cape
#

These panics occur because we unsafely get the EntityMapper from the receiving Link entity. You probably have an observer that accesses the Link entity in some way which gives you undefined behaviour

#

Can you think of some observer you have on receiving a replicated component that could affect the Link entity or the EntityMapper?

pine cape
unique plover
#

I'm looking at observers that could have an effect on mapping too, but I'm not sure yet, could it be a mismatch in mapping from the server?

#

Oh interesting, I do see

2025-09-28T00:41:19.454174Z  WARN lightyear_serde::entity_map: Failed to map entity 334v1#4294967630

earlier in the log

unique plover
#

Looks like it might be because I'm replicating a player entity that has a ChildOf the client link so that it benefits from the despawn heirarchy when the client disconnects. I have disable replicate hierarchy on the player, but it must be picking up ChildOf anyway since it's on the entity directly.

#

I added ComponentReplicationOverrides::<ChildOf>::default().disable_all() so I can still have the player despawned by the client disconnecting and that seems to work.

unique plover
#

Oh I may not need parent/child here and may be able to use a custom relationship instead since I'm using ControlledBy.lifetime

unkempt sedge
#

@pine cape Does the remote trigger also work for local triggers? Does it also run trigger:Trigger<E>, or just Trigger<RemoteTrigger<E>>

unkempt sedge
#
fn handle_external_goto(trigger: Trigger<RemoteTrigger<GoTo>>, mut commands: Commands) {
    let message = trigger.event().trigger;
    commands.trigger(message);
}

fn handle_goto(trigger: Trigger<GoTo>, query: Query<&PlayerOfClient>, mut commands: Commands) {
    let message = trigger.event();

    let player = message.player;
    let room = message.room;

    let PlayerOfClient(client) = query
        .get(player)
        .expect("Player entity to be the only one teleporting and to have player of client");

    commands.trigger_targets(RoomEvent::AddSender(*client), room);
    commands.trigger_targets(RoomEvent::AddEntity(player), room);
    commands.entity(player).insert(CurrentLocation(room));
    debug!("Changing rooms!")
}```
Would things like this be necesary @pine cape
pine cape
#

Yes; it only triggers the RemoteTrigger for now

spice rapids
#

hey @pine cape , i've been messing around with the new debug ui (which is awesome, by the way). I noticed that in the avian3d example the rollback count seems to increase consistently (even when there are no inputs). is that expected or the sign of a possible bug? lmk if you'd like a video

pine cape
#

It's expected, the reason is that avian uses some internal resources to speed up collision computation such as CollidingEntities and ContactGraph.
These are not replicated, so the physics computed on the client will be slightly different than the ones computed on the server. I think a way to lower the amount of rollback is simply to set a higher tolerance on the should_rollback functions

#

Actually in the case of deterministic replication (in the deterministic_replication example), only inputs are replicated and there are no rollbacks, because we also rollback the local ContactGraph and CollidingEntities resources

#

Maybe we just need to enable this in the avian3d example to also set the number of rollbacks to 0

#

I didn't try it though

spice rapids
#

seems like that would cause desync, right? maybe unless we used avian's enhanced-determinism

#

maybe i'm missing something - still seeing about 10 rollbacks per second with a very large margin on the should_rollback functions

feral mirage
#

@pine cape how many LocalTimeline ticks in a second?

pine cape
#

LocalTimeline ticks once per FixedUpdate

unkempt sedge
#
fn buffer_rotation(
    q_camera: Query<(&Transform, &CameraMode)>,
    mut players: Populated<Entity, With<Action<RotateInput>>>,
    mut commands: Commands,
) {
    let (transform, camera_mode) = q_camera.single().expect("Camera to have a transform");
    // Only do this if in tps mode
    if camera_mode.ne(&CameraMode::Tps) {
        return;
    }

    // Ordering matters here
    let (yaw, pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
    for player in players.iter_mut() {
        // This creates a pseudo-action, that continouslys gets fired every state
        let action_mock =
            ActionMock::new(ActionState::Fired, Vec2::new(pitch, yaw), MockSpan::Manual);
        commands.entity(player).insert(action_mock);
    }
}

@pine cape Is this the only option when it comes to overriding actions? So we can input buffer unto client? It feels clunka, something more intuitive would it be to make it so action is capable of having quat I guess.

pine cape
#

I think you can override with action_state.set_axis_pair

spice rapids
pine cape
unique plover
#

@pine cape did you happen to take a look at BEI input replication for HostClient, yet? No worries since you're busy with Bevy 0.17. I can wait until the dust settles.

#

Just wondering if I should check the current state again now, or wait until after the 0.17 upgrades.

pine cape
#

probably wait until after 0.17

unkempt sedge
#

@pine cape Replicate like, on scenes are constantly warning that the global transform/visibility components are not available. I have no clue on why, as i do have transform synced

pine cape
#

I guess something in your hierarchy is missing GlobalTransform. You should inspect the sender or receiver hierarchy

unkempt sedge
#
    let parent_entity = commands
        .spawn((
            OverworldRoomMarker,
            Replicate::to_clients(NetworkTarget::All),
            Room::default(),
            Name::new("Overworld room"),
            identifier,
            Transform::from_translation(Vec3::new(1.0, 0.0, 0.0)),
            InheritedVisibility::default(),
            // We dont need the scene garbase, we can recreate on client!
            DisableReplicateHierarchy,
            Phase(RoomSpawned),
        ))
        .id();

    let child_entity = commands
        .spawn((
            OverworldSceneMarker,
            ChildOf(parent_entity),
            Name::new("Overworld scene"),
            Transform::from_translation(Vec3::new(1.0, 0.0, 0.0)),
            InheritedVisibility::default(),
            SceneRoot(gltf_handle),
            Replicate::to_clients(NetworkTarget::All),
            NetworkVisibility::default(),
            // The deal here is that blender doesnt let you have the same name, we are going to abuse that
        ))
        .id();```
The issue isnt that, is that when it arrives on client. It keeps saying this  2025-10-02T21:39:21.005827Z  WARN bevy_ecs::hierarchy: warning[B0004]: Entity 434v2 with the GlobalTransform component has a parent without GlobalTransform.
stray sinew
fading pilot
pine cape
#

In which cases do you need InputBuffers for a single player game? I think you can just use BEI directly

#

You can use VisualInterpolation (renamed into FrameInterpolation) by using lightyear_frame_interpolation directly

unkempt sedge
#

It is when the replicated child entities arrive on client, they seen to only arrive with their given transform

#

Maybe becasue the scene root loads too fast?

pine cape
#

GlobalTransform is probably only added on entities that are children of entities with GlobalTransform, you would have to add a custom observer

unkempt sedge
unkempt sedge
#

@pine cape Mr Peri on another matter, I was trying to make it so my scene entities are mappable between server and client. I was doing something like this (where i basically transfer well the components amongs the sister scenes)
But I believe i can just make my client scene unto the aligned with lightyear scene, any ideas on how I can do that? Maybe moving lightyears components might work (although i am unsure)

fn transfer_meshes(
    trigger: Trigger<SceneInstanceReady>,
    probable_kin: Query<(Option<&ChildOf>, Option<&Children>)>,
    children: Query<&Children>,
    names: Query<&Name>,
    mut commands: Commands,
) {
    let temp_scene = trigger.target();
    let repl_scene = probable_kin
        .iter_siblings(temp_scene)
        .next()
        .expect("Scene to only have the replicated scene as a brother");

    // Flatten the entities
    let mut hashmap = HashMap::new();
    for child in children.iter_descendants(temp_scene) {
        let Ok(name) = names.get(child) else {
            continue;
        };
        hashmap.insert(name, child);
    }

    for child in children.iter_descendants(repl_scene) {
        let Ok(name) = names.get(child) else {
            continue;
        };
        let Some(match_entity) = hashmap.get(name) else {
            error!(
                "Failed to find a matching entity via name on {} with {}",
                temp_scene, name
            );
            continue;
        };

        // commands.entity(*match_entity).move_components::<(
        //     Mesh3d,
        //     GltfMaterialExtras,
        //     GltfMaterialName,
        //     MeshMaterial3d<StandardMaterial>,
        //     Aabb
        // )>(child);
    }
}
pine cape
#

In the new version you can use the PreSpawned component to make sure that a server entity maps with a prespawned client entity

unkempt sedge
#

I was thinking I could just update the RemoteEntityMap

pine cape
#

No in the unreleased version for bevy 0.17

#

I'm almost ready for the upgrade, mainly waiting for avian/aeronet to upgrade

silent patrol
#

hi! does RemoteEntityMap contain only Confirmed entities?
or can I get a remote entity by passing a Predicted/Interpolated entity as well?

pine cape
#

It only contains Confirmed entities; this means that sending messages from client to server about a Predicted entity is pretty unconvenient, as you have to first map from Predicted to Confirmed.
This will be changed in the 0.17 release (which is almost ready) because the Confirmed and Predicted/interpolated entities are merged into one

unkempt sedge
#

what is your deal mr peri how in da hell you make 8 thousand lines of code in one to two days

pine cape
#

A lot of it is automatic refactors

pine cape
#

Hm i'm pretty happy about the merging of the Confirmed and Predicted entities, but it does some hard to fix problems

#

For example, when you first receive Position from the server, it is now inserted as Confirmed<Position>.
In the previous system:

  • Confirmed entity receives Position. Spawns a Predicted entity with the same Position. The entity appears at the correct spot.
    In the new system:
  • Entity has the Predicted marker and receives Confirmed<Position>. We add a RigidBody, which inserts Position::Default via required components. The entity appears at Position (0, 0) and is corrected to the Confirmed<Position>
#

I'm wondering if the solution might not be to insert BOTH Confirmed<C> and C on a Predicted entity.

  • C is present so observers/required-components would work correctly.
  • There is no old value in the PredictedHistory so we start with an initial rollback anyway
silent patrol
#

had to invent a bit silly SystemParam to map them without too much boilerplate in systems :D

#[cfg(feature = "client")]
#[derive(bevy::ecs::system::SystemParam)]
pub struct ServerEntityMapper<'w, 's> {
    message_manager: Single<'w, &'static MessageManager>,
    confirmed_query: Query<'w, 's, &'static Confirmed>,
    predicted_query: Query<'w, 's, &'static Predicted>,
    interpolated_query: Query<'w, 's, &'static Interpolated>,
}

#[cfg(feature = "client")]
impl<'w, 's> ServerEntityMapper<'w, 's> {
    pub fn get_server_entity(&self, client_entity: Entity) -> Option<ServerEntity> {
        let confirmed_entity = self
            .interpolated_query
            .get(client_entity)
            .ok()
            .map(|interpolated| interpolated.confirmed_entity)
            .or_else(|| {
                self.predicted_query
                    .get(client_entity)
                    .ok()
                    .and_then(|predicted| predicted.confirmed_entity)
            })?;
        self.message_manager
            .entity_mapper
            .get_remote(confirmed_entity)
            .map(ServerEntity)
    }

    pub fn get_client_entity(&self, ServerEntity(server_entity): ServerEntity) -> Option<Entity> {
        let confirmed_entity = self
            .message_manager
            .entity_mapper
            .get_local(server_entity)?;
        let confirmed = self.confirmed_query.get(confirmed_entity).ok()?;
        confirmed.interpolated.or(confirmed.predicted)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ServerEntity(Entity);

impl ServerEntity {
    #[cfg(feature = "server")]
    pub fn new(entity: Entity) -> Self {
        Self(entity)
    }

    #[cfg(feature = "client")]
    pub fn from_client_entity(
        client_entity: Entity,
        server_entity_mapper: &ServerEntityMapper,
    ) -> Option<Self> {
        server_entity_mapper.get_server_entity(client_entity)
    }

    #[cfg(feature = "client")]
    pub fn client_entity(&self, server_entity_mapper: &ServerEntityMapper) -> Option<Entity> {
        server_entity_mapper.get_client_entity(*self)
    }
}
#

and it works great

pine cape
#

that's pretty good!

pine cape
# spice rapids <@263123021336805376> any insights into what is causing these rollbacks?

Had a look into that, it's because there is no tolerance for visual_velocity and angular_velocity.
Adding

fn linear_velocity_should_rollback(this: &LinearVelocity, that: &LinearVelocity) -> bool {
    (this.0 - that.0).length() >= 0.01
}

fn angular_velocity_should_rollback(this: &AngularVelocity, that: &AngularVelocity) -> bool {
    (this.0 - that.0).length() >= 0.01
}

fixes the rollbacks

spice rapids
pine cape
unique plover
pine cape
#

I just tested on main

#

There are mapping errors but does the example work with host client?

unique plover
# pine cape I just tested on main

Ah, I think we lost some context from our conversation a while back. I meant specifically input rebroadcasting, not just replication. My mistake that I didn't include that in my more recent messages.

#

The BEI example does not do rebroadcasting.

#

Host-client actions are not replicated to clients, however rebroadcasting messages do work, and then you get the errors I'm seeing.

#

I'll try updating the example for rebroadcasting and report back though.

#

Yeah, adding rebroadcasting to the BEI example on main results in the same errors I'm seeing in my codebase.

pine cape
#

Thanks; fixed this for the next release in branch cb/confirmed-merge

spice rapids
#

Still having a weird issue with stuttering on the client controlled character, but i won't bug you about it until i have a better visual or more info

pine cape
#

In HostClient mode?

spice rapids
# pine cape In HostClient mode?

No, I have been launching three windows for testing:

cargo run -- server
cargo run -- client -c 1
cargo run -- client -c 2

Though I just checked and it seems to be there in hostclient mode too

#

@pine cape for some reason it's a bit harder to see in videos, but if you look at the top right (client 1) which is where i'm sending inputs, you can see it's kind of jittery, compared to client 2 and the server where it's basically perfectly smooth movement

spice rapids
#

Maybe related to this? seems like the position is moved backwards on the client

#

Server doesn't have this and is smooth (as expected). let me know what you think!

pine cape
#

Yes there's a problem in my branch, i'm not entirely sure what it is yet.
The deterministic-replication example is broken as well

#

The Last vs FixedLast is because of FrameInterpolation; Last interpolates between the last 2 FixedUpdate Positions.

spice rapids
#

or I suppose it would be Controlled vs not

pine cape
#

but yeah there's some tricky bug ..

spice rapids
pine cape
#

yea it's probable

pine cape
#

The non-deterministic bug doesn't happen every time, which is 100% the sign of a missing system ordering constraint

#

those are quite hard to find unfortunately

unkempt sedge
#

frame interpolation causes stuttering, no idea on why

#

I believe the intention was to migrate to avian interpolation or something like that

#

But the moment I remove it everything was equal and worked fine, but no stutter

#

magic i guess

spice rapids
#

@unkempt sedge I noticed that as well. I'm wondering if avian and lightyear are overwriting the positions in a weird order

unkempt sedge
#

the logic is full of rcs quite easy to be bugged so it is almost guaranteed I guess bevy should upscale a interpolation api sooner than later

pine cape
#

Are you using FrameInterpolation<Transform> ?

spice rapids
unkempt sedge
#

@pine cape Would there a problem to mark an entity as replicated before server actually being started?

#

just wondering if is something that was scoped

pine cape
#

No there shouldn't be any issue

pine cape
#

I think I fixed the deterministic replication bug.
For the avian_3d_character; does it look smooth to you with InputDelayTicks = 10?
It does look smooth to me. Which means that the problem is not related to FrameInterpolation, but to Prediction/Correction

strong barn
#

I noticed something kinda weird when trying to figure out the frame interpolation/client input lockup.

2025-10-06T20:04:06.505081Z  INFO bevy_vello::integrations::lottie::systems: animation controller transitioning to=down-stopped

thread 'Compute Task Pool (1)' panicked at /Users/simbleau/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/lightyear_interpolation-0.24.2/src/interpolate.rs:213:21:
assertion `left != right` failed
  left: Tick(5052)
 right: Tick(5052)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

thread 'Compute Task Pool (3)' panicked at /Users/simbleau/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/lightyear_interpolation-0.24.2/src/interpolate.rs:213:21:
assertion `left != right` failed
  left: Tick(5052)
 right: Tick(5052)
Encountered a panic in system `lightyear_interpolation::interpolate::insert_interpolated_component<avian2d::position::Position>`!
Encountered a panic in system `lightyear_interpolation::interpolate::insert_interpolated_component<avian2d::position::Rotation>`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!

I am getting this pretty commonly when a new client joins