1+ use core:: mem;
2+
13use bevy:: {
24 ecs:: {
3- archetype:: { Archetype , ArchetypeEntity , ArchetypeId } ,
5+ archetype:: { Archetype , ArchetypeEntity , ArchetypeGeneration , ArchetypeId } ,
46 component:: { ComponentId , ComponentTicks , StorageType , Tick } ,
5- query:: { Access , FilteredAccess } ,
7+ query:: { FilteredAccess , FilteredAccessSet } ,
68 storage:: TableId ,
79 system:: { ReadOnlySystemParam , SystemMeta , SystemParam } ,
810 world:: unsafe_world_cell:: UnsafeWorldCell ,
@@ -39,7 +41,12 @@ impl<'w> ServerWorld<'w, '_> {
3941 storage : StorageType ,
4042 component_id : ComponentId ,
4143 ) -> ( Ptr < ' w > , ComponentTicks ) {
42- debug_assert ! ( self . state. access. has_component_read( component_id) ) ;
44+ debug_assert ! (
45+ self . state
46+ . component_access
47+ . access( )
48+ . has_component_read( component_id)
49+ ) ;
4350
4451 let storages = unsafe { self . world . storages ( ) } ;
4552 match storage {
@@ -90,90 +97,45 @@ impl<'w> ServerWorld<'w, '_> {
9097
9198unsafe impl SystemParam for ServerWorld < ' _ , ' _ > {
9299 type State = ReplicationReadState ;
93- type Item < ' world , ' state > = ServerWorld < ' world , ' state > ;
100+ type Item < ' w , ' s > = ServerWorld < ' w , ' s > ;
94101
95- fn init_state ( world : & mut World , system_meta : & mut SystemMeta ) -> Self :: State {
96- let mut filtered_access = FilteredAccess :: default ( ) ;
102+ fn init_state ( world : & mut World ) -> Self :: State {
103+ let mut component_access = FilteredAccess :: default ( ) ;
97104
98105 let marker_id = world. register_component :: < Replicated > ( ) ;
99- filtered_access . add_component_read ( marker_id) ;
106+ component_access . add_component_read ( marker_id) ;
100107
101108 let rules = world. resource :: < ReplicationRules > ( ) ;
102109 debug ! ( "initializing with {} replication rules" , rules. len( ) ) ;
103- let combined_access = system_meta. component_access_set ( ) . combined_access ( ) ;
104110 for rule in rules. iter ( ) {
105111 for component in & rule. components {
106- filtered_access. add_component_read ( component. id ) ;
107- assert ! (
108- !combined_access. has_component_write( component. id) ,
109- "replicated component `{}` in system `{}` shouldn't be in conflict with other system parameters" ,
110- world. components( ) . get_name( component. id) . unwrap( ) ,
111- system_meta. name( ) ,
112- ) ;
112+ component_access. add_component_read ( component. id ) ;
113113 }
114114 }
115115
116- let access = filtered_access. access ( ) . clone ( ) ;
117-
118- // SAFETY: used only to extend access.
119- unsafe {
120- system_meta. component_access_set_mut ( ) . add ( filtered_access) ;
121- }
122-
123- ReplicationReadState {
124- access,
125- marker_id,
116+ Self :: State {
117+ component_access,
118+ marker_id : world. register_component :: < Replicated > ( ) ,
126119 archetypes : Default :: default ( ) ,
127- // Needs to be cloned because `new_archetype` only accepts the state.
128- rules : world. resource :: < ReplicationRules > ( ) . clone ( ) ,
120+ generation : ArchetypeGeneration :: initial ( ) ,
129121 }
130122 }
131123
132- unsafe fn new_archetype (
133- state : & mut Self :: State ,
134- archetype : & Archetype ,
124+ fn init_access (
125+ state : & Self :: State ,
135126 system_meta : & mut SystemMeta ,
127+ component_access_set : & mut FilteredAccessSet ,
128+ _world : & mut World ,
136129 ) {
137- if !archetype. contains ( state. marker_id ) {
138- return ;
130+ let conflicts = component_access_set. get_conflicts_single ( & state. component_access ) ;
131+ if !conflicts. is_empty ( ) {
132+ panic ! (
133+ "replicated components in system `{}` shouldn't be in conflict with other system parameters" ,
134+ system_meta. name( ) ,
135+ ) ;
139136 }
140137
141- trace ! ( "marking `{:?}` as replicated" , archetype. id( ) ) ;
142- let mut replicated_archetype = ReplicatedArchetype :: new ( archetype. id ( ) ) ;
143- for rule in state. rules . iter ( ) . filter ( |rule| rule. matches ( archetype) ) {
144- for & component in & rule. components {
145- // Since rules are sorted by priority,
146- // we are inserting only new components that aren't present.
147- if replicated_archetype
148- . components
149- . iter ( )
150- . any ( |( existing, _) | existing. id == component. id )
151- {
152- continue ;
153- }
154-
155- // SAFETY: archetype matches the rule, so the component is present.
156- let storage =
157- unsafe { archetype. get_storage_type ( component. id ) . unwrap_unchecked ( ) } ;
158- replicated_archetype. components . push ( ( component, storage) ) ;
159- }
160- }
161-
162- // Update system access for proper parallelization.
163- for ( component, _) in & replicated_archetype. components {
164- // SAFETY: archetype contains this component and we don't remove access from system meta.
165- unsafe {
166- let archetype_id = archetype
167- . get_archetype_component_id ( component. id )
168- . unwrap_unchecked ( ) ;
169- system_meta
170- . archetype_component_access_mut ( )
171- . add_component_read ( archetype_id)
172- }
173- }
174-
175- // Store for future iteration.
176- state. archetypes . push ( replicated_archetype) ;
138+ component_access_set. add ( state. component_access . clone ( ) ) ;
177139 }
178140
179141 unsafe fn get_param < ' world , ' state > (
@@ -182,6 +144,43 @@ unsafe impl SystemParam for ServerWorld<'_, '_> {
182144 world : UnsafeWorldCell < ' world > ,
183145 _change_tick : Tick ,
184146 ) -> Self :: Item < ' world , ' state > {
147+ let archetypes = world. archetypes ( ) ;
148+ let old_generation = mem:: replace ( & mut state. generation , archetypes. generation ( ) ) ;
149+
150+ // SAFETY: Has access to this resource and the access is unique.
151+ let rules = unsafe {
152+ world
153+ . get_resource :: < ReplicationRules > ( )
154+ . expect ( "replication rules should've been initialized in the plugin" )
155+ } ;
156+ for archetype in archetypes[ old_generation..]
157+ . iter ( )
158+ . filter ( |archetype| archetype. contains ( state. marker_id ) )
159+ {
160+ trace ! ( "marking `{:?}` as replicated" , archetype. id( ) ) ;
161+ let mut replicated_archetype = ReplicatedArchetype :: new ( archetype. id ( ) ) ;
162+ for rule in rules. iter ( ) . filter ( |rule| rule. matches ( archetype) ) {
163+ for & component in & rule. components {
164+ // Since rules are sorted by priority,
165+ // we are inserting only new components that aren't present.
166+ if replicated_archetype
167+ . components
168+ . iter ( )
169+ . any ( |( existing, _) | existing. id == component. id )
170+ {
171+ continue ;
172+ }
173+
174+ // SAFETY: archetype matches the rule, so the component is present.
175+ let storage =
176+ unsafe { archetype. get_storage_type ( component. id ) . unwrap_unchecked ( ) } ;
177+ replicated_archetype. components . push ( ( component, storage) ) ;
178+ }
179+ }
180+
181+ state. archetypes . push ( replicated_archetype) ;
182+ }
183+
185184 ServerWorld { world, state }
186185 }
187186}
@@ -192,15 +191,16 @@ pub(crate) struct ReplicationReadState {
192191 /// All replicated components.
193192 ///
194193 /// Used only in debug to check component access.
195- access : Access < ComponentId > ,
194+ component_access : FilteredAccess ,
196195
197196 /// ID of [`Replicated`] component.
198197 marker_id : ComponentId ,
199198
199+ /// Highest processed archetype ID.
200+ generation : ArchetypeGeneration ,
201+
200202 /// Archetypes marked as replicated.
201203 archetypes : Vec < ReplicatedArchetype > ,
202-
203- rules : ReplicationRules ,
204204}
205205
206206/// An archetype that can be stored in [`ReplicatedArchetypes`].
@@ -268,20 +268,6 @@ mod tests {
268268 app. update ( ) ;
269269 }
270270
271- #[ test]
272- fn replicate_after_system ( ) {
273- let mut app = App :: new ( ) ;
274- app. init_resource :: < ProtocolHasher > ( )
275- . init_resource :: < ReplicationRules > ( )
276- . init_resource :: < ReplicationRegistry > ( )
277- . add_systems ( Update , |world : ServerWorld | {
278- assert_eq ! ( world. state. rules. len( ) , 1 ) ;
279- } )
280- . replicate :: < Transform > ( ) ;
281-
282- app. update ( ) ;
283- }
284-
285271 #[ test]
286272 fn empty ( ) {
287273 let mut app = App :: new ( ) ;
0 commit comments