packet systems prototype.
This commit is contained in:
parent
6792cebfd0
commit
07402169ee
@ -344,6 +344,35 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
|
||||
#relationship_target
|
||||
})
|
||||
}
|
||||
pub fn derive_packet(input: TokenStream) -> TokenStream {
|
||||
let mut ast = parse_macro_input!(input as DeriveInput);
|
||||
let bevy_ecs_path: Path = crate::bevy_ecs_path();
|
||||
|
||||
ast.generics
|
||||
.make_where_clause()
|
||||
.predicates
|
||||
.push(parse_quote! { Self: Send + Sync + 'static });
|
||||
|
||||
let struct_name = &ast.ident;
|
||||
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
|
||||
let inner_generic = if type_generics.to_token_stream().is_empty() {
|
||||
quote! {}
|
||||
} else {
|
||||
quote! {<'i>}
|
||||
};
|
||||
|
||||
let ts = TokenStream::from(quote! {
|
||||
impl #impl_generics #bevy_ecs_path::packet::Packet for #struct_name #type_generics #where_clause { }
|
||||
impl #impl_generics #bevy_ecs_path::packet::SystemInput for #struct_name #type_generics {
|
||||
type Param<'i> = #struct_name #inner_generic;
|
||||
type Inner<'i> = #struct_name #inner_generic;
|
||||
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
|
||||
this
|
||||
}
|
||||
}
|
||||
});
|
||||
return ts;
|
||||
}
|
||||
|
||||
const ENTITIES: &str = "entities";
|
||||
|
||||
|
@ -672,6 +672,10 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
|
||||
component::derive_component(input)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Packet)]
|
||||
pub fn derive_packet(input: TokenStream) -> TokenStream {
|
||||
component::derive_packet(input)
|
||||
}
|
||||
/// Implement the `FromWorld` trait.
|
||||
#[proc_macro_derive(FromWorld, attributes(from_world))]
|
||||
pub fn derive_from_world(input: TokenStream) -> TokenStream {
|
||||
|
@ -38,6 +38,7 @@ pub mod entity;
|
||||
pub mod entity_disabling;
|
||||
pub mod error;
|
||||
pub mod event;
|
||||
pub mod packet;
|
||||
pub mod hierarchy;
|
||||
pub mod intern;
|
||||
pub mod label;
|
||||
|
105
crates/bevy_ecs/src/packet/exclusivepacketsystem.rs
Normal file
105
crates/bevy_ecs/src/packet/exclusivepacketsystem.rs
Normal file
@ -0,0 +1,105 @@
|
||||
use crate::{component::{ComponentId, Tick}, system::{ExclusiveFunctionSystem, ExclusiveSystemParamFunction, IntoSystem, IsExclusiveFunctionSystem, System, SystemIn}, world::{unsafe_world_cell::UnsafeWorldCell, World}};
|
||||
|
||||
use super::{packetsystem::IntoPacketSystem, OptionPacket};
|
||||
|
||||
pub struct ExclusivePacketSystem<Marker, F>
|
||||
where
|
||||
F: ExclusiveSystemParamFunction<Marker>,
|
||||
{
|
||||
inner: ExclusiveFunctionSystem<Marker, F::Out, F>,
|
||||
}
|
||||
impl<Marker, F> IntoPacketSystem<F::In, F::Out, (IsExclusiveFunctionSystem, Marker)> for F
|
||||
where
|
||||
Marker: 'static,
|
||||
F: ExclusiveSystemParamFunction<Marker>,
|
||||
F::Out: OptionPacket,
|
||||
{
|
||||
type System = ExclusivePacketSystem<Marker, F>;
|
||||
fn into_system(func: Self) -> Self::System {
|
||||
ExclusivePacketSystem {
|
||||
inner: IntoSystem::into_system(func)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Marker, F> System for ExclusivePacketSystem<Marker, F>
|
||||
where
|
||||
Marker: 'static,
|
||||
F: ExclusiveSystemParamFunction<Marker>,
|
||||
F::Out: OptionPacket,
|
||||
{
|
||||
type In = F::In;
|
||||
type Out = ();
|
||||
|
||||
|
||||
#[inline]
|
||||
fn is_send(&self) -> bool {
|
||||
self.inner.is_send()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_exclusive(&self) -> bool {
|
||||
self.inner.is_exclusive()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_deferred(&self) -> bool {
|
||||
self.inner.has_deferred()
|
||||
}
|
||||
|
||||
fn run(&mut self, input: SystemIn<'_, Self>, world: &mut World) -> Result<Self::Out, crate::system::RunSystemError> {
|
||||
let out = <ExclusiveFunctionSystem<Marker, F::Out, F> as System>::run(&mut self.inner, input, world)?;
|
||||
out.run(world);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn apply_deferred(&mut self, world: &mut World) {
|
||||
self.inner.apply_deferred(world);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn queue_deferred(&mut self, world: crate::world::DeferredWorld) {
|
||||
self.inner.queue_deferred(world);
|
||||
}
|
||||
|
||||
fn get_last_run(&self) -> Tick {
|
||||
self.inner.get_last_run()
|
||||
}
|
||||
|
||||
fn set_last_run(&mut self, last_run: Tick) {
|
||||
self.inner.set_last_run(last_run);
|
||||
}
|
||||
|
||||
fn name(&self) -> bevy_utils::prelude::DebugName {
|
||||
self.inner.name()
|
||||
}
|
||||
|
||||
fn flags(&self) -> crate::system::SystemStateFlags {
|
||||
self.inner.flags()
|
||||
}
|
||||
|
||||
unsafe fn run_unsafe(
|
||||
&mut self,
|
||||
_input: SystemIn<'_, Self>,
|
||||
_world: UnsafeWorldCell,
|
||||
) -> Result<Self::Out, crate::system::RunSystemError> {
|
||||
panic!("exclusive system")
|
||||
}
|
||||
|
||||
unsafe fn validate_param_unsafe(
|
||||
&mut self,
|
||||
world: UnsafeWorldCell,
|
||||
) -> Result<(), crate::system::SystemParamValidationError> {
|
||||
self.inner.validate_param_unsafe(world)
|
||||
}
|
||||
|
||||
fn initialize(&mut self, world: &mut World) -> crate::query::FilteredAccessSet<ComponentId> {
|
||||
self.inner.initialize(world)
|
||||
}
|
||||
|
||||
fn check_change_tick(&mut self, check: crate::component::CheckChangeTicks) {
|
||||
self.inner.check_change_tick(check)
|
||||
}
|
||||
|
||||
}
|
213
crates/bevy_ecs/src/packet/mod.rs
Normal file
213
crates/bevy_ecs/src/packet/mod.rs
Normal file
@ -0,0 +1,213 @@
|
||||
pub mod packetsystem;
|
||||
pub mod exclusivepacketsystem;
|
||||
mod optionpacket;
|
||||
pub use optionpacket::OptionPacket;
|
||||
use core::any::{type_name, TypeId};
|
||||
use std::boxed::Box;
|
||||
use crate::{system::Commands};
|
||||
pub use crate::system::SystemInput;
|
||||
use crate::system::System;
|
||||
use packetsystem::IntoPacketSystem;
|
||||
use smallvec::SmallVec;
|
||||
use crate::{system::BoxedSystem, world::World};
|
||||
pub use bevy_ecs_macros::Packet;
|
||||
|
||||
pub struct PacketInSystem<E: SystemInput> {
|
||||
pub v: BoxedSystem<E, ()>,
|
||||
pub tid: TypeId,
|
||||
}
|
||||
pub struct RegisteredSystems<E: SystemInput>{
|
||||
pub v: SmallVec<[PacketInSystem<E>; 1]>,
|
||||
}
|
||||
pub trait Packet: Send + Sync + SystemInput + 'static { }
|
||||
|
||||
pub fn register_system<I, Out, F, M>(world: &mut World, f: F)
|
||||
where
|
||||
I: SystemInput + 'static,
|
||||
Out: OptionPacket,
|
||||
F: IntoPacketSystem<I, Out, M> + 'static,
|
||||
M: 'static,
|
||||
{
|
||||
// don't forget to put it back.
|
||||
let mut systems = world.remove_packet_system::<I>().unwrap_or_default();
|
||||
|
||||
let tid = TypeId::of::<F>();
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
for system in &systems.v {
|
||||
assert_ne!(system.tid, tid);
|
||||
}
|
||||
}
|
||||
let mut system = IntoPacketSystem::into_system(f);
|
||||
system.initialize(world);
|
||||
let system = PacketInSystem { v: Box::new(system), tid };
|
||||
systems.v.push(system);
|
||||
|
||||
// put back here.
|
||||
world.put_back_packet_system(systems);
|
||||
}
|
||||
pub fn unregister_system<I, Out, F, M>(world: &mut World, _: F)
|
||||
where
|
||||
I: SystemInput + 'static,
|
||||
Out: OptionPacket,
|
||||
F: IntoPacketSystem<I, Out, M> + 'static,
|
||||
M: 'static,
|
||||
{
|
||||
world.with_packet_system::<I>(|_, systems| {
|
||||
let tid = TypeId::of::<F>();
|
||||
systems.v.retain(|s| s.tid != tid);
|
||||
});
|
||||
}
|
||||
pub fn run_this_packet_system<'a, E>(packet: E, world: &mut World)
|
||||
where
|
||||
E: Packet,
|
||||
for<'d> E: SystemInput<Inner<'d> = E>,
|
||||
{
|
||||
run_for_ref_packet(world, &packet);
|
||||
run_for_val_packet(world, packet);
|
||||
}
|
||||
|
||||
fn run_for_val_packet<E>(world: &mut World, event: E)
|
||||
where
|
||||
E: Packet,
|
||||
E: for<'e> SystemInput<Inner<'e> = E>
|
||||
{
|
||||
world.with_packet_system::<E>(|world, systems| {
|
||||
let mut systems_iter = systems.v.iter_mut();
|
||||
let Some(system) = systems_iter.next() else { return };
|
||||
system.v.run(event, world);
|
||||
debug_assert!(systems_iter.len() == 0, "Only one system can take value {:?}", type_name::<E>());
|
||||
});
|
||||
}
|
||||
|
||||
fn run_for_ref_packet<E>(world: &mut World, event: &E)
|
||||
where
|
||||
E: Packet,
|
||||
{
|
||||
world.with_packet_system::<&E>(|world, systems| {
|
||||
for system in &mut systems.v {
|
||||
system.v.run(event, world);
|
||||
}
|
||||
});
|
||||
}
|
||||
impl<E: SystemInput> Default for RegisteredSystems<E> {
|
||||
fn default() -> Self {
|
||||
RegisteredSystems { v: Default::default()}
|
||||
}
|
||||
}
|
||||
|
||||
impl World {
|
||||
pub fn send<'a,'b,E>(&mut self, packet: E)
|
||||
where
|
||||
E: Packet,
|
||||
E: for<'e> SystemInput<Inner<'e> = E>,
|
||||
{
|
||||
run_this_packet_system::<E>(packet, self);
|
||||
}
|
||||
|
||||
pub fn register_packet_system<I, Out, F, M>(&mut self, f: F)
|
||||
where
|
||||
I: SystemInput + 'static,
|
||||
Out: OptionPacket,
|
||||
F: IntoPacketSystem<I,Out, M> + 'static,
|
||||
M: 'static,
|
||||
{
|
||||
register_system(self, f);
|
||||
}
|
||||
pub fn unregister_packet_system<I, Out, F, M>(&mut self, f: F)
|
||||
where
|
||||
I: SystemInput + 'static,
|
||||
Out: OptionPacket,
|
||||
F: IntoPacketSystem<I,Out, M> + 'static,
|
||||
M: 'static,
|
||||
{
|
||||
unregister_system(self, f);
|
||||
}
|
||||
|
||||
fn with_packet_system<I>(&mut self, f: impl FnOnce(&mut World, &mut RegisteredSystems<I>),)
|
||||
where
|
||||
I: SystemInput + 'static,
|
||||
{
|
||||
let Some(mut systems) = self.remove_packet_system::<I>() else {return};
|
||||
f(self, &mut systems);
|
||||
self.put_back_packet_system(systems);
|
||||
}
|
||||
|
||||
/// don't forget to put it back.
|
||||
fn remove_packet_system<I: SystemInput + 'static>(&mut self) -> Option<Box<RegisteredSystems<I>>> {
|
||||
let packet_systems = &mut self.packet_systems;
|
||||
let rv = packet_systems.remove(&TypeId::of::<I>());
|
||||
return rv.map(|v| v.downcast().unwrap());
|
||||
}
|
||||
|
||||
fn put_back_packet_system<I: SystemInput + 'static>(&mut self, systems: Box<RegisteredSystems<I>>) {
|
||||
let event_systems = &mut self.packet_systems;
|
||||
let tid = TypeId::of::<I>();
|
||||
debug_assert!(!event_systems.contains_key(&tid));
|
||||
event_systems.insert(tid, systems);
|
||||
}
|
||||
|
||||
}
|
||||
impl<'w,'s> Commands<'w,'s> {
|
||||
pub fn send<E>(&mut self, packet: E)
|
||||
where
|
||||
E: Packet,
|
||||
for<'e> E: SystemInput<Inner<'e> = E>,
|
||||
{
|
||||
self.queue(move |world: &mut World| world.send(packet));
|
||||
}
|
||||
}
|
||||
impl<E: Packet> SystemInput for &E {
|
||||
type Param<'i> = &'i E;
|
||||
type Inner<'i> = &'i E;
|
||||
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
|
||||
this
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{system::ResMut, world::World};
|
||||
use super::Packet;
|
||||
use crate::resource::Resource;
|
||||
|
||||
|
||||
#[derive(Resource)]
|
||||
struct Count(u8);
|
||||
|
||||
#[derive(Packet)]
|
||||
struct Input(u8);
|
||||
|
||||
#[derive(Packet)]
|
||||
struct Moved;
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(Count(0));
|
||||
world.register_packet_system(move_player);
|
||||
world.register_packet_system(count_moved);
|
||||
world.register_packet_system(count_moved1);
|
||||
world.register_packet_system(count_moved2);
|
||||
world.send(Input(b'a'));
|
||||
let count = world.get_resource::<Count>().unwrap();
|
||||
assert_eq!(count.0, 3);
|
||||
}
|
||||
|
||||
fn move_player(Input(input): Input) -> Option<Moved> {
|
||||
match input {
|
||||
b'a' => Some(Moved),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn count_moved1(_: &Moved, mut count: ResMut<Count>) {
|
||||
count.0 += 1;
|
||||
}
|
||||
fn count_moved2(_: &Moved, mut count: ResMut<Count>) {
|
||||
count.0 += 1;
|
||||
}
|
||||
fn count_moved(_: Moved, mut count: ResMut<Count>) {
|
||||
count.0 += 1;
|
||||
}
|
||||
|
||||
}
|
69
crates/bevy_ecs/src/packet/optionpacket.rs
Normal file
69
crates/bevy_ecs/src/packet/optionpacket.rs
Normal file
@ -0,0 +1,69 @@
|
||||
use crate::world::World;
|
||||
|
||||
use super::{run_this_packet_system, Packet, SystemInput};
|
||||
|
||||
pub trait OptionPacket {
|
||||
fn run(self, world: &mut World);
|
||||
}
|
||||
impl OptionPacket for (){ fn run(self, _: &mut World) {} }
|
||||
|
||||
impl<E: Packet> OptionPacket for E
|
||||
where
|
||||
for<'e> E: SystemInput<Inner<'e> = E>,
|
||||
{
|
||||
fn run(self, world: &mut World) {
|
||||
run_this_packet_system::<E>(self, world);
|
||||
}
|
||||
}
|
||||
impl<O: OptionPacket> OptionPacket for Option<O> {
|
||||
fn run(self, world: &mut World) {
|
||||
let Some(event) = self else {return};
|
||||
event.run(world);
|
||||
}
|
||||
}
|
||||
macro_rules! impl_option_event_tuple {
|
||||
($($param: ident),*) => {
|
||||
impl<$($param: OptionPacket,)*> OptionPacket for ($($param,)*) {
|
||||
fn run(self, world: &mut World) {
|
||||
#[allow(non_snake_case)]
|
||||
let ($($param,)*) = self;
|
||||
$(
|
||||
$param.run(world);
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_option_event_tuple!(O1);
|
||||
impl_option_event_tuple!(O1, O2);
|
||||
impl_option_event_tuple!(O1, O2, O3);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4, O5);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4, O5, O6);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4, O5, O6, O7);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4, O5, O6, O7, O8);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4, O5, O6, O7, O8, O9);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4, O5, O6, O7, O8, O9, O10);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11, O12);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11, O12, O13);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11, O12, O13, O14);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11, O12, O13, O14, O15);
|
||||
impl_option_event_tuple!(O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11, O12, O13, O14, O15, O16);
|
||||
|
||||
macro_rules! impl_option_packet_array {
|
||||
($($N: literal),*) => {
|
||||
$(
|
||||
impl<O: OptionPacket> OptionPacket for [O;$N] {
|
||||
fn run(self, world: &mut World) {
|
||||
for packet in self {
|
||||
packet.run(world);
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_option_packet_array!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
|
110
crates/bevy_ecs/src/packet/packetsystem.rs
Normal file
110
crates/bevy_ecs/src/packet/packetsystem.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use crate::{
|
||||
component::Tick,
|
||||
system::{
|
||||
FunctionSystem, IntoResult, IntoSystem, IsFunctionSystem, RunSystemError, System, SystemIn, SystemInput, SystemParamFunction
|
||||
},
|
||||
world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
|
||||
};
|
||||
|
||||
use super::OptionPacket;
|
||||
|
||||
pub trait IntoPacketSystem<In: SystemInput, Out, Marker>: Sized {
|
||||
type System: System<In = In, Out = ()>;
|
||||
fn into_system(this: Self) -> Self::System;
|
||||
}
|
||||
pub struct FunctionPacketSystem<Marker, F>
|
||||
where
|
||||
F: SystemParamFunction<Marker>,
|
||||
{
|
||||
inner: FunctionSystem<Marker, F::Out, F>,
|
||||
}
|
||||
impl<Marker, F> IntoPacketSystem<F::In, F::Out, (IsFunctionSystem, Marker)> for F
|
||||
where
|
||||
Marker: 'static,
|
||||
F: SystemParamFunction<Marker>,
|
||||
F::Out: OptionPacket,
|
||||
{
|
||||
type System = FunctionPacketSystem<Marker, F>;
|
||||
fn into_system(func: Self) -> Self::System {
|
||||
let inner = IntoSystem::into_system(func);
|
||||
return FunctionPacketSystem { inner };
|
||||
}
|
||||
}
|
||||
impl<Marker, F> System for FunctionPacketSystem<Marker, F>
|
||||
where
|
||||
Marker: 'static,
|
||||
F: SystemParamFunction<Marker>,
|
||||
F::Out: OptionPacket,
|
||||
{
|
||||
type In = F::In;
|
||||
type Out = ();
|
||||
|
||||
#[inline]
|
||||
fn is_send(&self) -> bool {
|
||||
self.inner.is_send()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_exclusive(&self) -> bool {
|
||||
self.inner.is_exclusive()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_deferred(&self) -> bool {
|
||||
self.inner.has_deferred()
|
||||
}
|
||||
fn run(&mut self, input: SystemIn<'_, Self>, world: &mut World) -> Result<Self::Out, RunSystemError> {
|
||||
let out = self.inner.run(input, world)?;
|
||||
let rv = out.run(world);
|
||||
return IntoResult::into_result(rv);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn apply_deferred(&mut self, world: &mut World) {
|
||||
self.inner.apply_deferred(world);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn queue_deferred(&mut self, world: DeferredWorld) {
|
||||
self.inner.queue_deferred(world);
|
||||
}
|
||||
|
||||
fn get_last_run(&self) -> Tick {
|
||||
self.inner.get_last_run()
|
||||
}
|
||||
|
||||
fn set_last_run(&mut self, last_run: Tick) {
|
||||
self.inner.set_last_run(last_run);
|
||||
}
|
||||
|
||||
fn flags(&self) -> crate::system::SystemStateFlags {
|
||||
self.inner.flags()
|
||||
}
|
||||
|
||||
fn name(&self) -> bevy_utils::prelude::DebugName {
|
||||
self.inner.name()
|
||||
}
|
||||
|
||||
unsafe fn validate_param_unsafe(
|
||||
&mut self,
|
||||
world: UnsafeWorldCell,
|
||||
) -> Result<(), crate::system::SystemParamValidationError> {
|
||||
self.inner.validate_param_unsafe(world)
|
||||
}
|
||||
|
||||
fn initialize(&mut self, world: &mut World) -> crate::query::FilteredAccessSet<crate::component::ComponentId> {
|
||||
self.inner.initialize(world)
|
||||
}
|
||||
|
||||
fn check_change_tick(&mut self, check: crate::component::CheckChangeTicks) {
|
||||
self.inner.check_change_tick(check)
|
||||
}
|
||||
|
||||
unsafe fn run_unsafe(
|
||||
&mut self,
|
||||
_input: SystemIn<'_, Self>,
|
||||
_world: UnsafeWorldCell,
|
||||
) -> Result<Self::Out, RunSystemError> {
|
||||
unimplemented!("no multithreading, use run")
|
||||
}
|
||||
}
|
@ -106,6 +106,7 @@ pub struct World {
|
||||
pub(crate) last_check_tick: Tick,
|
||||
pub(crate) last_trigger_id: u32,
|
||||
pub(crate) command_queue: RawCommandQueue,
|
||||
pub(crate) packet_systems: bevy_platform::collections::HashMap<TypeId, Box<dyn core::any::Any>>,
|
||||
}
|
||||
|
||||
impl Default for World {
|
||||
@ -127,6 +128,7 @@ impl Default for World {
|
||||
last_trigger_id: 0,
|
||||
command_queue: RawCommandQueue::new(),
|
||||
component_ids: ComponentIds::default(),
|
||||
packet_systems: Default::default(),
|
||||
};
|
||||
world.bootstrap();
|
||||
world
|
||||
|
Loading…
Reference in New Issue
Block a user