network code and stuff

This commit is contained in:
2022-08-09 15:30:47 +02:00
parent e5a83229f1
commit b0eadd5420
8 changed files with 1510 additions and 89 deletions

View File

@@ -5,6 +5,11 @@ edition = "2021"
[dependencies]
bevy = "0.8"
bevy_renet = "0.0.5"
bevy_egui = "0.15.0"
renet_visualizer = "0.0.2"
bincode = "1.3.1"
daggmask-shared = { path = "../shared" }
# Enable a small amount of optimization in debug mode
[profile.dev]

View File

@@ -1,59 +1,246 @@
use bevy::prelude::*;
use std::{collections::HashMap, net::UdpSocket, time::SystemTime};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.add_startup_system(spawn_player)
.add_system(move_player)
.run();
use bevy::{
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
prelude::*,
};
use bevy_egui::{EguiContext, EguiPlugin};
use bevy_renet::{
renet::{ClientAuthentication, RenetClient, RenetError},
run_if_client_connected, RenetClientPlugin,
};
use daggmask_shared::{
client_connection_config, setup_level, ClientChannel, NetworkFrame, PlayerCommand, PlayerInput,
ServerChannel, ServerMessages, PROTOCOL_ID,
};
use renet_visualizer::{RenetClientVisualizer, RenetVisualizerStyle};
#[derive(Component)]
struct ControlledPlayer;
#[derive(Default)]
struct NetworkMapping(HashMap<Entity, Entity>);
#[derive(Debug)]
struct PlayerInfo {
client_entity: Entity,
server_entity: Entity,
}
fn setup(mut commands: Commands) {
info!("hehe");
let mut camera_bundle = Camera2dBundle::default();
camera_bundle.projection.scale = 1. / 50.;
commands.spawn_bundle(camera_bundle);
#[derive(Debug, Default)]
struct ClientLobby {
players: HashMap<u64, PlayerInfo>,
}
#[derive(Debug)]
struct MostRecentTick(Option<u32>);
fn new_renet_client() -> RenetClient {
let server_addr = "127.0.0.1:5000".parse().unwrap();
let socket = UdpSocket::bind("127.0.0.1:0").unwrap();
let connection_config = client_connection_config();
let current_time = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap();
let client_id = current_time.as_millis() as u64;
let authentication = ClientAuthentication::Unsecure {
client_id,
protocol_id: PROTOCOL_ID,
server_addr,
user_data: None,
};
RenetClient::new(current_time, socket, 1, connection_config, authentication).unwrap()
}
fn main() {
let mut app = App::new();
app.add_plugins(DefaultPlugins);
app.add_plugin(RenetClientPlugin);
app.add_plugin(TransformPlugin);
app.add_plugin(FrameTimeDiagnosticsPlugin::default());
app.add_plugin(LogDiagnosticsPlugin::default());
app.add_plugin(EguiPlugin);
app.add_event::<PlayerCommand>();
app.insert_resource(ClientLobby::default());
app.insert_resource(PlayerInput::default());
app.insert_resource(MostRecentTick(None));
app.insert_resource(new_renet_client());
app.insert_resource(RenetClientVisualizer::<200>::new(
RenetVisualizerStyle::default(),
));
app.insert_resource(NetworkMapping::default());
app.add_system(player_input);
app.add_system(client_send_input.with_run_criteria(run_if_client_connected));
app.add_system(client_send_player_commands.with_run_criteria(run_if_client_connected));
app.add_system(client_sync_players.with_run_criteria(run_if_client_connected));
app.add_system(update_visulizer_system);
app.add_startup_system(setup_level);
app.add_system(panic_on_error_system);
app.run();
}
// If any error is found we just panic
fn panic_on_error_system(mut renet_error: EventReader<RenetError>) {
for e in renet_error.iter() {
panic!("{}", e);
}
}
fn update_visulizer_system(
mut egui_context: ResMut<EguiContext>,
mut visualizer: ResMut<RenetClientVisualizer<200>>,
client: Res<RenetClient>,
mut show_visualizer: Local<bool>,
keyboard_input: Res<Input<KeyCode>>,
) {
visualizer.add_network_info(client.network_info());
if keyboard_input.just_pressed(KeyCode::F1) {
*show_visualizer = !*show_visualizer;
}
if *show_visualizer {
visualizer.show_window(egui_context.ctx_mut());
}
}
fn player_input(
keyboard_input: Res<Input<KeyCode>>,
mut player_input: ResMut<PlayerInput>,
mouse_button_input: Res<Input<MouseButton>>,
target_query: Query<&Transform, With<Target>>,
mut player_commands: EventWriter<PlayerCommand>,
most_recent_tick: Res<MostRecentTick>,
) {
player_input.left = keyboard_input.pressed(KeyCode::A) || keyboard_input.pressed(KeyCode::Left);
player_input.right =
keyboard_input.pressed(KeyCode::D) || keyboard_input.pressed(KeyCode::Right);
player_input.up = keyboard_input.pressed(KeyCode::W) || keyboard_input.pressed(KeyCode::Up);
player_input.down = keyboard_input.pressed(KeyCode::S) || keyboard_input.pressed(KeyCode::Down);
player_input.most_recent_tick = most_recent_tick.0;
if mouse_button_input.just_pressed(MouseButton::Left) {
player_commands.send(PlayerCommand::BasicAttack {
cast_at: Vec2::default(), // TODO: spawn projectiles correctly
});
}
}
fn client_send_input(player_input: Res<PlayerInput>, mut client: ResMut<RenetClient>) {
let input_message = bincode::serialize(&*player_input).unwrap();
client.send_message(ClientChannel::Input.id(), input_message);
}
fn client_send_player_commands(
mut player_commands: EventReader<PlayerCommand>,
mut client: ResMut<RenetClient>,
) {
for command in player_commands.iter() {
let command_message = bincode::serialize(command).unwrap();
client.send_message(ClientChannel::Command.id(), command_message);
}
}
fn client_sync_players(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut client: ResMut<RenetClient>,
mut lobby: ResMut<ClientLobby>,
mut network_mapping: ResMut<NetworkMapping>,
mut most_recent_tick: ResMut<MostRecentTick>,
) {
let client_id = client.client_id();
while let Some(message) = client.receive_message(ServerChannel::ServerMessages.id()) {
let server_message = bincode::deserialize(&message).unwrap();
match server_message {
ServerMessages::PlayerCreate {
id,
translation,
entity,
} => {
println!("Player {} connected.", id);
let mut client_entity = commands.spawn_bundle(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Capsule::default())),
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
transform: Transform::from_xyz(translation[0], translation[1], translation[2]),
..Default::default()
});
if client_id == id {
client_entity.insert(ControlledPlayer);
}
let player_info = PlayerInfo {
server_entity: entity,
client_entity: client_entity.id(),
};
lobby.players.insert(id, player_info);
network_mapping.0.insert(entity, client_entity.id());
}
ServerMessages::PlayerRemove { id } => {
println!("Player {} disconnected.", id);
if let Some(PlayerInfo {
server_entity,
client_entity,
}) = lobby.players.remove(&id)
{
commands.entity(client_entity).despawn();
network_mapping.0.remove(&server_entity);
}
}
ServerMessages::SpawnProjectile {
entity,
location,
direction,
} => {
let projectile_entity = commands.spawn_bundle(SpriteBundle {
sprite: Sprite {
color: Color::rgb(0.25, 0.25, 0.75),
custom_size: Some(Vec2::new(50.0, 100.0)),
..default()
},
..default()
});
network_mapping.0.insert(entity, projectile_entity.id());
}
ServerMessages::DespawnProjectile { entity } => {
if let Some(entity) = network_mapping.0.remove(&entity) {
commands.entity(entity).despawn();
}
}
}
}
while let Some(message) = client.receive_message(ServerChannel::NetworkFrame.id()) {
let frame: NetworkFrame = bincode::deserialize(&message).unwrap();
match most_recent_tick.0 {
None => most_recent_tick.0 = Some(frame.tick),
Some(tick) if tick < frame.tick => most_recent_tick.0 = Some(frame.tick),
_ => continue,
}
for i in 0..frame.entities.entities.len() {
if let Some(entity) = network_mapping.0.get(&frame.entities.entities[i]) {
let translation = frame.entities.translations[i].into();
let transform = Transform {
translation,
..Default::default()
};
commands.entity(*entity).insert(transform);
}
}
}
}
#[derive(Component)]
struct Player;
fn spawn_player(mut commands: Commands) {
commands
.spawn_bundle(SpriteBundle {
sprite: Sprite {
color: Color::rgb(0., 0.47, 1.),
custom_size: Some(Vec2::new(1., 1.)),
..Default::default()
},
..Default::default()
})
.insert(Player);
}
fn move_player(keys: Res<Input<KeyCode>>, mut player_query: Query<&mut Transform, With<Player>>) {
let mut direction = Vec2::ZERO;
if keys.any_pressed([KeyCode::Up, KeyCode::W]) {
direction.y += 1.;
}
if keys.any_pressed([KeyCode::Down, KeyCode::S]) {
direction.y -= 1.;
}
if keys.any_pressed([KeyCode::Right, KeyCode::D]) {
direction.x += 1.;
}
if keys.any_pressed([KeyCode::Left, KeyCode::A]) {
direction.x -= 1.;
}
if direction == Vec2::ZERO {
return;
}
let move_speed = 0.13;
let move_delta = (direction * move_speed).extend(0.);
for mut transform in player_query.iter_mut() {
transform.translation += move_delta;
}
}
struct Target;