bevy_sync 0.19.0

Plugin for synchronizing entities and components between server and its clients.
Documentation
use bevy::prelude::*;
use bevy_app::{App, Startup, Update};
use bevy_asset::{Asset, Assets, Handle};
use bevy_camera::primitives::Aabb;
use bevy_color::Color;
use bevy_ecs::{
    component::Component,
    query::With,
    schedule::IntoScheduleConfigs,
    system::{Commands, ResMut, Single},
};
use bevy_internal::prelude::Meshable;
use bevy_internal::{DefaultPlugins, time::common_conditions::on_timer};
use bevy_math::Vec3;
use bevy_math::{
    Quat,
    primitives::{Cuboid, Plane3d},
};
use bevy_sync::{ConnectCommand, prelude::*};
use bevy_transform::components::Transform;
use std::{
    env,
    marker::PhantomData,
    net::{IpAddr, Ipv4Addr},
    time::Duration,
};
use uuid::Uuid;

fn main() {
    if env::var("RUST_LOG").is_err() {
        unsafe { env::set_var("RUST_LOG", "bevy_sync=debug") }
    }

    let ip = IpAddr::V4(Ipv4Addr::LOCALHOST);
    let port = 4000;
    let asset_port = 4900;
    let mut host = App::new();
    host.add_plugins(DefaultPlugins);
    host.add_plugins(SyncPlugin);

    host.sync_component::<Aabb>();
    host.sync_component::<Visibility>();
    host.sync_component::<Transform>();
    host.sync_component::<PointLight>();
    host.sync_component::<DirectionalLight>();
    host.sync_component::<SpotLight>();
    host.sync_component::<MeshMaterial3d<StandardMaterial>>();
    host.sync_component::<Mesh3d>();
    host.sync_materials(true);
    host.sync_meshes(true);
    host.sync_audios(true);

    host.add_systems(Startup, load_world);
    host.add_systems(Update, tick.run_if(on_timer(Duration::from_millis(200))));

    host.world_mut().commands().queue(ConnectCommand {
        is_host: true,
        config: SyncConnectionParameters::Direct {
            ip,
            port,
            asset_port,
        },
    });

    host.run();
}

fn tick(mut q: Single<&mut Transform, With<MyCube>>) {
    q.rotation *= Quat::from_rotation_x(0.1);
}

#[derive(Component)]
struct MyCube;

trait AddByUuid<A: Asset> {
    fn addu(&mut self, asset: A) -> Handle<A>;
}
impl<A: Asset> AddByUuid<A> for Assets<A> {
    fn addu(&mut self, asset: A) -> Handle<A> {
        let id = Uuid::new_v4();
        let _ = self.insert(id, asset);
        Handle::<A>::Uuid(id, PhantomData)
    }
}

fn load_world(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    commands.spawn((
        Mesh3d(meshes.addu(Plane3d::default().mesh().size(5.0, 5.0).into())),
        MeshMaterial3d(materials.addu(Color::srgb(0.3, 0.5, 0.3).into())),
        SyncMark,
    ));
    commands.spawn((
        Mesh3d(meshes.addu(Mesh::from(Cuboid::new(1.0, 1.0, 1.0)))),
        MeshMaterial3d(materials.addu(Color::srgb(0.8, 0.7, 0.6).into())),
        Transform::from_xyz(0.0, 0.5, 0.0),
        SyncMark,
        MyCube,
    ));
    commands.spawn((
        PointLight::default(),
        Transform::from_xyz(4.0, 8.0, 4.0),
        SyncMark,
    ));
    commands.spawn((
        DirectionalLight::default(),
        Transform::from_xyz(4.0, 8.0, 4.0),
        SyncMark,
    ));
    commands.spawn((
        SpotLight::default(),
        Transform::from_xyz(4.0, 8.0, 4.0),
        SyncMark,
    ));
    commands.spawn((
        Camera3d::default(),
        Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
    ));
}