#bevy_replicon

1 messages · Page 13 of 1

echo lion
#

What do you mean 1-frame delay?

spring raptor
# echo lion What do you mean 1-frame delay?

For some reason RenetClient becomes disconnected only after 2 updates. I.e. it requires

client_app.update();
client_app.update();

Not sure if renet2 you have the same behavior. Try copying this test.
Here is the assert.

echo lion
spring raptor
echo lion
spring raptor
echo lion
spring raptor
thorn forum
#

hey, would be nice to have a better way to skip some field in a Component, for example


#[derive(
    Component,
    Serialize,
    Deserialize
)]
pub struct GoldGeneration(pub u32, #[serde(skip)] pub Timer);

where the timer is ticked on server and client, so not need to replicate it.
having to write a RuleFns and write all 3 methods is quite cumbersome

#

ill split the u32 and the timer in two different components, to also allows only replicating the Timer once at insertion, which isn't possible with rulefns i think

spring raptor
spring raptor
thorn forum
dire aurora
#

I just network tick numbers for this reason

spring raptor
thorn forum
thorn forum
dire aurora
#

I use it for timers and the like, I track time based on ticks in the simulation rather than wall time

spring raptor
thorn forum
dire aurora
#

Ah, yea if it's visuals then the extra accuracy of a timer also does something

#

(The max accuracy if my approach is 1 tick, 1/60th of a second in my game for now)

raw idol
#

updated aeronet_replicon

spring raptor
# raw idol updated aeronet_replicon

Thanks!
Have you tested that the client can receive a message together with a disconnect if there are no packet loss?
Asking because in renet and the example backend I had to adjust the system ordering.

#

In the renet's draft it's under "Process received data on disconnect" in the description.
It's probably the main reason I made the RC 🙂

raw idol
spring raptor
spring raptor
#

Just to clarify: it's not a guarantee - we simply give the client a chance to receive the data.
It didn’t work out of the box in our Renet integration - I had to adjust system ordering. Otherwise, all received data was discarded if it arrived along with a disconnect.

It's not super important, but it's pretty useful for debugging.

dire aurora
#

This doesn't seem right 🤔

2025-06-08T15:38:51.148498Z TRACE bevy_replicon::shared::backend::replicon_server: received 0 message(s) totaling 0 bytes from channel 0
2025-06-08T15:38:51.165166Z TRACE bevy_replicon::shared::backend::replicon_server: received 0 message(s) totaling 0 bytes from channel 0
2025-06-08T15:38:51.181841Z TRACE bevy_replicon::shared::backend::replicon_server: received 0 message(s) totaling 0 bytes from channel 0
2025-06-08T15:38:51.198500Z TRACE bevy_replicon_renet2::server::plugin: forwarding 0 received bytes over channel 6
2025-06-08T15:38:51.198510Z TRACE bevy_replicon::shared::backend::replicon_server: received 0 message(s) totaling 0 bytes from channel 0
2025-06-08T15:38:51.215167Z TRACE bevy_replicon::shared::backend::replicon_server: received 0 message(s) totaling 0 bytes from channel 0
2025-06-08T15:38:51.231842Z TRACE bevy_replicon::shared::backend::replicon_server: received 0 message(s) totaling 0 bytes from channel 0
spring raptor
dire aurora
#

Only ever channel 0 yea. The event is indeed zero size, but replicon doesn't seem to pick it up

spring raptor
#

I ported the renet (not 2) to it, so you could try swapping them.

#

@echo lion by any chance you could port the renet2 to the RC as well just in case? The migration is most likely identical to the original renet.

dire aurora
#

Well there is probably some mismatch, the client tries to read about 8 channels, the server only channel 0 and 1

spring raptor
#

In the latest RC you will be able to RUST_LOG=bevy_replicon::shared::protocol=debug cargo run ... and clearly see what is registered.

dire aurora
#

Which is obviously weird because replicon is the one picking the channels bavy

spring raptor
#

Between yours replicon and renet2's

dire aurora
#

Everything pulls the exact same version though ferris_sob

spring raptor
#

Are you sure? 🤔 So with cargo tree you only have a single replicon version?

dire aurora
#

They actually communicate correctly too when it's just replication

spring raptor
#

Could you send me full log with bevy_replicon=trace for both client and server? Maybe I'll spot something.

dire aurora
#

-# Ignore the metric ton of errors on the client log

spring raptor
# dire aurora

I see that renet2 create channels properly.
Replication flows and you send send an event over channel 6 which is net_sync::CurrentTime.
Everything looks correct to me. Are you saying that it's not triggered on client or server?

#

Also what version are you running?

dire aurora
#

0.33.0

dire aurora
spring raptor
#

Because I don't see any sending event ... in the logs

spring raptor
#

But nothing gets send or received on the server

dire aurora
dire aurora
spring raptor
#

the plugin that reads channel is not created*

#

@dire aurora ah, by any chance you forgot to call App::finish on the server?

dire aurora
#

Hmmm, where would I need to call App::finish? 🤔

spring raptor
dire aurora
#

I do use App::run but I have a custom runner which might affect things, I'll try 🤔

#

OMG that was really it 🙃

spring raptor
dire aurora
#

Yea, I wonder if this was always how bevy behaved

#

If so, then the runner API just kinda sucks 🤣

spring raptor
#

Agree!
I don't even remember when it was introduced.
It worked for you before because we didn't use finish for events 2 Bevy versions ago 🤔

dire aurora
#

Yea, very possible

#

Now I'm finally onto my next issue

called `Result::unwrap()` on an `Err` value: DeserializeBadOption
   1: bevy_bundlication::deserialize
   2: logic::status::NetworkedStatus::read
```... Figuring out whatever the hell `DeserializeBadOption` means 🤣
#

Okay it's from postcard, but that doesn't look like an error that should be possible

spring raptor
#

Yeah, not easy to debug... Try to check if what you serialize is deserializable 🤔

#

I assume you use some custom ser/de

dire aurora
#

Yea, it's definitely custom, you can tell from the bundlication 😅

dire aurora
#

Hmmm, commeting that one out the next error is:

bevy_replicon-0.33.0/src/shared/replication/replication_registry.rs:144:32:
replication `FnsId(4292)` should be registered first
stack backtrace:
   0: rust_begin_unwind
   1: core::panicking::panic_fmt
   2: bevy_replicon::shared::replication::replication_registry::ReplicationRegistry::get
   3: bevy_replicon::client::apply_replication
``` ... Maybe it isn't as simple as just the ser/de being wrong 🤔
#

Oh also, current diff:

168 files changed, 3276 insertions(+), 15362 deletions(-)
spring raptor
#

@dire aurora wait, do you have 4292 replicated components? 🤔

#

It's probably a ser/de issue 😅

dire aurora
#

But yea, if it's a ser/de issue this is probably not coming from where the other error started 🙃

#

Probably just calling the wrong function somehow

spring raptor
dire aurora
#

Probably, the question is, which function

#

It's gonna be hard to find it in my diff 😅

spring raptor
#

Maybe add logging to each

dire aurora
#

Hmmmm, might be a bundlication bug 🤔

#

If I disable all groups it stops crashing, if any group is enabled I get crashes

spring raptor
#

I will see if we can log ser/de process on replicon side.
This would simplify debugging. You could check how much bytes each function takes and compare between client and server.

spring raptor
#

@dire aurora by any chance you aren't advancing the bytes cursor?

dire aurora
#

Hmmmmm, possible if there is something weird about the Read impl or how I pass it around 🤔

spring raptor
spring raptor
#

@dire aurora never mind, I just retargeted the PR to 0.33.0. You can just patch it with Cargo now.

dire aurora
#

Should I be getting these for every single entity in the world? 🤔

2025-06-09T10:44:25.484146Z DEBUG bevy_replicon::shared::event::server_event: ignoring broadcast for channel 4 for non-replicated client `0v1`
#

Seems to not happen consistently somehow, which is even weirder

dire aurora
#

-# The fact that no one noticed proves no one else used bevy_bundlication at least

spring raptor
# dire aurora Should I be getting these for every single entity in the world? 🤔 ``` 2025-06-0...

It's a silly bug I fixed on the latest master:
https://github.com/projectharmonia/bevy_replicon/commit/bd297c2e32745deac8eb784eed997c05cfbaca73

It has no effect on the logic, I just accidentally iterated over all entities in the world during event sending 😅 So feel free to ignore this message.

GitHub

I noticed that we iterated over all entities in the world.

spring raptor
dire aurora
#

The Bytes crate is a bit confusing, and it's not helped by the fact that bevy_bundlication relies on Read/Write which are std-only and thus off by default basically everywhere

#

Though honestly I'm not sure what I was thinking when I wrote this code either 😅

#
AsRef::<[u8]>::as_ref(cursor)
```"What could possibly go wrong?"
spring raptor
#

I'll draft a new release once messaging backends catch up with RC.
It's just one of the biggest releases and I want to make sure it's easy for backends to handle disconnects.

swift hamlet
#

Is there a way to use the matchbox crate with replicon on top for p2p (one player host others join) or any other way to do nat traversal currently?

spring raptor
# swift hamlet Is there a way to use the matchbox crate with replicon on top for p2p (one playe...

Matchbox provides a signaling server as a separate crate.
I haven’t used it myself, so I’m not sure if it’s tied to its I/O. If it is, you’d need to write an integration for it as a messaging backend. That’s not too hard - you can check out the backend module for documentation, look at real-world crates, or use the example TCP backend as a starting point.

Also, just to clarify: you’re describing a client-server setup - and that’s what you want.
P2P refers to a mesh topology.
Matchbox supports both 🙂

swift hamlet
# spring raptor Matchbox provides a signaling server as a [separate crate](https://github.com/jo...

Yes a setup that could be used in a jam, I prefer the server <-> client architecture in general, but it’s not really feasible to spin up servers etc. for a jam.

Also for development it would be really convenient if you simply can share a build people can just try.

Having one signaling server is no problem, but having one per instance of a game is problematic.

So I am looking for a good way to get around the NAT problem

spring raptor
spring raptor
swift hamlet
#

Will take a look, the simple example uses a simple tcp socket correct?

Are all traffic reliable in replicon?

spring raptor
# swift hamlet Will take a look, the simple example uses a simple tcp socket correct? Are all ...

Will take a look, the simple example uses a simple tcp socket correct?
Yes 🙂

Are all traffic reliable in replicon?
No, replication uses a dual-channel approach (reliable + unreliable). Events also have configurable guarantees.

But if the backend (TCP in this case) doesn't provide an unreliable channel, it's okay to downgrade to reliable - just not the other way around 🙂
It's a simple backend to run examples inside the repo without depending on other crates. And a good example by itself for how to write such backends.

tacit osprey
#

Hey, I updated https://github.com/Henauxg/bevy_replicon_quinnet to replicon 0.34.0-rc.1
It worked fine, but I do have some implementation issues with reliably sending pending messages on disconnect, hence I'm not testing it in my tests. I'm just ensuring that the disconnection functions properly.
I know why I have those issues, but I'm not sure yet about when/if I'll update this behavior. I'd need to think about it a bit more.

spring raptor
spring raptor
spring raptor
#

Looks like there are no issues from the Replicon's side in the latest RC 🤔
Will draft a new release today.

swift hamlet
#

Is there a simple way inside a system to check if its on the server or the client?

spring raptor
spring raptor
swift hamlet
# spring raptor Did you manage to hook matchbox? 🙂

not yet, gave it a short go, but I didn't have enough time to get it working.

I think it should be possible (even tough it creates a connection between each peer).

Once I have a working prototype with the existing backends I might give it another go.

swift hamlet
#

Is there a way to map entites of a Vec<MyStruct where

struct BigStruct {
    stuff: Vec<Vec<MyStruct>>
}
struct MyStruct {
  pub entity: Entity,
  pub value: f32
}

How could theset entities be properly be mapped?

swift hamlet
#

Ah its a simple as marking the entities fields with #[entities] and then simply implementing map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E).

Didn't expect that these nestings would be so easily possible.

thorn forum
swift hamlet
thorn forum
spring raptor
thorn forum
#

but maybe i dont understand how the milestone + release diff works

spring raptor
thorn forum
#

yeah dunno :(

spring raptor
#

Asked: #ecs-dev message

spring raptor
#

Unfortunately, looks like the change will be available since 0.17.

crimson imp
#

Hey there, I've just started integrating bevy_replicon (0.34) into one of my projects, I was just wondering - what's the best way to handle client side replicated entity lifetime - specifically when leaving a session? I've been trying to have a required state-scoped state that deswans entities locally after the client has disconnected from a session, but this seems to sometimes cause a panic in bevy_replicon/client.rs (621, in apply_mutations) as it looks like the despawn happens before replication tries to mutate it. I originally didn't bother having the state-scope on the client side, as I figured that anything that was replicated to it would be cleaned up automatically if the session that entity was replicated in despawns/expires, but it doesn't appear to be the case (these replicated entities are still present even after the client entity with Session is gone; after a Disconnected triggers). Perhaps I have an incorrect assumption or setup for how this should work. Any recommendations would be muchly appreciated!

crimson imp
crimson imp
spring raptor
spring raptor
thorn forum
thorn forum
#

hey, is there a way to see what is being replicated / updated to the client in realtime ? to investigate what is using the bandwidth. thanks

spring raptor
thorn forum
#

i can see how many bytes are sent, but not what is being sent. at connecting i get 11000 bytes send to each client, i would like to debug what they are for example what components are being sent

swift hamlet
#

Currently struggling to make the following setup work.

A replicated Component which references another struct which has a reference to to an entity.

#[derive(Component, Debug, Reflect, Serialize, Deserialize, Default, MapEntities)]
#[require(Replicated)]
pub struct GameManager {
    #[entities]
    pub player_registry: Vec<PlayerRegistryEntry>,
}

#[derive(Debug, Reflect, Serialize, Deserialize, Default, MapEntities)]
pub struct PlayerRegistryEntry {
    #[entities]
    pub player_entity: Option<Entity>,
}

=> no method named `map_entities` found for struct `std::vec::Vec<PlayerRegistryEntry>` in the current scope
   --> src/auction_mechanic/auction.rs:15:10
    |
15  | #[derive(Component, Debug, Reflect, Serialize, Deserialize, Default, MapEntities)]
    |          ^^^^^^^^^ this is an associated function, not a method

even when manually implementing MapEntities it doesn't seem to compile

dire aurora
#

Ah, it's that one fix that didn't get into 0.16.1 again ...

#

I think this? #1090432346907492443 message

#

For now you could make a wrapper type for the collection and implement MapEntities on that, or manually impl the map_entities function in Component

#

Or I guess patch bevy to include that PR in an 0.16.x release

swift hamlet
#

Thank you!

spring raptor
#

The release also includes replicate_once, which should come in handy for you.

thorn forum
#

nice thanks :) yes i want to update to 0.34 but waiting on renet2 support, for now its works so its fine

spring raptor
#

See this message if you are interested: #1090432346907492443 message

thorn forum
#

i tried when you released 0.34 but i wasn't sure of some things. ill try again thanks to your example on renet !

spring raptor
vital mist
#

@dire aurora lol after time i did my own client predicition / server reconciliation xd

spring raptor
vital mist
#

i just did to learn

#

not hard to be honest once you do one time

#

but because bevy Res<Time> is unreliable it have reconciliations even with 0 ms

spring raptor
vital mist
#

but yes do client predicition / server reconciliation is ez as f

spring raptor
thorn forum
thorn forum
# spring raptor You should be able to see exactly what you send in the latest release :) I impro...

hello

2025-06-21T09:34:06.867024Z TRACE bevy_replicon::server: writing insertion for `215v1` with `FnsId(0)` for client `226v1`
2025-06-21T09:34:06.867028Z TRACE bevy_replicon::server: writing insertion for `215v1` with `FnsId(5)` for client `226v1`
2025-06-21T09:34:06.867032Z TRACE bevy_replicon::server: writing insertion for `215v1` with `FnsId(7)` for client `226v1`
2025-06-21T09:34:06.867036Z TRACE bevy_replicon::server: writing insertion for `215v1` with `FnsId(9)` for client `226v1`
2025-06-21T09:34:06.867040Z TRACE bevy_replicon::server: writing insertion for `215v1` with `FnsId(10)` for client `226v1`
2025-06-21T09:34:06.867043Z TRACE bevy_replicon::server: writing insertion for `215v1` with `FnsId(19)` for client `226v1`
2025-06-21T09:34:06.867049Z TRACE bevy_replicon::server: writing insertion for `215v1` with `FnsId(20)` for client `226v1`
2025-06-21T09:34:06.867053Z TRACE bevy_replicon::server: writing insertion for `215v1` with `FnsId(23)` for client `226v1`
2025-06-21T09:34:06.867057Z TRACE bevy_replicon::server: writing insertion for `215v1` with `FnsId(62)` for client `226v1`

how can i see what the entity is ? i would like to log each entity that is being replicated with the components that are being sent. i can use a local bevy_replicon fork and add some log statements i guess ?
thanks :)

spring raptor
#

Another option is to take a look at 215v1 in the inspector. Like with the VSCode plugin or via bevy_inspector_egui

thorn forum
#

hm its going to be a little annoying with +60 fnsid haha. ill save the log and clean it i think to more easily understand the components.
its not possible to also query the Fns registry to get the name for the components when collecting changes on the server ?
oh its the mapped entity on the client ? i thought it was the server entity.
thanks !

spring raptor
spring raptor
thorn forum
#

my server is headless, i can re add DefaultPlugin and add inspector egui yeah good idea

spring raptor
thorn forum
#

oh with bevy remote protocol

#

thought it was bevy inspector egui haha

#

i dont use vscode but ill try it out thanks

spring raptor
thorn forum
#

oh yeah i read it as one haha

#

thanks with all that it will do it

spring raptor
thorn forum
#

zed is pretty cool, personally i miss too many plugins from the nvim ecosystem...
yeah BRP is pretty cool ill do that

#

sadly the vscode inspector dont support a search bar for the entity haha

spring raptor
spring raptor
thorn forum
spring raptor
# thorn forum wow thanks for the link they have improved the vim mode by a lot from last time ...

I miss Leap too! They implemented a Vim-sneak style motion, which is inferior in my opinion.
For some reason, they don’t mention it in the plugins list, but you can search for that keyword on the same page. Also, there are no labels when you jump - but they plan to improve it 🙂

I use the mouse sometimes, but it’s not like in VSCode or other editors because the Vim support is built-in.

thorn forum
#

zed has multiples small things better than nvim, ill have to try it out lol. but right now my nvim config is working well, LazyVim is really cool too. ill switch one day when zed has matured more, with flash/hop which are the best implementation imo.
Zeta looks cool, but i would like to run it locally to have unlimited generations.
looking at their top issues, they have multiples things missing that outweigh the little benefits for now. ill subscribe to their release note im hyped haha

spring raptor
thorn forum
#

yeah it looks nice

thorn forum
# thorn forum yeah it looks nice

btw im having a problem with replicon 0.34 that wasn't happening before (commands batching i guess ?). i have multiples Tiles entity, on client connection i have a trigger for OnAdd ConnectedClient. i add a new building entity for the player with ChildOf(tile_entity) but on the client i get a warning that the ChildOf tile_entity doesn't exist. i guess its because the tiles entities are inserted after the building entity on the client.

#

also it seems that server trigger made in the ConnectedClient trigger are not sent to the client that just connected

dire aurora
#

Finally have physics and movement working ... Besides some issues at the start, and needing to do some ugly workarounds for the lack of support for networked assets, I've had very little network issues with my migration so far ... The current diff is scary though:

167 files changed, 1553 insertions(+), 13991 deletions(-)
spring raptor
spring raptor
spring raptor
thorn forum
#

sorry if I wasn't clear

#

it's basically the parent and the child are both inserted on the client in the same tick, and it seems the child is inserted before the parent ?

spring raptor
#

I'll take a look

dire aurora
spring raptor
#

Sounds like a lot of work 😅

dire aurora
#

It sure is 😅

#

I also got one rollback-related crash, if that keeps happening I might have to investigate whats going wrong too

#

But it's to do with status effects so I don't really want to touch it, that code needs to be rewriten using 🌈 and first-party entity disabling after all

spring raptor
#

Yeah, I feel like rewriting things into new Bevy concepts is the hardest part of each update.

dire aurora
#

It's harder to first migrate the half-broken old patterns though

#

Which is what I did 😅

#

So many assumptions in my code broke due to required components existing 🤣

spring raptor
#

Things like one frame delay?

dire aurora
#

No, I had code that was like "if X doesn't exist, add it with this value"

#

And because other crates added their component later in the frame, it was always filled with that value, unless spawned otherwise

spring raptor
#

Ah, got it 🙂

Bevy evolved a lot, it's so much more convenient now. I hate migration, but I love the new features.

spring raptor
thorn forum
spring raptor
#

Awesome, will merge and draft a patch

thorn forum
#

but i still have this warning also "Entity 227v1 with the GlobalTransform component has a parent without GlobalTransform." where the entity is the building and the parent entity is the tile. both are spawned with a Transform on the server (i directly .replicate Transform to test, normally i use another struct for bandwidth saving).
i think its the same “architectural” problem as the previous warning, the child commands ? (here the required component) are run before the parent

thorn forum
spring raptor
spring raptor
spring raptor
thorn forum
thorn forum
#

thanks for the release btw

spring raptor
# thorn forum hm how can i create a simple reproduction for the issue ?

I don't think we need a reproduction in this case 🤔
Bevy checks for the existence of the parent global transform in a hook. Since we sometimes process a child first, the hook runs, sees that the entity exists, and emits a warning. This entity is empty because the replication for it hasn't been processed yet.
We just need to request a setting resource that disables this warning and we temporarily turn it off during the receive.

spring raptor
thorn forum
#

on the bevy side, its not possible to run the check parent has component only after all the commands are exhausted instead of in the component hook ?

spring raptor
#

On our side we don't do any commands, we just directly insert into the world for performance.

#

And hooks run immediately

thorn forum
#

ohh ok

#

so the issue would be more like a way to disable the warnings ? per entity and or/per components ?
maybe the warning about the ChildOf(entity) being invalid can also be disabled, since its the same timing problem ?
i dont know how disabling the warning would work but it could be dangerous if the warning is suppressed while it was actually legitimate, it happened to me multiples times that these warning were true and i forgot to insert some things on the client side

spring raptor
# thorn forum so the issue would be more like a way to disable the warnings ? per entity and o...

I think it should be a global toggle 🤔
Since we want to temporarily disable B0004 while applying replication in Replicon, you should still be able to get these warnings in your own code.
Not sure if it should be configurable per-warning or just for this specific check.

maybe the warning about the ChildOf(entity) being invalid can also be disabled, since its the same timing problem ?
What do you mean?

thorn forum
#

my previous problem for which you added a world.flush(), its the same problem no ? the ChildOf(entity) the entity was gonna be inserted, just not yet and the ChildOf(entity) was inserted. so the warning can be supressed

#

my safety concerns are, this disable the warning entirely, even if it was legitimate. for example if i replicate a child with a Transform, and the parent doesn't have one. the child is gonna have a GlobalTransform, while its parent not. it should still print the warning no ?

spring raptor
thorn forum
#

oh ok

#

sorry for my lack of knowledge

spring raptor
# thorn forum my safety concerns are, this disable the warning entirely, even if it was legiti...

It's a valid concern. But we can't distinguish between an actually missing GlobalTransform and one that just hasn't been processed yet 😢

Another option is to somehow fix it on our side, but I'm not sure how... Maybe we could flush at the end of the entire replication process. I'll think about it more. I agree that adding a way to temporarily suppress the warnings isn't a good idea.
Just ignore these warnings for now 🙂

spring raptor
thorn forum
#

so can't the validate_parent_has_component system run only after everything has been inserted ?
when using world, does observers also run directly like hook or On* triggers are run when flushing ? if not, validate_parent_has_component being a OnInsert trigger instead would allow it to run only when flushing after everything has been inserted ?

#

ive stopped opening the issue then as the requested solution is suboptimal

#

and bevy_replicon using commands instead of directly inserting components would be huge performance loss ?

spring raptor
spring raptor
#

Because hooks and observers don't wait for the flushing

thorn forum
spring raptor
#

I'm not sure if it's even possible to run something after commands 🤔

thorn forum
#

sad

#

replicon side, maybe sort the order of the insertions, where the parents would be put first ?

spring raptor
spring raptor
thorn forum
#

i dont like having a warning, so ill delay the spawn of the child one frame so parent has time to settle on the client haha

spring raptor
thorn forum
thorn forum
spring raptor
spring raptor
#

@thorn forum thinking about it more.
This problem should be even present in scenes when children defined before parents.
A possible solution would be to check for GlobalTransform in a system with Added 🤔

spring raptor
thorn forum
#

i thought of that 🤓🧠 when talking about running validate_parent_has_component after all commands but thought there was a better way internally than a system, but yeah actually system is just fine and that's what bevy use anyway for it's things

#

(message failed to send yesterday)

thorn forum
#

hi, still having problem with ChildOf 🤔

#[derive(Component)]
pub struct Test(#[entities] pub ChildOf);
error[E0599]: no method named `map_entities` found for struct `bevy::prelude::ChildOf` in the current scope
   --> game_shared/src/game/replicon/mod.rs:161:10
    |
161 | #[derive(Component)]
    |          ^^^^^^^^^ this is an associated function, not a method
    |
    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
note: the candidate is defined in the trait `bevy::prelude::Component`
   --> /home/mirsella/.local/share/cargo/git/checkouts/bevy-659f18987ae20c74/f27ff60/crates/bevy_ecs/src/component.rs:563:5
    |
563 |     fn map_entities<E: EntityMapper>(_this: &mut Self, _mapper: &mut E) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the derive macro `Component` (in Nightly builds, run with -Z macro-backtrace for more info)

i have the bevy prelude imported

#

oh its because ChildOf impl Component but not MapEntities 🤡

#

how can i work around that for the issue we talked about ?

#

manually implemented Component

impl Component for DelayedChildOf {
    const STORAGE_TYPE: StorageType = StorageType::SparseSet;

    type Mutability = component::Immutable;

    fn map_entities<E: EntityMapper>(this: &mut Self, mapper: &mut E) {
        Component::map_entities::<E>(&mut this.0, mapper);
    }
}
spring raptor
thorn forum
#

can I open a PR to also implement MapEntities on ChildOf ? or it has not been done for a reason ?

#

there a issue about Component using the MapEntities impl I think 🤔

spring raptor
thorn forum
#

oh of course !

#

I talked about doing a PR just to improve for other user on the long run etc, im fine with the manual impl

spring raptor
#

I think there are no cases to store ChildOf 🤔

thorn forum
#

yeah you're right, apart from using a type to be more clear on the usage

swift hamlet
#

I have an event called

    trigger: Trigger<FromClient<ClientSendsTrackRequestToServer>>,

it implements MapEntities (manually), and all the entities inside the struct are properly mapped.

but the trigger.client_entity always returns PLACEHOLDER,

What could I be missing?

swift hamlet
#

(this only happen if the listen server sends the request, the server which is also hosting a client, if a normal client sends the request it works as expected)

spring raptor
#

You probably looking for trigger.target()

swift hamlet
#

I expected that the client_entity would be the entity which holds the client connection (to send data to etc.)

#

(I also added some player data to that entity when the client connects)

swift hamlet
spring raptor
swift hamlet
#

It’s a listen server so technically yes

spring raptor
#

Then yeah, it will be a placeholder. It's equal to SERVER constant which is a placeholder

#

When we get resources as entities, it'll be the entity with RepliconServer.

thorn forum
#

hey ! does replicon use bevy DetectChanges to send a mutation or not ? so if i use bypass_change_detection replicon will not send it to clients ?

spring raptor
#

So if you mutate something often, I'd recommend checking if the value is actually changed

thorn forum
#

yep im using set_if_neq :)

#

it was for a component Target which hold a entity + its translation, for easy acess to the translation even if the entity is dead. i had this component replicated a LOT

#

i parsed the data from the replicon log btw:

❯ open mutations.json
╭───┬─────────────────────────────────────────────────────────┬────────╮
│ # │                          name                           │ count  │
├───┼─────────────────────────────────────────────────────────┼────────┤
│ 0 │ game_shared::card::Target                               │ 197666 │
│ 1 │ game_shared::card::AttackRelation                       │   7053 │
│ 2 │ game_shared::card::components::Health                   │   3976 │
│ 3 │ game_shared::card::TroopState                           │   3352 │
│ 4 │ game_shared::game::grid::pathing::Pathing               │   2883 │
│ 5 │ game_shared::card::cards::castle::Gold                  │   1786 │
│ 6 │ game_shared::card::components::LastHitBy                │    803 │
│ 7 │ game_shared::card::troops::necromancer::NecromancerMark │     88 │
│ 8 │ game_shared::game::replicon::Owner                      │     38 │
╰───┴─────────────────────────────────────────────────────────┴────────╯
❯ open insertions.json | first 10
╭───┬──────────────────────────────────────────────────┬───────╮
│ # │                       name                       │ count │
├───┼──────────────────────────────────────────────────┼───────┤
│ 0 │ bevy_transform::components::transform::Transform │  1816 │
│ 1 │ game_shared::game::replicon::Owner               │  1586 │
│ 2 │ game_shared::card::CardRef                       │  1418 │
│ 3 │ game_shared::card::components::Damage            │  1378 │
│ 4 │ game_shared::game::grid::Tile                    │  1114 │
│ 5 │ game_shared::card::components::Projectile        │  1015 │
│ 6 │ game_shared::card::Target                        │   832 │
│ 7 │ game_shared::card::Level                         │   764 │
│ 8 │ game_shared::card::components::Hitbox            │   764 │
│ 9 │ game_shared::card::components::Health            │   754 │
╰───┴──────────────────────────────────────────────────┴───────╯
spring raptor
#

Nice!
We need something like this built-in...

thorn forum
#

yeah would be cool :) maybe a feature flag that record the count of each event for each component, and then log them regularly for example

spring raptor
thorn forum
#

oh yeah a resource is much better

#

and that would be per client so nicer yeah

#

but if you want to do the total of all the clients it might not be straightfoward

#

or also having a ServerReplicationStats

spring raptor
dire aurora
#

Hmmmm, I feel like I've seen this one before 🤔

bevy_replicon-0.34.0/src/client/server_mutate_ticks.rs:161:9:
assertion failed: self.received <= self.messages_count
#

When I move from my town instance to a dungeon instance it just panics with this message after a while

spring raptor
spring raptor
dire aurora
spring raptor
#

@dire aurora sorry, but could you send it again with the latest changes in the branch?
No fix yet, just making logging and panicking informative.

dire aurora
#
bevy_replicon-39b0dac7548b572d/6219ba3/src/client/server_mutate_ticks.rs:170:9:
expected at most 2 messages, but confirmed 1
``` ![thonk](https://cdn.discordapp.com/emojis/1153851465765490742.webp?size=128 "thonk")
spring raptor
#

And what server sends, also 2 messages? 🤔

#

If there are no "splitting ...", then it's a single message

dire aurora
#
2025-06-29T14:21:34.515074Z TRACE bevy_replicon::client::server_mutate_ticks: confirming `RepliconTick(450)` which is 63 ticks ago

This sounds very much like a resetting issue, the moment we hit 63 ticks ago it crashes 🤔

#

Would explain why the longer I stay in the town, the longer it takes for the dungeon to crash

spring raptor
#

I trying to reproduce it locally, but can't

#

The following test works for me:

        let mut ticks = ServerMutateTicks::default();
        ticks.confirm(RepliconTick::new(1), 1);
        ticks.confirm(RepliconTick::new(u64::BITS + 1), 1);
        ticks.confirm(RepliconTick::new(2), 1);
        ticks.confirm(RepliconTick::new(u64::BITS * 2 + 1), 1);
        ticks.confirm(RepliconTick::new(u64::BITS + 2), 1);

Output:

[TRACE bevy_replicon::client::server_mutate_ticks] confirming `RepliconTick(1)` which is 1 ticks since last
[TRACE bevy_replicon::client::server_mutate_ticks] confirming `RepliconTick(65)` which is 64 ticks since last
[TRACE bevy_replicon::client::server_mutate_ticks] confirming `RepliconTick(2)` which is 63 ticks ago
[TRACE bevy_replicon::client::server_mutate_ticks] confirming `RepliconTick(129)` which is 64 ticks since last
[TRACE bevy_replicon::client::server_mutate_ticks] confirming `RepliconTick(66)` which is 63 ticks ago
#

Could you provide the rest of the log, so I could try to reproduce it closely?

dire aurora
#

It's not just 63 ticks ago, the moment I connect it starts with confirming ticks that were over 200 ago 🤔

#
confirming `RepliconTick(8)` which is 547 ticks ago
```Yea, it's pretty clear this hasn't been reset after disconnecting and reconnecting 😅
#

Then the moment it comes to a tick that is inside history it'll add a confirm beyond what it should receive and it panics

#
2025-06-29T14:46:49.469505Z DEBUG bevy_replicon::shared::backend::replicon_client: changing status to `Disconnected`
2025-06-29T14:46:49.485761Z DEBUG bevy_replicon::shared::backend::replicon_client: changing status to `Connecting`
2025-06-29T14:46:49.501657Z DEBUG bevy_replicon::shared::backend::replicon_client: changing status to `Connected`
2025-06-29T14:46:49.501699Z DEBUG bevy_replicon::client: sending `ProtocolHash(17816712812252468640)` to the server
```Looks like it is going trough the disconnect, connecting, connect cycle properly, so the reset should happen, right? 🤔
spring raptor
#

@dire aurora could you try again the same branch?

#

Wait, no 🙂

#

Should be good now!

thorn forum
#

hey ! it seems ProtocolHasher output is different on wasm web than on native 😃
exact same version, i greped all the "adding" log in a file, and the only diff between web and native is the hash. all the adding statement are the same, in the same order

edit: reproduction https://github.com/mirsella/bevy_replicon/tree/wasm_protocol_hasher
clone and run wasm-pack test --node while the test pass on native

edit2: its becuase of foldhash, it produce different hash on different platform.
their readme:

You expect foldhash to have a consistent output across versions or platforms, such as for persistent file formats or communication protocols.

foldhash::quality doesn't work either. no_std so no std hasher, we might need to pull in another hashing crate... ?

rough pawn
#

@spring raptor bit of an in-depth question when you have a few minutes...

I watched your Bevy Meetup #9 talk - really enjoyed it, thanks for putting it together.

I've also read the getting started guide and think I understand how to implement a listen server (basically start a network server and run both the server logic and client logic).

I have a question about implementing a mechanism in my game that achieves the same as Minecraft's "Open to LAN" feature.

I think I need to:

  1. Start a single player configuration game (no client or server connection, but both client and server game logic running).
  2. When 'opening to LAN', create a network server and add as a bevy resource, like this...

E.g. let's say I'm using renet:

let server_channels_config = channels.server_configs();
let client_channels_config = channels.client_configs();

let server = RenetServer::new(ConnectionConfig {
    server_channels_config,
    client_channels_config,
    ..default()
});

let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
let socket = UdpSocket::bind((Ipv4Addr::UNSPECIFIED, port))?;
let server_config = ServerConfig {
    current_time,
    max_clients: MAX_CLIENTS,
    protocol_id: PROTOCOL_ID,
    authentication: ServerAuthentication::Unsecure,
    public_addresses: Default::default(),
};
let transport = NetcodeServerTransport::new(server_config, socket)?;

commands.insert_resource(server);
commands.insert_resource(transport);

This essentially transitions my 'singleplayer' setup into a 'listen server' setup.

And as long as I've setup my replication component annotations, and configured the run conditions correctly in my bevy systems, then things should just work.

Am I correct in my understanding? Is there anything I'm missing?

dire aurora
# spring raptor Should be good now!

Seems fixed now, I go to about 500 ticks in my first instance, then switch to another one and get up to a couple thousand no crashes ...

2025-06-29T18:17:10.885056Z TRACE bevy_replicon::client::server_mutate_ticks: confirming `RepliconTick(3411)` which is 1 ticks since last
2025-06-29T18:17:10.885075Z TRACE bevy_replicon::shared::backend::replicon_client: received 1 message(s) totaling 23 bytes from channel 5
2025-06-29T18:17:10.885085Z DEBUG bevy_replicon::shared::event::server_event: receiving event `bevy_rewind_input::HistoryFor<movement::motion::MoveInput>` with `RepliconTick(524)`
```Bit confused about why this event from thousands of ticks ago keeps being received though 🤔
spring raptor
spring raptor
#

Ah, wait, the event is received 🤔

spring raptor
spring raptor
dire aurora
spring raptor
thorn forum
spring raptor
spring raptor
thorn forum
# spring raptor Because of the dev-dependencies

there is not build script, so the dev deps are only loaded with cargo tests / example ? so when using bevy_replicon as a library in a project, the dev deps are not pulled ? so its the same for library usage ?
but anyway i agree rustc-hash seems really good

#

ill test !

dire aurora
spring raptor
spring raptor
#

Once merged, I'll draft a patch for this and ticks reset fixes

spring raptor
thorn forum
#

ill test fnv hash maybe

spring raptor
thorn forum
#

also different

#

neither fxhash or wyhash have the same hash on wasm and native

#

but all of them have the same difference, the wasm hash is a lot smaller than the native hash, maybe on wasm rand or something use u32 instead of u64 values ?

spring raptor
#

I don't think they use rand at all 🤔

thorn forum
#

oh right since its a fixed seed

spring raptor
#

This should be cross-platform

thorn forum
#

different 🤡

#

they're saying it works on any platform i guess

spring raptor
#

@thorn forum could you compare strings we hash?

#

Becase we use type_name which might or might not be stable.

thorn forum
#

ill check

#

how do you deal with no println! or dbg! because the whole crate is no_std 😭
also wasm-pack test dont show the stdout of the tests so ill find another way of getting the type_name

#

i tried just panic with the type name given to the hash method and its the same thing, so its seems its not coming from this

#

tried with only the type_name and it works. its coming from the protocolpart enum

spring raptor
spring raptor
#

If yes, does #[repr(u8)] solves the issue?

thorn forum
#

the hash are different for the same ProtocolPart yes. repr(u8) change the hash of the enum, but sadly native and wasm still compute different hash.

#

as a last resort we can impl Hash ourself i think ?

spring raptor
spring raptor
#

It's okay to pull a dependency. We'll move it under a feature in the next major release

thorn forum
#

repr(C) doesn't work

spring raptor
thorn forum
#

no 😭

#

wtf manual impl of Hash also doesn't work 🤔

#

starting to think its the compiler 😂

spring raptor
thorn forum
#

no i removed the repr as i thought it wouldn't be used with the manual Hash impl

thorn forum
#
impl Hash for ProtocolPart {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            ProtocolPart::Replicate { priority } => {
                0u8.hash(state); // Use a fixed discriminant for this variant
                priority.hash(state);
            }
            ProtocolPart::ReplicateBundle => {
                1u8.hash(state); // Fixed discriminant
            }
            ProtocolPart::ClientEvent => {
                2u8.hash(state);
            }
            ProtocolPart::ClientTrigger => {
                3u8.hash(state);
            }
            ProtocolPart::ServerEvent => {
                4u8.hash(state);
            }
            ProtocolPart::ServerTrigger => {
                5u8.hash(state);
            }
            ProtocolPart::IndependentEvent => {
                6u8.hash(state);
            }
            ProtocolPart::IndependentTrigger => {
                7u8.hash(state);
            }
        }
    }
}
spring raptor
thorn forum
#

commented:

        // hasher.replicate::<StructA>(1);
        // hasher.add_custom(0);

so there shouldn't be any other variable possible and i still get a different hash !!

#

wtf

spring raptor
thorn forum
#

even if its not used ?
ok it worked, it was becuase of rustc-hash

#

tried with rapidhash and got the same hash

spring raptor
thorn forum
#

yes with u64

#

u64 + #[repr(u8)] + rapidhash

spring raptor
thorn forum
#

yes haha

#

removed my custom Hash impl

#

maybe another hash algo works tho

#

but not rustc-hash

#

fnv works

spring raptor
thorn forum
#

it does i think, we call value.hash(&mut hasher)

#

value.hash is the Hash impl on the values

spring raptor
#

Ah, let's use it then 🙂

thorn forum
#

re tried deterministic_hash+foldhash, foldhash, rustc-hash, they dont work.
we have
rapidhash 40kib
fnv 10kib

#

so lets go for fnv i guess ?

spring raptor
#

Ah, is it const-fnv1a-hash?

thorn forum
#

no just fnv ?

spring raptor
thorn forum
#

oh ok !
its only in the dev dependencies tree, any user pulling bevy_replicon as a library will not have it anyway i think.

spring raptor
thorn forum
#

oh ok didn't understand

#

I'll go to sleep, thanks for the discussion!

spring raptor
#

Thanks for testing!
I'll setup CI and apply the fix

spring raptor
woven forge
#

heyo, has anyone successfully used bevy_replicon with bevy_rapier2d? i'm getting segmentation faults inside bevy_rapier2d when I try

#

specifically, i get a segmentation fault on the client only, in the drop implementation of Collider, after it's called in a pile of unsafe functions by bevy_replicon, which makes me think the issue is in replicon somewhere

dire aurora
#

You can network Collider? That sounds a bit sketchy considering it's an Arc for a trait 🤔

woven forge
#

yeah it occurred to me much later that networking it doesn’t make any sense :p

#

it implements Serialize ¯_(ツ)_/¯

thorn forum
spring raptor
spring raptor
spring raptor
woven forge
# spring raptor This is weird... Yes, looks like it's an `Arc`, but it somehow implements the se...

I looked into it more- what I suspect is happening based on coredumps is somehow the Arc is getting directly copied without the data it points to being copied. Then, something else is causing a panic, and the Drop implementation tries to drop the data that the Arc would normally contain which is somehow not there and that triggers the segfault. I’m really not sure, it’s super strange. Anyways, thanks for the help!

spring raptor
#

Will investigate

spring raptor
#

@dire aurora since I borrowed your approach, you might also need a similar fix 🙂
Here you cast uninitialized memory into &mut C, but writing into it like this *ptr = component will trigger drop for the old uninitialized ptr value which is UB.

dire aurora
spring raptor
#

@dire aurora @thorn forum the patch-release is up, please run cargo update -p bevy_replicon 🙂

spring raptor
dire aurora
#

LGTM

swift hamlet
#

How is the best way to sync the server tick with the client?

I saw that entities have their last update tick from the server, but I could not find a way to access a client in a system.

spring raptor
swift hamlet
spring raptor
swift hamlet
spring raptor
swift hamlet
#

I think what I don’t fully grasp is what “tick” revers to. For example here:

ServerUpdateTick is greater than the tick

Which tick would I compare it to on the client?

spring raptor
spring raptor
swift hamlet
spring raptor
swift hamlet
#

I might be completely interpreting this wrong but I have the following scenario:

server starts countdown at server tick 10. It sets a parameter on the countdown timer

pub struct CountDown{
  started_at: Tick(10), 
  expires_at: Tick(30),
}

Now a client joins the game, how can the client display how long the countdown still lasts (in ticks or time), what I don't really understand how the client can know at what tick it currently should be.

spring raptor
#

Yeah, not happy about the PLACEHOLDER either. Maybe wrap the entity into enum? 🤔

swift hamlet
spring raptor
#

It's two resources instead of one because we need granular control for prediction crates.

swift hamlet
#

And as a side note, very pleasant api surface, and straight forward to implement networking with replicon, especially if the game aligns well with the out of the box features.

Thank you!

spring raptor
#

Glad you enjoy it 🙂

spring raptor
#

I have been thinking about an enum like this:

enum Sender {
    Server,
    Client(Entity),
}

This way you can store this enum instead of the entity. When resources become entities, we will be able to write it like this:

enum Sender {
    Server(Entity),
    Client(Entity),
}
swift hamlet
swift hamlet
# spring raptor Awesome!

One thing which is confusing to me is why the RepliconChannels have client and server parts.

int the tcp example we simply add the channel_id to the package (which I did up to now and that works), but ideally I would like to directly setup the different channels with the guarantees, but matchbox expects only one socket.

What is the difference between the server and client channels?

swift hamlet
#

Ok I think I figured it out 🤔

spring raptor
swift hamlet
spring raptor
# swift hamlet Yeah that I have setup now, what i'm not sfully sure is how I should set this up...

All backends usually differentiate between send and receive channels. Let’s imagine we create a server event — it results in a single server channel. RepliconChannels::client won’t contain it.

And when you create a server, you use server channels for sending and client channels for receiving. Here is an example from Aeronet. Looks like Matchbox doesn’t differentiate between sending and receiving, and a single channel can be used for both?

#

If so, just consider server and client channels as a single array.

swift hamlet
spring raptor
swift hamlet
spring raptor
swift hamlet
#

Its very strange I copy pasted the example from the docs for the events, but none of them are received...

spring raptor
#

So I suspect that the problem might be in the ported tests for events

swift hamlet
#

But also in the simple box example if I added the events from the documentations, they never reach the client 🤔

spring raptor
#

Let's debug. Add test-log as a dev-dependency to your code. Then add use test_log::test; to your integration test imports.
And then run the test like this RUST_LOG=bevy_replicon=trace cargo run --test <integration test name>. And send the logs here.

#

@swift hamlet ^

#

RUST_LOG is the environment variable. If you use Windows, take a look how to properly set it for a single command run, the example above is for Linux.

swift hamlet
#

Will be back in the office shortly and will test!

swift hamlet
#
[TRACE bevy_replicon::server::server_world] marking `ArchetypeId(4)` as replicated
[DEBUG bevy_replicon::shared::event::server_event] sending event `netcode::TestEvent` with `Broadcast`
[TRACE bevy_replicon::shared::backend::replicon_server] sending 0 bytes over channel 5
[DEBUG bevy_replicon::shared::event::server_event] sending event `bevy_replicon::shared::event::server_trigger::ServerTriggerEvent<bevy_replicon_matchbox_backend::server::OnHostDefinitionTrigger>` with `Direct(7v1#4294967303)`
[TRACE bevy_replicon::shared::backend::replicon_server] sending 18 bytes over channel 3
[DEBUG bevy_replicon::shared::event::server_event] resending event `netcode::TestEvent` locally

so it seems the event is sent, but

    let events = client_app.world().resource::<Events<TestEvent>>();

is always 0

#

and there is never a "receive" from the client.

#

here is the complete log, I log the number of events after multiple updates on the client side, but they stay at 0.

spring raptor
#

Just add an integer or something like that.

#

If it works, then something is wrong with how you handle zero-sized messages.

#

Because triggers aren't zero-sized, they include the entity.

swift hamlet
#

Result is the same

spring raptor
# swift hamlet

I see that the event is sent, but never received. You should see logs about receiving a message.

swift hamlet
#

Technically all is sent the same way, the strangest part is that triggers work

spring raptor
#

I'd suggest to now enable logs for you backend and see what messages you received.

#

And sent

swift hamlet
#

will double check the channels, maybe something is off with how I handle channels

spring raptor
#

It looks like you don't receive any messages at all

swift hamlet
spring raptor
#

It's okay, we all humans 😅
So it works now? Or did it fixed receiving for everything, except events?

swift hamlet
#

Still validating, but I have at least 1 event received on the client side, now need to validate the correct order of disconnect elements (like sening all events before actually disconnecting etc.)

spring raptor
#

Ah, yeah, that usually requires careful system ordering.

#

So the idea is to enter the disconnected state in PostUpdate, allowing the client to process the received messages.

swift hamlet
spring raptor
swift hamlet
spring raptor
#

I'd suggest to open an issue on the matchbox repo and advice to add integers to events 😅

#

Or manually add a special byte at the beginning of the each message.

swift hamlet
#

will do, initially I constructed my messages all on simply one channel, so adding the channel number prevented any 0 size messages to ever be sent.

#

I was thinking to simply add 1 byte to each message, which I drop at the other side... but not ideal

spring raptor
#

Yes, it's definitely a bug

#

I'd open an issue and add a byte as a workaround with a comment in the code.

swift hamlet
spring raptor
swift hamlet
spring raptor
#

I.e. with the example backend test and yours

swift hamlet
# spring raptor Try to enable logging and compare both tests

Ah its the AuthorizedClient component which was missing. Up to now, I allowed the application to handle insertion of AuthorizedClient on the server.

Is it expected that the backend implementation automatically adds this component on successfull connection?

spring raptor
swift hamlet
#

(I'm using replicon 0.34.x in case this has changed.)

spring raptor
#

Enable logging, run any test and send the logs here

#

It's purpose to verify protocol compatibility. This helps to avoid silly errors like having events registered differently on client and server.

swift hamlet
#

I don't receive anything from matchbox directly this time.

spring raptor
spring raptor
swift hamlet
spring raptor
# swift hamlet

I'm not seeing any received message on the client or the server.

#

I see client sending the message. But the server never receives it.

swift hamlet
#

That is strange...

#

all other events are received

spring raptor
#

Not in this test

swift hamlet
spring raptor
#

Yes, but I don't even see the received replication.

swift hamlet
#

could it be a timing issue?

#

without calling drain_sent() the messages stay queued up?

spring raptor
#

So you likely receive messages, just not the authorization.

spring raptor
swift hamlet
#

That could be, so as matchbox doesn't have a concept of "host/server" and client, I have to inform a newly connected client which of the peers is the host.

So until the client receives that event, it doesn't call drain_sent, I expected that the messages would be queing up until I call drain_sent but if that is not the case I likely skip that early message (as its not clear which peer the host is)

spring raptor
spring raptor
swift hamlet
spring raptor
swift hamlet
#

(which I assume most want to do)

spring raptor
#

Got it!
Double check the timings. Maybe you discard this message on the server because it was sent too early?

swift hamlet
#

checking currently, the client does send it properly it seems, so now validating the server

#

ok no it is the client

#

now when I queue up the message if it is sent too early, it seems to work.

#

Which is strange as nothing else drains the client events 🤔

spring raptor
#

But the event is sent only when you set the status to connected

spring raptor
swift hamlet
#

Yes I set connected too early, will try to set it only once the host has been identified

spring raptor
#

Here is how it should look like:

[DEBUG bevy_replicon::shared::event::client_event] sending event `bevy_replicon::shared::event::client_trigger::ClientTriggerEvent<bevy_replicon::shared::protocol::ProtocolHash>`
[TRACE bevy_replicon::shared::backend::replicon_client] sending 10 bytes over channel 1
[TRACE bevy_replicon::shared::backend::replicon_server] received 1 message(s) totaling 10 bytes from channel 1
[DEBUG bevy_replicon::shared::event::client_event] applying event `bevy_replicon::shared::event::client_trigger::ClientTriggerEvent<bevy_replicon::shared::protocol::ProtocolHash>` from client `5v1`
[DEBUG bevy_replicon::shared::event::client_trigger] triggering `bevy_replicon::shared::event::client_event::FromClient<bevy_replicon::shared::protocol::ProtocolHash>` from `5v1`
[DEBUG bevy_replicon::server] marking client `5v1` as authorized
[TRACE bevy_replicon::server] incremented ResMut(ServerTick(RepliconTick(2)))
[TRACE bevy_replicon::shared::backend::replicon_client] trying to receive from 0
[TRACE bevy_replicon::shared::backend::replicon_client] trying to receive from 2
[TRACE bevy_replicon::server] incremented ResMut(ServerTick(RepliconTick(3)))
[TRACE bevy_replicon::server::server_world] marking `ArchetypeId(5)` as replicated
[TRACE bevy_replicon::server] writing empty `6v1` for client `5v1`
[TRACE bevy_replicon::shared::backend::replicon_server] sending 4 bytes over channel 0
[TRACE bevy_replicon::shared::backend::replicon_client] trying to receive from 0
[TRACE bevy_replicon::shared::backend::replicon_client] received 1 message(s) totaling 4 bytes from channel 0
[TRACE bevy_replicon::client] applying update message with `UpdateMessageFlags(CHANGES)` for RepliconTick(3)
[TRACE bevy_replicon::shared::backend::replicon_client] trying to receive from 2
#

sending ... and then received ...

swift hamlet
#

The problem is that I use a simple replicon event for setting the host, but that only is sent when I set the connection as connected.

Will have to find a better flow and probably send the "which peer is the host" event not through replicon, but rather direclty through matchbox

spring raptor
spring raptor
swift hamlet
spring raptor
#

So I'd expect you to set the connected first on actual connect and then identify the host.

swift hamlet
#

So I have two choices, either I set the connected to true early, queue up the protocol hash message, and send it when I received which one is the host.

Or I add an additional channel which handles the host communication through matchbox, and then only set the connected to true once the host has been identified.

spring raptor
#

I’d probably handle the communication through Matchbox, since it sounds like something that’s part of the connection.

spring raptor
#

But are you sure it's not possible to use matchbox as a true client-server? I remember seeing a client-server example in the repo 🤔

swift hamlet
# spring raptor But are you sure it's not possible to use matchbox as a true client-server? I re...

from what I could find there are 3 samples in the bevy matchbox repo:

  • client only (requires separate signaling server)
  • host (client + signaling)
  • Signaling in bevy

So although from the samples, you could identify who the host is by running directly the signaling server inside the bevy application, I argue that would defeat the main benefit of matchbox, as the signaling server needs to be accessible from anywhere.

#

I managed now to have all tests pass, some I modified a slight bit, (primarily the server stop.

I have one strange issue, that I need to run the updates more than once after the event is send in the world, or a replicated component is spawned.

Bu otherwise it seems the tests all pass.

swift hamlet
spring raptor
swift hamlet
spring raptor
swift hamlet
spring raptor
viscid jacinth
#

I thought matchbox was p2p, how does it work with a more client-server crate like replicon

spring raptor
# viscid jacinth I thought matchbox was p2p, how does it work with a more client-server crate lik...

Yeah, It's a bit confusing, while they mention P2P in their readme, the signaling server actually supports both topologies. At least from a quick look at the repo, I never used matchbox myself 🙂
Here is the example: https://github.com/johanhelsing/matchbox/blob/main/matchbox_signaling/examples/client_server.rs
And the code: https://github.com/johanhelsing/matchbox/blob/main/matchbox_signaling/src/topologies/mod.rs

viscid jacinth
#

Oh cool

#

I don't really get how pure p2p topologies are even supposed to work. Does one client still act as the lead?

spring raptor
#

But it's all quite niche. For games, client-server is usually the better option: lower bandwidth usage, no NAT/firewall issues, and no complex consensus models.
I remember in the original Bevy Replication RFC, Joy even suggested supporting only a client-server topology.

swift hamlet
#

There are scenarios where a pure p2p could be interesting, but in most cases a client server architecture is often easier to reason about and often better for performance.

Even factorio moved from p2p to a server/client one and had a lot improved performance and less bugs

spring raptor
swift hamlet
spring raptor
#

How was your experience with porting? Which parts was unclear? I guess channels? 😅

swift hamlet
# spring raptor How was your experience with porting? Which parts was unclear? I guess channels?...

Yeah the channels confused me a lot at the start, Especially server/client etc. and how to map them to the socket channels.

Now what took the longest to get right is the timing of when what should happen (for the tests).

Overall it was both harder and easier then I expected 😅 .

I think the reason why I currently need an additional update for the tests is the timing of when the sockets sends the messages.

I currently don't see an easy way to work around that, as they are not on a bevy schedule (as far as I can tell).

spring raptor
swift hamlet
#

its not the part when I push the messages to the socket, its when the socket sends/receives the packages (I think at least at the moment)

swift hamlet
viscid jacinth
spring raptor
swift hamlet
spring raptor
spring raptor
swift hamlet
#

ah its the disconnection of the client, as there is no guarantee when (in terms of update sicles) the server detects that the peer has disconnected...

spring raptor
swift hamlet
spring raptor
#

I used netcode because renet has multiple inner backends.

spring raptor
#

Actually, I have another one 😅
Looks like you don't collect the coverage. So you don't need to run tarpaulin, so you can replace all these steps with a single cargo test.

spring raptor
#

Ah, and I think you need to replace bevy_replicon_renet with your crate name here.

swift hamlet
spring raptor
#

It's okay 🙂

spring raptor
#

And feel free to open a PR to add your crate to the list of messaging backends. I could do it myself, but I prefer authors to write description for their crates. Matchbox repo also have a showcase section, I'd recommend adding it there too.
Just to let people know about your crate. Announcement in #crates also helps.

dire aurora
#

@spring raptor happen to have any idea as to changes since 0.14 that could cause both my visibility to sometimes break and spawns of entities to occasionally get duplicated? 🤔

#

Considering it only seems to affect enemy entities, it's probably something silly in my code, but I have no clue what would've changed to make such issues possible 🤣

spring raptor
dire aurora
#

Hmmmm, might just be despawning behavior being broken there. If I leave a room, then exit it again, enemies sometimes duplicate ... And I guess the initial visibility thing might be visibility not always getting set correctly the first time around depending on system ordering 🤔

spring raptor
dire aurora
#

Latest patch ... But I think this might actually be caused by bevy_rewind_entity_management ... Since that's where I modify despawn behavior, and it might not be compatible with hierarchies somehow 🤔

spring raptor
#

Let me know if you want me to add logging to the visibility system to help you debug the issue.
I noticed that we don't log visibility changes

dire aurora
#

The visibility changes are easy enough to log in my own code luckily

#

Okay turns out that if you actually want entities to disappear ... You should actually despawn them on the client bavy

#

My code just disabled them the first time around, then during rollback re-enable them, and then never re-disable or despawn them

spring raptor
#

Ah, makes sense 🙂

dire aurora
#

Does replicon ever reuse previously spawned client entities when visibility is involved?

spring raptor
dire aurora
#

So I don't have to worry about the case where I disable an entity that becomes invisible, mark it to be despawned, and it then gets reused?

spring raptor
tall willow
#
#[derive(serde::Deserialize, Event, serde::Serialize, Clone)]
pub struct TransformFromClient { pub entity: Entity, pub transf: Transform, pub time: SystemTime }

#[derive(serde::Deserialize, Event, serde::Serialize, Clone)]
pub struct TransformFromServer { pub entity: Entity, pub trans: Transform, pub time: SystemTime }

#[derive(Component, Clone, Copy, Deref)]
pub struct MpAuthority(pub Entity);

pub fn handle_movement(
    mut commands: Commands,
    time: Res<Time>,
    mut query: Query<(Entity, &InputMoveDirection, &mut Transform), With<Being>>,//ignore this query not being correct (it is not suitable yet for multiplayer I have to fix it)
) {
    for (ent, input_move_direction, mut transform) in query.iter_mut() {
        let speed = 1000.0;
        let delta = time.delta_secs();
        let movement = input_move_direction.0 * speed * delta;
        transform.translation += movement;

        commands.client_trigger(
            TransformFromClient {
                entity: ent,
                transf: transform.clone(),
                time: std::time::SystemTime::now(),
            }
        );
    }
}
pub fn receive_transf_from_client(
    trigger: Trigger<FromClient<TransformFromClient>>,
    mut commands: Commands,
    mut query: Query<(&MpAuthority, &mut Transform,)>,
) {
   let (mp_auth, mut transf) = query.get_mut(trigger.entity).unwrap();

   if mp_auth.0 == trigger.client_entity {
        if transf.translation != trigger.transf.translation || transf.rotation != trigger.transf.rotation || transf.scale != trigger.transf.scale{
            commands.entity(trigger.entity).insert(trigger.transf.clone());

            commands.server_trigger(
                ToClients { mode: SendMode::BroadcastExcept(trigger.client_entity), event: TransformFromServer::from(trigger.event().event.clone()) },
                
            );
        }

   }
}

#

uh is this an acceptable way to sync characters' transforms for a realtime top-down 2D multiplayer game? (without complicating things too much for now and reducing latency).
Sorry if this has been asked before but I can't ctrl-F within this specific thread.

#

To summarize: Having the client locally compute his new transform, then sending it to the server through a Trigger, and then the server broadcasts it to the rest of the clients via another Trigger
(all this unreliably and unordered)

swift hamlet
spring raptor
spring raptor
tall willow
# spring raptor Depends on the game 🙂 But sending positions directly usually not a good idea. C...

I am making a Rimworld-like co-op game but with the capability of taking over and manually controlling pawns with WASD keys + mouse (to aim ranged weapons or spells for example). Players aren't strongly binded to a specific pawn/character and are able to take control of another if no other player is controlling it. But, the combat would be similar to Necesse (fast-paced, realtime, being able to accurately dodge projectiles is necessary) so low latency is ideal.

spring raptor
# tall willow uh is this an acceptable way to sync characters' transforms for a realtime top-d...

Ah, sorry, I should have read this earlier.
No, for a fast-paced game you need proper rollback/prediction.

Here are the very basics:

  • Clients broadcast inputs to the server (not transform!).
  • Server simulates the logic and sends the state back.
  • But clients don't wait for the response and continue to simulate with the local input (predict the result, basically). So the server is behind in time.
  • Clients receive the state and roll back their state in time to the server timestamp.
  • Then they snap to the received state from the server and re-play all the inputs up until the current time.

So basically, the client predicts the result, the server corrects it, and the client re-applies inputs since the last correction.

But there's a whole lot more to it.
For example, you don't want to predict everything. Imagine you predict death, and on misprediction, enemies wake from the dead 😅 So some things, like damage or deaths, usually wait for confirmation from the server and are just hidden behind visual effects.
You also may want to interpolate between the corrected state and yours for things like transforms to avoid jittery movement.
There are also 2 rollback strategies: rollback the entire world or specific entities individually. Depends on whether your game is physics-based or not.
There's also deterministic replication - it's where you only exchange inputs. But for your game (and most games), you want authoritative replication. That's where you replicate the state from the server, like I described above.
Can't describe everything in a discord message, but I can give some learning materials if you want.

#

So, for Replicon you need a solution on top of it.

I expose the necessary API for it.
It's not built-in because, as I mentioned, there are several strategies, and for my game I don't even need prediction/rollback. So I decided to make the crate modular to avoid maintaining things I don't need. Plus, this way more people can get involved.
It worked really well for messaging backends, but for prediction/rollback - not so much 😅 Probably because it's much harder to implement than messaging.
Currently, the only crate that utilizes the mentioned API is bevy_rewind. The developer is very knowledgeable, but the crate is not finished yet because she is busy with life stuff.
It's possible to try to integrate other crates. For example, there is Naia, which is engine-agnostic. And Lightyear recently refactored the prediction and rollback logic into separate crates, so it should be possible to integrate with those.

And implementing it manually is also an option. But as I mentioned, it's not an easy task 🙂

tall willow
#

Thank you very much for the very thorough answer 😀 , the learning materials would be useful if you have them. Doesn't seem easy to implement, as you said, but I will later see what solution I end up using. I will probably try the bevy_rewind crate first

spring raptor
#

Yeah, definitely try it out! Pretty sure @dire aurora will appreciate your feedback. It was a part of her game that was extracted into crates. Right now, the current focus is on porting the game between Bevy versions and to these crates, which takes time 🙂

As for learning materials, here are my favorites that are must to read/watch:

And for more materials, just see this repo.

vital mist
spring raptor
dire aurora
#

@spring raptor trying to port some code away from bundles, and it very much feels like I just wanna define rules as follows:

  • Send X and Y if we have both (we already have this)
  • Send X in a special way, and also Y (we also have this
  • Send X in this way if the entity has Y
  • Don't send X if the entity has Y
  • Send X and Y if it has both and Z
#

If we had filters, and ways to exclude components from replication under certain conditions, I think bevy_bundlication and its deref macro would become unnecessary

spring raptor
# dire aurora <@243426730851696640> trying to port some code away from bundles, and it very mu...

Makes sense. We have this issue that should address this.
Would be cool to just allow Bevy's With and Without.

I will prioritize this feature. Just need to make some final touches for BEI and I'll start working on it.

GitHub

It would be quite convenient to support Bevy's filters in replicate_with as in queries, via second generic parameter. These rules will be applied when filtering archetypes.

dire aurora
#

Yea, the only thing that might not work with just that is excluding, but that might be somewhat doable if we already have filters working (+ I might be able to work around it, even if it's a bit ugly)

spring raptor
dire aurora
#

Trying to fix some tests in bevy_rewind and I can't seem to figure out how to construct a DeferredEntity, should I take a different type on my functions so tests can use EntityMut still or am I missing something? 🤔

dire aurora
#
trait MutableEntity {
    fn get_mut<C: Component<Mutability = Mutable>>(&mut self) -> Option<Mut<'_, C>>;
    fn contains<C: Component>(&self) -> bool;
    fn id(&self) -> Entity;
}
```Fixed it with this really dumb trait for now
spring raptor
dire aurora
#

I use it like this btw, just repeated blocks of this (sometimes 2 writes)

let mut entity_mut = EntityMut::from(world.entity_mut(e1));
write_history_internal::<A>(comp_a, &mut entity_mut, r_tick(0), A(1), frames);
```Maybe we could have an API that just gives you a DeferredEntity within a scope from a `World` method 🤔
spring raptor
# dire aurora I use it like this btw, just repeated blocks of this (sometimes 2 writes) ```rus...

With the scoped version you would discard the buffer every time. I know it's for tests, but still...
Maybe just make things public? Opened: https://github.com/projectharmonia/bevy_replicon/pull/522
This will remove the trait requirement for you. But you will have to construct the buffer once somewhere. It's cleared on apply automatically.

dire aurora
#

Is entity.flush() whats used to apply the deferrd changes?

spring raptor
spring raptor
#

Continuing from #networking message: @vocal violet If you starting a new project, all others backends are also nice.

I probably should update the README to put the regular renet down on the list 😢

#

Ah, yeah, then renet2 would be the best choice for you.

spring raptor
#

The renet itself.

spring raptor
spring raptor
#

You won't have an entity for a server. We need resources as entities.

#

You can, but not for the server.
You can create your own server entity if you want.

#

Yeah, server can be a client too.
But it doesn't have its own entity, like clients do. Clients represented by entities with ConnectedClient component. But server is a resource for now.

#

Why not? Not sure If I get the question

#

If you want to use entities with ConnectedClient component to store your own data and need to support "server as a client", you can create your own server entity and check if it's a placeholder. Not Ideal, I know. I planning to make it strongly-typed in the future.

#

We just need resources as entities.

#

Another option is to use your own entities to represent players. You probably did it before since we didn't always have clients as entities.

#

Do you need to access client data on every message? 🤔

#

Are you sure we are talking about the same thing? It's not entities for which you trigger events. It's actual clients stored on the server in form of entities.

#

Ah, got it. Then a resource with client data would also work.

dire aurora
spring raptor
#

For server you don't have an ID because it doesn't have a connection, you could just store None or some special hardcoded value.
And we don't have a server entity because the server is not an entity. You can create an entity for it yourself, however. There is just nothing I could do, we need resources as entities. The work is started on it, but we won't get it in 0.17, sadly.

dire aurora
#
-let mut entity_mut = EntityMut::from(world.entity_mut(e1));
-write_history_internal::<A>(comp_a, &mut entity_mut, r_tick(0), A(1), frames);
+world.entity_scope(e1, |e| {
+    write_history_internal::<A>(comp_a, e, r_tick(0), A(1), frames);
+});
```Seems to work, just had to change a lot of lines like so
#

Yes, I really made a wrapper for that API to keep my tests clean

#
-        // Write A(2) to e1 for tick 1
-        let mut entity_mut = EntityMut::from(world.entity_mut(e1));
-        write_history_internal::<A>(comp_a, &mut entity_mut, r_tick(1), A(2), frames);
+        world.entity_scope(e1, |e| {
+            // Write A(2) for tick 1
+            write_history_internal::<A>(comp_a, e, r_tick(1), A(2), frames);

-        // Write A(4) and A(1) to e1 for tick 3 and 0 respectively
-        write_history_internal::<A>(comp_a, &mut entity_mut, r_tick(3), A(4), frames);
-        write_history_internal::<A>(comp_a, &mut entity_mut, r_tick(0), A(1), frames);
+            // Write A(4) and A(1) for tick 3 and 0 respectively
+            write_history_internal::<A>(comp_a, e, r_tick(3), A(4), frames);
+            write_history_internal::<A>(comp_a, e, r_tick(0), A(1), frames);

-        // Write A(3) to e1 for tick 2
-        write_history_internal::<A>(comp_a, &mut entity_mut, r_tick(2), A(3), frames);
+            // Write A(3) for tick 2
+            write_history_internal::<A>(comp_a, e, r_tick(2), A(3), frames);
+        });
```Actually might prefer how it looks for multiple writes in a single test
spring raptor
#

If yes, you can just share the snippet.

dire aurora
spring raptor
dire aurora
#

Patch release works, keeping my [patch.crates-io] for a while longer also works since it's only bevy_rewind's tests after all

spring raptor
empty musk
#

Hi there i am using a mapped server trigger:

//declaration
#[derive(Event, Deserialize, Serialize, MapEntities)]
pub struct NegateDamageTrigger {
    pub attack_id: u64,
    pub owner: Entity,
    pub victim: Entity,
    pub island: u64,
    pub offset: IVec3,
    pub damage: u64,
}

//in the plugin
.add_mapped_server_trigger::<NegateDamageTrigger>(Channel::Unordered)

//later in the code
commands.server_trigger(ToClients { 
    mode: SendMode::Broadcast, 
    event: NegateDamageTrigger {
    attack_id: negate_instance.0, 
    owner: damage_trigger.owner, //this is an entity, should be mapped
    victim: victim,              //this is also an entity, should be mapped
    island: damage_trigger.island,
    offset: damage_trigger.offset,
    damage: damage_trigger.damage,
   }},
 );```
But on both the server and the client i get the same entity outputs:
```server: Mapped entities, victim: 44v2#8589934636, owner 3371v1#4294970667```
```client: Mapped entities, victim: 44v2#8589934636, owner 3371v1#4294970667```
I am most likely missing something, but I can't figure out what
spring raptor
empty musk
#

Thanks! Will try it tomorrow

spring raptor
empty musk
#

yea I think some of it comes from me not having experience with some bevy concepts, that replicon is built on, the new comments you added seem perfect!

spring raptor
#

Made a small post about my project, which mentions this crate too 🙂
#1264625779296174110 message
Starting working on replication filters now.

spring raptor
#

Made our custom entity packing compatible with serde attributes, so users can now do the following:

#[derive(Serialize, Deserialize)]
struct Enemy {
    #[serde(with = "bevy_replicon::compact_entity")]
    entity: Entity
}
spring raptor
# dire aurora <@243426730851696640> trying to port some code away from bundles, and it very mu...

I'm unsure about the expected behavior of exclusion.
Consider these two rules:

  1. Replicate both X and Y.
  2. Exclude X if the entity has Z.

If an entity has components X, Y, and Z, should we replicate only Y or skip the entity entirely?

With only inclusion filters, the behavior is more explicit:

  • To skip this rule, add Without<Z> to rule 1.
  • To send only Y, create a higher-priority rule with With<Z>.

Do you think this would require too much typing? How did you handle this with bundlication?

dire aurora
#

With bundlication I register things like position and linear velocity absolutely everywhere in random bundles to avoid replicating it where unnecessary

dire aurora
#

(Perhaps we could implement it literally like that too, so it's not a seperate concept and follows all the same rules)

spring raptor
dire aurora
#

Yes, and a send policy of never

spring raptor
#

I like this idea!

Will think about the API now. Sadly, Rust doesn't provide default parameters for functions.
So writing replicate<A, ()> would be ugly. And adding _filtered variant to 5 replication functions is not very nice too...

spring raptor
#

I considered a wrapper like Filtered, but it's even more ugly 😅

#

I'll probably go with _filtered.

spring raptor
# dire aurora Yes, and a send policy of never

Will look weird, since rules have associated functions for components.
Probably should be a separate feature then.

But can't you emulate it with filters?
Like if you want to always exclude B if A is present, register B and Without<A> filter. If you need multiple rules for B you will need to write Without<A> for all of them, of course, but do you have that many places?

dire aurora
#

Yea we can emulate it with filters, it's just a lot messier

#

Registering Without<A> wouldn't work, but we could make a DontReplicateB marker that is added as a require somewhere by A

#

If we can't easily set it up I guess we'll have to life with the workaround 🤔

#

In a way it's a bit like the problem entity disabling solves, but on a smaller scale

spring raptor
#

Got it! Not necessarily hard, just a separate concept.
Something that could be added after filters.

spring raptor
#

I can port renet2 for you if you want to try this in action.
The breakages in the latest master are minimal.

dire aurora
#

Gonna need to wrap up my migration first ... Game is mostly functional again, just need to get my game off of all the local change sets now bavy

spring raptor
#

Okay, feel free to let me know!
While breaking changes on the latest master are minimal, you will need to patch both the replicon and its renet2 integration.

#

I planning to draft a new release before the first Bevy RC though. So patching might not be needed by that time.

weary kernel
#

How do i get the client id from

Trigger<OnAdd, ConnectedClient>

I can't seem to figure this out ;-/ or is there another way to retrieve it.

thorn forum
spring raptor
#

Or this if you want the backend-provided identifier which may be persistent across reconnects ^

spring raptor
#

Working on prioritization system, similar to Iris from Unreal Engine.

#

@waxen barn Are you still interested in it?
I remember you were interested in creating an example once the API was out. I'm hoping to implement it for the next release.
It's fine if you've moved on - I can take inspiration from your crowdsim code myself (if you're fine with it) 🙂

waxen barn
#

Honestly the crowdsim stuff is way too simple compared to Iris but ya im still around and interested!

#

Getting back into Bevy stuff again so this is good timing

spring raptor
# waxen barn Honestly the crowdsim stuff is way too simple compared to Iris but ya im still a...

The implementation itself will be similar to Iris, but I want to have a runnable example in the replicon repo, for which I plan to take inspiration from your crowdsim.
If you’re interested in trying the API early by porting your crowdsim into an example, I can ping you once I've implemented the feature. The built-in API for prioritization should allow you to crank up the simulation numbers and simplify the code 🙂

thorn forum
#

hi, no way with postcard to use #[serde(skip_serializing_if = "Option::is_none")]
on a field in struct ?
getting
bevy_replicon::client: unable to apply update message: unable to apply changes: Found an Option discriminant that wasn't 0 or 1

#

postcard is not a self describing format something like that i think ?

spring raptor
thorn forum
spring raptor
thorn forum
spring raptor
viscid jacinth
#

How do you know how Iris does things? The source is public or do they have documentation?

spring raptor
#

The documentation also helps.

waxen barn
#

For me its about its high level ideas too from the perspective of the user. So, like they encourage you to use a push model instead where you explicitly say precisely when a specific thing replicates.

And then the whole spatial stuff is cool. Nice and simple to setup.

The point of the push model is how they managed to squeeze our more performance doing it that way. Don't know how relevant it is under such a different stack

But Iris is basically made for MMOs

#

Ive been in their code before its quite interesting but very abstract I find

spring raptor
spring raptor
echo lion
#

@thorn forum bevy_replicon_repair is archived now, sorry about that. Reconnects should do a full clean up and connection cycle instead of trying to maintain state.

spring raptor
vital mist
#

@spring raptor shatur my boy, since you are good with network stuff can i dm you for a question?

spring raptor
#

Not that good, but sure 🙂

spring raptor
dire aurora
#

Oh right, AuthMethod::Custom is the new version of not starting replication immediately right?

dire aurora
#

If I set it to Custom, does the ProtocolHash check still happen?

spring raptor
# dire aurora If I set it to Custom, does the ProtocolHash check still happen?

No, it disables it too. But we have an example that shows how to do this check:
https://docs.rs/bevy_replicon/latest/bevy_replicon/shared/struct.RepliconSharedPlugin.html#structfield.auth_method

It's just a few lines of code.
Not entirely sure about the current design, but can't think of anything better 🤔

spring raptor
dire aurora
#

That's a very nice example of combining state synchronization and detereminism 🙏

spring raptor
#

@thorn forum You're making a TD game, right? Is your enemies’ movement server-authoritative?

thorn forum
spring raptor
thorn forum
#

while im here i was wondering if its possible to manually trigger a resync of a Component ? for example on command to update the transform to a certain client (to resync in case of desync if the client lagged out). currently i just have a struct holdings timers and transform that i manually get and set

thorn forum
#

but i fail to understand what does it have to do with replication, please enlighten me

spring raptor
spring raptor
spring raptor
#

@stone horizon Answering #networking message
You don’t need to create your own backend if you only want to manually manage some channels.
Replicon reserves certain channels from the backend, and this information is stored in the RepliconChannels resource.
However, you can still create your own channels on top of it - just after the channels reserved by Replicon.

Or do you simply want to have your own I/O?

stone horizon
# spring raptor <@276840728485691392> Answering https://discord.com/channels/691052431525675048/...

currently using one tokio task per client(connection) and one per bevy_ecs world with channels in between them. the client connection task initially does session (~a loaded bevy world) lookup / startup so needs to run before anything on bevy side. i think i need to keep a separation between the game instance (game messages) because there are certain things i cant/dont want to handle in the bevy app. (e.g. monitoring of the server across game instances)

#

ideally i would just forward a filtered stream of websocket messages to something in the bevy app and 🪄

spring raptor
#

Ah, got it. You probably want a backend then.

spring raptor
stone horizon
#

i had assumed so, so didnt specifically ask about it but happy to have it confirmed. also: orphan rule 😭

spring raptor
stone horizon
#

yeah my point was that having traits serve as implementation guides would be a good thing, but that's a rust problem ofc

spring raptor
#

Ah, true.

But I actually like the current approach 🤔 Things like entity management can't be nicely expressed via traits anyway.

spring raptor
spring raptor
#

Yeah, looks like using a modified version of boids + formations is a way to go...
Since it's an example, I won't need pathfinding 🙂

spring raptor
#

Making progress. Now let me try to network it...

dire aurora
#

If I send a DisconnectRequest the client entity should despawn eventually right? 🤔

dire aurora
#

Ah, looks like my problem was elsewhere, my logic to despawn the entity a client owns tried to despawn the client again instead of the entity they own 😅

spring raptor
spring raptor
#

Polished the example. Server executes all the logic and clients just render it. Now the only thing left is to add interpolation.

#

@dire aurora I'm curious, do you interpolate positions in your game?

dire aurora
#

I don't super_bavy

spring raptor
dire aurora
#

Exactly!

#

I should really fix that, but I haven't gotten around to doing that yet

#

It's not super important for the current state of my game

spring raptor
dire aurora
#

Transforms would probably be the biggest thing to interpolate, and a lot of other things that need it (like animations) shouldn't live inside the simulation but rather use the tick + offset directly

spring raptor
#

Makes sense.
It's the same in Unreal: there's no option to enable interpolation for replicated data. Only movement is automatically interpolated.

dire aurora
#

Anything that doesn't get synced outside of your control would need manual systems to get visualized anyway, which means you could just account for it there

spring raptor
#

Makes sense.
I'll explore options, maybe it worth to provide a built-in integration (and gate it via feature) or create a separate crate for integration with Jondolf's work.

spring raptor
#

I mean, it's quite an important feature, and my game will eventually need it too. Life simulators are similar to RTS games: you right-click to move to a location.

#

I'll look into this. But it really is usually just a position 🤔

#

Yeah, I mean it's usually only needed for position.
So I thinking wheter it makes sense to make it more specialized or not.

spring raptor
#

Hm... Looking into the code and looks like the interpolation happens only on the client 🤔

#

@viscid jacinth is that right? You only interpolate client entities?

thorn forum
# spring raptor <@291992695616962561> I see you opened a few issues on https://github.com/Jondol...

yeah ive been using for a few months, but i was thinking of forking it or making my own custom for my game.
with the Transform being DerefMut every frame, my main problem with it especially is that i can't update the Transform in Update, only in FixedUpdate. it should work i think, its implemented in this plugin, but it doesn't, on my project at least.

so on the client i have some systems that adds visuals/sprites and change the transform to add some visuals offset, and they need to all be in FixedUpdate instead of Update, right after received the entity.

spring raptor
thorn forum
#

for example i replicate_once my Translation(Vec2) component, and i have a system move_troop which runs on both server and client in FixedUpdate. i use the plugin only on the client to smooth the movements

spring raptor
viscid jacinth
spring raptor
viscid jacinth
#

Yes that's a good point! For listen server you should interpolate between each FixedUpdate, I do this in lightyear_frame_interpolation, which is similar to what avian_transform_interpolation does

spring raptor
dire aurora
#

Hmmm, do we have any patterns for matching predicted entities with server entities outside of prespawning and sending the ID?

#

Specifically for status effects I'd like to avoid prespawning (as there is no way to reliably network that, since it's a side effect of the simulation, not a player controlled thing), but if the server sends say Poison, AppliedBy(12v1), but I already predicted that, then they should become the same entity 🤔

echo lion
dire aurora
#

Ah, yea that might work in this case. Wouldn't work as a good general solution since the server might reference it elsewhere, but why would anything other than the relationship target reference a status effect

#

Might be worth considering a more general entity matching system, the prespawning thing we have now is already somewhat clunky to being able to just recognize two entities are the same like I did in bevy_bundlication (though arguably a more ECS-friendly system would be better, like specifying components that can uniquely describe an entity)

#

Didn't lightyear do something with hashing a registered set of components? 🤔

spring raptor
spring raptor
dire aurora
#

I do something similar for rollback, I just keep a map from some "spawn reason" to the entity I spawned, then reuse it if it was there

spring raptor
dire aurora
#

Did someone say per-component visibility? 👀

spring raptor
dire aurora
#

That would be great, though I'm still behind on catching up to other features

#

As you can probably guess from my previous question, I'm only now finally starting to try the related entities stuff to replace my awful ActiveStatuses map I used to replicate 🤣

#

Removing all the bookkeeping on that one map, as well as the weird rollback logic necessary for it, already removed over 500 lines of code 🫠

spring raptor
dire aurora
#

Entities that were synchronized to the client get Replicated on them right? 🤔

spring raptor
spring raptor
dire aurora
#

Is there a reason we don't just pass an interned schedule label? 🤔

spring raptor
#

On second thought, I can make the plugin generic 🤔

#

And just default to FixedPostUpdate

dire aurora
#
pub store_schedule: Interned<dyn ScheduleLabel>,
``````rust
.add_systems(
    self.store_schedule,
    set_store_tick::<Tick>.before(RollbackStoreSet),
)
```This JustWorksTM though 🤔
#

-# Example from bevy_rewind

spring raptor
spring raptor
#

Looking into visual interpolation between fixed updates for the listen server.
bevy_transform_interpolation is quite nice. It even includes Hermite! I think it's better to use it instead of rolling our own.
It also doesn't require any special integration with Replicon: you just slap the interpolation component into listen server or singleplayer modes and it will work.
However, it needs a small adjustment: avoid triggering extra change detection. I will try asking about this in #1124043933886976171.

spring raptor
#

Tick-based interpolation for clients is a bit trickier. It requires having a buffer and interpolates between network ticks.
But the rest is similar to the interpolation between FixedMain runs.

Unfortunately, bevy_transform_interpolation is not flexible enough for it.
I'll try discussing it with the author.

spring raptor
#

Asked: #1124043933886976171 message

If you have other opinion - let me know 🙂

spring raptor
#

We'll be able to use bevy_transform_interpolation. It already works as-is for a listen server or deterministic simulation on the client.
For interpolating the received transform from the server, I'll write a custom backend for it. This will require me to PR a small feature to customize t. Jondolf agreed to this change.

But it looks like I need tick synchronization and component history to implement it 🤔
@dire aurora what do you think about moving some of your code to Replicon?

dire aurora
#

Tick syncrhonisation doesn't currently live in bevy_rewind, but I can try to grab all that code from my codebase for you

#

As for the component history stuff, feel free to copy the code if you need it

#

It does still have some issues though. But those are mainly in the deduplication when saving and loading, idk how relevant those would be

spring raptor
dire aurora
#

Plus it might be worth seeing if there is any value in pulling some of the blob storage types in bevy out into a crate and adding a deque version, that's easily the majority of the scary rewind code

spring raptor
#

Glad you're on board, I'll start with the buffer!

brittle mulch
#

Question, from what I can see replicon does not support fps, style of replication. If this were to be implemented (interpolation between client in general) would it be in a new crate or replicon itself?

dire aurora
#

I quickly filtered trough some of my connection logic, and this is all the stuff that is in some way related to connecting. About half of it is purely clock sync, the other half is possibly relevant for some context, but would probably look different in the context of replicon or a standalone crate (be it for interpolation, rollback, or both)

spring raptor
# brittle mulch Question, from what I can see replicon does not support fps, style of replicatio...

Interpolation will be part of the crate - that's my current priority.
Originally, I hadn't planned for it and only exposed the necessary API, but then I realized I need it for my game.
Since it requires clock sync and component history in the crate as well, I asked @dire aurora about moving some parts of bevy_rewind and the clock sync from her game into Replicon.

I think this is a good change, as it could be reused for both FPS- and Rocket League–style rollbacks.

FPS-style rollback still needs to be implemented. I'm not currently planning to include it - I'd prefer someone to write a crate on top of mine. But I'm open to discussion.

spring raptor
brittle mulch
spring raptor
# brittle mulch Well defini what sort of replciation there is is something that a library called...

What you're mentioning is not replication - it's a rollback strategy.
The main reason it's not included is that my game doesn't need it 🙂
I also think it's fine to keep them separate, since there are several approaches to it.
I know it's not working in Replicon's favor, as it means users still don't have an option for client-side prediction. But I hope someday bevy_rewind becomes a solid option - the main dev is just quite busy with her own game.

brittle mulch
#
  • rollback strategy i guess
dire aurora
#

Well, a bit more than mere speculation. The best prediction comes from guessing inputs and running the entire simulation for whatever is being predicted. This then requires rollback to resimulate

#

You could also extrapolate things, but that has very bad results

spring raptor
brittle mulch
#

So it is like replicon implements client_replication

#

Other crates implement the speculative side/ rollback?

dire aurora
#

Yep, technically you don't need a crate for prediction, since your simulation is probably the prediction

brittle mulch
#

yes true

dire aurora
#

Though there are some enhancements you can do if you send inputs that arrived early at the server rather than just repeating the previous inputs

spring raptor
# brittle mulch So it is like replicon implements client_replication

What do you mean under "client replication"?
If sending authoritative state from client to server - no. And most networking crates usually don't allow to replicate client state to server by design.
If sending authoritative state from server to client - yes.
From client you can also send events, so clients can replicate their state to server by sending inputs. You can also make it optimized, which is what bevy_rewind_input does.

brittle mulch
#

i mean client information being the source of truth

#

For a few seconds

spring raptor
#

Just to clarify: the client doesn't need to be the source of truth for prediction/rollback.

#

It's actually the opposite. It's the reason why rollback happens 🙂

spring raptor
dire aurora
#

Yea that was the issue I had with bevy_bundlication in the past too

#
fn serialize_as_past_tick_u16<T: Component + std::ops::Deref<Target = Tick>>(
    ctx: &SerializeCtx,
    value: &T,
    message: &mut Vec<u8>,
) -> Result<()> {
    let tick = *value.deref();
    let ago = Tick::from(ctx.server_tick) - tick;
    message.extend(ago.to_be_bytes());
    Ok(())
}

fn deserialize_from_past_tick_u16<T: Component + From<Tick>>(
    ctx: &mut DeserializeCtx,
    message: &mut Bytes,
) -> Result<T> {
    let mut b = message.iter();
    let v = [*b.next().unwrap(), *b.next().unwrap()];
    let ago = u16::from_be_bytes(v);
    Ok(T::from(Tick::from(ctx.message_tick) - ago as u32))
}

/// A replication rule to (de)serialize a value as a u16 offset into the past
pub struct AsPastTickU16<T: Component + std::ops::Deref<Target = Tick> + From<Tick>>(
    PhantomData<T>,
);

impl<T: Component + std::ops::Deref<Target = Tick> + From<Tick>> Default for AsPastTickU16<T> {
    fn default() -> Self {
        Self(PhantomData)
    }
}

impl<T: Component<Mutability: MutWrite<T>> + std::ops::Deref<Target = Tick> + From<Tick>>
    IntoComponentRule for AsPastTickU16<T>
{
    fn register_component(
        self,
        world: &mut World,
        registry: &mut ReplicationRegistry,
    ) -> ComponentRule {
        let (id, fns_id) = registry.register_rule_fns::<T>(
            world,
            RuleFns::new(serialize_as_past_tick_u16, deserialize_from_past_tick_u16),
        );
        ComponentRule::new(id, fns_id)
    }
}
```Also I have been slowly replacing bevy_bundlication with hacks like this 😅
#

Which then registers like so:

.replicate_with((AsPastTickU16::<AppliedAt>::default(),))
spring raptor
#

So you convert u32 ticks into u16 to save traffic?

#

Ah, you are sending the diff, smart 🙂

dire aurora
#

The original component in question btw:

#[derive(Component, Deref, DerefMut, Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct AppliedAt(pub Tick);
#

I could probably make something a bit cleaner for this usecase, or maybe we should add it to replicon directly

#

Similar stuff with bevy_bundlication looked like this:

pub struct Vec3Data;

impl<T: Component + std::ops::Deref<Target = Vec3> + From<Vec3>> NetworkedWrapper<T> for Vec3Data {
...
}
```Though it might be possible to change up the traits so it's not this weird Deref + From thing but just a simple `From`/`Into` you impl for your own component
#

Both are still uglier than the serde as/with thing it's trying to replace though 🤔

spring raptor
dire aurora
#

Well we could have first party stuff for tick too, but I mean more generally make replicate_with nicer to use first party

spring raptor
dire aurora
#

Well the way I used this on bevy_bundlication is like so:

#[bundlication(as = Vec3Data)]
pub position: Position,
#[bundlication(as = QuatXYData)]
pub rotation: Rotation,
#[bundlication(as = Vec3Data)]
pub velocity: LinearVelocity,
#

I basically just say "This is my type, please network it as X instead"

#

And I internally just register a function that converts say Position to Vec3Data, then networks it

brittle mulch
#

a good way of converting those pesky wrapper component

spring raptor
dire aurora
#

Also makes cases like say the Transform but without scale thing easy. You just impl a From<Transform> for TansfomWithoutScale. a Fom<TansfomWithoutScale> for Transform, slap Serialize, Deserialize on TransformWithoutScale and call replicate_as::<Transfom, TransformWithoutScale>

spring raptor
dire aurora
#

Ofc replicate_with can still be useful, but only when you want something fancy like compression, a different serialization format, etc

spring raptor
#

But it would work only for single types, right? 🤔

dire aurora
#

wdym single types?

spring raptor
dire aurora
#

Hmmm, I wonder if we could do something similar to that SendRate trick

#

Might not work if we just say (T, From<T>+Serialize+Deserialize) though, I'd imagine that conflicts with the SendRate one because you could add those traits there

#

Maybe some wrapper struct to hold those two args could make that work

#

Though we have the same issue with replicate_with already, no?

#

My new status effect replication doesn't use the bundle thing either atm 😅

app
  .replicate::<Affects>()
  .replicate_with((AsPastTickU16::<AppliedAt>::default(),))
  .replicate_with((AsFutureTickU16::<ExpiresAt>::default(),))
  .replicate::<AppliedBy>();
#

(ExpiresAt is also optional though, so it could never all be 1 bundle)

#

-# Which is funny because I once removed the optional property from bevy_bundlication, convinced a bundle would never get an optional field

#

With filters that would be easy to handle at least

spring raptor
#

But even this will require adding replicate_as, replicate_once_as, replicate_filtered_as, replicate_once_filtered_as 😅

#

I wish we could have default types on functions. The lack of it is the reason we need _filtered.

dire aurora
#

Yea, I wonder if we could go for a different pattern there 😅

spring raptor
#

I explored a few options, couldn't find anything better 😢

dire aurora
#

If we make an impl for the trait replicate_with expects we could use ReplicateAs::<Transform, TransformWithoutScale> everywhere at least, though that's not the most discoverable thing

spring raptor
spring raptor
#

Opened: https://github.com/simgine/bevy_replicon/issues/572

My backlog is really growing, but I might take a crack at it tomorrow since it should be easy to add. It will be a nice addition to filters in this release.
I still haven't looked into buffers and tick sync yet, as I was quite busy with other stuff today.
If 0.17 drops earlier, I will publish what I have and switch to working on RC, which will require quite a few adaptations due to the events rework in Bevy.
But even if I don't implement per-component visibility and interpolation before 0.17, they will remain my priority, so I'll draft another release right after they are ready. I wonder if I can even make these features part of a patch release, since they shouldn't be breaking 🤔

GitHub

To customize serialization for a type we do something like this: app.replicate_with( RuleFns::new(serialize_translation, deserialize_translation) .with_in_place(deserialize_transform_in_place), ); ...

pulsar garnet
#

I've seen in some networking designs the server still spawns the gameobject/entity with authority first, then it can transfer authority to a client. So a client can never just "do whatever", it is a controlled process the server initiates.

#

aside but I'm watching this atm 🙂 cool interview with Photon employee https://www.youtube.com/watch?v=zDM9HnuXYX0

This is a Game Dev Podcast with my guest Erick Passos from Photon Engine (Exit Games Inc.), a company that provides networking solutions and server architecture for online multiplayer games. I try to understand more about how how online multiplayer works in general and in particular how to use Photon's Quantum and Fusion to develop online games ...

▶ Play video
#

I'm writing my own visibility layer over replicon atm, was just wondering if there was anything like that in the pipeline atm? So I can put a VisibileToEveryone component on an entity and it automatically sets client visibilities. Or visibility based on proximity to location etc.

spring raptor
# pulsar garnet It's not that niche. It's relatively common in a game like valheim or minecraft ...

I think you're confusing client-side prediction with client authority over the state.
Fast-paced games usually predict certain things by simulating on the client and sending the input to the server. The server simulates too and sends the state back. So client is ahead of the server. Then the client either compares the simulation in the past and rolls back if necessary (or does it unconditionally, depending on the strategy), and then replays the input from that point.

The same thing applies to spawning. The client can predict the spawn, but if the server denies it for whatever reason, the client has to despawn (or hide the misprediction somehow).
So the server has authority over the state; the client can't dictate what’s happening.
All of this is possible with Replicon, exept we don't provide a high-level client-side prediction, only expose the necessary API to implement it on top.

When I say "client authority," I mean the client’s ability to dictate the state, like "I have this position."
In Replicon, you can simulate it with events, but there is no automatic replication from the client to the server.

spring raptor
pulsar garnet
# spring raptor I think you're confusing client-side prediction with client authority over the s...
#

Fully shared willy nilly distributed authority is a whole other beast, I think only Unity has it with their "distributed authority" topology

spring raptor
# pulsar garnet > When I say "client authority," I mean the client’s ability to dictate the stat...

Yeah, I meant authority on certain entities - i.e., replicating their state from the client to the server.
Unity doesn't provide client-to-server replication. You can only use RPCs and write into certain variables if you have authority, similar to events in Replicon.
In Unreal, position replication from the client isn't part of the general replication API - it's special to movement. Which isn't a bad idea, since I can't think of many use cases for client replication besides movement. That kind of API could also be implemented on top using Replicon events.
Godot is the only one that does this, but I think that's because they support P2P 🤔

I'm not against adding this feature, but I want to prevent users from abusing it. That's why I think it shouldn't just be just replication from client to server.
I like Unreal's approach, but I'm open to exploring other ways that better fit ECS.

spring raptor
dire aurora
#

Hmmm, I'm not sure if the in place would even work well with the semantics of as 🤔

spring raptor
dire aurora
#

Hah, it can't get much more cursed than this, can it? 🤣

#[require(IsValid(true), Attached)]
#[cfg_attr(feature = "server", require(Replicated))]
#[cfg_attr(feature = "client", require(Predicted))]
#[relationship(relationship_target = AffectedBy)]
dire aurora
spring raptor
#

Most of the code are just examples, it's a very simple addition 🙂
Thank you for the suggestion.

spring raptor
#

Looks like RC dropped. I'll release the current changes for 0.16 and start working on RC.

spring raptor
#

A bit too early, I'll wait for the migration guide 😅

dire aurora
#

That replace in hooks hack sure creates annoying edge cases 😅

#

Currently dealing with:

  • Stasus gets spawned
  • Status gets replaced
  • Status gets rolled back to befote it was supposed to exist
  • Status gets spawned again, it should reuse the server one, but it got despawned somewhere
#

Thus a new one is spawned and replicon spams errors

dire aurora
#

Oh ... Does bevy_replicon remove RepliconClient while applying changes?

spring raptor
dire aurora
dire aurora
spring raptor
#

Koe promised to review it all soon and I plan to draft a release for 0.16 right after that

spring raptor
#

The better pre-spawning*

dire aurora
#

I think I have all the edgecases fixed now, so it's not a major issue for now, but it just shows that we're gonna need a better pre-spawning solution eventually 😅

#

The hacks I have now are still a lot smaller than what I had before

#

Would also be useful if I can then use a matching design for reuse of spawns, my current API is not the most intuitive

#

The current API just relies on creating a SpawnReason which is some arbitrary struct with fields that should uniquely explain a spawn:

    fn reuse_spawn<'a, Reason: SpawnReason>(
        &'a mut self,
        reason: Reason,
        bundle: impl Bundle,
    ) -> EntityWorldMut<'a> {
#

Not great to have to introduce something like that 😅

spring raptor
#

I think it's worth looking into pre-spawning now...
Interpolation and per-component visibility are bigger features.
But pre-spawning is something we might be able to solve before 0.17 🤔

dire aurora
#

Well, if we decide on say the ability to match on a unique combination of registered components, then I could use a similar approach for my bevy_rewind_entity_management crate, rather than having a completely different API like I do now (because replicon has no features to match entities atm)

spring raptor
spring raptor
#

Ah, got it now!

dire aurora
#

An example of this in action for spawning a projectile:

let _entity = commands.reuse_spawn(
    &spawns,
    SkillSpawn {
        source: *cast.skill,
        tick: *tick,
        trigger: SpawnTrigger::StatusTick,
        number: *frame / spread,
    },
    (bundle)
);
#

In fact, having those APIs line up is probably very important. Because ultimately I probably need to network skill effects like this to clients too, especially clients that weren't around when a skill actived

#

(Currently if you don't observe an entity casting a skill, you won't see the effects from it either, and every side effect besides status effects will not be networked either, even though they might affect you)

spring raptor
#

@dire aurora okay, so right now we have the following API:
The client spawns an entity and sends a user-defined event. On this event, the server also spawns an entity and associates a mapping from the entity in the event.
It's unergonomic.

In Lightyear, it looks like they attach a special component that hashes all the components on the entity and stores a tick. (link)
Then the server matches it. Do you think something automatic like this would be better than yours?

dire aurora
#

Yea, I think something automatic would work better, however I think it might make more sense to work with only components registered to be used as part of the has, and send it from the server to the client (that way you can never miss any matches for any reason)

spring raptor
dire aurora
#

If you're replicating a player for example you might replicate PlayerId, which the client could then insert correctly on its own entity.
If we're replicating a status effect we can replicate the effect, source, and time it started.
If we're replicating a projectile we could use some components that relate it back to a certain origin and time of creation, without creating the need to have the exact position be perfectly deterministic

spring raptor
#

Ah, I get the idea. So we need to hash things depending on what we are spawning.

dire aurora
spring raptor
#

Yes, I totally agree. It's a really good idea.

dire aurora
#

Oh, and we probably need some component informing replicon it should be hashed

spring raptor
# dire aurora Oh, and we probably need some component informing replicon it should be hashed

Yeah. I think we can provide a component with a generic constructor which accepts a bundle and stores its TypeId.
Then we create a hash of components inside a hook and send it to the server. If an entity with the same component is spawned on the server, we send a mapping to the client during replication.
So the API for creating such component would look like this:

EntityMatcher::new::<(A, B, C)>()
#

Maybe not a Bundle, but our custom trait that implemented for tuples of components.

dire aurora
#

Then we create a hash of components inside a hook and send it to the server.
Better to send it the other way around I think, the client can just keep a list of all spawned entities it hashed, and the server just sends the hash once when it replicates them

spring raptor
#

Sounds simple to implement. Will start working on it soon.
If you have ideas or maybe naming suggestions - please, let me know 🙂

dire aurora
spring raptor
#

@dire aurora there is a small disadvantage with this approach: hashes will be sent to all clients 😢

#

Actually, I think we can just add an optional ClientId to this component.

dire aurora
#

Shouldn't it be client entity or NetworkId?

spring raptor
#

But I think storing a plain client entity makes more sense, this doesn't make sense for the server 🤔

gilded sail
#

Heya!

Question about deterministic_boids example.

When boids are replicated from server to client, we don't read any tick information.
Wouldn't that mean due to latency client's local simulation will be couple ticks "in the past" from the server?

Also - FixedUpdate from bevy probably doesn't guarantee it being deterministically fixed?

(I do understand that this is just an example. Just trying to wrap my head around crate to see whether I want to throw away Unity).

GitHub

A server-authoritative replication crate for Bevy. - simgine/bevy_replicon

spring raptor
gilded sail
#

@spring raptor I must say, documentation is very good.
At first I was - "well, how the hell I should do anything".
Then I actually started reading through getting started, and one-be-one it answers all my questions.

Very impressed! Like it alot.

spring raptor
gilded sail
#

Is there somewhere an example how to implement snapshot interpolation for transform? (I assume it should based on markers + history)

spring raptor
# gilded sail Is there somewhere an example how to implement snapshot interpolation for transf...

This is something I plan to provide out of the box. The RTS example needs it badly 😅
Unfortunately, I won't be able to make it in time for the next release. I'm currently working on a more ergonomic entity matching and planning to draft a new release right after I done for 0.16, and then focus on porting to 0.17 to provide an RC.

But this feature is on top of my priority list, so expect it to be present in the next Replicon release.

I assume it should be based on markers + history
Correct, that's how it will be implemented! There are actually 2 kinds of interpolations:

  1. Interpolation between fixed updates for the listen server. No buffering needed. You can already just use https://github.com/Jondolf/bevy_transform_interpolation for it.
  2. Interpolation between snapshots. This requires history. I plan to re-use https://github.com/Jondolf/bevy_transform_interpolation for it, just write a custom backend. This also requires adding PRing a customizable overstep fraction. I asked Jondolf about it and he agreed.

So I will re-export bevy_transform_interpolation from Replicon with special helpers for snapshot interpolation.

GitHub

Transfom interpolation for fixed timesteps for the Bevy game engine. - Jondolf/bevy_transform_interpolation

gilded sail
spring raptor
spring raptor
dire aurora
#

Good to hear. Sounds promising!

spring raptor
#

I started working on the docs, but realized that I'm not quite satisfied with the API for global vs. client-specific signatures.
Right now, if the optional client entity on the signature is set, it will be replicated only to that specific client. But it's a bit awkward, because on the client the SignatureMap resource (which maps hashes to entities) stores all hashes, both temporary and global, while on the server it stores only global ones.
I opened a draft: https://github.com/simgine/bevy_replicon/pull/574
I will think about it for one more day.

spring raptor
#

@dire aurora you might be interested ^
Let me know if you have any suggestions 🙂

#

Will draft a new release right after merge.

dire aurora
#

#[require(Replicated, Signature::of::<ClientPlayer>())]
Arguably too OP 🤣

#

Nice, all the issues I saw before have been fixed, except that the of vs of_many is kind of ugly

#

(Was of_single vs of before which was worse)

spring raptor
spring raptor
# dire aurora Nice, all the issues I saw before have been fixed, except that the `of` vs `of_m...

If the naming, I considered these options:

  • from for a component, from_many for many components and from_hash for a user-defined value. But this might be confusing because from wont't be from the From trait.
  • from_component/from_components. I like the explicitness, but only a single letter difference...

If you have other suggestions - please, let me know. Not really satisfied with of/of_many myself 🙂

dire aurora
dire aurora
#

And spawn, and insert, etc

spring raptor
#

Yep, because the trait is defined by Bevy.
In our case, we can't create a function that accepts Component and a tuple of Components :(

#

Just because upstream can, in theory, impl Component for a tuple of Components. It won't happen, but Rust doesn't know that.

spring raptor
dire aurora
#

Ah. Is it possibly to make our own trait and blanket impl that?

#

Or would that still fail on the fsct that it could get impld and thus conflicts?

#

Well, if we can't I guess we'll have to live with the seperate functions

#

Maybe shorten of_many to just of_n. And I just realized we might want a dynamic version, like of_ids