use bevy::prelude::*;
use bevy_iroh::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Component, Serialize, Deserialize, Clone)]
struct Cube {
color: [f32; 3],
}
fn main() {
App::new()
.add_plugins((
DefaultPlugins,
IrohPlugin::default().with_display_name(whoami()),
))
.replicate::<Cube>()
.add_systems(Startup, setup)
.add_systems(Update, (drive, print_ticket, announce_peers))
.add_observer(dress_cube)
.run();
}
fn whoami() -> String {
std::env::var("USER").unwrap_or_else(|_| "someone".into())
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
match std::env::args().nth(1) {
Some(ticket) => {
let ticket: RoomTicket = ticket.parse().expect("that is not a ticket");
info!("joining {}", ticket.name);
commands.spawn(Room::join(ticket));
}
None => {
commands.spawn(Room::host("cubes"));
}
}
let hue = rand::random::<f32>() * 360.0;
let color = Color::hsl(hue, 0.8, 0.5).to_linear();
commands.spawn((
Cube {
color: [color.red, color.green, color.blue],
},
Shared::default(),
Transform::from_xyz(
rand::random::<f32>() * 4.0 - 2.0,
0.5,
rand::random::<f32>() * 4.0 - 2.0,
),
));
commands.spawn((
Mesh3d(meshes.add(Plane3d::default().mesh().size(12.0, 12.0))),
MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))),
));
commands.spawn((
DirectionalLight {
shadow_maps_enabled: true,
..default()
},
Transform::from_xyz(4.0, 8.0, 4.0).looking_at(Vec3::ZERO, Vec3::Y),
));
commands.spawn((
Camera3d::default(),
Transform::from_xyz(0.0, 7.0, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
));
}
fn dress_cube(
add: On<Add, Cube>,
cubes: Query<&Cube>,
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let cube = cubes.get(add.entity).unwrap();
commands.entity(add.entity).insert((
Mesh3d(meshes.add(Cuboid::from_length(1.0))),
MeshMaterial3d(materials.add(Color::linear_rgb(
cube.color[0],
cube.color[1],
cube.color[2],
))),
));
}
fn drive(
keys: Res<ButtonInput<KeyCode>>,
time: Res<Time>,
mut mine: Query<&mut Transform, (With<Cube>, Without<Remote>)>,
) {
let mut dir = Vec3::ZERO;
if keys.pressed(KeyCode::ArrowLeft) {
dir.x -= 1.0;
}
if keys.pressed(KeyCode::ArrowRight) {
dir.x += 1.0;
}
if keys.pressed(KeyCode::ArrowUp) {
dir.z -= 1.0;
}
if keys.pressed(KeyCode::ArrowDown) {
dir.z += 1.0;
}
if dir == Vec3::ZERO {
return;
}
for mut t in &mut mine {
t.translation += dir.normalize() * 3.0 * time.delta_secs();
}
}
fn print_ticket(tickets: Query<&Ticket, Added<Ticket>>) {
for ticket in &tickets {
println!(
"\njoin with:\n\n cargo run --example cube -- {}\n",
ticket.0
);
}
}
fn announce_peers(
mut joined: MessageReader<PeerJoined>,
mut left: MessageReader<PeerLeft>,
peers: Query<&Peer>,
) {
for j in joined.read() {
let label = peers.get(j.peer).map(|p| p.label()).unwrap_or_default();
info!("{label} joined");
}
for l in left.read() {
info!("{} left", l.id.fmt_short());
}
}