#lightyear

14521 messages · Page 15 of 15 (latest)

pine cape
#

Do you run into bandwidth issues?

molten socket
#

Thanks for your insight, that’s an interesting organization. It seems that you prefer conditional compilation with feature flags so that client-specific, server-specific, and shared code can live side by side.
I have two questions for you:

  1. What about src/core/physics.rs? Does it contain anything that is specific to the client or the server?
  2. What do you put in src/core/protocol.rs?

I find it difficult to clearly define what the protocol really is when using lightyear. As I understand it, the protocol is all the structured information communicated between clients and the server. So what lightyear calls Messages are obviously part of it, but technically, replicated components are part of it too.
I imagine that for a large project like Computronium, protocol.rs doesn't actually contains every replicated components. Most of the time these components are not just "data to be replicated" since they are also part of the client/server logic.

plucky smelt
#

Ok I'm a little stuck. I have created the Client on the client, the NetcodeServer on the server, added MessageSender on the server and MessageReceiver on the client, registered my message, and created a channel for it. Yet my message is not being received on the client...

Client spawner:

  let auth = Authentication::Manual {
    server_addr: config.ip,
    client_id: 0,
    private_key: Key::default(),
    protocol_id: 0,
  };
  let client_addr = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 0);
  let client = commands
    .spawn((
      Client::default(),
      LocalAddr(client_addr),
      PeerAddr(config.ip),
      Link::new(None),
      ReplicationReceiver::default(),
      NetcodeClient::new(auth, client::NetcodeConfig::default()).unwrap(),
      UdpIo::default(),
      MessageReceiver::<ServerGreeting>::default(),
      MessageSender::<ClientReady>::default(),
    ))
    .id();
  commands.trigger(Connect { entity: client });

Server spawner:

  let server = commands
    .spawn((
      NetcodeServer::new(server::NetcodeConfig::default()),
      LocalAddr(SocketAddr::new(
        IpAddr::V4(Ipv4Addr::UNSPECIFIED),
        config.port,
      )),
      ServerUdpIo::default(),
    ))
    .id();

New client handler:

fn handle_new_client(event: On<Add, Connected>, mut commands: Commands) {
  commands.entity(event.entity).insert((
    MessageSender::<ServerGreeting>::default(),
    MessageReceiver::<ClientReady>::default(),
  ));

  let entity = event.entity;
  commands.run_system_cached_with(send_greeting, entity);
}
#

Is there some other step I'm missing?

#

I can see that my client is connecting, and I added a log that it's hitting the send.

#

I am seeing in my logs that I am sending my message before the connection is "confirmed". So maybe sending messages in On<Add, Connected> isn't allowed?

#

Nope looks like that's not it. I delayed the message by 1s (after confirmation) and it still wasn't sending the message...

molten socket
#

Did you put the right direction when registering the message?

#

I think you've already checked, but you never know..

#

I don't know if there is something weird on my end but I don't have to insert MessageSender and MessageReceiver components

#

they are already on the entities

plucky smelt
#

Yup! the channel directions look correct, as well as the message directions

#

Oh hmmm let me try removing those then

#

Oh interesting, yeah I can remove the inserts as well looks like. Still not receiving the message though :/

random palm
plucky smelt
#

AGHHHH Turns out the problem was I was putting my message listening systems in PreUpdate. Running them in Update fixes things. Maybe also just configuring them after the receive systems will be enough

#

Frustrating

#

Maybe MessageReceiver::clear_typed should add a log message that messages are being dropped?

unique plover
# molten socket Thanks for your insight, that’s an interesting organization. It seems that you p...
  1. What about src/core/physics.rs? Does it contain anything that is specific to the client or the server?

Yes, but only because we have a custom picking system to do physics-based "sub-picking", otherwise it's just shared setup, and done in core to load everything ahead of any gameplay systems.

This is physics.rs

use crate::prelude::*;
use bevy_tnua::prelude::*;
use bevy_tnua_avian3d::*;

pub(super) fn plugin(app: &mut App) {
    app.insert_resource(avian3d::physics_transform::PhysicsTransformConfig {
        transform_to_position: false,
        position_to_transform: true,
        ..default()
    });

    app.add_plugins(PhysicsPlugins::default().build()
        // disable the position<>transform sync plugins as it is handled by lightyear_avian
        .disable::<PhysicsTransformPlugin>()
        .disable::<PhysicsInterpolationPlugin>()
        .disable::<IslandPlugin>()
        .disable::<IslandSleepingPlugin>(),
    );

    // Tnua will run in rollback
    app.add_plugins(TnuaControllerPlugin::new(FixedUpdate));
    app.add_plugins(TnuaAvian3dPlugin::new(FixedUpdate));
}

#[cfg(feature = "client")]
pub(super) mod client_only {
    use avian3d::math::*;
    use bevy::{picking::{backend::{ray::RayMap, HitData, PointerHits}, PickingSystems}};

    use super::*;

    pub fn plugin(app: &mut App) {
        // Cameras also need to be marked PhysicsPickable
        app.insert_resource(PhysicsPickingSettings {
            require_markers: true,
        });

        // Custom physics picking system, reimplements PhysicsPickingPlugin from Avian
        app.init_resource::<PhysicsPickingSettings>();

        app.add_systems(PreUpdate, physics_picking_system.in_set(PickingSystems::Backend));
    }

    fn physics_picking_system(...) { ... }
}
unique plover
# molten socket Thanks for your insight, that’s an interesting organization. It seems that you p...
  1. What do you put in src/core/protocol.rs?

Add any plugins, register components, and I do some specific stuff for our mod synchronization systems using rooms. Pretty much anything lightyear related.

Here's a stripped-down version:

use crate::prelude::*;
use std::time::Duration;

use lightyear::{
    ...
};

pub(super) fn plugin(app: &mut App) {
    let tick_duration = Duration::from_secs_f64(1.0 / 64.0);

    // Server and Client plugins (must be first)
    app.add_plugins(server::ServerPlugins{ tick_duration });
    #[cfg(feature = "client")]
    app.add_plugins(client::ClientPlugins{ tick_duration });
    app.add_plugins(RoomPlugin);

    app.add_plugins(InputPlugin::<NetworkInputComponent> {
        config: InputConfig {
            rebroadcast_inputs: true,
            ..default()
        },
    });

    app.add_plugins(LightyearAvianPlugin {
        replication_mode: AvianReplicationMode::PositionButInterpolateTransform,
        ..default()
    });

    app.add_plugins(HierarchySendPlugin::<SomeRelation>::default());

    // Actions
    app.register_input_action::<SomeAction>();

    // don't know if this is still necessary, or a remnant from older versions

    app.register_type::<Actions<NetworkInputComponent>>();
    app.register_type::<ActionOf<NetworkInputComponent>>();

    // Channels
    app.add_channel::<UnorderedReliableChannel>(
        ChannelSettings {
            mode: ChannelMode::UnorderedReliable(ReliableSettings::default()),
            ..default()
        }
    ).add_direction(NetworkDirection::Bidirectional);

    // Events
    app.register_event::<SomeEvent>()
        .add_direction(NetworkDirection::ClientToServer)
        .add_map_entities();

    // Components
    app.register_component::<SomeComponent>();

    // These are the settings that I've found best for my use of Tnua

    app.register_component::<Position>()
        .add_prediction()
        .add_should_rollback(position_should_rollback)
        .register_linear_interpolation()
        .add_linear_correction_fn()
        .enable_correction();

    app.register_component::<Rotation>()
        .add_prediction()
        .add_should_rollback(rotation_should_rollback)
        .register_linear_interpolation()
        .add_linear_correction_fn()
        .enable_correction();

    app.register_component::<LinearVelocity>()
        .add_prediction()
        .add_should_rollback(linear_velocity_should_rollback);

    app.register_component::<AngularVelocity>()
        .add_prediction()
        .add_should_rollback(angular_velocity_should_rollback);
}

fn position_should_rollback(this: &Position, that: &Position) -> bool {
    (this.0 - that.0).length() >= 0.1
}

fn rotation_should_rollback(this: &Rotation, that: &Rotation) -> bool {
    this.angle_between(*that) >= 0.1
}

fn linear_velocity_should_rollback(_this: &LinearVelocity, _that: &LinearVelocity) -> bool {
    false
}

fn angular_velocity_should_rollback(_this: &AngularVelocity, _that: &AngularVelocity) -> bool {
    false
}

// there's also some modding specific workflow using lightyear rooms here, omitted for brevity

#[cfg(feature = "client")]
pub(super) mod client_only {
    use super::*;

    // I had some issues with my configuration of frame interpolation
    // and is commented out in my current version
    // so your mileage may vary
    use lightyear_frame_interpolation::FrameInterpolationPlugin;

    pub fn plugin(app: &mut App) {
        app.add_plugins(FrameInterpolationPlugin::<Transform>::default());
    }
}
unique plover
# molten socket Thanks for your insight, that’s an interesting organization. It seems that you p...

Most of the time these components are not just "data to be replicated" since they are also part of the client/server logic.

I'm handling this distinction using conditional compilation. I only register and replicate components that need to be replicated. I use conditional compilation to handle anything else - including changing required components based on client/server distinction.

You can even get really crazy with cfg_attr and have multiple required component definitions that will be merged.

#[derive(Component, Debug, Reflect, Serialize, Deserialize, Clone, PartialEq)]
#[reflect(Component)]
#[cfg_attr(feature = "dev", require(
    Name::new("Avatar"),
))]
#[cfg_attr(feature = "client", require(
    Visibility::default(),
    bevy_tnua::TnuaAnimatingState::<PlayerAnimationStates>::default(),
))]
#[require(
    Position::new(get_random_vec3(Vec3::new(-5.0, 10.0, -5.0), Vec3::new(5.0, 10.0, 5.0))),
    RigidBody::Dynamic,
    Collider::capsule(0.3, 0.8),
    LockedAxes::ROTATION_LOCKED,
    Transform,
    SleepingDisabled,
    BlockingComponent,
    WallBlockingComponent,

    TnuaController,
    TnuaAvian3dSensorShape(Collider::sphere(0.1)),
    InputAccumulationComponent,
)]
pub struct AvatarComponent {
    pub avatar_color: Color,
}
molten socket
molten socket
unique plover
# molten socket Wow! Thank you for taking the time to answer me. In my case, I think I will try ...

Correct, all components are defined in src/data/components.rs. This isn't a permanent rule for us though. We may split the file into multiple inside of the src/data directory. It will be loaded the same way though.

The crate prelude in src/lib.rs manages visiblity for all the stuff in data so every component doesn't have to be specified as a use ... in all the systems.

in src/lib.rs

extern crate self as computronium;

use bevy::prelude::*;

mod core;
mod data;
mod systems;

...

pub(crate) mod prelude {
    pub use super::data::exports::*;

    pub use avian3d::prelude::*;
    pub use bevy::prelude::*;
    pub use lightyear::input::bei::prelude::*;
    pub use lightyear::prelude::*;
}

src/data/mod.rs

use crate::prelude::*;

mod actions;
mod components;
mod events;
mod states;

pub mod exports {
    pub use super::{
        actions::*,
        components::*,
        events::*,
        states::*,
    };
}

pub(super) fn plugin(app: &mut App) {
    app.add_plugins(states::plugin);

    #[cfg(feature = "client")]
    app.add_plugins(client_only::plugin);

    #[cfg(feature = "dedicated_server")]
    app.add_plugins(ds_only::plugin);
}

#[cfg(feature = "client")]
#[path = ""]
mod client_only {
    use super::*;

    pub fn plugin(app: &mut App) {
        app.add_plugins(states::client_only::plugin);
    }
}

#[cfg(feature = "dedicated_server")]
#[path = ""]
mod ds_only {
    use super::*;

    pub fn plugin(app: &mut App) {
        app.add_plugins(states::ds_only::plugin);
    }
}
molten socket
unique plover
# molten socket Thanks :D Does your game support a single-player mode? If so, I suppose that you...

Does your game support a single-player mode?

Single player is just connecting to a local lightyear server. There was a configuration we had in the past that wouldn't even attempt to create the socket, but that hasn't been patched on our end since the last major upgrade to lightyear.

If so, I suppose that you need both the client and dedicated_server features to be enabled when building the client binary.

Nope, "server" code is available to the client for peer based networking, but dedicated_server code is specific to a headless server. We have states for making the server standby and a custom runner to limit the tick rate.

Also, with your architecture, it seems that splitting the project into multiple crates wouldn’t be easy

Probably not, but I do have separate macro crates for both procedural and declarative macros. I don't foresee a necessity to make more crates in this repo personally. Anything that would be a shared library with other games would live in a different repository completely and then would become a dependency.

By the way, did you encounter any complication with this architecture (e.g. compilation time)?

This is hard to quantify. I don't have any equally scaled projects to check against. A majority of the compilation time is dependencies from a fresh build, and we use bevy dylib to cut down on incremental compilation time. I imagine you could use hot patching to avoid most of the compile time we experience.

We don't hot patch (yet) because we like to run in debug mode. That's a whole separate topic that I have done a lot of work to optimize.

molten socket
# unique plover > Does your game support a single-player mode? Single player is just connecting...

Single player is just connecting to a local lightyear server.
Currently, I use crossbeam channels to communicate with the internal server, which is a headless bevy app launched in a separate thread.

I don't foresee a necessity to make more crates in this repo personally. Anything that would be a shared library with other games would live in a different repository completely and then would become a dependency.
Yeah, I can understand that. From what I understand, splitting a large project into separate crates can help with compilation times, since different crates can be compiled in parallel.

This is hard to quantify. I don't have any equally scaled projects to check against.
Fair 😅

We don't hot patch (yet) because we like to run in debug mode.
If I recall correctly, hot patching doesn’t work well with workspaces, so that’s actually a plus for your architecture 😄

unique plover
# molten socket > Single player is just connecting to a local lightyear server. Currently, I use...

hot patching doesn’t work well with workspaces

This could probably be worked around by using just conditional compilation with a main.rs instead of a library crate and separate bin files. This organizational pattern wouldn't see much change otherwise I don't think.

Edit: Oh wait, you mean workspaces with the other organizational patterns. Yes, this would be a bonus to my pattern. You do need to adapt it to not be a library crate though since that won't work with current hot patching.

unique plover
fallen path
#

Hello, i'm running some lightyear examples, and I can't seem to figure out how to select a particular transport.
I skimmed through the book and examples but couldn't find an answer.

quasi hare
#

Hi, I'm want to use .glb model of a map for the game with lightyear. But I have problem with headless mode and with Replicating of the collider.

So ColliderConstructorHierarchy doesn't work in headless mode. Is there some other way to get collider from custom model and replicate it to client?

    commands.spawn((
        SceneRoot(assets.load("maps/playground.glb#Scene0")),
        RigidBody::Static,
        ColliderConstructorHierarchy::new(ColliderConstructor::ConvexHullFromMesh),
        Name::new("Floor"),
        Replicate::to_clients(NetworkTarget::All),
        FloorMarker,
    ));
unique plover
# quasi hare Hi, I'm want to use .glb model of a map for the game with lightyear. But I have ...

I wouldn't replicate a collider or anything that would be only on the client. I would replicate a marker component (I guess in this case it might be FloorMarker?) and then have an observer watch for when that is created on the client and attach your colliders then using the following:

commands.entity(trigger.entity).insert((
    ColliderConstructorHierarchy::new(ColliderConstructor::ConvexHullFromMesh,
    // other components here to add on the client...
));

I believe this is referred to as the "blueprints" pattern.

You could also do something like what I mentioned in an earlier message using required components and conditional compilation to have components attached in a client-only context.
#1189344685546811564 message

fallen path
molten socket
#

I’m trying to make clients predict their own character locally while interpolating other characters. I’m using avian3d.
Since I can’t figure out how to make this work properly in my project, I’m trying to make the avian_3d_character example use this behavior instead.

Am I right in thinking that I need to replace PredictionTarget::to_clients(NetworkTarget::All) with PredictionTarget::to_clients(NetworkTarget::Single(client_id)) and also add InterpolationTarget::to_clients(NetworkTarget::AllExceptSingle(client_id)) in server::handle_connected?
I’ve also replaced Added<Predicted> with Added<Replicated> in client::handle_new_character.

#

First I launch the server:

#

then connect the first client: (no problem)

#

then the second client and things start to get weird

#

I can also end up in this situation by connecting/disconnecting the client in specific order

pine cape
#

Yes that's the idea, I think the simple_box example does that: predict your own player and interpolate others

molten socket
# pine cape Yes that's the idea, I think the `simple_box` example does that: predict your ow...

yep, I’ve already looked at simple_box to adapt avian_3d_character. I think my issue is that simple_box relies on gizmos for rendering and also doesn’t use Avian.
The "bug" where a client can’t see both characters can be "fixed" by moving the character on its own client. Once that happens, it suddenly appears on the other client.
It feels like some component is missing or not initialized when it's first spawned.

pastel palm
#

@pine cape I have a fork that has multi transport capabilities worked out. If you are interested I can make a pr 🙂 It works with all transports but I'm unfamiliar with using steam in that manner or if that would be desired to have as well so I left it out for now.

pine cape
pastel palm
# pine cape sure i'm interested; what kind of changes did you make? Maybe just share a first...

Sorry for the delayed reply kid had me pretty busy yesterday. The main change is separating the logical server from the transport layer. I went over your notes in the issue on github and decided to approach it the same way, which aligned pretty closely to how mirror/fishnet and other libs handle it.

Instead of the server being tied to one transport, you spawn a single Server entity, then spawn separate transport entities (UDP, WebTransport, WebSocket) that all point to it via TransportOf::new(server).

When clients connect, I had lightyear add a ViaTransport component to each client link entity - this tells you which transport they came through. I used this to name players by their transport ("UDP", "WT", "WS") and assign different colors.

For network clients (UDP/WS/WT) you use the full transport stack with NetcodeClient, ClientUdpIo, etc. For host-client mode (server + client same app), the client just spawns with LinkOf { server } pointing directly to the server - no transport components needed.

I will get a first draft version worked out I wanted to make sure this had nearly complete code coverage before even mentioning it lol I'm still going over each example to test for functionality and the lightyear tests all seem to pass.

#

It also required a change to how we checked for started since the server technically is not really a netcode server itself any more and had to insert that component manually. So when we trigger Start on the transport entities, Started gets added to them, not to the Server entity.

for example:

fn handle_connected(
    trigger: On<Add, Connected>,
    client_query: Query<(&RemoteId, &LinkOf, &ViaTransport), With<ClientOf>>,
    ...
) {
    let Ok((remote_id, link_of, via_transport)) = client_query.get(trigger.entity) else { ... };
    let server_entity = link_of.server;
    
    // Use ViaTransport to identify the transport
    let player_name = transport_names.get(via_transport.transport)
        .map(|n| /* ... determine UDP/WT/WS from name */ )
}```
#

that part is was mainly just a poc and functionality check.

pastel palm
#
commands.entity(server).insert(Started);```
stray sinew
# random palm Im not sure, when there is more than 100+ zombies, remote server lags, but in lo...

First, figure out whether the lag is network-bound or simulation/physics-bound.

  1. Network vs sim
  • Run the client with the lightyear/debug feature enabled and watch the traffic stats.
  • If received bytes are low during the lag, it’s likely not the network, it’s probably your physics/simulation work.
  1. If it’s simulation/physics
  • Add timing logs around your physics loop (AI/pathing/distance calcs) to pinpoint what’s taking time.
  1. If it’s network-related
  • Lower TPS
  • Send targets less often: instead of updating zombie position every tick, update the goal/target every N ticks or on ticks with special events. On the client, move zombies toward that target using the same movement rules as the server (so visuals stay consistent).
    You can keep a non-replicated “visual/estimated position” component client-side while the server maintains the authoritative position.
  • Visibility System: only replicate the closest N zombies (or those within a radius), and stop sending updates for the rest.
muted relic
#

Does anyone know if lightyear supports avian3d with the f64 feature? If I use the f64 for avian3d, it seems that both f32 and f64 are used, because the "avian3d" feature in lightyear seems to use f32, so I get conflicts.

[dependencies]
bevy = "0.17.3"
lightyear = { version = "0.25.5", default-features = false, features = [
    "client",
    "server", 
    "netcode",
    "replication",
    "udp",
    "leafwing",
    "avian3d",
] }
lightyear_frame_interpolation = "0.25.3"
avian3d = { version = "0.4.1", default-features = false, features = [
    "3d",
    "f64",
    "parry-f64",
    "parallel",
    "serialize",
    "collider-from-mesh",
    "debug-plugin",
    "default-collider",
    #"xpbd_joints",
    "bevy_scene",
    #"bevy_picking",
]}
leafwing-input-manager = "0.19"
clap = { version = "4.5.53", features = ["derive"] }
serde = "1.0.228"
├── avian3d feature "f32"
│   └── avian3d feature "parry-f32" (*)
├── avian3d feature "f64"
│   └── avian3d feature "parry-f64" (*)
├── avian3d feature "parallel"
├── avian3d feature "parry-f32" (*)
├── avian3d feature "parry-f64" (*)
└── avian3d feature "serialize"
opaque wing
#

I'm the author of bevy-tnua, and I've just released version 0.27. This version is a big refactor, and one of its implications is that TnuaController can now be serialized and deserialized (TnuaGhostOverwrites too, if you use ghost sensors)

I understand that the inability to do so was what stopping Tnua from being used with Lightyear. So it should work now. I haven't tested it myself (I don't really do networking) but I know that this topic was brought several times both here and in Tnua's own channel (thread, really) so I'm sure some of you will want to try it out - can you please tell me if it works? If not - I'm willing to try and assist on my side.

Please note that in order to make TnuaController serializable and deserializable, you need to:

  • Turn on the serialize feature in bevy-tnua.
  • Use #[scheme(serde)] when deriving the control scheme.
  • #[derive(Serialize, Deserialize)] on the control scheme (Tnua's own derive macro cannot automate this for you)
north skiff
#

using the native input handling, how would I best go about transforming a picking event such as On<Pointer<Click>> to an action?

#

do I just turn it into a buffered event or so? maybe just write to a resource I can read from, since I won't be needing to process more than one per frame?

north skiff
#
fn buffer_action(
    mut player: Single<&mut ActionState<Action>, With<InputMarker<Action>>>,
    mut current_action: ResMut<CurrentAction>,
) {
    player.0 = current_action.0.clone();
    current_action.0 = Action::None;
}

I guess this works.

pine cape
# pastel palm Sorry for the delayed reply kid had me pretty busy yesterday. The main change is...

Yes separating the transport-server layer from the logical server layer seems ideal to me!
The one thing i'm wondering is if we still need to make everything entitified.
In 99% of cases users would only want a single Server entity, in which case the Server logically oversees all the Link entities in the app, and we wouldn't need to check for ViaTransport. But that's an even bigger change..

pine cape
opaque wing
# pine cape Thanks, will check it out! The `TnuaController` is the only thing that needs to ...

Yes - unless you are using TnuaGhostOverwrites, in which case you need to synchronize it as well. The other important components Tnua uses don't need synchronization:

  • The sensors and trackers don't need synchronization because Tnua will just read into them from the physics engine which should already be synchronized.
  • The motor does not need synchronization, because the controller overwrites its state every single frame.
#

Though... I think I messed up a bit. I've skipped some of the fields in the controller, reasoning that there is no need to synchronize them: https://github.com/idanarye/bevy-tnua/blob/b56c4c0c1bb262bc607f9a33d33f1b897869ff43/src/controller.rs#L153-L163
But... now that I think about it, if the controller is serialized as a whole, this just means that they'll be set to their default! This is bad.

GitHub

A floating character controller for Bevy. Contribute to idanarye/bevy-tnua development by creating an account on GitHub.

#

I'm mainly concerned about these two fields:

  • sensors_entities is a struct which holds Entity fields. Can Lightyear synchronize Entity values? Do I need to do something special to support this?
  • config holds an Handle. Can Lightyear synchronize these? Unlike entities, Bevy does not implement Serialize/Deserialize on handles even when the feature flag is enabled.
    If it's possible to synchronize without adding a dependency on Lightyear then I can make a bugfix. If not, I'll have to move them outside the controller which means a new release.
plucky smelt
#

Does lightyear have any infra for debugging mispredictions? I'm trying to network bevy_ahoy, and am currently just logging everything on the server, logging mispredictions on the client, and then manually trying to match them up and find where things are going wrong.

#

I'm currently thinking about having the client send a message to the server with a bunch of debug data for a replay of a rollback, keeping a buffer of debug data on the server, and then when the server receives one of these replay rollbacks, automatically align and diff them. That's a lot of infra though so I'm hoping there's existing tooling here?

#

In theory this could also be a crate all on its own

#

Honestly the main thing that would be annoying is just building the server-side state buffer, since we need to do like a rolling purge or something.

sudden bridge
#

Hey all, running into an issue that I can't quite figure out, and wondering if anyone has encountered something similar.

For some reason, a system that I have that runs in FixedPostUpdate, right after the PhysicsSystems, seems to be running faster on the Client than it does on the Server. It looks like the LastPhysicsTick on the client generally outpaces the server, despite both the client and the server having the same fixed timestep and both using PhysicsPlugin during FixedPostUpdate. If anyone has any ideas, I'd really appreciate it!

opaque wing
muted relic
# pine cape sorry maybe this fixes it? https://github.com/cBournhonesque/lightyear/pull/1371

It fixes the conflict, however I get this error (at least when compiling my project):

error[E0277]: the trait bound `DVec3: From<Vec3A>` is not satisfied
   --> C:\Users\Rask\.cargo\git\checkouts\lightyear-16a1ca81dacb5ed5\c8a0dce\lightyear_avian3d\..\lightyear_avian\src\correction_3d.rs:143:63
    |
143 |                 &Position(visual_correction.error.translation.into()),     
    |                                                               ^^^^ the trait `From<Vec3A>` is not implemented for `DVec3`
    |
    = help: the following other types implement trait `From<T>`:
              `DVec3` implements `From<(DVec2, f64)>`
              `DVec3` implements `From<(f64, f64, f64)>`
              `DVec3` implements `From<BVec3>`
              `DVec3` implements `From<BVec3A>`
              `DVec3` implements `From<IVec3>`
              `DVec3` implements `From<Matrix<f64, Const<3>, Const<1>, S>>`
              `DVec3` implements `From<OPoint<f64, Const<3>>>`
              `DVec3` implements `From<Translation<f64, 3>>`
            and 4 others
    = note: required for `Vec3A` to implement `Into<DVec3>`
    = note: the full name for the type has been written to 'C:\Users\Rask\Documents\GitHub\space_western\target\debug\deps\lightyear_avian3d-cae87f3e37112bfa.long-type-7378993982440218206.txt'
    = note: consider using `--verbose` to print the full type name to the console
For more information about this error, try `rustc --explain E0277`.

swapping the .into() for .as_dvec3() like this seems to do the trick&Position(visual_correction.error.translation.as_dvec3())I am not sure if this causes any complications, but it seems to work

opaque wing
random palm
#

how can i replicate Transform only once ? When the entity is spawned

random palm
#
2026-01-05T20:40:49.551077Z  WARN bevy_ecs::hierarchy: warning[B0004]: Entity 1091v361 with the GlobalTransform component has a parent (522v8) without GlobalTransform.
#

Getting this error kind of annoying

#

I spawn a SceneRoot as children to replicated entity

pine cape
pine cape
# sudden bridge Hey all, running into an issue that I can't quite figure out, and wondering if a...

Hm maybe LastPhysicsTick and Time<Physics> need to be added to the list of resources to rollback here? https://github.com/cBournhonesque/lightyear/blob/c3c6150cf542762e99b767067366168a7483e1b7/lightyear_avian/src/plugin.rs#L299
Could you try that?

GitHub

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

pine cape
sudden bridge
pine cape
#

How fast is the client outpacing the server?
To keep the client and server timelines in sync, the client slightly slows down or speeds up to stay close to the server. So if it's only going up to 5-10% faster it can be expected

sudden bridge
#

Well the weird thing about it is that I see it happen even before the client has actually connected to the server, even though PhysicsPlugins are added in a shared plugin, and I use a single const tickrate when building Lightyear's server and client plugins. I'm sure it's some bug on my end, just not really sure what I did to make that happen

opaque wing
random palm
#

how can i calculate delta_secs using localtimeline's tick ?

#
2026-01-08T10:51:29.894527Z ERROR lightyear_deterministic_replication::checksum: Checksum mismatch from client RemoteId(Netcode(2588418976474603113)) at tick Tick(3423): expected bb8c9df5f7b87b17, got 23c720cc8538a715
random palm
#

I'm trying to make deterministic prediction but hashes in server and client are different somehow

161010383619278091)) at tick Tick(9597): expected d6f5011c0a62eb29, got 8aaae8d262dc4bb6
2026-01-08T11:13:11.895257Z ERROR lightyear_deterministic_replication::checksum: Checksum mismatch from client RemoteId(Netcode(17161010383619278091)) at tick Tick(9598): expected d6f5011c0a62eb29, got 8aaae8d262dc4bb6
2026-01-08T11:13:12.062390Z ERROR lightyear_deterministic_replication::checksum: Checksum mismatch from client RemoteId(Netcode(17161010383619278091)) at tick Tick(9600): expected d6f5011c0a62eb29, got 8aaae8d262dc4bb6
#

this error happens if i use

InputTimelineConfig::default().with_input_delay(InputDelayConfig::no_prediction())
#

and rollbacks not working

pine cape
random palm
dense lantern
#

I'm sharing my experience with lightyear:
Using the provided generate.sh for the cert was greeting me with a panic: "failed to parse private key as RSA, ECDSA, or EdDSA") ; I noticed it was working when using the self signed from examples, so I wrote a script to use that approach: https://gist.github.com/ThierryBerger/c905fcec169a1e706865e87947f0ce84

pine cape
#

Weird, the script works for me. But I like your rust version better! Would you mind submitting a PR with it?

dense lantern
#

wip but serves as a discussion starters as well as sharing incorrectly(?) generated certificates

#

the ci is also currently broken which is a bit of a « bad look » for a crate with such hard work gone into it 🙂 ; let me know if you'd welcome PRs to fix it, and if you have some insights on particular difficulties to it

inner hill
#

does lightyear overwrite Time::<Fixed>?

#

trying to configure my fixed timestep right now, but it keeps getting reset by something

plucky smelt
#

(it works even if I change the tick_duration to 1.0/10.0)

inner hill
#

no I'm just inserting a resource at the start, its just not being respected and I can't figure out why

#

I set it to 1.0 delta, but when i checked in game it was still 0.017

#

I vendored my dependencies and lightyear seems like the main one that might do something, but I haven't looked too deep into it yet

plucky smelt
random palm
#

When i try to interpolate 50+ entities, some of the entities not updated

plucky smelt
#

It looks like lightyear is automatically replicating children of my player (including its mesh). Is there a way to disable that? I only want the root player entity to replicate, and maybe manually mark some children that they also need to replicate

unique plover
plucky smelt
unique plover
pine cape
random palm
#

Is there a way to send inputs from server to client with bei implementation ?

#

also can we set a setting to not send not state affecting inputs like 0,0 movement input

wicked oak
#

HOLD ON a minute i tought periwink was a spider on pfp, now i see its a cat

sharp raptor
#

Hey hey, I was wondering if there's a recommended way for a client to disconnect itself?

Currently I'm sending a request to the server to disconnect. The server then inserts Disconnected on that client entity. However, when I then attempt to reconnect with the same client, the server spawns a new LinkOf, while the old Disconnected one still exists, which gives me the following warning:

Netcode error: ClientIdInUse(Netcode(3))

Should I be despawning the old entity after the client has disconnected? It feels more intuitive that the old one is simply changed back to a Connected state.

I've also tried triggering Disconnect on the client, but that leaves the same client still Connected on the server

Error receiving UDP packet: An existing connection was forcibly closed by the remote host. (os error 10054)

sharp raptor
random palm
#

@pine cape is there a way to delta compress position and rotation ? also is there a way to disable sending empty inputs ?

pine cape
#

If you use BEI, inputs are not sent when the context is disabled

#

I think both position/rotation already implement Diffable

random palm
random palm
#

is there any predicted despawn component ?

peak ice
#

did something change for leafwing inputs? I recently update to the current git version, and im getting errors with

app.add_plugins(leafwing::InputPlugin::<PlayerActions> {
    config: InputConfig::<PlayerActions> {
        rebroadcast_inputs: true,
        ..default()
    },
});
pine cape
#

What kind of errors? Lightyear might not be compatible with the latest leafwing version, I haven't upgraded to 0.18

pine cape
peak ice
#

also when tryin go figure out in a system whether it is the server or client

has_server: Single<Has<Server>,Without<ClientOf>>,

seems to make systems be skipped, does anyone have a full proof way to check if its a server or client in a system

silent patrol
pine cape
#

I'm preparing a branch now; the tests pass but for some reason things are not displayed on screen when i run examples

#

I wonder if there's some feature name that changed

pine cape
#

@silent patrol released 0.26!

potent canopy
#

is it just me? i cannot compile lightyear with bevy 0.18.0.

#

i tried clearing cargo cache, cargo.lock, cargo clean. none of that worked

#

lightyear version is 0.26.0

#

oh nvm

#

it suddenly works

#

i probably did something wrong

silent patrol
# pine cape <@223375442369970178> released 0.26!
[[package]]
name = "lightyear"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "215fe4678b72af3e6e34a3d9605a5b96685666df408e9d0ad685ab02a6815142"
dependencies = [
 "aeronet_io",
 "bevy_app 0.17.3",
 "bevy_ecs 0.17.3",

Seems like lightyear is still pulling some bits of Bevy 0.17

#

Seems like it's pulling Bevy 0.17 because of bevy_web_keepalive

potent canopy
#

Compiling lightyear with only default features works.
But when I enable avian3d feature it doesn't.

#

Oh wait. Even when it compiles, two different bevy versions are used.

silent patrol
stiff quiver
pine cape
#

Thanks, will push an update tonight

pine cape
#

actually i need the new version of bevy_web_keepalive to be released first

#

maybe the easiest is to just vendor it

silent patrol
#

thanks for the patch!

#

@pine cape oh you still have bevy_web_keepalive in the dependency list, which keeps pulling bevy 0.17 :D

#

from my Cargo.lock:

[[package]]
name = "lightyear"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9210597b60f7a3787fec3f4b07782861f3c1b1a5e19056f4f0ff260f8e193990"
dependencies = [
 "aeronet_io",
 "bevy_app 0.18.0",
 "bevy_ecs 0.18.0",
 "bevy_web_keepalive",
pine cape
#

i'm not sure how that's possible.. cargo tree | grep bevy_web_keepalive or cargo tree -i bevy_web_keepalive returns nothing for me

#

published another update; tat one should be good :p

wet pine
#

Is there a minimal example which has both a client and server running at the same time?
I'm trying to make a client-hosted server, but would rather be consistent and use the same messaging interface for the "local player", even in singleplayer.
I tried looking at the lobby example on github but there's so much going on in there.

silent patrol
autumn furnace
#

is there an example for mapping entities in events/components/relations?

pine cape
pine cape
stray sinew
#

Found a bug in Lightyear

Summary

  • On first connection / initial relevance, entities with NetworkVisibility replicate normally and clients can see them.
  • As soon as an entity loses network visibility once, it can never become visible again even when ReplicationState::gain_visibility is called.

Suspected flaw
In visibility/immediate.rs, NetworkVisibilityPlugin::update_network_visibility deletes the entire per-sender entry when visibility is Lost:

if state.visibility == VisibilityState::Lost {
  return false; // deletes PerSenderReplicationState
}

In the comment above it's mentioned that this could possibly be unsafe, but for some reason it was never an issue before?

Workaround
I stopped deleting the per-sender entry on Lost. Instead, the entry is kept and we only update the visibility state.

if state.visibility == VisibilityState::Lost {
  // We already sent DESPAWN, but keep the entry so we don't lose metadata
  // like predicted/interpolated (and authority).
  state.visibility = VisibilityState::Default;

  // We want a future gain_visibility() to cause a SPAWN again.
  state.spawned = false;

  return true;
}

This makes my case work again, but I'm not sure if this is actually a good fix. I did not have this issue in 9266179 which is odd.

Also worth noting: update_network_visibility only mutates/cleans entries when the sender’s send_timer.is_finished(), maybe this was altered when updating to 0.18?

stray sinew
stray sinew
# stray sinew Found a bug in Lightyear **Summary** - On first connection / initial relevanc...

When update_network_visibility drops the PerSenderReplicationState on Lost, the next gain_visibility() recreates the sender entry via per_sender_state.entry(sender).or_insert_with(PerSenderReplicationState::with_authority).

That constructor recreates a “blank” per-sender state (interpolated=false, predicted=false), and the visibility helpers only update visibility, they don’t re-apply InterpolationTarget / PredictionTarget.

Since those flags are normally set only by Replicate/ReplicationTarget insert/connection logic the recreated entry keeps incorrect defaults, leading to incorrect respawn behavior after a visibility loss.

pine cape
#

Your fix seems sensible to me, I would have to think about it more

cloud patio
pine cape
#

LGTM! out of curiosity, what kind of user-data are you sending?

red elm
#

the meetup talk was great!

pine cape
#

Thanks! Was nervous about it haha

plucky smelt
red elm
#

at that timestamp (although the dependency injection talk today was good too and came earlier in the stream)

strong barn
#

Q: In older versions, after a client connects the other players would be in their correct locations. Now when a client connects, everyone is spawned at 0,0 instead of their server location.

Is there a way to sync all the player positions on connect? I'm not sure what changed.

#

I am guessing there is a new way to say "Start with state replication"

plucky smelt
#

lightyear docs are broken btw 😢

plucky smelt
strong barn
#

Started in 0.25

plucky smelt
# strong barn Started in 0.25

I didn't notice this personally in 0.25? Maybe you have a system ordering issue like your replicated component isn't being set on spawn?

strong barn
#

I have a when a player connect, the server adds a

#[derive(Bundle)]
pub struct PlayerBundle {
    pub name: Name,
    pub player: PlayerId,
    pub appearance: PlayerAppearance,
    pub movement_target: PlayerMovementTarget,
}

The movement target is an Input for BEI, e.g.


/// Player input context used by Bevy Enhanced Inputs
#[derive(Component, Serialize, Deserialize, Clone, Debug, Default, PartialEq, Reflect)]
pub struct PlayerMovementTarget(pub Option<Vec2>);

#[derive(Debug, InputAction)]
#[action_output(Vec2)]
pub struct ClickToMove;

and finally, they are admitted and replicated like this:


fn admit_client(
    commands: &mut Commands,
    sender: &mut ServerMultiMessageSender,
    server: &Server,
    client_entity: Entity,
    client_peer_id: PeerId,
    player: PlayerBundle,
) {
    let entity = commands
        .spawn((
            player,
            Replicate::to_clients(NetworkTarget::All),
            PredictionTarget::to_clients(NetworkTarget::Single(client_peer_id)),
            InterpolationTarget::to_clients(NetworkTarget::AllExceptSingle(client_peer_id)),
            ControlledBy {
                owner: client_entity,
                lifetime: Default::default(),
            },
        ))
        .id();

lmk if anything here looks weird

pine cape
#

Are you using avian?

#

I think it's because avian's sync from Position/Rotation to Transform is only done when both Position/Rotation are present

#

your entity might get spawned with only Position (maybe because of interpolation), so it starts by getting spawned at (0, 0)

pine cape
#

I agree that it is frustrating, and it can be hard to prevent

plucky smelt
#

I wonder if something goes a little wrong since your player exists early?

strong barn
pine cape
#

It should work yea; because then Pos/Rot are inserted together (i'm assuming you're missing Rot) so your Transform will get updated by avian

strong barn
#

Inputs still trigger on both clients, but yeah Im not sure why the server isnt updating the players' positions

#

Weird

unkempt sedge
#

@pine cape ought of curiosiry why did you develop lightyear what was your motivation for such an ambitious cratem

pine cape
unkempt sedge
peak ice
#

Do you think this is error is something on my end? I'm in the process of updating to bevy 0.18

2026-01-31T06:10:48.941116Z  INFO lightyear_netcode::client_plugin: Client Netcode(3466457520131969991) connected

thread 'main' (48676) panicked at C:\Users\eliza\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\bevy_ecs-0.18.0\src\error\handler.rs:125:1:
Encountered an error in command `<bevy_ecs::system::commands::EntityEntryCommands<'_, bevy_ecs::hierarchy::Children>::and_modify<<bevy_ecs::hierarchy::ChildOf as bevy_ecs::relationship::Relationship>::on_insert::{{closure}}>::{{closure}} as bevy_ecs::error::command_handling::CommandWithEntity<core::result::Result<(), bevy_ecs::world::error::EntityMutableFetchError>>>::with_entity::{{closure}}`: Entity not yet spawned: The entity with ID PLACEHOLDER is not spawned; enable `track_location` feature for more details.
Note that interacting with a not-yet-spawned entity is the most common cause of this error but there are others

    If you were attempting to apply a command to this entity,
    and want to handle this error gracefully, consider using `EntityCommands::queue_handled` or `queue_silenced`.

note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `lightyear_replication::receive::ReplicationReceivePlugin::apply_world`!

thread 'main' (48676) panicked at C:\Users\eliza\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\bevy_ecs-0.18.0\src\error\handler.rs:125:1:
Encountered an error in command `<bevy_ecs::system::commands::entity_command::insert_with<bevy_ecs::hierarchy::Children, <bevy_ecs::hierarchy::ChildOf as bevy_ecs::relationship::Relationship>::on_insert::{{closure}}>::{{closure}} as bevy_ecs::error::command_handling::CommandWithEntity<core::result::Result<(), bevy_ecs::world::error::EntityMutableFetchError>>>::with_entity::{{closure}}`: Entity not yet spawned: The entity with ID PLACEHOLDER is not spawned; enable `track_location` feature for more details.
Note that interacting with a not-yet-spawned entity is the most common cause of this error but there are others

    If you were attempting to apply a command to this entity,
    and want to handle this error gracefully, consider using `EntityCommands::queue_handled` or `queue_silenced`.

Encountered a panic when applying buffers for system `lightyear_inputs::server::receive_input_message<lightyear_inputs_leafwing::input_message::LeafwingSequence<gnome_player::protocol::PlayerActions>>`!
Encountered a panic in system `bevy_ecs::apply_deferred`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
error: process didn't exit successfully: `target\debug\bevy-code-gnome.exe client` (exit code: 101)
peak ice
#

the interesting thing is it comes from lightyear_inputs::server::receive_input_message, but its on the client

peak ice
#

ripping out my world plugin seemed to fix it so i think its on my end

strong barn
#

I get these constantly spamming my terminal:

#

Using BEI

plucky smelt
#

Yeah these warnings were also happening in 0.25

pine cape
strong barn
#

Hide how? RUSTLOG?

#

Any plans to fix it?

pine cape
#

Yea RUSTLOG

cloud patio
tacit kelp
#

I have been stuck for a few days trying to make a simple_box example clone to get aquainted with the api of the library to build a third person shooter/hack and slash.
Every time I add linear interpolation the replicated entities stop working (after a very tiny delay). Am I missing a component, am I replicating too fast? (16 ms)
The simple box example does work so I assume I am doing something wrong but I get no output from the interpolation system warning me.
Here I append the whole project without the target directory.

#

Thanks in advance

strong barn
#

If you add prediction to a component, it should not be overwritten by the server, right?

Why is the server overwriting this component when it changes locally? I must be doing something wrong here.

plucky smelt
#

So yes, the server can make the component overwritten.

strong barn
plucky smelt
strong barn
#

I mean I didn't add .add_rollbacks or .should_rollback or whatever the function is

#

I basically gave up on implementing the Input plugin with BEI because for the past year I have never gotten it to work despite feeling like I understand how lightyear should work.

So I am transitioning to having the client send a message that says "Here's where I clicked, please replicate that to other clients".

Thus, the protocol is that I have a "PlayerMovementTarget" component on players that is controlled by the clients and the server just replicates that to other clients

#

AFAIK that should mean I just need to add prediction

plucky smelt
plucky smelt
plucky smelt
#

Send the movement target as an input, and that input can be replicated to clients

strong barn
#

Can you help me understand how replication works?

I have the server spawn a bundle of things on an entity, e.g.

  • Player
  • PlayerAppearance
  • PlayerMovementTarget

And I want the server to tell all clients that if they do not match the server, they can be overwritten. They should stay synced with the server.

HOWEVER, PlayerMovementTarget is supposed to be an exception. I want the client to own authority over that component specifically, never listen to the server, etc.

How do I stop that component from being changed on the client?

strong barn
plucky smelt
#

It uses raw messages internally

strong barn
#

Does that mean I have to split the entities?

#

I thought that too, but it's not really clear in docs that I've seen.

plucky smelt
strong barn
#

Yea, fair. Still curious about entity replication

plucky smelt
plucky smelt
strong barn
#

sweet ill try that

#

Busy the next hour but ill lyk

tacit kelp
stray sinew
# tacit kelp (I wanna add I suspect it might be because of the extra bad conditions I put on ...

In NetworkedPlugin you're adding ClientPlugins and ServerPlugins after registering replicated components. According to their documentation you need to add the client/server plugins before component registration.

Also, I noticed you're adding client and server plugins at the same time. Unless this is meant to be a host client setup, you should gate these behind features so only one is enabled at a time.

plucky smelt
pine cape
pine cape
tacit kelp
# stray sinew In `NetworkedPlugin` you're adding `ClientPlugins` and `ServerPlugins` after reg...

I will change the order of adding the plugins and registering them thanks. Although I already have tried that before and the linear interpolation still breaks after a few ticks.

As for the last point, I plan to slowly build a real game out of it. And realistically I need to use both plugins as the players would be both host clients or just clients. Having to select a type on launch would be cumbersome for the average player. Furthermore, besides inputs being broken in host client mode, everything seemed to work fine on the examples.

tacit kelp
rain swan
#

Does lightyear support multiple wasm clients to the same server on the same machine?

pine cape
strong barn
#

@pine cape can I request a new example to lightyear?

#

I’ve given Claude code access to lightyear and tried to set it up but no matter what I try it doesn’t seem to work.

I would like a 2D example with native inputs where a player clicks somewhere on the screen and the player walks towards the target until it arrives.

I also would like this to work with avian2d and move the Position but apply to the Transform.

vagrant moth
#

Hello all 🙂

Sorry to bother if it has already been asked before but, how can we test our games with lightyear ?

For now I have a game up and running (I mean : playable, networked, replicated etc..), and I would like to test it and tried like :

#[cfg(test)]
mod test {
  #[test]
  pub fn test_something(){
    let mut server_app = create_server_app(true, NetworkMode::Udp);
                                                                        // Headless
    let mut client_app1 = create_client_app(1, "../../assets".to_string(), true, NetworkMode::Udp);
    let mut client_app2 = create_client_app(2, "../../assets".to_string(), true, NetworkMode::Udp);
    
    // app.update() for all
    let mut q2 = client_app2.world_mut().query_filtered::<(), (With<Client>, With<Connected>)>();
    let c2_connected = q2.iter(client_app2.world()).next().is_some();
    
    // It is connected !
    }
}  
// But then searching for replicated components I can't find some... 
// (Like my custom LobbyState, etc... )

I then run with cargo test -- --test-threads=1 (as asked by bevy)

note: create_client_app is a function that create a bevy app and add all the plugins and systems to make the game run, and it runs well, (headlessly also for tests).

Do you have any recommendation or way to test your games ?

strong barn
#

I found it because I've been having stutters and rollbacks sporadically with absolute randomness, until I added a 1 tick input delay, which fixed the networking inputs entirely

#

Also kindof important to note, I was using a 15Hz Tick rate, which made things more clear

peak ice
#

I might be remembering this wrong, but lightyear doesn't sync entities across client and server, but uses a lookup table, do we have access to this lookup table?

#

and by sync entity i mean the entity id

silent patrol
pine cape
pine cape
strong barn
#

Ever since then my entire 1 year feud with inputs stuttering and locking up was fixed

strong barn
#

btw, could you upgrade getrandom in lightyear? Ive had to use this explicit dependency because you're pulling in getrandom 0.2 somehow

getrandom = { version = "0.2.16", features = ["js"] }
#

I think the newest version of bevy is on 0.4 or 0.3 at the least

pine cape
#

I did that because it was needed for wasm to work correctly, not sure if things have changed; i'm open to PRs

pliant bison
#

i'm having trouble trying to understand the minimum parts of the simple_box needed to make things work, and get it into my code

#

i have made a udp connection between server and client, but both programs give a bunch of errors in the terminal when connected

#

let me grab the exact error text

#

also, i have confirmed that the "simple_box" example is building and running just fine so i must be missing something
i tried to copy only what i need from that example but something must not be right

#

server:

2026-02-13T23:46:08.355222Z ERROR lightyear_transport::plugin: Error processing packet: ChannelReceiveError(MissingMessageId)

client:

2026-02-13T23:46:08.382156Z ERROR lightyear_messages::receive: Error receiving messages: Serialization(BincodeDecode(Io { inner: Error { kind: UnexpectedEof, message: "failed to fill whole buffer" }, additional: 1 }))

client also gets this occasionally:

2026-02-14T00:01:04.106839Z ERROR lightyear_messages::receive: Error receiving messages: Serialization(BincodeDecode(InvalidIntegerType { expected: U16, found: U32 }))
2026-02-14T00:01:04.207238Z ERROR lightyear_messages::receive: Error receiving messages: Serialization(BincodeDecode(InvalidIntegerType { expected: U16, found: U64 }))
2026-02-14T00:01:04.321625Z ERROR lightyear_messages::receive: Error receiving messages: Serialization(BincodeDecode(InvalidIntegerType { expected: U16, found: U128 }))
2026-02-14T00:01:04.407207Z ERROR lightyear_messages::receive: Error receiving messages: Serialization(BincodeDecode(InvalidIntegerType { expected: U16, found: Reserved }))
#

i am guessing i've somehow messed it up so the protocol is not the same on both? but i haven't figured it out

#

i know Rust decently at this point, but i don't understand Bevy much, and Lightyear even less so

#

it was a mistake to think i could whip this up in a single week long jam lol

#

i have noticed that the spawn_connections function in cli.rs in the examples/common folder does not ever use UDP, all that is commented out in favor of WebTransport

#

for the server, specifically

#

the default features seem to imply that UDP is used by the client but then how can they communicate if the server is using WebTransport?

#

in the case of the simple_box demo (which i was able to compile and run no problem on my computer)

silent patrol
#

just stumbled upon this as well. Even though I did setup refreshing connect tokens, apparently, there's still some edge case where I fail to do that?..
anyway, it would be nice to have a way to handle this error and close the connection

atm, both client and server are just stuck in the connecting state (until a 15s timeout?), and the server only spams with the logs Netcode error: Packet(TokenExpired), and I can't find any way to handle this in a more elegant way rather than just waiting for a timeout

pine cape
pine cape
pliant bison
#

i think instead i'll change my code to use webtransport if i can

#

i was planning to do that anyway, i just don't understand the certificate stuff

silent patrol
# pine cape You would like some sort of callback where you handle the error and potentially ...

well, I think lightyear should even close the connection itself in this scenario
I'm not sure if there's any reason to keep a half-established connection if a connect token is expired (unless I'm missing anything?)

but it also would be nice to have some API to report an expired token (as a disconnect reason for example)

I saw there's

pub struct Disconnected {
    pub reason: Option<String>,
}

but I don't really like the fact that it's a string, as it makes it difficult to match against possible errors

pliant bison
#

this would have been a good place to use a non-exhaustive enum instead of a string

#

that way you can always add new variants without causing old code that uses the library to not compile

pliant bison
#

it's funny now i can't build the example at all lol

#

it's just hanging on the final build of the binary

peak ice
#

I'm not sure when this bug showed up, but for some reason my client crashes when it joins a server with more than 4 enemies already there. Any guesses what could be causing this? the client terminal log isn't very helpful: (updated with rustbacktrace=1)

Encountered an error in command `<bevy_ecs::system::commands::EntityEntryCommands<'_, bevy_ecs::hierarchy::Children>::and_modify<<bevy_ecs::hierarchy::ChildOf as bevy_ecs::relationship::Relationship>::on_insert::{{closure}}>::{{closure}} as bevy_ecs::error::command_handling::CommandWithEntity<core::result::Result<(), bevy_ecs::world::error::EntityMutableFetchError>>>::with_entity::{{closure}}`: Entity not yet spawned: The entity with ID PLACEHOLDER is not spawned; its index was last despawned by /Users/elizabethsuehr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_ecs-0.18.0/src/entity/mod.rs:1234:17.
Note that interacting with a not-yet-spawned entity is the most common cause of this error but there are others

    If you were attempting to apply a command to this entity,
    and want to handle this error gracefully, consider using `EntityCommands::queue_handled` or `queue_silenced`.
   2: core::ops::function::FnOnce::call_once
   3: bevy_ecs::world::command_queue::RawCommandQueue::apply_or_drop_queued
   4: lightyear_replication::registry::buffered::TempWriteBuffer::batch_insert
   5: lightyear_replication::registry::buffered::BufferedChanges::apply
   6: lightyear_replication::receive::GroupChannel::apply_actions_message
   7: lightyear_replication::receive::ReplicationReceivePlugin::apply_world::{{closure}}
   8: <bevy_ecs::system::exclusive_function_system::ExclusiveFunctionSystem<Marker,Out,F> as bevy_ecs::system::system::System>::run_unsafe
   9: bevy_ecs::system::system::System::run
note: Some "noisy" backtrace lines have been filtered out. Run with `BEVY_BACKTRACE=full` for a verbose backtrace.

Encountered a panic in system `lightyear_replication::receive::ReplicationReceivePlugin::apply_world`!
Encountered an error in command `<bevy_ecs::system::commands::entity_command::insert_with<bevy_ecs::hierarchy::Children, <bevy_ecs::hierarchy::ChildOf as bevy_ecs::relationship::Relationship>::on_insert::{{closure}}>::{{closure}} as bevy_ecs::error::command_handling::CommandWithEntity<core::result::Result<(), bevy_ecs::world::error::EntityMutableFetchError>>>::with_entity::{{closure}}`: Entity not yet spawned: The entity with ID PLACEHOLDER is not spawned; its index was last despawned by /Users/elizabethsuehr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_ecs-0.18.0/src/entity/mod.rs:1234:17.
Note that interacting with a not-yet-spawned entity is the most common cause of this error but there are others

    If you were attempting to apply a command to this entity,
    and want to handle this error gracefully, consider using `EntityCommands::queue_handled` or `queue_silenced`.
   2: core::ops::function::FnOnce::call_once
   3: bevy_ecs::world::command_queue::RawCommandQueue::apply_or_drop_queued
   4: <bevy_ecs::system::function_system::FunctionSystem<Marker,In,Out,F> as bevy_ecs::system::system::System>::apply_deferred
   5: bevy_ecs::schedule::executor::multi_threaded::apply_deferred
   6: <async_executor::AsyncCallOnDrop<Fut,Cleanup> as core::future::future::Future>::poll
   7: async_task::raw::RawTask<F,T,S,M>::run
   8: bevy_tasks::thread_executor::ThreadExecutorTicker::tick::{{closure}}
   9: <bevy_ecs::schedule::executor::multi_threaded::MultiThreadedExecutor as bevy_ecs::schedule::executor::SystemExecutor>::run
  10: bevy_ecs::world::World::try_schedule_scope
  11: bevy_app::main_schedule::Main::run_main
  12: bevy_ecs::system::system::System::run_without_applying_deferred
note: Some "noisy" backtrace lines have been filtered out. Run with `BEVY_BACKTRACE=full` for a verbose backtrace.
dreamy silo
# pliant bison i was planning to do that anyway, i just don't understand the certificate stuff

Hey. Not sure what part you don’t understand around certs but hoping my little finding might help you get setup at least for during your development.

I’ve been working a couple hours today to get webtransport via browser using the wasm client server working locally on my network and came across this something that helped me with bypassing the very strict webtransport requirements for certs in my browser locally:

Chrome: enter chrome://flags and set #webtransport-developer-mode to Enabled```

I think things will be easier to setup in a production environment where you can get real CA certs more easily. At first I tried using self signed CA ones using mkcert but didn’t find any success. Very positive it’s just skill issues on my end and not doing it correctly but at least this workaround for local makes it easier to get on with just working on developing everything first. 

And also for lightyear including this feature could help with certain cert issues :

`webtransport_dangerous_configuration`
#

Oh just noticed there’s a webtransport_self_signed feature flag too. Maybe that’s why my self signed stuff hasn’t been working properly

pine cape
pine cape
pliant bison
dreamy silo
#

Do itch.io support browser games? Is that a platform mostly for game client distribution?

peak ice
pliant bison
#

and yes itch.io supports browser games. and my experience is that most itch users want to play that way, especially for jams

#

i got a bare bones basic bevy "game" running on itch.io's site no problem, i just have not tried networking because i was first testing native linux client to native linux server

#

i think now that i have officially missed the jam window, i'm going to just try building and uploading the simple-box demo, see if that just works

#

unfortunately i am going to ghost in three minutes because i'm in an institution that turns off the wifi at 830

dreamy silo
# pliant bison unfortunately i am going to ghost in three minutes because i'm in an institution...

I see. So itch hosts the client, you host the game server right? I’m pretty sure itch io has its own ca certs but you’ll need a ca certificate for your game server that browser clients can trust. For that I’d use certbot. You can eventually also try pointing your wasm client to the same certs using a trunk.toml config file. Kinda like this:

[serve] addresses = ["0.0.0.0"] port = 8080 tls_cert_path = "certificates/cert.pem" tls_key_path = "certificates/key.pem"

#

Don’t use self signed stuff for itch trying to connect to your game server, it most likely won’t work. That’s best only for local if I’ve understood self signed correctly

dreamy silo
peak ice
peak ice
#

So I asked my friend Claude to fix it and it seems to be working, didnt look into the problem because you're planning the replicon rework, but yeah no need to look into it further as I have a temp solution lol

pliant bison
#

i am locally running the web build of the client for simple_box, using bevy run web as the readme instructs, and i also ran the server, but i have yet to get them to connect. once the server starts, after trying to connect, the client says this on-screen:

#

the server i am running as cargo run -- server, and in the terminal it says

INFO lightyear_webtransport::server: Server WebTransport starting at 0.0.0.0:5888

among other things

#

(the rest of the terminal spew is just regular bevy stuff about the gpu and window)

dreamy silo
#

If this is a local run. And just incase, you generated self signed certs right using the generate.sh in /certificates right?

pliant bison
#

ah no i didn't generate the certs

#

i have just run certificates/generate.sh from the lightyear crate root, will rebuild and test

#

also earlier i noticed the instructions for how to build a headless server (for simple_box) caused build errors. but the normal build is fine. i think it just needs a couple bevy includes

#
error: linking with `rust-lld` failed: signal: 7 (SIGBUS) (core dumped)

well that's unusual

#

i think my disk is full of artifacts lol

dreamy silo
dreamy silo
pliant bison
#

building it from the example root just errors, it's looking for the certificates folder

pliant bison
#

it seems to be having trouble still tho. instead of disconnecting immediately, the simple_box client now sits on "connecting" indefinitely. it's not even timing out

#

i'll try the spaceships one later

dreamy silo
#

I had the exact same issues as you. Still a bit unsure how I solved it but try these aswell

dreamy silo
pliant bison
#

ah no i didn't do that part

#

tbh i'd rather just skip all this stuff and test on itch's site directly

dreamy silo
#

Unfortunately that I don’t know how. Haven’t gotten my game to a production worth state so hasn’t tried it on a real domain

#

Only local network ip address

pliant bison
#

i changed the browser setting but the behavior is the same, stuck "connecting"

#

server is unaware of client's existence

pine cape
#

Then I ran

certificates/generate.sh

and

cargo run --no-default-features --features=server,netcode -- server
bevy run web

to get a client connecting to the server in wasm

dreamy silo
#

this helped stop the indefinitely "connecting" on my end.

#

Webtransport doesn’t seem to work at all for via Firefox based browsers. So stick to chromium

dreamy silo
pliant bison
pliant bison
#

i think i'll keep looking into certbot and also try to see if anyone has gotten a similar setup working on itch (not with lightyear specifically, just with WebTransport / QUIC)

pine cape
pliant bison
night flare
#

Hi, why does this snippet work well even without the With<Predicted> filter? ```/// The client input only gets applied to predicted entities that we own
/// This works because we only predict the user's controlled entity.
/// If we were predicting more entities, we would have to only apply movement to the player owned one.
fn player_movement(
// timeline: Single<&LocalTimeline>,
mut position_query: Query<(&mut PlayerPosition, &ActionState<Inputs>), With<Predicted>>,
) {
// let tick = timeline.tick();
for (position, input) in position_query.iter_mut() {
// trace!(?tick, ?position, ?input, "client");
// NOTE: be careful to directly pass Mut<PlayerPosition>
// getting a mutable reference triggers change detection, unless you use as_deref_mut()
shared::shared_movement_behaviour(position, input);
}
}

pine cape
#

Probably because we only added input handling (the ActionState component) to the predicted entity

marble lava
#

is there a migration guide somewhere? I just came back from a long hiatus on my project, and I'm bumping by 1 major bevy (and lightyear) version at a time. I see ServerReplicate has been removed between 0.19 -> 0.24 (as in bevy 0.15 -> 0.16), but I'm not sure what the logic is now

grave coral
#

Did something change between 0.25 and 0.26.4 that would have led to the Controlled component not getting added in host-client setups where it would have been added previously?

dreamy silo
#

Anyone here know if lightyear websocket is noticeably less performant than lightyear webtransport or is it nearly the same? Might try websocket instead because of better browser compatibility.

violet stream
#

Hi, I encounter following error client-side whenever I spawn an entity with many children (say 1000) on Connected observer:

Encountered an error in command `<bevy_ecs::system::commands::entity_command::insert_with<bevy_ecs::hierarchy::Children, <bevy_ecs::hierarchy::ChildOf as bevy_ecs::relationship::Relationship>::on_insert::{{closure}}>::{{closure}} as bevy_ecs::error::command_handling::CommandWithEntity<core::result::Result<(), bevy_ecs::world::error::EntityMutableFetchError>>>::with_entity::{{closure}}`: Entity not yet spawned: The entity with ID PLACEHOLDER is not spawned; its index was last despawned by C:\Users\ZX\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\bevy_ecs-0.18.0\src\entity\mod.rs:1234:17.
Note that interacting with a not-yet-spawned entity is the most common cause of this error but there are others

Spawning looks like this

    pub(crate) fn handle_connected(
        trigger: On<Add, Connected>,
        query: Query<&RemoteId, With<ClientOf>>,
        mut commands: Commands,
    ) {
        let Ok(client_id) = query.get(trigger.entity) else {
            return;
        };
        commands
            .spawn((
                Replicate::to_clients(NetworkTarget::All),
            ))
            .with_children(|spawner| {
                for _ in 0..1000 {
                    spawner.spawn(());
                }
            });
    }

For low numbers this does not crash. Does anyone might know what could be wrong?

pine cape
pine cape
pine cape
violet stream
night flare
#

Hi everyone! I'm hitting a consistent panic when using Lightyear with Avian 2D for a multiplayer project.
The Error:
called Option::unwrap() on a None value

Encountered a panic in system avian2d::collision::narrow_phase::update_narrow_phase<avian2d::collision::collider::parry::Collider, ()>!
Context:
The panic occurs on the Server when a player "pushes" hard against a static collider (a wall). It seems to be related to Lag Compensation / Rollback.
I suspect that when Lightyear triggers a rollback to a previous tick, the sudden "teleportation" of the Position component confuses Avian's internal contact island solver, as it tries to reconcile new contacts with cached ones from a future that was just rolled back.
My Setup:
Bevy latest
Lightyear: Latest
Avian 2D: latest
The player has : collider: Collider::rectangle(PLAYER_SIZE, PLAYER_SIZE),
collider_density: ColliderDensity(1.0),
rigid_body: RigidBody::Dynamic,
restitution: Restitution::new(0.0),
constraint: LockedAxes::new().lock_rotation(),
dumping: LinearDamping(10.0),
swept: SweptCcd::default(),
I am using LagCompensationHistory on the player entity.
What I've tried:
Disabling LagCompensationHistory stops the panic, but I need it for hit registration.
I suspect my SystemSets might be ordered incorrectly.
Question:
How should I correctly sync Avian's physics step with Lightyear's FixedUpdate loop to prevent the solver from panicking during rollbacks? Should I be using separate hitboxes for lag compensation instead of the main physics body?
Thanks in advance! P.S. Maybe there is a way to create my own HistoryBuffer<>?

pine cape
#

Have you disabled Islands? Indeed the islands plugins breaks down during rollback because some of its internal invariants are broken

#

This happens even without lag compensation being enabled

wise flint
#

@pine cape Is it still the plan to replace part of lightyear internally with replicon, per your draft PR from December? I'm trying to pick between lightyear and replicon, and if lightyear ends up being a layer on top of replicon that makes it an easy "use lightyear if I need what it adds, otherwise replicon" decision

peak ice
#

I was also curious about this! Not that I’m switching, I love lightyear, I just wanna know when/if I should expect a big change

lilac compass
#

I'm using lightyear 0.26.4. I'm spawning 100 "creep" entities in my game with an interpolated EntityPosition component, and all entities are in the default ReplicationGroup.

I found that many of these entities are only updated once every few seconds.

My ReplicationSenders look like this, with no bandwidth cap:

ReplicationSender::new(Duration::from_millis(33), SendUpdatesMode::SinceLastAck, /*bandwidth_cap_enabled*/ false),

I've solved this by adding ReplicationGroup::new_from_entity() to every creep that I'm spawning, but it leaves a few questions:

  • Should this be happening with the default ReplicationGroup? I understand that entities in the same ReplicationGroup are updated atomically(?). Is this just expected behavior, then, or is it a bug?
  • Should entities be contained in their own ReplicationGroup by default, rather than sharing one big default group? If not, should the examples or documentation call out that you likely want to put entities in their own groups?

I've attached a couple of videos showing the effects with and without individual ReplicationGroups.

unique plover
# pine cape It is possible that a bug was introduced, the host client logic is a bit brittle

I think I've confirmed that this is the case. Running the bevy_enhanced_inputs example in 0.25.5 works, but running the same example on 0.26.x or main does not because handle_predicted_spawn is checking for Has<Controlled> Is there something you could point me to that I could try fixing the issue? Unfortunately, this is the only thing blocking us from upgrading to 0.18 and is starting to become too difficult to hold off.

unique plover
#

I may have found part of the issue. At least for Controlled - in lightyear_replication/src/host.rs HostServerQueryData.replicate_like is not an Option, so root_query is empty.

This solves Controlled not existing for our implementation, but the bevy_enhanced_inputs example is still broken. I'm not sure why, as I'm using BEI in Computronium and it seems to work when changing replicate_like to an Option.

unique plover
unique plover
#

The bevy_enhanced_inputs example has additional problems, even outside of host-client mode. With a server and two clients I get a lot of log error spam and the movement becomes choppy.

#

It's fine when there's a single client FYI.

#

Relevant log lines:

2026-03-09T22:08:18.290007Z  INFO bevy_winit::system: Creating new window Lightyear Example: lightyear_examples_common (0v0)
2026-03-09T22:08:18.292707Z  INFO lightyear_netcode::client: client connecting to server 127.0.0.1:5888 [1/1]
2026-03-09T22:08:18.292730Z  WARN lightyear_webtransport::client: Connecting with no certificate validation
2026-03-09T22:08:18.635070Z  INFO lightyear_netcode::client_plugin: Client Netcode(0) connected
2026-03-09T22:08:18.868856Z  WARN bevy_enhanced_inputs::client: Add InputMarker to entity: 183v0
2026-03-09T22:08:41.638379Z  WARN bevy_enhanced_inputs::client: Add InputMarker to entity: 189v0
2026-03-09T22:08:42.139276Z ERROR lightyear_inputs::client: received input message for unrecognized entity entity=190v0 target_data.states=BEIStateSequence { start_state: ActionsSnapshot { state: None, value: Axis2D(Vec2(0.0, 0.0)), time: ActionTime { elapsed_secs: 0.0, fired_secs: 0.0 }, events: ActionEvents(0) }, diffs: [SameAsPrecedent, SameAsPrecedent, SameAsPrecedent, SameAsPrecedent] } end_tick=Tick(13694)
#

Ah! Interesting. These errors only occur on main not on tag 0.26.4

spice sentinel
#

Hi, If I was to use lightyear with steam, what would I need to change from a default lightyear setup

pine cape
pine cape
violet stream
#

I can't figure out how to replicate input to other clients with leafwing. It looks like I've got the same setup as examples meaning InputPlugin has rebroadcast_inputs: true and controlling client spawns InputMap but still only the server replicates ActionState components. I've enabled debug logs and see that Rebroadcast input message... message appears so it looks like the other client should receive those...

livid lake
#

@pine cape I've got a pretty general question, sorry if it's been asked before but I can't really find anything about it in the docs

Is predicting dynamic component insertions / removals supported? I feel like each time I remove a synced component it causes significant lag on the clients, and I can't tell whether this behavior just isn't supported or the rollbacks are caused by something else entirely (e.g. client input which leads to the component being removed).

Weirdly, refactoring that removal to simply mutate a component instead seems to stabilize things significantly. I just want to know if this behavior simply isn't fully supported or I should be debugging something else.

plucky smelt
#

In previous versions of lightyear I could get a list of the entities that a ReplicationTarget is sending to through ReplicationTarget::sender. But it looks like that's been removed in 0.26. How can I go about migrating this?

Do I just need to query for all senders and match against the ReplicationMode and just handle every case?

#

For additional context, I want to set ComponentReplicationOverrides for my component so that it only replicates to the prediction targets. But ComponentReplicationOverrides is keyed on the sender entity, whereas the prediction target is looking for the PeerIds

plucky smelt
#

Ooof actually looks like ReplicationTarget::mode is private, and ReplicationState (which is where the ::senders moved to it seems) doesn't allow you to access the senders

#

So it looks like this is just a regression

pine cape
earnest fog
#

Periwink, are you open to structural change PRs right now? I’d like to add support for GGPO style input rollback and deterministic late join but a lot of the current code is tightly coupled. ie. determinism code is coupled with prediction and interpolation, input is coupled with prediction, etc. I’m happy to make the changes but I’m not sure how you’d want to handle structural changes if you’re in the middle of porting to replicon

tulip violet
#

Hi trying to migrate my project from an older version, does anyone know how to use observers for host-client setup in latest versions (0.26.4) of lightyear? I was able to receive events for remote clients using On<RemoteEvent<MyEvent>> but it doesn't seem to trigger for the host client/RemoteId(Local(0)). I was using
ServerMultiMessageSender to trigger the event like:

message_sender.send::<MyEvent, MyChannel>(
  &MyEvent(0),
  server.into_inner(),
  &NetworkTarget::All);

I know I could directly trigger the event for the host client, but is there a consolidated way for the server to send a bevy Event to all clients?

pine cape
# earnest fog Periwink, are you open to structural change PRs right now? I’d like to add suppo...

yep let's wait on the replicon integration. It's almost ready, the status is:

  • all tests are passing
  • most examples are working

Missing features:

  • replicon has a single Client or Server resource, so multiple clients/servers in an app is not supported
  • main blocker: replicon doesn't support having a Client and Server in the same app, so the server cannot receive replication updates from clients. BEI integration relies on the client replicating some Action entities to the server so this is the main issue I'm facing currently. (also the client_replication example is broken because of this)
  • for similar reasons, authority-related features are broken
pine cape
tulip violet
#

It could also be something wrong with my setup, just started migrating the host server parts. edit: I needed to add the Linked component when creating the host client

marble lava
#

I managed to get my old project updated to latest bevy/lightyear and it "works" again but something is fundamentally wrong. I'm using a dedicated server (e.g. no graphics/audio etc.) and a full game client setup. The basics work, but the client is extremely "choppy", it seems like things only get updated on the server update tick. Another odd thing is it only works at all if server is using default ticks (1/60) while the client is using 1/64. Using same value doesn't work anymore, no input gets registered

plucky smelt
#

I think there's a bug with lightyear_avian where because of the ordering of systems, if a networked object moves in the same frame it spawns, a child collider will be given the wrong ColliderTransform, making the child collider basically permanently out of sync.

#

For context, I am making a simple elevator. In FixedUpdate I change its Position to move it up or down. Because of this syncing issue, it clips into the floor (and desyncs across the network).

If I make it wait for a couple seconds before starting movement, it works perfectly fine.

#

My broader concern is how much of avian lightyear has to rip out and reimplement. Is this really necessary?

#

My understanding is this is done so lightyear can do smoothing of server corrections. But that seems like a heavy hammer to swing. Could we instead just add our interpolated server corrections before the last transform propagation, then subtract them in like PreUpdate or something?

It's possible there's more to it that I'm missing though.

plucky smelt
#

Oh actually I was misunderstanding, the default for the avian plugin is to only interact with the position, and frame interpolate the position as well... Either way, applying the corrections and then reverting them after rendering still could apply?

#

It looks like this is sorta what AvianReplicationMode::PositionButInterpolateTransform, though it still ends up needing to reimplement some avian stuff which is sad

plucky smelt
plucky smelt
#

In my case both the client and server are using a tick rate of 1/10 and that breaks client inputs

plucky smelt
#

Also it looks like the fps example I. Lightyear doesn't use any interpolation: setting the tick rate low results in unsmooth movement

tight glen
#

Safari iOS doesnt seem to be able to connect through WebTransport. I got it working from Android phone, but not iPhone, on latest v26.4 with WebTransport is enabled in advanced features / feature flags in iOS. Anyone know how to fix?

marble lava
plucky smelt
#

The "problems with prediction/interpolation" is from the fact that my simulation isn't deterministic, because it's relying on Transform which is being messed with by interpolation.

#

(Basically I'm fighting between lightyear, avian, and bevy_ahoy all trying to mess with the Position and Transform in different ways)

marble lava
#

ah, yeah Ican def. see the delay if I set it low for input itself ON TOP of the choppiness being terribad

#

this is kinda sad coz it used to work in older lightyear/bevy

strong barn
#

lightyear's native client_config only has two paths — with_server_certificate_hashes (digest pinning, 14-day limit) or with_no_cert_validation (insecure). There's no path to with_native_certs for standard CA validation.

Any plans to change this? @pine cape

I have to renew these certs every 14 days which is causing my server downtime having to restart with new certs

#

Maybe something I'm missing but why don't you change the empty-digest fallback from with_server_certificate_hashes([]) to with_native_certs() in lightyear?

hexed ruin
#

Hey so this is more of a general server question but since I'll be using Light-year in my project I think it's applicable. So basically I want cross platform determinism and originally I was looking into dynamic lockstep architecture and since I've been told that it's easier to achieve determinism on it and it doesn't cost a lot of server resources.

However my main concern is lag. Now I know I can use a relay server to ban connections with exceptionally high ping. But my main concern is that I fear it would region lock players from playing on other servers due to creating lag that will impact everyone.

The other option is prediction and rollback. But my main concern with it is that it will mess with the determinism and make it a pain to implement (not to mention balancing rubber banding and such).

I do know that the game will heavily involve physics interactions as well as likely being 8-16 player game (maybe more I'm still working on what that would possibly be.)

#

Feel free to ping me so I don't miss the answer

wicked oak
#

Determinist is basead on others things not on the Network api

#

The Network just send and read what You give

#

Like For Physics avian have Determinism feature

fathom heath
#

I seem to be having trouble mapping a reference to an Entity from the client to the server.
On the server I create an Entity with an ItemId, avian3d::Position (Both are registered under protocol.rs), and a Replicate component.
It appears on the Client as expected, but when the client targets the entity (I've inspected components and made sure its the right one) and sends a message to the server with a PlayerInteract(pub Entity) struct, the server doesn't find an Entity that contains the avian3d::Position or ItemID component.
I'm aware the client & server have differing Entity IDs, but when trying to use the EntityMap within MessageManager like so, no entity is mapped, whether using local_to_remote or remote_to_local.
let target_entity = manager.entity_mapper.local_to_remote.get(&interaction.0).expect("No entity mapped?");
Am I missing something and/or going about this the wrong way? How should I have the server & client agree on which entity they want to do work on?

fathom heath
#

I figured it out, searched through examples and used .add_map_entities() when registering the message in protocols

pulsar dragon
#

Is there a branch of lightyear to use with bevy 0.19-dev?

unique plover
orchid gorge
#

Hi everyone, I need some tips
I've been trying to implement a host-client system with lightyear
All of examples I've seen on the official repo do client/server separate binaries
I basically want so that, when the game is in single player, it actually communicates to a hidden server in the background, an you can just opt to open it up for other players
So that the entire game is built on top of networking from the ground up
Can anyone point me to an example or to the right direction? Is lightyear adequate for this?

peak ice
#

its all one binary, but different threads and apps, which might not be what you are thinking of

pine cape
violet stream
#

Hi, I'm having an issue with input processing on the server side (using leafwing). Sometimes the client sends and input, the server receives it (I see input buffer update in logs), but the shared system responsible for processing that input sees it only client-side. This results in a situation where client predicts a movement and moment after it is rollbacked like the input never happened. Using default InputPlugin and PredictionManager settings if that matters. Does anyone have idea what could I be doing wrong?

fallen path
fallen path
#

I managed to seemingly fix it by changing system ordering, but idk if I broke it because the example doesn't seem to work very well, the client host cannot shoot, and the joining client's shots are stuttery and don't register well (goes through the target then despawns), when I thought client side prediction would look better especially in a localhost scenario.

fallen path
#

Also the avian_3d_character example seems to have the same problem where in HostClient mode, the input doesn't work

strong barn
#

@pine cape Any plans to split the PeerId enum into variant types?

It's kindof a rough edge how I have to unwrap a PeerId as the Netcode variant everytime when it will only ever be that one type.

orchid gorge
#

Hi guys
I've been having a weird issue regarding input replication to the server when running host-client mode
Has anyone faced this? When only the host is online, I can't control my character (the aircraft). The client is generating inputs, but the server doesn't replicate them and just rolls the player back.
However, it starts working when another client joins... then I can control both the host player and the joining client player.
I've tried some of the examples from the lightyear repo (avian_3d_character, simple_setup, bevy_enhanced_input) and they all face the same issue on the host-client mode.
I've used avian_3d_character for reference for my code.

#

Update: I actually found an issue now on github regarding that exact problem.

https://github.com/cBournhonesque/lightyear/issues/1394

Unfortunately it hasn't yet been fixed. Has anyone found any workarounds for hsot-client mode when playing alone?

GitHub

Whenever I run any example on host-client mode I cannot move or interact in any way. If I connect extra clients those do work without issue, so I assume the input map is just getting ignored somehow

orchid gorge
worldly hollow
#

Hi guys!
I noticed that the lightyear section in Cargo.toml doesn't include a [package] section, and there's no name = “” for that section. But it is present in lightyear/lightyear/Cargo.toml.
Could someone please explain to me why it's set up this way?

silent patrol
#

sorry for necro-replying, but I was wondering whether it's possible to do p2p with lightyear in wasm, and stumbled upon this. are there any plans to introduce matchbox transport in lightyear by any chance? :)

unique plover
pine cape
#

I'm going to merge the replicon integration soon

#

It will also fix the BEI examples

orchid gorge
#

Yeah if anyone sees this, in my current project, adding a small input delay (1-3 ticks) actually fixed all issues (in the examples, the added input delay is 0). Maybe not the most optimal solution but fine for now in my case.
It feels like a race condition issue for sure
I tried replicating it in the examples, but it didn't fix them there, so something is different and I couldn't figure out what exactly it is to make a PR

#

If I happen to figure out the issue and it still exists by then, I will submit a PR for sure
Been loving this crate

slow kernel
#

A few versions ago I know if I added a delay of 0 it would behave weirdly, but not adding the delay config at all behaved correctly I believe. Something like that anyway

trail moss
#

Hi, have factorio like game (but cannot go lockstep), singleplayer first. I cannot quite understand what performance cost Local connection can introduce compared to singleplayer only game. They say "No packets are actually sent over the network since the client and server share the same World." but is there any data duplication or sync via crossbeam channel happening?

pine cape
#

There is almost no data getting sent, replication/input messages are skipped for the host client

trail moss
#

what cost is still present tho?

onyx salmon
# trail moss what cost is still present tho?

Can't say about the state right now, but after the migration to replication there shouldn't be any cost at all. The connection is emulated "logically" by simply draining server event and reemiting client events.
I explained this approach in the replicon docs if you're curious.

tepid whale
#

actually, they are not addressing host-client, only networked, sorry

#

I will have to probably check if any of my PRs are relevant when replicon is merged

vale stratus
#

I'm struggling with a weird problem in a host-client setup where my "ControlledBy" entity associated with a "HostClient" doesn't get a "Controlled" component..

unique plover
trail moss
#

Hi, how one will do main menu in which you choose singleplayer (host) or client? 2 different apps, one for menu, 2nd created depending on chosen mode?

trail moss
#

Also i wanted to ask if there will be a significant api changes after migration to replicon

final rain
#

Hi there, I'm currently trying to setup avian2D with rollback and i'm having trouble setting up. Currently, the initial entity is replicated, but there is no issued rollback. The entity has the Predicted Component and has confirmed positions and history but there does not seem to be any rollback checks. As shown on the GIF i provided.

I tried using the avian physics example and added the following plugins, but I think I might be missing something?

// physics
app.add_plugins(lightyear::avian2d::plugin::LightyearAvianPlugin {
    replication_mode: AvianReplicationMode::Position,
    ..default()
});
app.add_plugins(
    PhysicsPlugins::default()
        .build()
        // disable the position<>transform sync plugins as it is handled by lightyear_avian
        .disable::<PhysicsTransformPlugin>()
        .disable::<PhysicsInterpolationPlugin>(),
)
.insert_resource(Gravity(Vec2::ZERO));

In my project setup, the toml has interpolation and prediction as such:
lightyear = { version = "0.26.4", features = ["client", "server", "netcode", "replication", "udp", "avian2d", "interpolation", "prediction"] }

Thanks in advance for anyone who has an idea of what I could have forgotten about.

pine cape
pine cape
final rain
#

Thank you so much for the help!

final rain
strong barn
#

literally looks like an iron dome simulation

#

😂

final rain
strong barn
#

or just a fun project

final rain
# strong barn you work in defense?

This is basically something that I aim to be similar to Artemis/Emtpy Epsilon (while addressing some of the limitations I dislike).

Most of the work so far has been on lua scripting for scenarios/saving/game master actions. So nothing flashy so far, but once I tackle networking I will finally have the technical foundation to start working on gameplay.

As much as it's just a fun project but has been so for almost a decade. I intend to use that software to open some sort of space ship immersive theatre like https://bridgecommand.space/

trail moss
pine cape
#

You can have one app with both ClientPlugins and ServerPlugins, and only start the server if you select 'host mode' in the menu

plucky smelt
#

And I'd argue it's easier for people to remove client-only stuff after the fact to create a dedicated server, than it is to get the client+server plugins living happily in the first place

pine cape
#

You can start all examples in host-client mode, or maybe you mean something else?

plucky smelt
# pine cape You can start all examples in host-client mode, or maybe you mean something else...

Currently most examples have a match like this https://github.com/cBournhonesque/lightyear/blob/29daa4ab5ef8135672276e967ddfd411149766b0/examples/avian_3d_character/src/main.rs#L35

That kinda implies that these plugins can't coexist, which is not at all true. Ideally the features should just change which plugin is added, and the mode should just control which components are spawned that enables the particular behavior

GitHub

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

final rain
#

Some selection sharing for different game masters in what I'm creating! So far lightyear has been a breeze to work with, I really appreciate the work you guys put in it!

vocal sentinel
final rain
trail moss
#

by only start the server if you select 'host mode' in the menu you mean adding everything server related into one big systemSet and using run_if condition?

final rain
#

Those events don't need to trigger unless you want them to be running.

#

I assume there is also a stop/disconnect event

trail moss
final rain
#

If you're predicting. Likely. Which is why there are usually server, client, and shared components in examples.

#

Here I'm talking solely when deciding how to connect.

#

A host client will have the server and client component running at the same time.

trail moss
#

i am not talking about shared plugins and prediction, those seems trivial

final rain
#

Yeah good point, I have not looked into that too much yet. But so far I have not run in the issue as most of my system are dependent on clients being connected ex client_query: Query<&RemoteId, With<ClientOf>>,

pine cape
trail moss
pine cape
#

Yeah you would have to add them all if you want to potentially support host mode. But I think now bevy has a way to remove systems/system-sets, so you could also do that.
I guess use run conditions or wait for bevy to have more dynamic plugins

trail moss
#

i see

stray sinew
#

I upgraded my project to the newest lightyear commit and I keep getting this crash on the client-side. It seems to be triggered by joining a server or spawning predicted entities, but it will also happen randomly with no apparent cause. Anyone know what could be causing it?

pine cape
#

It means that there is a tick missing in the mapping between replicon tick and lightyear tick, let me look into it

final rain
#

Some more progress on some game master tools.

I was wondering, would anyone know why despite not moving all the physics entity in Avian2D do not go into sleep and always get called back into active mode? That might lead to using a lot of resources at scale.

stray sinew
#

I think update_cursor_state_from_window in the projectile example should have With<InputMarker::<PlayerContext> when querying ActionMock. I have a similar setup, without this filter there are 2 matches for the query and constant rollbacks.

stray sinew
pine cape
pine cape
pine cape
final rain
stray sinew
#

I noticed I get this error to occasionally, it only happens immediately after connecting to a server

peak ice
#

Was kinda curious if the bevy_replicon change was still in the works? I've finally debugged some stuff and I'm easily handling 100+ enemies (could probably do more just didn't test it). Is replicon known to be more optimized than lightyear? what exactly is the driving idea behind the switch? I'm asking because I'm quite happy with where lightyear is now:)

stray sinew
pine cape
#

@stray sinew before that you were doing replication on every tick?

stray sinew
pine cape
#

Sg, will test in these conditions

edgy shoal
#

I was kind of surprised that lightyear did not have any webrtc transport, so I decided to make it.. It kind of works!

edgy shoal
edgy shoal
#

Hey, I've been playing aroudn with lightyear recently and I have noticed a strange thing that I couldn't quite find any explanation in docs, at least not in the book (I read the whole "advanced replication" and anything that mentioned replication at all). It would appear that occasionally updates to replicated entities are missed in that client does not receive them. This only happens occasionally (maybe one in 10-20 changes), I listen for changes on client using Changed<T> and sometimes client does not seem to see a change to component T. It looks as if replication just lost that updated completely. I understand that updates and inserts are tracked separately, but nowhere in docs I saw actual statement that it is expected for updates to be completely missed in some situations.

Anyone has any idea if this is actually expected or it is more likely that I messed something up?

#

It seems to work as expected if I remove/reinsert instead of mutating, but this seems like very complex way of having to do this now for all changes that I need replicated or accept occasional random "it does not work this time" situation

stray sinew
#

Joining a server with a lot of entities crashes the client and causes this log spam on the server

pine cape
pine cape
rocky turtle
#

Heyy, I’m trying to use lightyear 0.26.4 and looking at one of the examples “common” it uses a macro lightyear_debug_event!() but can’t seem to find anything about it?

pine cape
#

This is for a custom tracing layer in lightyear_tools/src/debug.
My goal was to provide some helpers to store some structured logs in jsonl format that can then be analyzed later in duckdb or something similar

vale stratus
#

I'm having issues with replication groups. I have separate entities for the body (position) and view (camera orientation) for my player. The Player has a body_handle and a view_handle containing ids of previously spawned Entities. I'm using the MapEntity trait, but I'm getting a PLACEHOLDER on the client because the view and body entities are being replicated after the Player.

pine cape
#

One solution is to put all of these in the same replication groups, which guarantees that these entities are replicated together.
Another is to switch to the main branch, which uses replicon as the replication layer. In replicon all entities are always replicated together

plucky smelt
pine cape
#

probably at the same time as 0.19
I will release the replicon version for bevy 0.18 and bevy 0.19

plucky smelt
#

Awesome! I'm interested to see this!

onyx salmon
pine cape
#

Sure that would be helpful! thanks

onyx salmon
# pine cape Sure that would be helpful! thanks

Will draft tomorrow. Probably not as a patch since I merged https://github.com/simgine/bevy_replicon/pull/696 which adds an enum variant.
Even though it's most likely never matched by users, technically it's a breacking change.

GitHub

Adds AllExcept<S> filter scope and VisibilityScope::AllExcept, a counterpart to Components. When a VisibilityFilter denies visibility, every component except the listed ones is hidden...

dark ether
#

just linking this back here, I think that it is relevant #ecs-dev message

stray sinew
#

Will there be a replacement for the old ComponentReplicationOverride to support per-component replication control?

onyx salmon
#

The mentioned PR will to go into Bevy 0.19 release since I already have an RC for it. But this shouldn't be a blocker for you 🙂

pine cape