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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
use std::time::Duration;
use crate::{
data::DataIndex,
game::Game,
protocol::{Message, PacketC, PacketS, PlayerID},
};
use anyhow::{anyhow, Result};
use clap::Parser;
use log::debug;
use tokio::sync::broadcast::Sender;
pub struct State {
index: DataIndex,
tx: Sender<PacketC>,
pub game: Game,
}
#[derive(Parser)]
#[clap(multicall = true)]
enum Command {
Start {
#[arg(default_value = "small-default-default")]
spec: String,
#[arg(default_value = "420")]
timer: u64,
},
Effect {
name: String,
},
End,
}
impl State {
pub fn new(tx: Sender<PacketC>) -> Result<Self> {
let mut index = DataIndex::default();
index.reload()?;
let mut game = Game::new();
game.load(index.generate("lobby-none-none".to_string())?, None);
Ok(Self { game, index, tx })
}
pub async fn tick(&mut self, dt: f32) -> anyhow::Result<()> {
if self.game.tick(dt) {
self.tx
.send(PacketC::ServerMessage {
text: format!("Game finished. You reached {} points.", self.game.points),
})
.ok();
self.game
.load(self.index.generate("lobby-none-none".to_string())?, None);
}
while let Some(p) = self.game.packet_out() {
debug!("-> {p:?}");
let _ = self.tx.send(p);
}
Ok(())
}
pub async fn packet_in(&mut self, player: PlayerID, packet: PacketS) -> Result<Vec<PacketC>> {
match &packet {
PacketS::Communicate {
message: Some(Message::Text(text)),
persist: false,
} if let Some(command) = text.strip_prefix("/") => {
match self.handle_command_parse(player, command).await {
Ok(()) => return Ok(vec![]),
Err(e) => {
return Ok(vec![PacketC::ServerMessage {
text: format!("{e}"),
}]);
}
}
}
_ => (),
}
self.game.packet_in(player, packet)?;
Ok(vec![])
}
async fn handle_command_parse(&mut self, player: PlayerID, command: &str) -> Result<()> {
self.handle_command(
player,
Command::try_parse_from(
shlex::split(command)
.ok_or(anyhow!("quoting invalid"))?
.into_iter(),
)?,
)
.await?;
Ok(())
}
async fn handle_command(&mut self, player: PlayerID, command: Command) -> Result<()> {
match command {
Command::Start { spec, timer } => {
let data = self.index.generate(spec)?;
self.game.load(data, Some(Duration::from_secs(timer)));
}
Command::End => {
self.tx
.send(PacketC::ServerMessage {
text: format!(
"Game was aborted by {}.",
self.game
.players
.get(&player)
.ok_or(anyhow!("player missing"))?
.name
),
})
.ok();
self.game
.load(self.index.generate("lobby-none-none".to_string())?, None);
}
Command::Effect { name } => {
self.tx
.send(PacketC::Communicate {
player,
message: Some(Message::Effect(name)),
persist: false,
})
.ok();
}
}
Ok(())
}
}
|