#lightyear
1 messages · Page 9 of 1
The hashes are based on the tick + the type of all the components present on the entity when PreSpawnedPlayerObject is added
If I assign/insert/spawn a session id to an entity as a component with a string inside containing said id, is it somehow readable by another clever user?
Any tips on how I could store session ids on clients without exposing them to the game itself? Perhaps only give the game client itself a client id, which then on the server can be associated to a session id on a db lookup. And versa.
Okay, there may actually be some types I left out, I know I forgot at least one component previously, so there may be more
You can also manually compute the hash by providing a hash inside the PreSpawnedPlayerObject component, if that's easier
What does that mean, without exposing to the game itself?
If the session id is on the client's computer they can read it. If you don't want them to read it, don't give it to them
I was toying with the idea of just using a monotonically increasing counter for minions and using that as the biggest source of data for the hash, but I'll try to get the proper way working first
what is the intended api through which i enable visual interpolation for something? my player is definitely visually interpolated just from registering interpolation_fns for the appropriate components it seems like. so i lean towards saying, "yes, they are visually interpolated" (edit: might be a frame-pacing or camera issue instead of netcode, holup)
Not sure what I mean but if someone had world inspector on a game in release mode, could they see the session id string by looking at a entity’s component?
True, but could another player read it? Not that it matters I could easily secure game transactions using a session key and session id system. If key isn’t provided at attempts for exchange, the tx is denied. Not sure how complex I’d like it yet but I guess multiplayer games with should have some security bottom line and that no one can just read the key and do things on their behalf.
I could be overthinking stuff for a multiplayer game lol. Perhaps the client id associated with the correct user alone is sufficient. Just need to make the db reducer code right, where all the user’s data gets read and written from.
If you only replicate it to the one user (or maybe easier to send a message to the specific user to be sure it only goes there) it can't be read by anyone else no
But most clients will know of client ids from other players I think, so you shouldn't use that for authentication without some form of token that you only send to the specific user it belongs to
Interpolation interpolates (using your registered interpolation functions) Interpolated entities by interpolating between 2 replication updates received from the server.
VisualInterpolation interpolates Predicted entities (also using your registered interpolation functions) to interpolate the FixedUpdate components across the PostUpdate schedule. So yes it's a framepacing issue. Maybe there should be a way to do this automatically for all Predicted entities by setting .add_visual_interpolation() on the registry.
This will 100% fix your jittering artifacts
For now you have to add this plugin: https://github.com/cBournhonesque/lightyear/blob/main/examples/fps/src/renderer.rs#L25
and then add this component on the entity: https://github.com/cBournhonesque/lightyear/blob/main/examples/fps/src/renderer.rs#L144
But I wouldn't really bother with considering security to begin with honestly
Absolutely agree, I’ll boil it down to just client ids first. Just wanna make sure I don’t make it too hard to implement later if I need to
I don’t know how hackable netcode is lol
In theory it should be pretty simple to tack on a token system at a later stage, but security is also notoriously complicated, so who knows
Will probably never get to that point unless game actually is fun and people wanna get ahead. I’ll just have it in mind if I think it could happen in any case
lightyear uses the netcode protocol for connections which is already 100% secure. You just need a secure way (for example https) to send a private ConnectToken to a user
This example (https://github.com/cBournhonesque/lightyear/tree/main/examples/auth) shows how to do that
Im currently writing my database columns together with their reducers. Just tryna think if there’s anything obvious I’m missing in regards to security
You’re right. Netcode makes it pretty secure already.
Nice, exactly what I need
huh. i turned my tickrate down so i could see better. setting this up doesn't appear to fix the jitter. visual interp is definitely enabled, because it looks / feels different when i toggle the plugin on/off.
some kind of ordering issue maybe? 
Maybe you also have avian interpolation enabled which is messing it up?
Also is your pos/rot -> transform enabled? Otherwise I don't really know what it is
already had both of those things correct. darn. i'll keep spinning on it
seems like it works great on the character example and that's where i stole half my setup from so 
oh the answer is literally explained in a comment in that example
trigger_change_detection: true,
now enabling VisualInterpolation causes some duplicating / smearing during rollbacks, especially at a lower tickrate. hrm
butter smooth in the happy case tho, very lovely
are you running VisualInterpolation on Position or on Transform?
Transform
I wonder why you need trigger_change_detection; I guess because you need to somehow propagate the transform to GlobalTransform?
also that's weird; the rollback should leave the Time<Fixed>.overstep() exactly the same, so the visual interpolation shouldn't affect anything
it could technically be from prespawns instead of rollbacks, those two things just happen to be one in the same for me right now lol
Is this the correct syntax for receiving a message (server-side)?
pub fn foo(
mut message: EventReader<MessageEvent<MyMessage>>,
) {
for _ in message.read() {
// Do something...
}
}
hmm i can't even get vis interp for remote players working in the avian character example
in lightyear 0.19, yes
that's not visual interpolation issue; looks like there's constant rollbacks
was a bad example for me to use to debug anyway, that example's predicting remote players 
yeah it only works with enough input delay to cover the RTT
at which point it might be worth simply interpolating everything (including current player)
hm even with a lot of input delay there's some jitter, i'm not sure why...
Constant ccollision with static floor collider perhaps?
hmm, by default, on main, when do the avian position to transform sync systems run relative to the (network) interp systems?
seems like the former in PostUpdate, the latter in Update, which would make sense... edit: ohh, no avian sync uses the same schedule as PhysicsPlugins by default. so it's only syncing on fixed possibly
You don't need to run physics for interpolated entities
And visual interpolation should already be ordered correctly with respect to avian systems
yeah but i am syncing position and rotation over the network. so network interpolation gets applied to those values. when do the interpolated positions get sync'd to the transform for display?
Ah yes I made a custom sync system that is a copy of avians but also works for entities that are not rigid body
yeah that did it. thanks. (edit: should such a system be built in?)
i did hit one other snag. the real thing that fixed my problem was manually setting an InterpolationConfig. the default one has send_interval_ratio: 2.0 - that means it buffers two ticks, yeah? seems to...not do that. i can only get something working with min_delay
same issue here when trying to run a second client on my windows 11 machine after spinning up the server. its def because the exe that cargo run builds and runs is already occupied by the first client/server. classic case of windows not allowing two programs with the exact same filepath, name and file extension to run at the same time?
not really a concern, server wont run on the same machine as the client anyways.
Is there a way to receive messages from the client to the server on that same client? My use-case is trying to avoid having to duplicate implementation, so I would love to be able to run the same logic on the server and client (one example is that I use a message for spawning minions, and currently I send a message to the server, but on the client I just create it immediately). This is probably causing them to be created on different ticks (which is probably why I'm struggling to get PreSpawning to work actually), but maybe if there was a way to combine the message logic it would be easier to get them running in the same tick on both the server and client?
No it buffers components for 2 * send_interval; if your server sends updates every 100ms, it will buffer for 200ms to guarantee that we have 2 components to interpolate against. Now that I think 2 * send_interval is not required, something like 1.1 might work.
Are you sure you have send_interval set to something?
I think you can specify a --target so that the exe has a different path
Yes messages between client/server within the same App should work fine
I mean like a remote Client sends a message to the Server to spawn a "minion", but now I want the client to prespawn the minion, so I need to somehow capture that message on the client that sent it.
Also just to confirm, but messages arrive on the server in the same tick as they are sent from the Client, right?
Normally you would have some game Event that runs in both the client and the server that you would react to in order to spawn a PreSpawn entity
how come the client knows to spawn a minion but not the server?
I guess I can test this by printing out the tick that the minions are spawned actually. But my true goal is to have a single system that I can run on both the server and client that accepts my Message struct and handles it
Oooh I just realized my minions don't work with PreSpawning because to make it easy for myself I didn't add a Name in the client one, so the components are indeed different...
Actually I think I confused myself, because spawning minions is handled with the Input, so that's already good I guess. But I have some other logic that is handled through Messages, specifically updating the target location for minions to move to, that's a good chunk of logic I'd want to consolidate, and it'll obviously grow as the game grows
I think the tools you can use are:
- PreSpawn: spawn an entity on the server and on the predicted timeline on the client. You need to run the same system in both client and server.
- PrePredicted: spawn an entity on the predicted timeline on the client, and give the authority to the server. This is used when only the client knows about the entity that needs to be spawned, i.e. you cannot run the same system in both client and server
In your case of the client 'spawning' a minion, I think you need PrePredicted, not PreSpawn
(the naming is confusing but I don't have any better ideas)
So I should make my message hold the event and then just emit the event on the server-side's message reading system? And then both client&server will have the same system that reacts to the event? That does seem easy to implement and easier to reason about
Ooh, I hadn't heard of PrePredicted before, I'll give that a shot
It's not super straightforward:
- the client spawns a PrePredicted entity: https://github.com/cBournhonesque/lightyear/blob/main/examples/avian_physics/src/protocol.rs#L52
- the server reacts on receiving the entity replicated from the client and adds its own Replication component: https://github.com/cBournhonesque/lightyear/blob/main/examples/avian_physics/src/server.rs#L114
- maybe the query could filter based on PrePredicted instead of InitialReplicated
setting server_replication_send_interval explicitly makes send_interval_ratio work, yep.
this means the combination of the default SharedConfig (send_interval = 0) and the default InterpolationConfig (min_delay = 0, send_interval_ratio = 2) will always result in a configuration that can't interpolate effectively? confusing
you're right that's pretty bad...
wow
such a cool bug check it out
My bullet logic only gets rollbacks when we add player base velocity into it
on a single entity, can i take a component that has add_prediction(ComponentSyncMode::Full), but then stop syncing it? for example with a projectile, i can deterministically predict it's position perfectly once the server confirms its location once, i don't need the confirmed entity's position sync'd after that
ComponentSyncMode::Once is basically the behavior i want, but i want it at the entity level. i thought e.g. ReplicateOnceComponent::<Position> might do it, but it seems like the client is still trying to sync the confirmed entity's Position that is no longer being updated by the server when i do that
I don't think that's possible right now; would being able to override the ComponentSyncMode on the entity level work?
yeah i think that's sufficient
And how are you stopping the replication btw? Are you just removing Replicating
mmm mostly trying to get it working with ReplicateOnce because i need it to be per-component; i still want the replication (server-issued despawn, for example)
it’s kinda awkward in the case of remote clients. i really don’t want to replicate position data for projectiles, but if if the remote clients’ projectiles are in the predicted timeline and the remote players are in the interpolated one, it is gonna look bad. like they are shot from positions the shooter hasn’t reached yet
i can’t just stop replicating projectile position data and then set predicted to true for all projectiles for all clients. remote clients’ projectiles need to be correctly fired in the interpolated timeline. their position data, however, still needs to be extrapolated from that point on
But if the projectile's trajectory is deterministic, why not PreSpawn it on both client and server then?
- then the projectile moves via physics (or just linear velocity) on the client, and gets despawned on collision, etc.
- damage computation are still done exclusively on the server
that's what i do
struggling to reason about prespawning something from a remote player. you already have the confirmed entity; what sense does it make to do prespawning and entity matching at that point?
and that still puts the projectile in the predicted timeline but i am displaying enemy players in the interpolated one, which is gonna look disjointed
I tought that what you usually did was transfer the ownership of prespawned client entities to server?
is your game fast paced? Or more slow paced just curious
ah i thought your remote players were also predicted. Prespawning would only make sense if your remote players are predicted
Why does ReplicateOnceComponent::<Position> not work? Does your confirmed entity's Position still get updated somehow?
it DOESNT get updated which causes infinite rollbacks for the shooter
the other clients are fine when i do that, minus the projectile not being visually interpolated because it’s neither predicted or network interpolated now
well, neither really. i am limit testing the design space to see what i can get away with. but probably slower paced overall / i will make the tradeoffs that slower paced games do
very concerned about bandwidth primarily
You're predicting your own player and interpolating other players?
correct
Option 1
- client 1 presses Fire and spawns a local bullet
- server receives the input and spawns a non-replicated bullet
- The client/server bullets should be fired from exactly the same spot thanks to prediction on the client 1's player
- server sends a message to other clients saying that C1 fired a bullet, and those clients fire a bullet upon receipt of the message.
The issue is that there's no guarantee that the remote player will fire the bullet from the interpolated character's position.
Option 2:
- client 1 presses Fire and spawns a prespawned bullet.
- server spawns prespawned bullet at the same time and adds
ReplicatewithPredicted = C1, Interpolated = AllExceptC1. AlsoReplicateOnceComponent::<Position> - You add
ComponentSyncMode::<Position> = Onceon the client 1 (either on the Confirmed or Predicted entity, to be determined) - the Position is only replicated once to C1, but since you have
ComponentSyncMode::<Position>on the C1's entity we don't check for rollbacks based on Position. - the bullet is spawned at the right interpolated position on the remote client C1, but it doesn't receive any more updates. You run a system on clients that still moves interpolated bullets so that you can keep moving bullets without any server updates
Option 3:
- same as option 2 but you write every predicted position in the PredictedHistory to avoid rollbacks?
- Theoretically this is not required because the way rollback works is that we only check for rollback if we received any update for any entity in the ReplicationGroup. So even if you don't send any more replication update for a bullet we would not check for rollback at all anymore.
So it looks like a combination of:
ReplicateOnce<Position>on the server- on the client, run movement systems for interpolated entities too
I will still open an issue for this because the current solutions are definitely not ideal, it would be great to have more flexibility on how Prediction/Interpolation works
i had considered option 1, the biggest problems being
- i am sending a message to do replication which is a primary feature of lightyear, pretty dirty
- projectile should be in the interpolated timeline (message should say what tick to fire on) but since it’s not network interpolated via lightyear it doesn’t get visually interpolated
option 2 is my preference right now just because i know sync mode: once works. but again, i can’t use lightyear’s visual interpolation here without faking the network updates, because the objects aren’t in the predicted timeline (despite their positions being extrapolated)
option 3 makes me wonder if i have a bug, though? when i do that, the shooter’s projectiles are fine until the prespawned entity confirms. then the location of the projectile forever bounces back and forth between the first confirmed location and the first predicted one after that. constantly trying to roll back to the position where the prespawned entity was confirmed
the history faking is non trivial too, seemingly. i need to dissect some lightyear code to figure out what order of operations i have to do.
For option 1: you would then move the remote-client bullet yourself on the client, you don't need Interpolation. VisualInterpolation is independent from replication, it can be applied to any component that gets updated in FixedUpdate. You can totally use visual interpolation without receiving network updates
I think option 3 should work in your use case, i would need more details to see why it doesn't work. Do you have a branch?
idk why i thought Predicted was a requirement for vis interp, great if i can just add it to whatever
i'll set something up in a sec
once branch in my repo
i am guessing based on your wording that i am causing problems by having one replication group per client / that client's entities? so that group still gets updates, even if that individual object does not.
so i tried giving each projectile a dedicated replication group, which has the hilarious behavior of all future projectiles shooting an additional projectile from the spawn location of every past projectile that hasn't despawned yet.
That's a possibility, but why are any of your projectiles receiving a replication update? What other component besides Position is receiving updates?
well im saying they were in the same group as the player thus the problem, but giving them their own group causes rollbacks
because of prespawn maybe?
Maybe, if you enable debug logs it could tell you which component is causing the rollback
ooh okay i was on the wrong track at first, here's something i think
i am getting rollbacks when the spawn command for my projectile is split into two messages.
here is an example of where the spawn message fit in one message
EntityActionsMessage { sequence_id: MessageId(0), group_id:
ReplicationGroupId(12114142938702618892), actions: [(34v1#4294967330,
EntityActions { spawn: Spawn, insert: [b"\r", b"\n",
b"\x05\xc6\x17\xebA\0\0\0\x80\xd8\"\xc1\xc0", b"\x04d\0\x9a\x99\xcdA",
b"\x06\xd0\xeb\x89?gff@e\t%@", b"\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80?",
b"\x08\x01\xfd\x0c!\xad\xbb\xd1\x14\x1e\xa8"], remove: [], updates: [] })] }
all good. no rollback. there is no other message for tha treplication group.
here is an example of where the spawn message was split into two:
EntityActionsMessage { sequence_id: MessageId(0), group_id:
ReplicationGroupId(12114142938702618943), actions: [(35v1#4294967331,
EntityActions { spawn: Spawn, insert: [b"\r", b"\n",
b"\x05\x17\x17\x94\xc1\0\0\0\x80\xf8\xdc\xbc\xc1", b"\x04d\0\x8f\xc2\xd5A",
b"\x06\x7f\xf6\x9d\xbefff@V\xb4IA", b"\x08\x01\xfd?!\xad\xbb\xd1\x14\x1e\xa8"],
remove: [], updates: [] })] }
// The prespawned entity’s predicted entity is created and sync'd here, before this next message comes in.
EntityActionsMessage { sequence_id: MessageId(1), group_id:
ReplicationGroupId(12114142938702618943), actions: [(35v1#4294967331,
EntityActions { spawn: None, insert: [b"\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80?"],
remove: [], updates: [] })] }
THAT causes a rollback. the insert, which is really just completing the original spawn command, is causing the rollback.
Do you know what that extra component is?
golly. yes it is because of that specific component. i wasn't explicitly specifying a Rotation on the server-spawned entity, merely relying on it to be passively added from required components of the other physics components
need to add it explicitly right when i spawn the entity
i might be good now 👀
Hm normally required components should add it at thr same time
But avian doesn't use required components for rotation I believe
I think they have specific systems to add missing components
does rolling back to correct one object roll back the entire client simulation? seems like my primary problem now is that if any rollback happens (from a natural cause like cpu lag, packet loss, switching too quick between windows, etc), any projectile in flight gets reset to its starting position
Question, why we disable the colliderhierarchyplugin, when utilizing avian? Just curious, I guess is something with how the propagation works
You don't need to disable it; i just disabled it because i didn't need the plugin
it rollsback only Predicted entities. Maybe your solution would be to:
- spawn bullet for the Predicted client (non-prespawn)
- spawn replicated bullet with interpolation AllExceptSingle(client) on the server
Sorry that this hasn't been straightforward!
equally sorry i’m causing so much trouble 😅
so if i spawn the predicted bullet and don’t replicate it to the shooter at all, it LOOKS fine, but the projectile can’t get server-sent despawn updates because i don’t replicate it
if i do replicate it, but don’t use prespawn, i just get projectile duplication. or if i don’t fire it on the client at all, i get firing lag
maybe per-entity sync mode is still gonna be the way 🤔 just using ReplicateOnce (now that i fixed all my other bugs) is good enough for me to move forward with experimenting though.
but the projectile can’t get server-sent despawn updates because i don’t replicate it
that might be fine, because i assume you would still run collision detection on the client for projectile VFXs
Another solution might be to remove the Predicted component on the pre-spawned bullet to stop it from being affected by rollbacks, but that's not super straightforward either.. Maybe a DisableRollback component could work?
Per-entity sync mode is not super straightforward because currently I add systems based on the component sync mode.
So the rollback systems are only added for the ComponentSyncMode::FULL components.
Being able to change syncmode means that I would have to add rollback systems for all replicated components, and then apply runtime filtering inside the system based on the OverrideSyncMode component.
Maybe just allowing overriding from Full->Simple or Full->Once but not the other directions would work
DisableRollback would be sufficient for me, yes. on the server side this is fully handled by ReplicateOnce already
i don’t want to run fully predicted hit confirms on the client like that. with the interpolated other players it’s gonna feel bad. could replicate the impact independently and treat it as an event from which to manually despawn the projectile on the client i guess
or i suppose i could lag comp
If you use interpolated enemies, you would lag comp on the server for accurate hit detection; but on the client you wouldn't do any lag comp, you would show VFX on actual collisions between predicted/interpolated
yeah that’s what i’m saying. realistically since comp isn’t perfect i’d probably do a small local vfx and then a big confirmed vfx+sfx
but i am hoping to avoid lag comp entirely (or to have very generous / lazy comp) with big slow projectiles with generous hit boxes and a decent connection. but i truly don’t know if that is tunable into something that feels good or not. that’s part of the whole exercise im doing here i guess
Has anyone ever encountered an issue where sometimes when a client connect, one gets a massive amount of rollbacks? It seens to be correlated to system ordering, as it sometimes occurs and it doesnt. The issue is truly very crazy, as the cause is totally a mistery to me dont even know how to start debuggin
It give me this panic from time to time no idea why
overflow when subtracting durations
Encountered a panic in system lightyear::client::prediction::rollback::run_rollback!
Does this crate expose an abstraction to connect to sockets over either normal TCP or websockets (I want to use the former for native builds and the latter for web builds)? I added auth based on the auth example, but tokio's net feature doesn't compile for wasm.
Oh, I think PacketSender and PacketReceiver is what I need
Is there a way to get a WebSocketClientSocket? WebSocketClientSocketBuild is pub(crate)
You can take a look at https://github.com/cBournhonesque/lightyear/blob/bevy-main-simplify-replicate/examples/common/src/settings.rs#L404-L404 for how to use the various transports, including websockets
WebTransport doesn't fix your usecase?
do you have the exact line of the panic?
Unfortunately closed the terminal. I was just wondering, how would one go about fixing rollback loops issues? Like what metric can give me the component that is the root cause of those rollbacks. Perhaps them I can at least know where to start
If you have visualizer feature enabled, type 'rollback' to find graphs that will tell you which components are the cause of the rollback
great thanks
hmm it seens the rollback loop overcharges my machine, any diagnostics info that may be usefull here?
the visualizer becomes very stale
did you try just turning on debug logging and writing everything to a file then searching for “rollback”? that’s how i debugged mine, going step by step through exactly what happened. default debug logs seemed sufficient to suss it out
yep, or lightyear::client::prediction::rollback=debug
hi im having some trouble connecting with the client when the host is in a different machine
im connecting using Netcode, and the server is set to localhost on the port 5000
pub fn get_server_net(config_data: &ConfigData) -> lightyear::prelude::server::NetConfig {
NetConfig::Netcode {
config: server::config::NetcodeConfig {
private_key: config_data.private_key,
protocol_id: PROTOCOL_ID,
..default()
},
io: IoConfig::from_transport(ServerTransport::UdpSocket(SocketAddr::new(IpAddr::V4(config_data.server_ip), config_data.server_port))),
}
}
pub fn get_client_net(config_data: &ConfigData) -> lightyear::prelude::client::NetConfig {
lightyear::prelude::client::NetConfig::Netcode {
auth: Authentication::Manual {
server_addr: SocketAddr::new(IpAddr::V4(config_data.server_ip), config_data.server_port),
client_id: config_data.client_id,
private_key: config_data.private_key,
protocol_id: PROTOCOL_ID,
},
io: lightyear::prelude::client::IoConfig::from_transport(ClientTransport::UdpSocket(SocketAddr::new(IpAddr::V4(config_data.server_ip), config_data.server_port))),
config: NetcodeConfig::default(),
}
}
to connect from the client i use the actual ip and the same port
is that configuration correct?
Set the server to 0.0.0.0 instead of localhost
The general gist is that picking the ip for the socket is a local OS concept completely unrelated to your public ip
when you choose an ip you are implicitly chosing a network interface. when you choose 127.0.0.1 you are choosing the loopback interface which only accepts connections originating from the same machine.
This is for configuring what lightyear uses, though. My problem is getting a token from the server on web, so this is before lightyear connects. Since lightyear already abstracts over socket types, I want to just use the same abstractions that it uses.
Ah i see; no lightyear doesn't provide this; you can make a PR to make WebSocketClientSocketBuilder pub, but the Transports currently have some extra stuff that is only needed by lightyear
so i tried some things with 0.0.0.0, couldnt get it to work, im pretty sure my config is just wrong though, i cant connect on 127.0.0.1 after i made some changes to test it on different machines, could someone confirm if its correct?
Ok, I will soon, thanks
is your client listening on 0.0.0.0 too?
yes, i tried it with both the server and client on my machine
yes
ok so the true correct setup is
- client listen address is the client host’s local IP as assigned by the router
- server address (on the client) and server listen address are both the server host’s local IP as assigned by the router
you can usually cheat both listen addresses by choosing 0.0.0.0, which is why you’re getting that advice. it accepts connections on all network interfaces
is the local ip the same as the public ip?
nope it’s distinct
if you list network interfaces for your OS it should be listed in there
and this setup wouldnt work when doing it over the internet, right?
over the internet you need the public IP, right
but you’ll still listen on the local IPs, the router uses those IPs to know which computer to forward to
that’s why you have to set up port forwarding in your router when you expose something to the internet from home. the router has to know, when a connection comes in on a certain port, which computer on the local network do i send it to?
once you are production deployed in some cloud it’ll be different again probably, depending on your setup
ok i think i understand
well, i understand the local ip and public ip + port forwarding
just want to make sure on this one, the host can do 0.0.0.0, but the client has to use their public ip
but if i wanted to test it locally i can do 0.0.0.0 on both?
The server specifies 0.0.0.0 for its own server_addr, but the client needs to use the server's public ip as server_addr.
Same for client
sorry what do you mean when you say "Same for the client"?
i understand the first part, i think
in lightyear it would translate to the server NetConfig io using 0.0.0.0 and the client NetConfig auth using the server's public ip
do you mean that the client NetConfig should also be 0.0.0.0?
I think the client should specify their own address as 0.0.0.0, but the server would specify the client-addr as public_ip:port
this is right yeah. the address of the UdpSocket you pass to client_config.net.io is the address upon which the client will listen. that's the one that should be 0.0.0.0, because you want to listen on all network interfaces
I migrated to main and the player can't move anymore. There aren't any new warnings/errors in the logs
are you using leafwing inputs or native?
native
I'm checking to see if the same issue happens in the examples, but I have to figure out why steamworks isn't compiling
simple_box works fine in main
our building system is being held back because version 0.19, does not support avian 0.2.1. I saw it had something to do with "issues" what they might be? Perhaps we can help
Ok, sometimes when I run my game, the player can move. Attacking causes the player to despawn, though, which I suspect is an issue with hierarchy stuff, bc that spawns an attack that's a child of the player
I think I'll just make my changes off 0.19 for now
hm i'm unsure of what could be wrong
Here's the issue I created: https://github.com/Jondolf/avian/issues/643
there seems to be a problem with how the ColliderAABB is computed
Something in avian 0.2.1 is breaking the way my ColliderAABB is computed. My flow: after Solver but before SpatialQuery, I update the Position/Rotation/Collider of an entity that is a child of a pa...
The way you can test it is use avian 0.2.1 and run the fps example. The ColliderAABB for lag compensation are in the wrong position
Super dumb question, but what crates do I need to import to make the simple startup work? Downloading the full repo works fine, but recreating it throws six or so errors
Sorry if this is a dumb question 😓
no such thingy as dumb questions
Just chec my mre cargo should be more than enough to get you starrted
trust i got thousands of them 😭
also it worked, tyvm king!
oh my jebus
that's fine, you just have higher jitter so you're receiving old updates
i'm beeing stupid right now. havent had this problem on an older version:
When running in HostServer mode, the client connection needs to be of type Local
i'm using the build_client_plugin() and build_server_plugin() from the simple box example.
alright, discordd was eating parts of my message, the when running in hostServer mode.... is the panic message i'm getting when trygin to connect to the server i started before in the same app
I'm having to make a lot of internals public, and it's kind of contrived to make this work for my use case, so I think I'll just write my own websocket stuff for auth
What's the best way to let a server send replication updates to a client, for the purposes of spawning an entity, but give the client authority such that it can despawn the entity and replicate that update to the server? I tried giving the entity client authority on the server side (on initial spawn), but then the client never receives the spawn replication update from the server
I don't think that's possible. You could have the client send a message to the server to despawn the entity
Hmm, okay. I'm thinking of attaching some sort of ID to each of these entities through the server to solve this. Is there a better way of telling the server which entity to despawn?
implement MapEntities for the message type and send the Entity directly
Thanks!
I'm currently splitting off my complex sim systems so they're not running in rollback and I noticed that gizmos are cleared out during rollback and are not rendered when set during the regular FixedUpdate. It results in gizmos flickering when some rollbacks occur. I can definitely set the gizmos during rollback too to fix this issue, or swap so I'm not using gizmos for these systems (since they'll be actual rendered models in the future), but this does point to a complex issue of Bevy and library provided FixedUpdate interactions with the rollback of the entirety of FixedMain. I'm wondering if a configurable rollback schedule might be better, but I think that would have to happen during one of the fixed schedules and would have to ignore Bevy's fixed loop when more than one FixedMain needs to happen in a frame.
Ideally for me rollback systems are "opt in"
I could probably solve this with my own implementation of a fixed sim schedule, but that seems like overkill.
Make sure you use .add_map_enitites() in your protocol when you .register_message
I'm using 0.19.0, and I get this error when sending a message. This seems like an oversight, since lightyear now uses varints for encoding fragments?
Yes it probably is, there might be an old check on the number of fragments that I forgot to remove
looks like it
also thinking about it
if FragmentIndex is a u64, how does this work on platforms where usize is 32 bit?
I still think that FixedUpdate should be used for rollback. A user would use fixed update when they need their system to react precisely to inputs or when they need to correctly match the simulation time. In my experience most fixedUpdate systems need to be rolled back.
Ah I experienced the flickering as well and was wondering what was causing it, you think it's due to gizmos?
would it be possible to release a 0.19.1 to fix this?
Definitley FixedMain should remain the default for rollbacks, but I'm thinking a configurable option at plugin build time would help.
Gizmos clear during FixedFirst and then collected during FixedLast, so during a rollback if you are not setting a gizmo then it will be cleared. I don't know why, but the final FixedUpdate after rollback doesn't refresh the gizmo for me.
https://github.com/bevyengine/bevy/blob/main/crates/bevy_gizmos/src/lib.rs#L273
Sure can you make a PR? I won't have time immediately but I can do it by sunday
Ah, yes I can try to make it configurable. But then the update_tick system would also have to be part of the new configurable scheduke
I can try a PR early next week if you have other priorities.
Should I target main or bevy-main?
Maybe a Rollback schedule could be added which runs roughly at the same time as FixedUpdate?
Main should work
I think letting the user decide (optionally) where to put the schedule is the best setup personally, but yeah parallelizing the rollback while FixedMain goes through its own loop could be a solid architecture for me.
This is used to filter out excessive tracing correct?
Well according to the logs, when my client disconnects and quickly reconnects it seens server didnt have the time to despawn it is old entities. Which causes rollbacks right on the get go. Because he still tries to replicate his previous entitties to client itself, this was my bug I wonder how I could fix it, guess I just need to wait or make despawn more immediate as server despawn seens very slow for some reason
the bug might also occur when one, has network-relevance manager enabled with replicate target and sync target all entities. As it seen that the sync target component applies it is logic before the room manager (sometimes, system order non defined) actually applies, causing rollback as he will receive replicate from entitites in other rooms yet he has no information on them
Guess the "get started" system from sync target is a little faster than network relevance manager, which makes sense when I come to think of it
The fix make replication targers unique to client id, as room manager logic self increases both sync target and replication target
Which is appreciated
Can you open an issue?
I will first refactor my mre to check my theory and a continous sample, but from what I see yes it occurs first, in my bullet logic, when you make them consider rooms. You get constant "trying to despawn entity error" even tho that bullet shouldnt even be on that room.
Ah I see, yes a mre would be helpful!
i have some non-sync’d predicted projectiles with VisualInterpolation<Transform>.
when those projectiles undergo a Position misprediction as they spawn (since they were not prespawned), the correction function is properly applying the correction to Position.
i cannot, however figure out when to extract that corrected Position to Transform in a way that does not break the Visual Interp somehow. any thoughts? it’d be easy if corrections were applied in the fixed schedule, but looks like they get updated in PostUpdate
like, in the normal, non-corrected scenario, i don’t need to extract those positions manually at all, it just works. but the corrections are getting swallowed by vis interp somewhere if i don’t manually copy them over
You're right
you might have to run a sync system (from pos to transform) again in PostUpdate, after correction
And i guess we could either disable visual interpolation if the component is being corrected
Or order correction to happen after visual interpolation
how can i change the netcode to be local? i'm trying to understand the lobby example, but having a hard time following the "common" folder 🙂
alright, i got it.... lol
vast improvements on current main compared to the 0.19 release.
A lot less jitter, even with cubes and jumping it feels really good when predicted.
Still the interpolated other player seems to be jittery when changing direction under the provided networking conditions:
latency_ms: 50,
jitter_ms: 1,
packet_loss: 0.03,
Is there a way to modify how the interpolation of other controlled entities work?
Like adding a little bit more lag but having it smoother for the interpolation?
there is an InterpolationConfig https://github.com/cBournhonesque/lightyear/blob/d7ff0b0ead980b0ef4b6cb69ec80f1b3fdc3c5c2/lightyear/src/client/interpolation/plugin.rs#L60
personally i am using a min_delay of the length of 1 tick + my max expected jitter, and that works well. i set send_interval_ratio to 0. worth playing around with tho
turns out i was already doing this, and it was working, before i asked. i just had a different bug that made it look like it wasn't 🥲 awkward little gotcha there though
hm
when the predicted projectile fires on the remote player's screen (right player shoots on the top screen), a rollback happens since there was no prespawned projectile. this (correct) rollback causes the predicted player (top screen, left) to jitter even though they were correctly predicted.
the addional jitter is there even when i disable all my interpolation and correction copying. it's like the rollback of the predicted timeline is spitting out a slightly different result for the player. struggling to understand how it could be different though..
Can you open issues for this? I'm at a ski trip now so I might forget about them when I come back if they're not on the github
Yes I think in most cases you would to limit your bandwidth by sending updates less frequently
oh yes i just wanted your intuition to see where i should look before i went to the trouble of making a proper repro
realize it's a pretty vague ask
But yes that's strange. It's expected that all predicted entities are rolled back when a rollback happens, but I don't know why they would jitter if they were correctly predicted
You would need to log the values for each tick to see if they are really diverging
that's the thing, i did, they are. lol
it's by 2 ticks, but i think my logging has a system ordering issue and it's actually by one tick
ill fiddle with an example and see if i can repro
Do you use gizmos? Someone was saying that rollbacks can cause them to flicker
not in this case but i definitely have that issue when i do. is that why the box that encloses the spaceships example constantly flickers while a remote player is moving?
I think so yes
Hmm I believe in that case it is correlated to collisions rollbacks
As in sole clients that doesnt occur
Hmm interesting just found out that if a bullet has a different rigidbody definition than my player rigidbody. When I have a bullet rollback it expects lineardamping on it, something solely applied on my character physical rigid body
man debug has truly unlocked some good shit
I'm trying to add a singleplayer mode in my game. I chose to use the LocalChannel client transport with Netcode.
But when I simulate a crash from the internal server app or even when I stop the server normally (commands.stop_server();), the client spams error in the console (even after exceeding client_timeout_secs):
2025-02-16T21:23:24.153303Z ERROR lightyear::connection::netcode::client::connection: error updating netcode client: Transport(Io(Custom { kind: Other, error: "error receiving packet: Disconnected" }))
2025-02-16T21:23:24.153407Z ERROR lightyear::client::networking: Error updating netcode: netcode error: error receiving packet: Disconnected
2025-02-16T21:23:24.153958Z ERROR lightyear::client::networking: Error sending packet: netcode error: error sending packet
Switching to UdpSocket transport don't cause these problems (even after a crash from the server)
LocalChannel, so 2 apps in the same process? Could you please open an issue?
Yes 2 apps in the same process. The internal server app is launched in a seperate thread
i think client error handling might just need some love in general
it was disguised by other bugs, but this ultimately was due to my correction-copying system. idk why the player is getting corrected tho. logs are fine, rollback simulation sync is fine with previous frames.
excluding the player from the position_to_transforms_after_correction system fixes it, so that must be the problem. but if there weren't any mispredictions, why was there a correction?
overall it is fine because i am treating "predicted and fully replicated" differently from "predicted and fully extrapolated", so i'll just only extract corrections for the latter...just can't clock why the player is getting corrected at all
we are in business tho. with all of my known bugs fixed this feels great and doesn't need me to do lag comp. 🙂 maybe a little silly looking with the sped-up projectiles on the target
For me it was only when I was rendering gizmos in FixedUpdate and not(is_in_rollback)
Gizmos are cleared in FixedFirst
looking smooth, how much lag and jitter did you use?
both clients are 100ms, jitter 5ms (my settings technically cover up to like, idk, 9?), but packet loss 0%. i think i need to give up a whole extra tick of latency to cover dropping a single packet cleanly, but just haven't tried yet
also dropped a comment on https://github.com/cBournhonesque/lightyear/issues/894
predicted projectiles resetting during rollbacks is my last real game-ruiner
Awesome, so the problem is that during rollbacks some things are corrected even though they don't need to be? Yes I think that's the current behaviour, currently I rollback everything without tracking which entities didn't need to be rollbacked. Great find, thanks!
I would appreciate if you could send me your test repo
It would also be nice if we could just rollback the prepawned entity and nothing else.. maybe during check rollback I can add a ToBeRollbacked marker on the Predicted entities that are mispredicted, and leave the rest. That's a bit risky though
This sounds like the same issue maybe? You see them being rollbacked visually because of correction, if we disabled correction for correctly predicted entities your projectiles would not move even during rollback
i am sitting here trying to decide if my entities are considered “correctly predicted” by lightyears systems if the confirmed entity only gets updated once
probably not, right, because the confirmed tick will be way too old relative to the prediction window of “when projectile spawned until now”
Also can you tell me more about your approach? If I understand correctly your enemies are interpolated, and you replicate a bullet with both Interpolated and Predicted? Or are you using prespawning? I saw something about spawning a bullet on the interpolated timeline, and then fast-forwarding it to the predicted timeline. How do you achieve that?
They should, I only check rollback if the Confirmed entity receives an update. However if any entity rollbacks, I rollback all predicted entities
my repo is up to date if you wanna go poke around. you can repro just by lowering the shoot cooldown and spamming shots with two clients open (cooldown is above my player component declaration)
enemies are interpolated but enemy projectiles are predicted. i don’t prespawn them, i just let them rollback into the predicted timeline from the confirmed one. this makes them “fast forward” kinda via the correction function.
the idea is to have enemy projectiles be more in the interpolated timeline when they are close to the enemy (so it looks like they shot from the right position) but more in the predicted timeline when close to you (so you can dodge it). since the local player is predicted you want to be able to dodge things in that same timeline
then yeah only rolling back the things that were actually mispredicfed seems like it would work
but uh. say i fire a projectile on tick 100. on tick 120 i fire another one, causing a rollback of, say, 5 ticks. when all my systems run for tick 115-120, where during those executions is the original tick 100 projectile in the simulation? just at its historical predicted location?
bc otherwise how could you resimulate its position starting from 115 when your confirmed data is stale from tick 100
oh even better i made this earlier, here, snag my branch of the 3d character example. here's the diff. just stand still and press q to fire, then fire again whenever to see the incorrect rollback. character movement is rollbacky w my changes but not required for this
Yea but what about your own shots trying to hit an interpolated enemy?
shooters shots are in the interpolated timeline - they lag when they fire. i am going for “moba” gameplay not for “fps”
Ah I see, you could interpolate everything including the current player, then
gotta predict player movement or it feels like crap, which causes all the downstream problems haha
less bad in a click to move game; with wasd it’s truly unplayable to have unpredicted movement
i’ve been using a lag injector to check how some games work so i can steal it, and this setup seems to be the consensus
Well that is actually the rollback ocurring perhaps visual interpolations is not working as expected?
Technically the components are there to trigger it (as it’s the example from the repository), but it does look like something isn’t working properly.
I see , cuz league of legends doesn't do prediction for instance, if you lag your own actions are delayed
iirc league has a movement prediction option that’s on by default, but yeah, everything else is delayed
Nope it's off by default
But you're right that they have it as an option
I never thought of having prediction on just for the movement, but not for sprlls
i rejected it the first time i came across the solution and didn’t revisit it until i studied Battlerite with my lag simulator, hah
i think some mmos pull the same trick
battlerite does this?
But also you said that other players shoot projectiles which are sped up into the predicted timeline
but that doesn't work for projectiles from interpolated player 1 to interpolated player 2
in that case you want the projectile to remain interpolated no?
well ideally sure but if you’re gonna give up visual consistency, rather it be between two players you are not interacting with
i think ideally the way the projectile might work is to have it be more predicted the closer it is to you (the dodger), and more interpolated the further it is away. sounds tricky
idk about the projectile fast forwarding, just the predictive movement with lagged abilities
their melee is crazy, the visual is just a lie. attacker’s visual in predicted timeline, but the hitbox in confirmed 😬
that's good to know, i'd love to have a resource that lists examples of how other games do this kind of stuff
it's funny that your predicted players shoots projects in interpolated timeline, and interpolated players shoot projectiles in predicted timeline
if only! that would’ve saved me some time
Question, what would be the ideal use, of a pseudo client?
My case scenario -We have a tower space, which is basically a room. That has it is own kinda lobby/room. we ideally always want that room to exist but for a room to exist it must have a client id connected to it
Ok i ran this. When I press q again, the first bullet gets rolledbacked. How come it doesn't get corrected back to the initial position?
as in, why is it snapping instead of correcting when we have corrections enabled?
I didn't check the settings carefully; but I think correction is enabled?
I think you should be able to create a room even if no client-ids are connected to it
i think i disabled it to make it obvious it was snapping
yeah i did
oh no youre right - i enabled it. turn it up? lol
I believe there is no add room function in room manager.
ahhh, remember my issue where i said visual interp was blowing out corrections? it's that
i didn't port my fix for that
i thought this would fix it
but for some reason it doesn't seem to work
ah maybe that's it
Could you make a PR with your fix to lightyear? Is it just a system ordering? or is it an avian-sync issue
i wonder if that PR you just linked fixes the problem i am about to describe (edit: it doesnt) but, i don't have a general solution atm. what i'm doing...
app.add_systems(
PostUpdate,
(
position_to_transform_for_corrections
.before(TransformSystem::TransformPropagate)
.after(InterpolationSet::VisualInterpolation),
),
);
pub fn position_to_transform_for_corrections(
mut query: Query<(&mut Transform, &Position), (With<Correction<Position>>, Without<PlayerId>)>,
) {
for (mut transform, pos) in &mut query {
transform.translation = pos.f32();
}
}
but since i keep getting inaccurate (?) corrections put on my player i need to explicitly except them, so upstreaming would break me
it also makes the assumption that you want lightyear to be responsible for the pos <- -> transform flow everywhere, which means we should upstream the 3d and 2d versions of this too
but idk to the extent that different games / users want to configure that differently. although i do believe there should be one "blessed" avian setup out of the box without the workarounds
refactored my protocol into it's own crate. incremental compilation time to the common crate 33s -> 7s. 🎉
can't tell you how much time ive wasted compiling
I know there is Host mode, but it’s more challenging to reason about compared to server/client mode.
Is it possible to run an android app with client/server?
Or would you need to spin up a server for an android app if you don’t want to use Host Mode?
I have no idea, are android apps single threaded?
No, they could run multi threaded, there are not many threads available, but nowadays I think most of them should have multiple.
Small request for docus update on the
/// Percentage of packet loss
pub packet_loss: f32,
For the package loss, I think adding that the value is between [0,1] would make it clearer, as I though 1.0 would mean 1% package loss, and got confused why I couldn't connect to the server...
Hmm the hashsets keys, inside entity to rooms. Never get cleared is that an expected behaviour?
Ought to think just repopping the entities would be the same time, and wouldnt cause excessive memory storage here
Btw if you dont clear client from a room and he reconnects to that same room some very weird shit happens
Just to confirm, if a pre-spawned entity, then receives the server confirmed entity, both will still exist (one makred with Predicted the other with Confirmed, but they will not merge. is that correct?
Feel free to open a PR, I'll approve it 👍
done
I tested main and the new skip-correction branch, but I still have very visible stuttering for physics objects.
I am doing the same as is done in the 2d spaceship example, but in 3d something seems to be different.
Stuttering like that can be due to one of 2 things:
- visual interpolation is not setup properly so your objects move in FixedUpdate, but not in Update schedule
- you have constant rollbacks
I think you should first try to see which one it is
Since gravity is enabled avian_3d character it has constant collision. Try disabling gravity and go inside your egui. Check prediction metrics
If that little guy is going banana, well it is gonna look like shit
ClientInterpolation is added through the ClientPlugin (also If I try to add it on the client, I get an error that is has already been added).
I also tried to modify the parameters to see if that would improve the stutter but not really any success.
What is a good way to check for rollbacks?
Comparing the confirmed and predicted positions per tick, or is there another way to check if a rollback occured?
Disabling gravity makes it look a lot less jittery. But as gravity is applied on both server and client, that should not real to rollback?
this is how
Go to your egui, and open this guy
Another way is enabling rollbacks debug on log plugin
I dont know how to do that tho using the setting setup? Mayber overriding but seens unecessary
I have thousands
Yes as you can see not good
You can say that indeed...
Its basically every tick
yes it is
I think I will refactor that sample.
@pine cape Is it necessary, for all samples to follow the "low-code" approach utilized with the predispose settings file?
I believe it would be a good idea to split them into portions. For example: Avian 3d character makes a character that moves physically.
Not a character that moves physically both in host mode and in separate mode. And is friendly with edgegap
it's convenient for me to be able to test all examples in all modes
Yes exactly. The pre-spawned entity on the client becomes the Predicted entity after the merge, and the server sends replication updates to the Confirmed entity
No, things should be cleared
Hmm I see, but alas It seen maintenance will become overbearing at same point (my impression is that most sample are already unstable). Also most games just follow one "style", never heard of a game that transitions, between host mode to separate mode according to servers. Perhaps we can make most samples using the common separate mode and one general testing one, instead of multiple different scenarios and codes.
I think most examples are working fine, it's mostly just the avian samples that are having issues since I changed a lot of rollback related stuff recently
Yes it seems, that he Avian example suffers from constant rollbacks on current main. (basically every tick).
Even without anything else except the two characters.
that's unfortunate, the rollbacks were completely gone when removing the cubes. You mean the avian_3d example right?
the avian_3d_character example
by using the following conditioner:
conditioner: Some(Conditioner {
latency_ms: 100,
jitter_ms: 20,
packet_loss: 0.01,
}),
Ah they are gone unless you bump once into the other character
It looks like as soon as there is any collision there are continous roolbacks afterwards (every tick)
I give u 100 buck if you fix promise on my mother, this godamm collision shenanigans hohoho
@pine cape the fact that we have continuous rollbacks, does that mean we have a simulation that never converges again?
Would that mean the predicted and the confirmed entities have differences every frame?
Hello everyone! I am looking for someone to possibly play a game demo and then have a conversation about what kind of networking shenanigans I need to use for it to feel right. Right now my code is heavly based on the starship example, I just don't think things feel right on the client side, and when there is large amounts of latency (100ms) the client side is unplayable. I'm looking for a recommended networking setup for a PvE game that you play with friends where one friend is the hostserver.
Spaceships utilize avian, and recently avian + lightyear has been really unstable with dynamic bodies.
Perhaps you can try using kinematic bodies (that has worked out for me) with sensor colliders as hitboxes.. Or just dont use physics at all
I am using kinematic bodies, that isn't the issue right now. Its more along the lines of, do I predict? do I interpolate? have input lag? who has authorty over what?
Depend on your game, is it fast paced, is it slow paced? Input lag is generally utilized with predicted entities and mostly used with high ping conditions. Server most of the time should be the authority figure, he should tell who spawns, when replication occur and so on. But sometimes you can use client_replication, to avoid over using server example: Read cursor movement
yeah the game is kinda fast paced, It intended for friends playing together so I don't care about cheating which opens up client side authority. I have a demo on steam I could share with anyone trying to get a better idea on the style of game.
fast paced, should have predicted entities. For player, and interpolated for npcs. You can make all interpolated and one sole client predicted (specially if there is no pvp) for the player scenario
ok, so fast paced games should have predicted players. Im noticing input lag kinda ruins the feel on the client side, can you do predicted entities without input lag?
you can
it usually should be 0
Once we figure out what is causing the rollbacks, prediction should feel really good.
We are about to release a fully networked experience in VR where we use the prediction/client/server tech (similar to what lightyear is using) it it feels very responsive.
So if it feels unresponsive its more likely related to some issue in lightyear (either on your implementation or the framework itself) rather than the networking model.
I would have to check debug logs to see, it could be some avian non-determinism
The simplest version would probably to interpolate everything. You would have a delay on your own inputs but it could be acceptable
Then you could predict your own actions and interpolate everything else, which would make your own actions feel responsive but you might have to use lag compensation
If your game has a lot of physics-based interactions (collisions, etc) you could try to predict everything, but as you have seen in the spaceships example it mostly feels good only when there are no mispredictions. I think for things to feel good even with mispredictions you would need more tuning: maybe extrapolation using velocity/acceleration, tweak the correction parameters, etc.
for the pve with friends i would just give up server authority tbh
Or you could use client-authority instead of lag compensation in some cases. For example battlefield has the client tell the server that the player hit an enemy
So it seems the controlled entity is not the issue but the other entity is (without any boxes).
From the log I don't fully understand the meaning:
Correction { original_prediction: Position(Vec3(2.1028938, 1.2499865, 0.11440856)), original_tick: Tick(3642), final_correction_tick: Tick(3657), current_visual: Some(Position(Vec3(2.1028936, 1.2499865, 0.11440855))), current_correction: None }
It seems to be off by a very small amount, and the current_correction is None,
Is there a way to define quantization for the synced values?
So it seems to be related to collisions, when Gravity is set to 0, the rollbacks stop after a while.
But even then there are rollbacks as soon as the other player is moved.
(but only when stoppind and starting the movement, when moving continously the rollbacks stop without gravity)
to be expected. It is extrapoloting, your user input the only way to not have those rollbacks is input delay
But the current_correction is None
oh yeah it is
oh now it isnt
check the prediciton value and currentt value
thei have a 0.00001 difference
So a rollback yotu shall have
I added input delay
input_delay_ticks: 16,
correction_ticks_factor: 15.0,
but it seems not to make any difference
Yes there is a small difference, but shouldn't the current_correction be Some instead of None?
You still get rollback when starting to move?
HMM
yes
The part which I can't find up to now is why the current_visual is Some and the current_correction is None, from what I can see is that the current_correction is only None if its a new correction (but then the current_visual should be None as well.
My my that explains a lot of my rollback loops
I have no idea why it occurs my guess is it thinks it should rollbacks, but it doesnt return the correction component
Therefore he keeps rollbacking
And maybe sometimes he gets the component
I checked the collisions, and they appear to be reported with the same values and the same order
After analyzing some more logs, it seems that they collisions re not identical, different point data, normal_impulse etc.
So it seems the collisions diverge between the client 2 and the client 1.
values are close but diverge slightly, like -0.029934 vs -0.029934008
Are you sure you're using the correct clock? I.e. Time<Fixed>
Not sure what you mean? I'm currently using the avian_3d_character example of the repo.
I'm sorry, I missed the context, ignore me 😅
Actually that example does use Res<Time>, it would be worth checking if Res<Time<Fixed>> makes a difference. It did cause desyncs for me, but that was also on 0.14, so maybe the behaviour is different for 0.15
even when replacing all Res<Time> with Res<Time<Fixed>> I get continuous rollbacks.
So it still is an issue. What I'm not sure about if the corrections aren't properly applied (and we get different collisions every frame).
Or if the collisions are inherently diverging.
It looks like at the start the collisions are identical, but after I bump into the other character they diverge (ever so slightly).
I couldn't really find a place where the correction functions are used in the lightyear source, but I might just be missing it.
(I checked, and the functions are called which are provided in the protocol, but even when returning the target value withour interpolating I get continous rollbacks)
That is lack of determinism with avian itself
But contact pairs seems to be in the same order now (I think)
that doesnt make sense, if they have the same order why would they diverge between clients?
Btw where are you getting all those logs from?
is it prediction::rollback tralalal =debug?
Simply logging all collisions for each tick and comparing all contact pairs and forces.
Randomly sampling a few ticks
Perhaps it would be a good idea to leave such logs on debug and pr that
I would appreciate it
There are in the example but for the boxes, I just added them for the characters, as I disabled the boxes.
Could I ask for some file management / module advice in here kings? Like where explicitly what kind of functions would go in which file (main.rs, client.rs, shared.rs and server.rs etc)
I read through the cheatbook and it was p good-- but I dont got the game development knowledge to extrapolate much from that
Doing something of a very basic 2d rpg if that helps any
The game has a lot of colliders, sensors, but very minimal dynamic bodies in terms of how I'm using the physics engine. The main reason I'm even here is this problem:
On the server side the client player moves smooth, on the client side the server player (and other client players) seem to overcorrect for inputs and they jump around, but only when there is latency (set to 100ms, similar value to live testing with a friend).
I'm not sure why this is happening. The code is based on the spaceship example so I know its server authoritive were everything is predicted, which is something I could give up on because of PvE. But why does the server side's client player still look smooth? I feel like I should be able to get better results without moving from prediction to interpolation or changing who's the authority of the player.
I think that up to you, and depends on what kind of game you're making. Is there a dedicated server? Hostserver? etc?
Dedicated, yeah. Trying to avoid crossing everything up and making a MESS without knowing the whys n wheres
Something simple, tile based, probably simpler than a roguelike even
lol i might be in that situation haha
I would maybe check out https://github.com/cBournhonesque/sixdof, he made lightyear and all the server code is in the server folder, and all the client code is in the client folder
I will take a look, ty homie
When I last looked at this guys stuff I found it very uh, daunting 😅
yeah it took me like 2 weeks just to get a main menu with a hostserver and client button working lol
I personally found getting an example "working" without his lightyear_example_common library was a good place to start. It abstracts a lot of the setup of lightyear making the examples easier to read and harder to copy.
That may be the shout homie, Ill see if I can pull it off 😭
Also here's a menu example for hostserver/client setups including steam networking options https://github.com/SueHeir/lightyear-menu
That link 404s for me
it was private my bad, is it working now?
Yess thank you, I've been wanting to get something like this set up
Especially the part about connecting to steam friends seems awesome
Just a warning, I only tested steam connections with my actual steam game app id, I'm pretty sure it will still work with the default 480 app id but it wasn't tested.
regarding the constant rollbacks with prediction and avian integration.. presumably values are nearly correct, are we talking tiny floating point discrepencies causing rollbacks? wondering if anyone has tried quantizing the physics values (position, rotation, linvel, etc) before and after the physics step, on client and server?
gaffer suggests this so you can transmit the values using fewer bits, but it would also maybe hide any minor desync issues (See the Quantize both sides section)
i never got to properly testing this to see what the side effects are, but i just rediscovered it and put it in a gist in case anyone wants to experiment: https://gist.github.com/RJ/74e598b84dd81feb40f72407dee4ad79
it quantizes stuff before physics runs, and after physics but before physics syncs transforms etc. so the game/networking should only ever see quantized values for physics states (client & server). in this case i'm using a scale factor of 1/8192, which means ~ 0.0012 is the smallest difference in values you can represent.
It feels a lot like stardew
lol the artwork for the actual game is also pixel art
@long marsh this should help improve the correction logic; https://github.com/cBournhonesque/lightyear/pull/913
i'll also merge the other PR
That was my next plan. I talked to Jondolf, and we tested with the deterministic2d sample, and when no joints are involved, even if the entity id's are different, the result should be deterministic.
Testing with quantization is the next thing to try, but I only have time later in the day to see if it helps.
What schedule would you use for the quantization? Would you run it twice?
i'd use the same schedule as avian, which by default is fixedpostupdate iirc
i'm not sure it needs to be run twice.. i'd test by running it before physics and after physics but before avian's sync set for starters i think
to make sure none of your code or lightyears code ever sees a non-quantized physics value
not if you change the order of entities. You can change the order that the entities are spawned and the results will be different
What do you mean by quantization? Which library is introducing quantization?
like rounding to a multiple of some small fixed amount, to reduce the accuracy of the floats but in a deterministic way. i think this is often done by multiplying by a scale factor, rounding to an i32, and then converting back. it limits the available accuracy for physics values, so you could transmit them as a type of integer. but i was mainly thinking of using it to paper over any small floating point disrepencies
from the gaffer article "In the cube simulation I found it necessary to have 4096 position values per-meter" so he's tuned the quantization so he can represent 1000mm in 4096 integers, ie 1000/4096 = 0.25mm accuracy
Question, does replicateoncecomponent needs to be registered in the protocol?
doesn't need to be baked into avian for an experiment. just write systems that mutates all the postion, rotation, linvel, etc. and run it before physics set and before physics sync.
you probably only need to quantize any physics values that are in the protocol and being replicated, ie position, rotation, linearvelocity, maybe mass or angular velocity or some others depending on the game
in the case of Position, instead of operating on a 2d or 3d plane represented by float coords, operates on a snap-to-grid of distinct values where the quantization scale defines the grid spacing. values after quantization will be very similar to before, but snapped to the nearest grid position.
yes
Ah you mean you want to add quantization to fix the issue?
I'm pretty sure avian is mostly deterministic, there's just loss of determinism due to:
- entity ordering (in hashmaps, etc.)
- ordering of contact points
yes, quantization having the added benefit of maybe making it easier to save bits on the wire, but really just to hide any small differences due to non deterministic avian shenanigans and make stuff work without constant rollbacks
obviously fixing the root cause would be ideal 🙂
Them replicate once component should be used, when you want to add a component after some server logic?
Intead of being right on build time like in protocol
You register component C in the protocol, then you add ReplicateOnce<C> on your entity to make sure that no updates are sent after the initial update
Okay so it ceases the replication good to know
Ok testing with the quantization doesn't stop the rollbacks (if I add the cubes again) in the example.
too bad... which example are you using?
avian_3d_character
I caught up on the determinism discussion
the issue is definitely in avian
were you able to run the avian_determinism test with randomly ordered entities and multiple contact points and get a passing test?
yeah determinism_2d is fully deterministic with shuffled entity spawning order (but without joints)
The server is a dedicated server? or are you running in host-server mode?
with joints it's not deterministic with shuffled entities atm because of query iteration order
good to know, thanks!
2025-02-19T15:55:21.572718Z DEBUG lightyear::client::prediction::rollback:247: Rollback check: mismatch for component between predicted 77v1#4294967373 and confirmed 72v1#4294967368 on tick Tick(161) for component "avian3d::dynamics::rigid_body::LinearVelocity". Current tick: Tick(267) predicted_exist=false confirmed_exist=true
I believe there is a condition missing that should check, if predicted history exist before rollback on current main
oh just saw the todo
that is not what I could observe.
if I schuffle the columns (as suggested):
let mut cols = (0..COLUMNS).collect::<Vec<u32>>();
cols.shuffle(&mut rand::thread_rng());
for col in cols {
let x = x_root + col as f32 * delta_x;
The results produce different hashes every time.
No that's expected. Whenever a entity gets replicated with prediction it triggers a new rollback to fill the PredictionHistory with initial values
(answered here #1124043933886976171 message)
So I could reproduce it when sorting the entities which produce the hash (as Jondolf suggested).
So it seems the rollback are not triggered by avian, so that means lightyear is the source of the rollbacks somehow?
(and I also tested with latest main, which has the replication changes merged in, but with the same results)
this does correct the interaction between corrections and vis interp, but there's something funky going on with corrections now
i just confirmed with the logs, that sometimes i see the (visual) correction being applied a tick late. the object will spend 1 tick at its final predicted position, then the correction kicks in and it teleports back to get corrected the rest of the way.
when it works, this log is showing up on the same tick that the predicted object is created (https://github.com/cBournhonesque/lightyear/blob/3748543999b82f9bd74e8ae9b9f27e4404da9ed5/lightyear/src/client/prediction/correction.rs#L72)
when it doesn't work, that log shows up a tick late
the actual Correction component is there on the first tick in both cases and seems to be in the same state 🤔
Hm, the sync plugin needs to run after Correction, that might be why
So that visual interpolation has the correct Transform values to interpolate between
When there's 2 FixedUpdate in one frame (which is most of the time), then the sync plugin gets applied
but if there's only 1 FixedUpdate in one frame, then Position is corrected but Transform isn't
I'll try to move it to FixedPostUpdate instead of FixedLast, and add the required orderings
This video is of a hostserver and client but the issue is still there if i run a server and two clients
guys despite the rollbacks we be having check out this character
At least I have the simplest sample now:
- 1 cube (dynamic rigidbody)
- 1 Floor (static rigidbody)
even without player inputs produces continous rollbacks and never gets to rest.
The server also has continous movement (due to no sleeping), but for some reason, even without any player input we have continous rollbacks.
One think I don't understand is why:
correction=Correction { original_prediction: Position(Vec3(-1.0952371, 0.99995565, -0.17343313)), original_tick: Tick(19399), final_correction_tick: Tick(19400), current_visual: None, current_correction: None }
the current_correction is always None. Its as if the correction is never applied?
as inside the get_visually_corrected_state system, the value should always be Some...
They are colliding?
I expect so
With the floor yes
Perhaps you should try circumventing that issue
He is quite troublesome
The goal is to find out what causes the rollbacks, so this is a very good setup
Oh okay
Can’t make a game with lightyear if you can’t use physics 😅
when I enable debug for lightyear I get the following outputs for the rollbacks:
2025-02-19T21:49:44.012479Z DEBUG lightyear::client::prediction::rollback: Rollback check: mismatch for component between predicted 66v1#4294967362 and confirmed 64v1#4294967360 on tick Tick(896) for component "avian3d::dynamics::rigid_body::LinearVelocity". Current tick: Tick(897) predicted_exist=true confirmed_exist=true
2025-02-19T21:49:44.012496Z DEBUG lightyear::client::prediction::rollback: Rollback check: mismatch for component between predicted 66v1#4294967362 and confirmed 64v1#4294967360 on tick Tick(896) for component "bevy_transform::components::transform::Transform". Current tick: Tick(897) predicted_exist=true confirmed_exist=true
2025-02-19T21:49:44.012578Z DEBUG lightyear::client::prediction::rollback: in prepare rollback
2025-02-19T21:49:44.012585Z DEBUG lightyear::client::prediction::rollback: in prepare rollback
2025-02-19T21:49:44.012586Z DEBUG lightyear::client::prediction::rollback: in prepare rollback
2025-02-19T21:49:44.012625Z DEBUG lightyear::client::prediction::rollback: in prepare rollback
2025-02-19T21:49:44.012628Z DEBUG lightyear::client::prediction::rollback: in prepare rollback
2025-02-19T21:49:44.012603Z DEBUG lightyear::client::prediction::rollback: in prepare rollback
2025-02-19T21:49:44.012656Z DEBUG lightyear::client::prediction::rollback: in prepare rollback
2025-02-19T21:49:44.012650Z DEBUG lightyear::client::prediction::rollback: in prepare rollback
2025-02-19T21:49:44.013438Z DEBUG lightyear::client::prediction::rollback: Rollback between Tick(897) and Tick(897)
2025-02-19T21:49:44.013454Z DEBUG lightyear::client::prediction::rollback: Rollback tick: Tick(897)
is it expected that the rollback happens between the same ticks? (897)
Nope; are you testing with very little latency?
but with the capsule there are no rollbacks right? So isn't it the multiple points of contacts between the cube and the floor that are not deterministic?
100ms
From the avian deterministic test (with multiple colliding cubes) it seems that avian itself is deterministic independent of entity id orders
(Unless you use joints, but that will be solved at a later point)
With the capsules I also have rollbacks, especially once the bump into each other, but I tried to get to the simplest case where rollbacks happen every frame (floor + 1 cube)
So it seems from the experiments I ran that avian (and the contact points or entity ID order) is not the cause of indeterminism.
Question what is the difference between server conditioner and client conditioner?
do you still get those when you disable correction? correction_factor = 0.0
client conditioner = applied to packets received by the client, server conditioner = applied to packets received by the server
I only used server conditioner
I set correction_ticks_factor: 0.0,, and still receive these rollbacks (and same tick)
server conditioner is:
Conditioner {
latency_ms: 100,
jitter_ms: 20,
packet_loss: 0.01,
},
@pine cape Check this out Mr peri chompi boi, made a construction system with lightyear
Hmm there should bbe a check for that
I believe
If prediction extrapolates what shall occur why would it is extrapolation tick ever be equal to cureent tick
We take away he current_correction value in PreUpdate to update the component to have the correct value instead of the visually interpolated value.
If you print Correction in FixedUpdate the current_correction will be None because of this
hello bros, i have another foolish question;
coming from the setup in the cheatbook i believe i have made an error, not entirely certain why but this is what im getting with a copy of what's in the cheatbook protocol.rs
Question when using the simple setup, where is the field in each I can disable confirmed entities
I have just so many of them my egui is bvecoming clustered
To be able to use the linear interpolation function, your component must implement Mul and Add , like so: https://github.com/cBournhonesque/lightyear/blob/main/lightyear/src/tests/protocol.rs#L44
when using interpolated entities, who are predicted in their client but interpolated in others into whon should i station the collider? In the interpolated i assume
You should probably put physics components like colliders in the predicted entity
but them my other client wouldnt have the collider if they share a room would him
fn add_physics_to_player(
physical_entities: Query<
(
Entity,
Has<Predicted>,
Has<Interpolated>,
Has<ReplicationTarget>,
),
(Added<PlayerMarker>, Without<Confirmed>),
>,
mut commands: Commands,
) {
for (entity, is_predicted, is_interpolated, is_replicated) in physical_entities.iter() {
if is_predicted || is_replicated {
commands.entity(entity).insert(CharacterPhysics::default());
}
if is_interpolated {
commands
.entity(entity)
.insert(RigidBody::Kinematic)
.insert(Collider::cuboid(1.0, 1.0, 1.0));
}
}
}```
Shoudl i do something like this?
Another question, how would a client know, the action my interpolated entity is making. It seens there is no input buffer in interpolated entities?
Instead of the if checks you use Or<(With<Predicted>, With<Interpolated>, ...)> I made one in my own repo called Relevant: https://github.com/OleStrohm/bevy_aoe/blob/43dc7ca41907ccb964e5f60ed7af89c399f42917/src/game.rs#L18-L23 which isn't necessarily finished, but something similar might work for your usecase
There is no direct message to client if separate mode correct? One cannot send a message from one client to another
If they are not hosts I mean
Correct, all messages go through the server
Is it a good idea to mix TCP and UDP? One of the features of my games is modding and I’d like players to be able to download the files through a TCP connection. But I’d like them to actually play the game through a UDP connection when going against players. Is such a thing a good idea?
Yes I think that's fine! The "auth" example mixes TCP and UDP
I'd use http for downloading files, it's good at that and you can easily add caches/CDNs/hosting services etc later if needed.
is it possible to unit test code which uses ConnectionManager?
Yes, depending on what you mean. You can check some of the unit tests in the repo
How do you get logs that show the PreSpawnedPlayerObject hash and stuff? I tried the vizualiser, but that doesn't seem to have the logs
Bevy_inspector_egui should be able to show the component value, right?
But the object disappears once the replication comes through, so it's gone in an instant
I'm trying to debug a prespawned object not being replaced as I'd expect, I check that I'm using all the same components, but I might be missing something
@pine cape Mr Peri when it comes to ai, what would your approach be? I want to make it both for player and npc. As if a player ragequits the other at least have a bot to play with them. Would you make it entirely server side?
Hmm, turns out the issue with PreSpawnedPlayerObject was just because I was still using Time instead of Time<Fixed> in some places 😅
Time is equivalent to Time<Fixed> in FixedUpdate. PreSpawnedPlayerObject should only be used in FixedMain schedule
You can turn on the logs using the LogPlugin, then
Yes I think so, server side
I know, and yet... Is FixedUpdate different to FixedMain? I seem to be using FixedUpdate
FixedMain contains FixedPreUpdate, FixedUpdate, FixedPostUpdate, etc.
Hello again! I'm trying to create a menu system that runs a server in a separate thread. So far I'm trying to spawn the server thread using https://github.com/EkardNT/bevy-tokio-tasks, in a bevy system. I have the code here https://github.com/SueHeir/lightyear-menu. I believe the issue is that the crossbeams channels aren't working with bevy-tokio-tasks, but im not confident on that. The setup should start the server when you click the button and stop the server when you exit, not sure how else to accomplish this without the bevy-tokio-tasks plugin.
maybe the server needs spawned at the beginning, and then somehow told to start when you click the button, not sure
Maybe a simpler option would be to start the other thread with the server and leave it always running, but then use a run-condition/state to enable/disable it
so the thread would be spawned in main, and the server would always be running, but wouldn't let people connect until the host client is connected?
This might be a option, but then if I run two instances of the game on the same computer while testing it we'd have servers trying to use the same ports
The server wouldn't always be running; the thread would.
You could use a channel to let the thread know to call server.start() and server.stop()
oh snap I messed up the server address, should have been LOCAL_SOCKET!!
@wicked tulip @young prawn I have 0 rollbacks without collisions. I believe the main issue with rollbacks when collisions are involved is that
I need to rollback the Collisions resource to the server-state at tick T. Currently I do a non-networked rollback, meaning that I rollback the resource to its state at rollback_tick in the client-history. This doesn't necessarily match the state of the resource on the server at rollback_tick, which is why we see a discrepancy. This would mean that to completely avoid constant rollbacks we would need to replicate the Collision resource through the network, which might be expensive. I wonder if there is a way in avian to compute collisions from scratch from a given tick using all Positions, etc. without requiring the Collisions resource?
So https://github.com/SueHeir/lightyear-menu should be working for separate mode, hostserver mode, client mode, and just server mode, im very excited about it lol
Awesome, I'll try it!
some of my fixes are questionable, but its just a first pass, a minimally viable menu if you will... Looks at handle_disconnections system
just tested this on windows and it doesn't work soo.. yeah nevermind
works on mac os, no idea why
switch it to spawn the server thread at the start seems to fix my windows issues, the only problem is when I try to control it with a channel message my server doesn't work. I've pinned it down to having a system request a resource that is the channel receiver. Everything is working until I add this one system https://github.com/SueHeir/lightyear-menu/commit/df6e72dc7ef62fce78a1c50c30026b3091037f77
I think i got it fixed now:)
seems like Collisions uses a sorted map with (Entity, Entity) as the key, so since local entities differ from remote, the ordering could be different. i wonder if that's enough to cause non determinism.
and i suppose when a client joins, they don't have the collisions from the previous frame stored in Collisions, which the comments suggest it would be on the server version "..contains collisions from both the current frame and the previous frame". perhaps that has a subtle knock-on effect too.
Saw your behaviour tree
Impl very nice, from the ai crate i saw yours is the most intuitive one just wanted to let you know
thanks, yeah I am happy with the API, it ended up nice and simple to use
could you ask in #game-ai don't want to go too offtopic in here
i have two workspace server and client, does lightyear support dedicated server?what i want rn is on main from server workspace start the server and on client main workspace connect to the server
You can have a server only application in lighyear.
(also headless server)
I'd recommend having most of you're project if not all of it in the same workspace, and then use feature flags to control if its a client or sever. It's probably the simplest way to have a shared protocol, check out the lightyear examples!
i ended up with one crate for server, one for client, then additional shared crates, all in one workspace. client and server each their own binary. that was good for pure dedicated server
then when i wanted client host, i just also made the server crate a lib and made it an optional / feature flagged dependency on the client
no i prefer have two workspaces
me to
can i see your examples?
like how do i start the server
i don't have anything of mine public
but there is a command extension to start it https://github.com/cBournhonesque/lightyear/blob/main/examples/simple_setup/src/server.rs#L71
thanks piefayth
yeah no, the example is old @long marsh
either missing serde dependency or missing bevy serialize feature
wydm
i need add serde dependecy
i see
..
this seens not a dedicated server example
i mean i just think lightyear doenst support different workspaces
But maybe there could be a (potentially more expensive way) to just not use Collisions from the previous frame and recompute contacts from scratch?
It does
I think periwink made a few games that are subidivided in workspaces
well iam trying but i cant somehow
I think brianh was developing a shooter of sort in conjunction with mr peri.
I am not sure tho, perhaps you could take a look into it
i don't know if that's gonna be any simpler https://github.com/cBournhonesque/sixdof
yes, that would be handy. does it work if you just nuke Collisions every frame?
the bad thing about examples are the unecessary thing they put on example
like the example also build players and bots, why bro, i just want connect, they should make simple examples
guess i will do via https
with rust api
make sure you are looking at the same version of the example as the version of lightyear you are using
your error before looks like it thought it was in HostServer mode but there was no client. in main branch lightyear i’m pretty sure that gets detected correctly automatically, but in 0.19 you need to manually specify the mode
'ou need to manually specify the mode'
but i did
welll
i will try use https rust protocol
since there is not a reliable plugin for bevy rn for it
wrong mode
Separate mode works
cool, hwo do i check when a player connected on server? @long marsh
nvm
i saw the tutorial
questions guys, how do i generated the private_key and protocol_id?
guys why the event is not firing ?
impl Plugin for ServerConnectionPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(setup_server_connection()).add_systems(Startup,start_server).add_systems(Update, handle_connections);
}
}
and yes i start the server / client workspaces
hmmmm
i see
wich can be the cause?
nvm
i fixed
the api is very clear now
In theory you could just nuke all the collisions, but this would break collision events (every collision is a "new" collision) and make things pretty expensive. Especially the upcoming improved contact pair management relies a lot on persisting contact pairs to optimize things.
I'm pretty sure disabling warm starting should be enough to prevent contacts from previous frames from affecting the simulation though
Iam curious ,what is the problem he is facing? Since iam using lightyear and avian too @young prawn
rollbacks when objects collide
I wanted to know how the replication works for players controlling a character and how safe its, iam making a battlegrounds game,open map everyone vs everyone, will have powers and movement abilities and even teleport skills, usually how i do is:
1-Player move on client instantly
2-it tells the server the movement and the reason of the movement
3-Server checks if he can move on that position taking in consideration the reason of movement, Example: If he is just walking it will take the player speed as consideration, if he used a teleport skill it will check if the teleport position distance is correctly basead on the max distance of the skill, etc etc
4-if the serve thinks its invalid so it will teleport the player back, or where the player should be
So how does lightyear handle the replication, is similar ?
@pine cape since you are th owner i wanted to know
@wicked oak there is the avian3d example in the repo which pretty much should explain your questions
the example show how setupt it, doenst explain how it works
it implemented the movement and server client logic. isnt that what you asked for ?
sry if i misinterpreted your question
you wanted to know how lightyear handles the character movement and replication,right?
yes
in that case, you have the answer in the avian3d example. it implements a simple scene with 3d character movement. You have leafwing as inputmanager wich gets reprocessed by the server and transported back to the clients
hang on, i'll link it to you
its the one i started with and its working pretty well so far. sometimes soemthing breakes, but thats normal for an engine/lib in this state
clone the repo and start the example, this way you shoud see if its what you need to start with
from there, just build up on it
if you have any specific question, don't hesitate to aks, i'm happy to help you with it since i was having some trouble at first too 🙂
so i know the feeling and struggles
@wet kelp hm
look i created a plataform on server for example
how would i replicate for client
this
its becuase i make a plataform on server and its not replicated when the player join aftr
yes it doenst get replicated for the client
commands.spawn((
RigidBody::Static,
Collider::cylinder(50.0, 0.1),
Mesh3d(meshes.add(Cylinder::new(50.0, 0.1))),
MeshMaterial3d(materials.add(Color::WHITE)),
Replicate::default()
));
just appear on server
there is no clear simple examples of how do it
have you tried to do it the same way the example handles floors, boxes and the player?
it should work the same way, create a marker, and call a function if it got added
give me a sec
i'll give you an example
so? @wet kelp
the examples are messy
they are not going straight to point
it calls a lot of others mods to do a simple stuff, making it messy
sry, i'm at work right now, will do it as soon as i have a bit of time. got surprised with a meeting, sry for that, the examples are fine tho. look in the example i linked you how they do it with the floor and just follow that
i did but they are messy, i would need copy all others 4 rust files it calls for just spawn one part? lol
it should be straight to point
like just here is 3 new rust files, like why, make it simple bro
FloorMarker
FloorPhysicsBundle::default(),
REPLICATION_GROUP
like lmao
if you don't need physics, just dont add it. its just components
the marker is fort the query
wich query, where
did you follow the marker?
hello from Berlin ❤️
the marker is really just a component, if you look into the renderer.rs you have the add_floor_comsetics function which gets triggerd by the added floormarker and adds the meshes
it really is that easy
sry, have to go afk again for a bit
yeah bro, i tryed, no sucess
protocol plugin
the renderer
= nothing
it just dont replicate
this info never prints
i know it can be frustrating, don't give up, we will figure out whats going wrong.
as soon as i finished work, i can help you better
that is it, nothing works
xd
gonna use the whole day to figure out, if the examples were straight to point .
what a zen approach penguin
congratulations
are you using bevy_inspector_egui? it might help to use that look at the state of the components on the server and client. especially making sure that
- The
FloorMarkeractually exists on the server - The
ReplicationTargetcomponent on the floor on the server is set toAll FloorMarkerfor sure isn't on the client at all
etc
i would also verify you are actually registering the ProtocolPlugin
FloorMarker is on shared workspace, both client and server have acess
the ReplicationTarget is all as you can see
floormarket is on client yes
and yes protocol is registering
on client too
all checks out
did you add the Protocolplugin to your shared or main plugin, wherever you call them?
Protocolplugin is called on server and on client
alright....
yeah this looks good to me
do you know how to set your log level to debug and write those logs to a file?
look let me add a print on it
here is supposed to floor appea
on client
let me play
so i’m asking because lightyear has a TON of additional logging hidden behind the debug log level. it would give you more information about what is happening from WITHIN lightyear
no
my server / net config
fn net_config() -> NetConfig{
let io_config = IoConfig{
transport: ServerTransport::UdpSocket(SERVER_ADDR),
..default()
};
let netcode_config = NetcodeConfig::default()
.with_protocol_id(PROTOCOL_ID)
.with_key(PRIVATE_KEY);
NetConfig::Netcode{
config: netcode_config,
io: io_config,
}
}
fn setup_server_connection() -> ServerPlugins{
ServerPlugins::new(ServerConfig {
shared: shared_config(),
net: vec![net_config()],
..default()
})
}
client / net config
fn net_config() -> NetConfig{
let io_config = IoConfig{
transport: ClientTransport::UdpSocket(CLIENT_ADDR),
..default()
};
let auth = Authentication::Manual {
server_addr: SERVER_ADDR,
client_id: 1,
private_key: PRIVATE_KEY,
protocol_id: PROTOCOL_ID,
};
NetConfig::Netcode {
auth,
config: Default::default(),
io: io_config
}
}
fn setup_client_connection() -> ClientPlugins {
ClientPlugins::new(ClientConfig {
shared: shared_config(),
net: net_config(),
..default()
})
}
assuming you are in PowerShell or Terminal run this: $env:RUST_LOG="debug"
then do cargo run *> server_out.txt but replace cargo run with your normal command for server/client. (and for client, change it to client_out.txt)
then just start both, close them, and look at the output filefs
you can get your logs back to normal with $env:RUST_LOG="info"
shared config
pub fn shared_config() -> SharedConfig {
SharedConfig {
server_replication_send_interval: Duration::from_millis(0),
tick: TickConfig { tick_duration: Duration::from_secs_f64(1.0 / 64.0)},
mode: Mode::Separate,
}
}
i may have an idea,. have you tried running lightyear with the main branch yet?
?
there is one main rust file per workspace
just on shared that is a lib
this is my workspace
sry for beeing unclear, still at work ^^
lightyear = { git = "https://github.com/cBournhonesque/lightyear.git", branch = "main", features = [
"avian3d",
"bevy_egui",
"leafwing",
"lz4",
"mock_time",
"steam",
"trace",
"track_change_detection",
"visualizer",
"websocket",
"webtransport",
"zstd",
] }
put this into your Cargo.toml and comment out your version
i had some issues with the non main version
but i need add the features list?
or it will add all features if i dont use it?
i prefer not need to list all lol
let me try
this?
you just need to add the features you need.
after updating it, you also need to change your shared_config. i think you need to remove the Mode:Separate part.
? there is no mode now
yes
why
mode is not necessary anymorew
exactly
can you push your stuff to git and give me the link, i would love to debug it
that may be import
let me show
this on client have this entity
i removed the floor on server to test, and when i do this entity is not created on client
so seens something is getting replicated but
this never triggers
making not possible to add the collider
this also doenst trigger

oh so the entity IS getting replicated but FloorMarker isn't, that helps
all you should have to do to replicate FloorMarker is
- add it to your protocol
- put the component on the entity on the server
that's...the whole thing
this is odne already
right
use bevy::prelude::{App, Component, Plugin};
use lightyear::prelude::{AppComponentExt, ChannelDirection, ReplicationGroup};
use lightyear::prelude::client::ComponentSyncMode;
use serde::{Deserialize, Serialize};
pub const REPLICATION_GROUP: ReplicationGroup = ReplicationGroup::new_id(1);
#[derive(Component, Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct FloorMarker;
pub struct ProtocolPlugin;
impl Plugin for ProtocolPlugin {
fn build(&self, app: &mut App) {
app.register_component::<FloorMarker>(ChannelDirection::ServerToClient)
.add_prediction(ComponentSyncMode::Once);
}
}
protocol
commands.spawn((
RigidBody::Static,
Collider::cylinder(50.0, 0.1),
//Mesh3d(meshes.add(Cylinder::new(50.0, 0.1))),
//MeshMaterial3d(materials.add(Color::WHITE)),
FloorMarker,
Replicate{
group: REPLICATION_GROUP,
target: ReplicationTarget {
target: NetworkTarget::All,
},
..default()
}
));
server spwaning
that's kinda why i was trying to get your debug logs, cause i agree everything looks right
iam using rust over can i add the server_out.txt here?
server_out.txt
on the execute commands
oh that's a great question, try it
but it has to be *> server_out.txt
idk if they execute that command in a powershell context or not, will just have to try
if not you can just open powershell and do it that way
honestly you might even have to set the log level environment variable in that menu too
the RUST_LOG="debug"
how
idk but definitely with this box somehow
OR you can modify LogPlugin https://docs.rs/bevy/latest/bevy/log/struct.LogPlugin.html
i just do it with environment var so i can switch without recompiling
yeah ok i kinda figured
nothing gets created
you will have to do it in Terminal or PowerShell, or like, forget the file thing and just write it all to the console
if you dont mind scrolling through a million miles of logs
write wht?
the debug logs
this?
yeah but need the logs from a time where the client succesfully connected
looks like they have some connection error there
client might not have had debug logging on either, that looks like just info and error
no, this is because i closed server beforre client
so the last sutff is client disconnecting
oh ok in that case you didnt have debug logs on the clinet
make sure you set the env in both terminal instances
$env:RUST_LOG="debug"
weird. FloorMarker is definitely in both protocols, but it looks like the server just isn't sending it 
[3mremote_tick[0m[2m=[0mTick(2799) EntityActionsMessage { sequence_id: MessageId(0), group_id: ReplicationGroupId(1), actions: [(20v1#4294967316,
EntityActions { spawn: Spawn, insert: [], remove: [], updates: [] })] }
that's the message the client gets; no components listed to insert
do you have something on your server that removes floor marker?
like code that finds all floor markers, does something to them, then removes it?
take a look
you have FloorMarker defined twice, im guessing the one in your protocol isn't the one you're actually putting on the entity
happy to help
iam happy that you exist bro
So I've been pretty happy with how my lightyear project is coming along, runs very well most of the time. I've noticed that when the person I'm testing it with is using wifi I get incredible lag spikes when they're hosting the server. (its happened with two different people now). The person claims they never have any issues when they play multiplayer games, league, wow, overwatch, etc.
Question: Do PvP - all predicted style games need a dedicated server running from a server provider to compensate for people's bad internet?
Is there anyway to debug this issue? Or does everyone playing this game just need to buy an ethernet cord? Could it be a bandwidth issue?
If the host has bad internet, there is really not much too do. Except reconnect mechanics. Perhaps you can transfer host to someone with less latency, but I am not sure if lightyear provides the infra.
Could be a compression issue, tho? Perhaps you are just sending too much information. Via server and so on
yeah the issue always happens when I spawn in a bunch of enemies (like 10, not a lot), but sometimes it happens when we're just standing there
so how do I check the bandwidth usage? what is a resonable amount for a game?
You can check the bandwidth usage via the visualizer feature
How often are you sending replication updates
ok sick I'll look into that, and 20 ms
I know that by sampling, that lightyear handles "acceptably" massive amounts of server replicated entities. At least with simple behaviour trees and transform adjustments. You just need to be carefull to no use events, as they tend to die out before doing your code logic
yeah if the person is connected with ethernet then spawning enemies is never an issue, 100's of them is fine.
Hmm ya could just be the bandwidth limitations but ideally the host is never on WiFi. The games mentioned your friend would have never hosted, and would have only ever experienced internet traffic from a client's perspective, as those games have dedicated servers ran only by the developers AFAIK. So I don't think they're a good benchmark for this.
If you get stuck on this, is it feasible to scatter these spawns out over time?
Could they be saturating the WiFi itself? Does lightyear have a way to customize the MTU per packet?
hey wanna ask if prespawning can work in this scenario, I have a scene (which have multiple hierarchies in it) i wanted to spawn in both server and the client. I want most of the things to be in sync with the server, can this work using prespawning? and how rould that work? (or is this a bad idea?)
is there a reason you want to use pre spawning over replicating the object normally? what kind of “thing” is your scene?
it's a blenvy scene, but yeah replicating can work as well, just need extra work to each of the object in the scene..
if the scene isn’t dynamic i would just replicate a marker and use the marker to indicate to the client to load the scene
but if you want to pick and choose specific objects that do or do not get replicated dynamically, you can’t escape having to identify them programmatically somehow
truee, the scene is partially static and partially dynamic, which means i need to mark those that are dynamic
i get why you’re asking about prespawning though, you want to match those dynamic entities up? so you just load the scene normally on both ends and it all syncs?
that might actually work if you went through the hierarchy and put the prespawn component with an appropriate id on every dynamic entity on both the client and server
but i do NOT know how prespawning works with hierarchies; never tried that
yeah, that's what i'm attempting haha, so that i wouldn't need to rely on replication for the spawning to happen, and instead locally spawned then synced up
i still think the most straightforward way is still replicating..
agree 👍
hey guys, how could i replicate this component to client, so client can know the combatant type
#[derive(Component)]
pub enum Type{
Player,
Npc
}
Is the lightyear cheatbook now out of date? I get errors using the example code / some from the github
Yes it is
Ah, gotcha homie 🙏
If someone tried both approaches, why would you pick lightyear over bevy_replicon? I'm familiar with the overview of both, but in practical terms what's "better"?
Replicon has better performance and tries to provide an abstraction for messaging/replication can build upon.
Lightyear has more features (prediction, interpolation, input handling, authority, etc.)
Would you say a bevy project can be adapted to lightyear later in development, or would doing so be significantly more difficult out of interest
couls i have some answer?
It's not impossible but in general I would strongly suggest to start from scratch with multiplayer in mind
You would just load the asset on the client no?
Does Prespawning for the scene not work? If you add Replicate it should propagate recursively to all children
2025-02-27T20:41:41.771954Z DEBUG lightyear::client::prediction::prespawn: PreSpawnedPlayerObject hook, setting the hash on the component entity=456v5#21474836936 tick=Tick(983) hash=2984040181942278987 2025-02-27T20:41:41.973191Z DEBUG lightyear::client::prediction::prespawn: found a client pre-spawned entity corresponding to server pre-spawned entity! Spawning/finding a Predicted entity for it 2984040181942278987 2025-02-27T20:41:41.973207Z DEBUG lightyear::client::prediction::prespawn: re-using existing entity 2025-02-27T20:41:41.973218Z DEBUG lightyear::client::prediction::prespawn: Added/Spawned the Predicted entity: 456v5#21474836936 for the confirmed entity: 457v1#4294967753 2025-02-27T20:41:41.974191Z DEBUG lightyear::client::prediction::rollback: Rollback check: mismatch for component between predicted 456v5#21474836936 and confirmed 457v1#4294967753 on tick Tick(983) for component "bevy_transform::components::transform::Transform". Current tick: Tick(996) predicted_exist=false confirmed_exist=true. Why? It is weird that even tho my pre spawned predicted entity gets spawed with a transform it says there isnt any
Oh found the origin
commands.spawn((bullet, prespawned)) it was literally this line of code, the reason I have no idea, but I believe is correlated to bad syncing
I haven’t tried haha. Abit hesitant to try (also with my project deadline nearing soon 🤣)
Also prespawning wouldn't reduce the bandwidth, if that's what you're interested in. The component still needs to be replicated
Just my two cents after finally getting a more serious look at lightyear:
I love the fact that you're mostly not (or maybe none at all?) relying off macros, this makes things more clear when looking at a protocols.rs (which I recommend having), not a fan of magic, so bravo!
However, there's a flip side to that. When I'm looking at a component's definition, for example:
#[derive(Component, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Moveable {
pub velocity: Vec3,
pub angular_velocity: Vec3,
pub collision_shape: ShapecastMoveableShape,
pub collision_mask: LayerMask,
}
There's no clear way to know if this is a replicated component or not without looking at protocols.rs
I don't know what the solution is to this, is it really a problem? ehhhh at the end of the day probably not, but just food for thought
Better performance due to less features or why is the performance better in replicon?
You can replicate it the same way as any other component, or why would this component require specific treatment?
? I Already fixed
I guess one could make a derivable trait. That marks that is specified for protocol
Even go further and auto insert it for you, but seens a little overreachy
Yeah definitely overreachy
A mix of
- I'm less focused on perf and more on adding new features
- I have some features (e.g. ReplicationGroup) which prevent some optimization
- skill?
Xd skill
This is a Nice point
Iam Also worried about bevy update and peri abandon the project you know
But i made a plugin that call the others functions so If i need implement a New network i just need Deal with this plugins and not modify the wholeeee system
God lord, finally found out the cause of my rollback on spawn bug
Animation component require transform...
He inserted it before the prediction set could dot it is thing
Got rollback
There are certainly many optimizations still possible, but adding features is a good thing to focus on (along with bufixes).
Would be really nice to have an ICE compatible transport (for natpunching similar to matchbox).
Does anyone know if there is a way to explicitly exclude an entity from rollback, I'm trying to find the source of extreme jitter/corrections on a non-replicated entity, kinda shooting in the dark here
sorry, to be clear, it looks like they're being corrected
because they should be moving about 1/4 of that speed, sometimes it looks fine but its really rare
Or better yet, how do I know I'm currently being corrected/in the middle of a rollback? is there a resource or something I can access
on main there is a DisableRollback component
nice, also I just found the Rollback resource
perfect was typing that
yeaaaaa this fixed it:
let rolling_back = rollback.map_or(false, |r| r.is_rollback());
for (entity, mut simulation, mut transform) in simulations.iter_mut() {
// If we're in a rollback AND the moveable is not predicted, skip it
// otherwise it will move multiple times in a frame and we dont want
// that for non-predicted moveables
if rolling_back && !predicted.contains(entity) {
continue;
}
Wellllll now its acting up again, oof im tired lol
I think its a separate issue, ignore me
yeah ok similar issue, timers were being ticked in rollback too, so thats fixed now
Just to confirm the Visual Interpolation section of the cheatbook is outdate, and to get visual interpolation the setup is not needed anymore (with avian physics)
you're on main? the stuff about changing which schedule the sync plugin is in is out of date, yeah. you still need to add the vis interp component to predicted stuff
What is it called now? VisualInterpolateState I can't find
sorry not the component
still waking up
app.add_plugins(VisualInterpolationPlugin::<Transform>::default());
oh also the component though VisualInterpolateStatus::<Transform>
i thought so
the status postfix on that name is not my favorite for something that has to be user-added
Thank you, was hoping that would fix the jitteriness of my predicted pysics based bullets, but they are still very jittery
are they rolling back?
or just jittery
its continously rolling back, as the collision resource is not synced yet.
Its strange on the client side it looks like no interpolation is applied at all
(or rollback correction)
yeah it just looks that way when it's constantly rolling back. i think if correction was 100% perfect and the rollbacks were due to very small differences, it would look seamless still, but i think there's some goofiness somewhere that makes it jittery in the perpetual rollback case
i would focus on fixing the rollbacks
or if you aren't prespawning the projectile, you will always get rollbacks when you spawn a predicted one
rollbacks are due to the collisions (most likely) not beeing rolled back.
I use prepsawning
Do you mean you always get rollbacks if you prespawn the bullet?
if you dont prespawn it (because the history needs backfilled)
yeah I prespawn...
o if this is that avian collision resource problem i can't help you, but uh, that's interesting. are there actual collisions happening when it rolls back or just perpetually rolling back as soon as it exists?
perpetual roolsback, even if it doesn't collide
what do the logs say about what component is causing the rollback
how can you log the component that causes the rollback?
either set the LogPlugin to have a log level of debug or set the RUST_LOG environment variable to debug
might pipe that output to a file too, there will be a lot 😅
Ok I get an output I don't fully understand:
Predicted entity Some(85v1#4294967381) was not found when preparing rollback for "lightyear_experiment_main::protocol::Weapon"
(the weapon is spawned on the player, and I would expect it would be simply synced to the client?)
haven't encountered that! are you getting rollbacks before you spawn the projectile? or is it fine
that's confusing because, looking at the code, it implies there is a Confirmed entity with a reference to a predicted Entity that doesn't exist lol
no, before bullet spawn all is fine
pretty sure I did something wrong, but not sure what yet
is Weapon the only component the logs suggest need rolled back? or is it trying to roll back like everything that is sync'd?
could be as simple as the state of your prespawned entity just isn't the same as the state on the server
I resgistered the component in the protocol, and then add it when I spawn the player character.
The weapon is spawned on the server (so not prespawned)
when the player connects I spawn the player and add the Weapon Component to it.
app.register_component::<Weapon>(ChannelDirection::ServerToClient)
.add_prediction(ComponentSyncMode::Full);
thats how it registered in the protocol.
Its also not just at the beginning but constantly
Is there anything else needed?
you get that error without spawning a projectile?
like it's happening as soon as you spawn your player
and then happens forever?
Only once the first bullet gets spawned
just to be clear then... so after you fire your first projectile, the predicted entity for your Weapon goes missing? lol
Yes, its very confusing, here is the repo if that might help.
Feels like something obvious is missing, but I just can't find it
Yes sorry, just for getting more debug info, you can replace it with main of lightyear
Let me know if you can spot anything obviously wrong
spent some time looking through the logs. the initial rollbacks were getting triggered by ComputedMass being different, so i just took it out of the protocol (which, makes sense to me, it's computed!) and they stopped rolling back
i didn't test it too much tho; can you try / what do you think about that?
you are also rendering your confirmed bullets btw
which might be adding to the confusion here
Yes just noticed... how could the mass be such a problem?
and THANK YOU!
yeah i am not sure why replicating that is an issue since it should end up the same anyway
no problem
I agree that its computed and doesn't need to be synced (unless you plan to change it freequently) but still confusing
Its also in the example @pine cape, probably a good idea to remove it:
https://github.com/cBournhonesque/lightyear/blob/main/examples/avian_3d_character/src/protocol.rs
Ok this is creating more questions in my head than answers, but that is really good news
It is finnally SMOOOTH 
Ok there is one last issue remains is that as soon as there are any collisions there are continuous rollbacks.
And when that happens everything is jittery again, as it seems rollback on every frame brake it again 😭 (no matter what I use for the correction_ticks_factor).
No idea why it creates also issues with the physics mass sync, but will be interesting to see if that persists once we have resource syncing.
We already have rollbackable resources i think
We do? I thought the implementation is not yet finished?
There is a resource (prediction metrics I think it’s called) it shows you how often a rollback occurred.
Thank you, and does lightyear have a way of displaying ping anywhere?
you know what, i should dig at the examples first lol
Hmm ok so it seems like I get rollbacks every frame whenever I move
despite it being very smooth
I take it that's not intended?
Oh maybe it is:
Sync the component from the confirmed to the interpolated/predicted entity with the most precision Predicted: we will check for rollback every tick Interpolated: we will run interpolation between the last 2 confirmed states
Could I get a better idea of what you're seeing? So collisions are causing jitter?
It’s not very easy to see in the video, but the bullet is not flying smooth after the rollbacks start happening:
#1189344685546811564 message
It looks like its not being visually interpolated
not saying thats what it is, but definitely looks like FixedUpdate jitter
But yeah from my understanding I think continous rollbacks are supposed to happen based on this comment for ComponentSyncMode::Full
Certainly looks like that indeed.
But in theory there is the correction smoothing function which should interpolate from the rollback.
You can use the visualizer feature to get useful plots about lightyear internals; or just check the PredictionMetrics resource via inspector-egui
Nope, if the client and server simulation are deterministic and give the same results, you shouldn't have any rollbacks
iiiiinteresting, ok I can look into whats going on then
I dont think I understand whats going on here, this should be sending updates to the client, right?
app.register_component::<CurrentWeaponIndex>(ChannelDirection::ServerToClient);
Then I have this query:
mut query: Query<(
Entity,
&UniqueIdentity,
&Transform,
&mut WeaponInventory,
&CurrentWeaponIndex,
&ActionState<PlayerInput>,
),
Or<(With<Predicted>, With<Replicating>)>>,
But it doesn't seem to find anything when CurrentWeaponIndex is in there
Is it because of the Predicted component?
I'm seeing two player entities 🤔 one has the CurrentWeaponIndex, the other doesnt, but both are Controlled, and one is Predicted. hmmm ok
ok so that means I basically need to predict everything, at least in the context of what im trying to do. Interesting
oh ok I know what to do
I get it
brain expanding noises
@pine cape there's something really funky going on, so check this out, its working fine here (note the rollback count top left)
But sometimes its constantly rolling back (trying to get a video)
Ok I restarted the client several times and it was fine, then I restarted the server and now its not fine:
important to note that the link conditioner is on
It's like as if the server sometimes boots into a bad state, usually its continuously rolling back, but every once in a while it appears to boot into a good state
I've checked everything, I've gone back to what I know is a more deterministic movement and yet its still doing it
And also note it does not appear to be collision related
I have pushed these changes to sixdof in main (Use TAB if you want to toggle the mouse on and off @pine cape )
