1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
use crate::protocol::*;
use crate::server::network::*;
use crate::shared::imperative::*;
use crate::shared::*;
use bevy::prelude::*;
use bevy::utils::HashMap;
use lightyear::prelude::*;
use rand::Rng;
mod network;
#[derive(Resource, Default)]
struct EntityMap(HashMap<ClientId, Entity>);
pub fn main(transport: TransportConfig) {
App::new()
.add_plugins(MinimalPlugins)
.add_plugins(ServerPlugin { transport })
.run();
}
struct ServerPlugin {
pub transport: TransportConfig,
}
impl Plugin for ServerPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(EntityMap::default())
.add_plugins(NetworkPlugin {
transport: self.transport.clone(),
})
.add_systems(Update, connections)
.add_systems(FixedUpdate, player_input)
.add_systems(Update, imperative);
}
}
fn connections(
mut commands: Commands,
mut connects: EventReader<server::ConnectEvent>,
mut disconnects: EventReader<server::DisconnectEvent>,
mut entity_map: ResMut<EntityMap>,
) {
let mut rng = rand::thread_rng();
for connection in connects.read() {
let client_id = connection.context();
info!("connected: {:?}", client_id);
let position = Vec2::new(
50. * rng.gen_range(-2..=2) as f32,
50. * rng.gen_range(-2..=2) as f32,
);
let color = Color::hsl(360. * rng.gen_range(0..=15) as f32 / 16., 0.95, 0.7);
let entity = commands.spawn(PlayerBundle::new(*client_id, position, color));
entity_map.0.insert(*client_id, entity.id());
}
for connection in disconnects.read() {
let client_id = connection.context();
info!("disconnected: {:?}", client_id);
if let Some(entity_id) = entity_map.0.remove(client_id) {
commands.entity(entity_id).despawn();
}
}
}
fn player_input(
entity_map: Res<EntityMap>,
mut input_reader: EventReader<server::InputEvent<Inputs>>,
mut imperatives: Query<&mut Imperative>,
) {
for input in input_reader.read() {
let client_id = input.context();
if let Some(input) = input.input() {
if let Some(entity_id) = entity_map.0.get(client_id) {
match input {
Inputs::Imperative(new_imperative) => {
if let Ok(mut imperative) = imperatives.get_mut(*entity_id) {
*imperative = *new_imperative;
}
}
_ => {}
}
}
}
}
}
const MOVEMENT_SPEED: f32 = 80.;
fn imperative(mut players: Query<(&mut Imperative, &mut PlayerPosition)>, time: Res<Time>) {
for (mut imperative, mut position) in players.iter_mut() {
match *imperative {
Imperative::Idle => {}
Imperative::WalkTo(target) => {
let distance = (target - position.0).length();
let direction = (target - position.0).normalize_or_zero();
let new_position = position.0
+ f32::min(MOVEMENT_SPEED * time.delta().as_secs_f32(), distance) * direction;
if position.0.distance(new_position) < f32::EPSILON {
position.0 = target;
*imperative = Imperative::Idle;
} else {
position.0 = new_position;
}
}
}
}
}
|