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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
pub mod prelude {
    pub use batbox::*;
    #[cfg(feature = "rendering")]
    pub use geng::{self, prelude::*};
}

use prelude::*;

#[cfg(feature = "rendering")]
mod app;
#[cfg(feature = "client-gen")]
pub mod client_gen;
mod debug;
mod player;
mod processor;

#[cfg(feature = "rendering")]
pub use app::*;
pub use debug::*;
pub use player::*;
pub use processor::*;

pub trait PlayerOptions<G: Game>: From<TcpPlayerOptions> + From<EmptyPlayerOptions> {
    fn get(&self) -> Pin<Box<dyn Future<Output = Result<Box<dyn Player<G>>, PlayerError>>>>;
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum GameInitOptions<G: Game> {
    Ready(#[serde(bound = "")] G),
    New(#[serde(bound = "")] G::Options),
}

impl<G: Game> Default for GameInitOptions<G>
where
    G::Options: Default,
{
    fn default() -> Self {
        Self::New(default())
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum GameInitConfig<G: Game> {
    LoadFrom(std::path::PathBuf),
    Create(G::OptionsPreset),
}

impl<G: Game> From<GameInitConfig<G>> for GameInitOptions<G> {
    fn from(config: GameInitConfig<G>) -> Self {
        match config {
            GameInitConfig::LoadFrom(path) => Self::Ready(
                serde_json::from_reader(std::fs::File::open(path).expect("Failed to read file"))
                    .expect("Failed to parse file"),
            ),
            GameInitConfig::Create(preset) => Self::New(preset.into()),
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct FullOptions<G: Game> {
    pub seed: Option<u64>,
    #[serde(bound = "")]
    pub game: GameInitConfig<G>,
    pub players: Vec<G::PlayerOptions>,
}

impl<G: Game> FullOptions<G> {
    pub fn save(&self, writer: impl Write) -> std::io::Result<()> {
        Ok(serde_json::to_writer_pretty(writer, self)?)
    }
    pub fn load(reader: impl Read) -> std::io::Result<Self> {
        Ok(serde_json::from_reader(reader)?)
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct FullResults<G: Game> {
    players: Vec<PlayerResult>,
    results: G::Results,
    seed: Option<u64>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PlayerResult {
    crashed: bool,
    comment: Option<String>,
}

pub trait Game: Diff {
    type Options: Serialize + for<'de> Deserialize<'de> + Sync + Send + Clone + 'static;
    type OptionsPreset: Debug
        + Serialize
        + for<'de> Deserialize<'de>
        + Sync
        + Send
        + Clone
        + 'static
        + Into<Self::Options>;
    type PlayerOptions: PlayerOptions<Self>
        + Serialize
        + for<'de> Deserialize<'de>
        + Sync
        + Send
        + Clone
        + 'static;
    type Action: Serialize + for<'de> Deserialize<'de> + Trans + Sync + Send + Clone + 'static;
    type Event: Serialize + for<'de> Deserialize<'de> + Trans + Sync + Send + Clone + 'static;
    type PlayerView: Serialize + for<'de> Deserialize<'de> + Trans + Sync + Send + Clone + 'static;
    type Results: Serialize + for<'de> Deserialize<'de> + Sync + Send + Clone + 'static;
    type DebugData: Serialize + for<'de> Deserialize<'de> + Trans + Sync + Send + Clone + 'static;
    type DebugState: Serialize + for<'de> Deserialize<'de> + Trans + Sync + Send + Clone + 'static;
    fn init(rng: &mut dyn RngCore, player_count: usize, options: Self::Options) -> Self;
    fn player_view(&self, player_index: usize) -> Self::PlayerView;
    fn process_turn(
        &mut self,
        rng: &mut dyn RngCore,
        actions: HashMap<usize, Self::Action>,
    ) -> Vec<Self::Event>;
    fn finished(&self) -> bool;
    fn results(&self) -> Self::Results;
}

/// Message sent from client
#[trans_doc = "ru:Сообщение отправляемое клиентом"]
#[derive(Serialize, Deserialize, Trans)]
#[trans(no_generics_in_name)]
pub enum ClientMessage<G: Game> {
    /// Ask app to perform new debug command
    #[trans_doc = "ru:Отправить отладочную команду приложению"]
    DebugMessage {
        /// Command to perform
        #[trans_doc = "ru:Команда для исполнения"]
        #[serde(bound = "")]
        command: DebugCommand<G>,
    },
    /// Reply for ServerMessage::GetAction
    #[trans_doc = "ru:Ответ на ServerMessage::GetAction"]
    ActionMessage {
        /// Player's action
        #[trans_doc = "ru:Действие игрока"]
        action: G::Action,
    },
    /// Signifies finish of the debug update
    #[trans_doc = "ru:Сигнализирует окончание отладочного обновления"]
    DebugUpdateDone {},
    /// Request debug state from the app
    #[trans_doc = "ru:Запросить отладочное состояние приложения"]
    RequestDebugState {},
}

/// Message sent from server
#[trans_doc = "ru:Сообщение отправляемое сервером"]
#[derive(Serialize, Deserialize, Trans)]
#[trans(no_generics_in_name)]
pub enum ServerMessage<G: Game> {
    /// Get action for next tick
    #[trans_doc = "ru:Получить действие для следующего тика"]
    GetAction {
        /// Player's view
        #[trans_doc = "ru:Информация доступная игроку"]
        player_view: G::PlayerView,
        /// Whether app is running with debug interface available
        #[trans_doc = "ru:Доступен ли отладочный интерфейс приложения"]
        debug_available: bool,
    },
    /// Signifies end of the game
    #[trans_doc = "ru:Сигнализирует конец игры"]
    Finish {},
    /// Debug update
    #[trans_doc = "ru:Отладочное обновление"]
    DebugUpdate {
        /// Player's view
        #[trans_doc = "ru:Информация доступная игроку"]
        player_view: G::PlayerView,
    },
}

#[cfg(feature = "rendering")]
pub trait RendererData<G: Game>: Diff {
    fn new(game: &G) -> Self;
    fn update(&mut self, events: &[G::Event], prev_game: &G, game: &G) {
        #![allow(unused_variables)]
        *self = Self::new(game);
    }
}

#[cfg(feature = "rendering")]
pub struct CurrentRenderState<'a, G: Game, T: RendererData<G>> {
    pub game: &'a G,
    pub renderer_data: &'a T,
    pub debug_data: &'a HashMap<usize, DebugDataStorage<G>>,
}

#[cfg(feature = "rendering")]
pub struct RenderState<'a, G: Game, T: RendererData<G>> {
    pub current: CurrentRenderState<'a, G, T>,
    pub prev: Option<CurrentRenderState<'a, G, T>>,
    pub global_debug_data: HashMap<usize, DebugDataStorage<G>>,
    pub t: f64,
    pub prev_events: &'a [G::Event],
}

#[cfg(feature = "rendering")]
pub trait Renderer<G: Game>: 'static {
    type ExtraData: RendererData<G>;
    type Preferences: Debug + Clone + Default + Serialize + for<'de> Deserialize<'de> + 'static;
    fn default_tps(&self) -> f64;
    fn update(&mut self, delta_time: f64) {
        #![allow(unused_variables)]
    }
    fn draw(&mut self, state: RenderState<G, Self::ExtraData>, framebuffer: &mut ugli::Framebuffer);
    fn process_event(&mut self, event: &G::Event) {
        #![allow(unused_variables)]
    }
    fn handle_event(&mut self, event: &geng::Event) {
        #![allow(unused_variables)]
    }
    fn debug_state(&self, game: &G, player_index: usize) -> G::DebugState;
}

pub fn save_replay_tick_handler<G: Game, T: Write + Send + 'static>(
    mut writer: T,
) -> Box<dyn FnMut(Option<&Vec<G::Event>>, &G) + Send> {
    let mut last: Option<G> = None;
    Box::new(move |events: Option<&Vec<G::Event>>, current: &G| {
        if let Some(events) = events {
            events
                .write_to(&mut writer)
                .expect("Failed to write replay");
        }
        match &last {
            None => current.write_to(&mut writer),
            Some(last) => last.diff(current).write_to(&mut writer),
        }
        .expect("Failed to write replay");
        last = Some(current.clone());
    })
}