use bevy::utils::tracing;
use bevy::{ecs::event::ManualEventReader, prelude::*};
use bevy_twite::{twite::frame::MessageType, ServerEvent, TwiteServerConfig, TwiteServerPlugin};
use component::*;
use packet::*;
pub mod component;
pub mod packet;
pub mod macros;
fn main() {
let subscriber = tracing_subscriber::FmtSubscriber::new();
tracing::subscriber::set_global_default(subscriber).unwrap();
info!(
"StarKingdoms server v{} starting up",
env!("CARGO_PKG_VERSION")
);
App::new()
.insert_resource(TwiteServerConfig { port: 3000 })
.add_plugins(MinimalPlugins)
.add_plugins(TwiteServerPlugin)
.add_systems(Startup, spawn_planets)
//.add_systems(Update, on_connection)
.add_systems(Update, on_message)
.add_systems(FixedUpdate, on_position_change)
.run();
info!("Goodbye!");
}
fn spawn_planets(mut commands: Commands) {
info!("Spawning planets");
let earth_pos = Transform::from_xyz(0.0, 0.0, 0.0);
commands.spawn(PlanetBundle {
planet_type: PlanetType::Earth,
transform: TransformBundle::from(earth_pos),
});
}
/*fn on_connection(
mut commands: Commands,
planet_query: Query<(Entity, &PlanetType, &Transform)>,
mut reader: Local<ManualEventReader<ServerEvent>>,
mut events: ResMut<Events<ServerEvent>>,
) {
let mut packets = Vec::new();
for ev in reader.read(&events) {
info!("{:?}", ev);
if let ServerEvent::Connection(addr) = ev {
info!("client connected");
let _id = commands
.spawn(PlayerBundle {
part: PartBundle {
part_type: PartType::Hearty,
transform: TransformBundle::from(Transform::from_xyz(0.0, 0.0, 0.0)),
},
addr: Player(*addr),
})
.id()
.index();
let mut planets = Vec::new();
for (entity, planet_type, transform) in planet_query.iter() {
planets.push((entity.index(), Planet {
planet_type: *planet_type,
transform: proto_transform!(transform)
}));
}
let packet = Packet::PlanetPositions { planets };
let buf = serde_json::to_vec(&packet).unwrap();
packets.push(ServerEvent::Send(*addr, MessageType::Text, buf));
}
}
for packet in packets {
events.send(packet);
}
}*/
fn on_message(
mut commands: Commands,
planet_query: Query<(Entity, &PlanetType, &Transform)>,
player_query: Query<(Entity, &Player)>,
part_query: Query<(Entity, &PartType, &Transform)>,
mut packet_recv: Local<ManualEventReader<ServerEvent>>,
mut packet_send: ResMut<Events<ServerEvent>>,
) {
let mut packets = Vec::new();
for ev in packet_recv.read(&packet_send) {
if let ServerEvent::Recv(addr, MessageType::Text, data) = ev {
let data = String::from_utf8_lossy(&data);
let json: serde_json::Value = err_or_cont!(serde_json::from_str(&data));
let packet_type = json["t"].clone();
let data = json["c"].clone();
let packet_type = some_or_cont!(packet_type.as_str());
match packet_type {
// handshake
"ClientLogin" => {
// spawn player
let username = data["username"].clone();
let username = some_or_cont!(username.as_str());
let transform = Transform::from_xyz(0.0, 0.0, 0.0);
let id = commands
.spawn(PlayerBundle {
part: PartBundle {
part_type: PartType::Hearty,
transform: TransformBundle::from(transform),
},
player: Player { addr: *addr, username: username.to_string() },
}).id().index();
// tell this player the planets
let mut planets = Vec::new();
for (entity, planet_type, transform) in planet_query.iter() {
planets.push((entity.index(), Planet {
planet_type: *planet_type,
transform: proto_transform!(transform)
}));
}
let packet = Packet::PlanetPositions { planets };
let buf = serde_json::to_vec(&packet).unwrap();
packets.push(ServerEvent::Send(*addr, MessageType::Text, buf));
// tell the player already existing users
let mut players = Vec::new();
for (entity, player) in &player_query {
players.push((entity.index(), player.username.clone()));
}
let packet = Packet::PlayerList {
players,
};
let buf = serde_json::to_vec(&packet).unwrap();
packets.push(ServerEvent::Send(*addr, MessageType::Text, buf));
// tell other players that a player has spawned in
let packet = Packet::SpawnPlayer {
id,
username: username.to_string(),
};
let buf = serde_json::to_vec(&packet).unwrap();
packets.push(ServerEvent::Broadcast(MessageType::Text, buf));
// tell the player where parts are
let mut parts = Vec::new();
for (entity, part_type, transform) in &part_query {
parts.push((entity.index(), Part {
part_type: *part_type,
transform: proto_transform!(transform),
}));
}
parts.push((id, Part {
part_type: PartType::Hearty,
transform: proto_transform!(transform),
}));
let packet = Packet::PartPositions {
parts
};
let buf = serde_json::to_vec(&packet).unwrap();
packets.push(ServerEvent::Send(*addr, MessageType::Text, buf));
}
_ => continue
};
}
}
for packet in packets {
packet_send.send(packet);
}
}
fn on_position_change(
mut commands: Commands,
part_query: Query<(Entity, &PartType, &Transform), Changed<Transform>>,
planet_query: Query<(Entity, &PlanetType, &Transform), Changed<Transform>>,
mut packet_send: EventWriter<ServerEvent>,
) {
let mut updated_parts = Vec::new();
for (entity, part_type, transform) in part_query.iter() {
let id = commands.entity(entity).id().index();
updated_parts.push((id, Part {
part_type: *part_type,
transform: proto_transform!(transform),
}));
}
if !updated_parts.is_empty() {
let packet = Packet::PartPositions { parts: updated_parts };
let buf = serde_json::to_vec(&packet).unwrap();
packet_send.send(ServerEvent::Broadcast(MessageType::Text, buf));
}
let mut planets = Vec::new();
for (entity, planet_type, transform) in planet_query.iter() {
let id = commands.entity(entity).id().index();
planets.push((id, Planet {
planet_type: *planet_type,
transform: proto_transform!(transform)
}));
}
if !planets.is_empty() {
let packet = Packet::PlanetPositions { planets };
let buf = serde_json::to_vec(&packet).unwrap();
packet_send.send(ServerEvent::Broadcast(MessageType::Text, buf));
}
}