Skip to content

Commit

Permalink
get offline sessions working again in app
Browse files Browse the repository at this point in the history
  • Loading branch information
inodentry committed Aug 15, 2024
1 parent 301c52d commit 49c7ac1
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 91 deletions.
Empty file removed .raroot
Empty file.
9 changes: 4 additions & 5 deletions lib/app/mw_app_game_minesweeper/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use mw_app_core::{driver::*, graphics::*, player::*, session::*, settings::{GraphicsStyleSettings, PlidColorSettings}, user::*};
use mw_game_minesweeper::MinesweeperSettings;

use crate::{map::SimpleMapGenerator, offline::SetupOfflineGame, prelude::*, settings::SimpleMapSettings};
use crate::{map::SimpleMapGenerator, offline::SetupOfflineGame, prelude::*, settings::{OfflineMinesweeperSettings, SimpleMapSettings}};

pub fn plugin(app: &mut App) {
app.register_clicommand_noargs(
Expand All @@ -19,6 +19,7 @@ fn start_minesweeper_singleplayer(
let s_mapgen = settings.get::<SimpleMapSettings>().unwrap();
let s_colors = settings.get::<PlidColorSettings>().unwrap();
let s_gfx = settings.get::<GraphicsStyleSettings>().unwrap();
let s_offline = settings.get::<OfflineMinesweeperSettings>().unwrap();

let e_subplid = commands.spawn((
SubPlidBundle::new(0, &q_user.single().0),
Expand All @@ -42,10 +43,8 @@ fn start_minesweeper_singleplayer(
size: s_mapgen.size,
},
SetupOfflineGame {
settings: MinesweeperSettings {
n_plids: 1,
..Default::default()
},
settings: s_offline.game.clone(),
minegen: s_offline.minegen.clone(),
},
));
let e_gov_gfx = commands.spawn((
Expand Down
9 changes: 2 additions & 7 deletions lib/app/mw_app_game_minesweeper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,17 @@ pub mod prelude {
}

mod cli;
mod settings;
mod input;
mod map;
pub mod offline;
pub mod settings;

use crate::prelude::*;

pub fn plugin(app: &mut App) {
app.add_plugins((
mw_app_io::offline_host::OfflineHostPlugin::<
mw_game_minesweeper::GameMinesweeperTopo<Hex>,
mw_game_minesweeper::MinesweeperInputAction,
mw_common::game::GameEvent,
>::new(),
mw_app_io::offline_host::OfflineHostPlugin::<
mw_game_minesweeper::GameMinesweeperTopo<Sq>,
Box<mw_game_minesweeper::GameMinesweeper>,
mw_game_minesweeper::MinesweeperInputAction,
mw_common::game::GameEvent,
>::new(),
Expand Down
48 changes: 17 additions & 31 deletions lib/app/mw_app_game_minesweeper/src/offline.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy::tasks::{block_on, poll_once, AsyncComputeTaskPool, Task};
use mw_app_core::{driver::{DriverGovernor, NeedsDriverGovernorSet}, map::{MapDataOrig, MapDescriptor, MapGovernor, MapTileDataOrig}, session::NeedsSessionGovernorSet};
use mw_app_core::{driver::{DriverGovernor, NeedsDriverGovernorSet}, map::{MapDataOrig, MapDescriptor, MapGovernor, MapTileDataOrig}, session::{NeedsSessionGovernorSet, PlayersIndex, SessionGovernor}};
use mw_app_io::offline_host::OfflineHost;
use mw_game_minesweeper::{GameMinesweeperTopo, MinesweeperSettings};
use mw_game_minesweeper::{builder::GameMinesweeperBuilder, minegen::MineGenSettings, GameMinesweeper, MinesweeperInitData, MinesweeperSettings};

use crate::prelude::*;

Expand All @@ -19,19 +19,20 @@ pub fn plugin(app: &mut App) {
#[derive(Component)]
pub struct SetupOfflineGame {
pub settings: MinesweeperSettings,
pub minegen: MineGenSettings,
}

#[derive(Default)]
enum SetupState {
#[default]
NotStarted,
AwaitingHex(Task<Box<GameMinesweeperTopo<Hex>>>),
AwaitingSq(Task<Box<GameMinesweeperTopo<Sq>>>),
Awaiting(Task<Box<GameMinesweeper>>),
Done,
}

fn setup_offline_game(
mut commands: Commands,
q_session: Query<&PlayersIndex, With<SessionGovernor>>,
q_driver: Query<(Entity, &SetupOfflineGame), With<DriverGovernor>>,
q_map: Query<(&MapDescriptor, &MapDataOrig), With<MapGovernor>>,
mut state: Local<SetupState>,
Expand All @@ -41,53 +42,38 @@ fn setup_offline_game(
let Ok((mapdesc, mapdata)) = q_map.get_single() else {
return false.into();
};
let n_plids = q_session.single().e_plid.len() - 1;
let (_, setup) = q_driver.single();
let rt = AsyncComputeTaskPool::get();
match mapdesc.topology {
Topology::Hex => {
let settings = setup.settings.clone();
let mapdata = mapdata.map.clone();
let task = rt.spawn(async move {
let game = GameMinesweeperTopo::<Hex>::new(
settings, &mapdata.rekey(),
|c: &MapTileDataOrig| c.kind()
);
Box::new(game)
GameMinesweeperBuilder::new(settings, n_plids as u8)
.with_mapdata_hex(mapdata.size(), |c| mapdata[c.into()].kind())
});
*state = SetupState::AwaitingHex(task);
*state = SetupState::Awaiting(task);
}
Topology::Sq => {
let settings = setup.settings.clone();
let mapdata = mapdata.map.clone();
let task = rt.spawn(async move {
let game = GameMinesweeperTopo::<Sq>::new(
settings, &mapdata.rekey(),
|c: &MapTileDataOrig| c.kind()
);
Box::new(game)
GameMinesweeperBuilder::new(settings, n_plids as u8)
.with_mapdata_sq(mapdata.size(), |c| mapdata[c.into()].kind())
});
*state = SetupState::AwaitingSq(task);
*state = SetupState::Awaiting(task);
}
}
false.into()
}
SetupState::AwaitingHex(task) => {
SetupState::Awaiting(task) => {
if let Some(game) = block_on(poll_once(task)) {
let (e_driver, _) = q_driver.single();
let (e_driver, setup) = q_driver.single();
commands.entity(e_driver).insert((
OfflineHost::new(game, None),
));
*state = SetupState::Done;
true.into()
} else {
false.into()
}
}
SetupState::AwaitingSq(task) => {
if let Some(game) = block_on(poll_once(task)) {
let (e_driver, _) = q_driver.single();
commands.entity(e_driver).insert((
OfflineHost::new(game, None),
OfflineHost::new(game, Box::new(MinesweeperInitData {
minegen: setup.minegen.clone()
})),
));
*state = SetupState::Done;
true.into()
Expand Down
12 changes: 12 additions & 0 deletions lib/app/mw_app_game_minesweeper/src/settings.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
use mw_game_minesweeper::{minegen::MineGenSettings, MinesweeperSettings};

use crate::prelude::*;

pub fn plugin(app: &mut App) {
app.init_setting::<SimpleMapSettings>(SETTINGS_APP.as_ref());
app.init_setting::<OfflineMinesweeperSettings>(SETTINGS_APP.as_ref());
}

#[derive(Reflect, Default, Debug, Clone)]
#[reflect(Setting)]
pub struct OfflineMinesweeperSettings {
pub game: MinesweeperSettings,
pub minegen: MineGenSettings,
}

impl Setting for OfflineMinesweeperSettings {}

#[derive(Reflect, Debug, Clone)]
#[reflect(Setting)]
pub struct SimpleMapSettings {
Expand Down
67 changes: 30 additions & 37 deletions lib/app/mw_app_io/src/offline_host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ pub struct OfflineHostPlugin<G: Game, EIn, EOut> {

impl<G: Game, EIn, EOut> OfflineHostPlugin<G, EIn, EOut>
where
EIn: Event + Clone + Into<G::InputAction>,
EOut: Event + From<(Plids, G::OutEvent)>,
EIn: Event + Clone + Into<<G::Io as GameIo>::InputAction>,
EOut: Event + From<(Plids, <G::Io as GameIo>::OutEvent)>,
{
pub fn new() -> Self {
Self {
Expand All @@ -25,8 +25,8 @@ where

impl<G: Game, EIn, EOut> Plugin for OfflineHostPlugin<G, EIn, EOut>
where
EIn: Event + Clone + Into<G::InputAction>,
EOut: Event + From<(Plids, G::OutEvent)>,
EIn: Event + Clone + Into<<G::Io as GameIo>::InputAction>,
EOut: Event + From<(Plids, <G::Io as GameIo>::OutEvent)>,
{
fn build(&self, app: &mut App) {
app.add_systems(Update,
Expand All @@ -53,14 +53,14 @@ pub struct OfflineHost<G: Game>(OfflineHostState<G>);

enum OfflineHostState<G: Game> {
NotInitialized {
game: Box<G>,
init_data: Option<Box<G::InitData>>,
game: G,
init_data: Box<G::InitData>,
},
Initializing {
task: Task<(Box<G>, HostState<G>)>,
task: Task<(G, HostState<G>)>,
},
Initialized {
game: Box<G>,
game: G,
host: HostState<G>,
},
Running {
Expand All @@ -75,21 +75,21 @@ enum OfflineHostState<G: Game> {
enum TaskIn<G: Game> {
GameInput {
plid: PlayerId,
event: G::InputAction,
event: <G::Io as GameIo>::InputAction,
},
SchedTrigger(Instant),
Maintain,
}

enum TaskOut<G: Game> {
GameOutput(GameOutput<G>),
GameOutput(GameOutput<G::Io>),
NextSched(Instant),
NoSchedsRemain,
GameOver,
}

impl<G: Game> OfflineHost<G> {
pub fn new(game: Box<G>, init_data: Option<Box<G::InitData>>) -> Self {
pub fn new(game: G, init_data: Box<G::InitData>) -> Self {
Self(OfflineHostState::NotInitialized { game, init_data })
}
}
Expand All @@ -102,22 +102,15 @@ fn init_offline_game<G: Game>(
let r;
*state = match temp {
OfflineHostState::NotInitialized { mut game, init_data } => {
if let Some(init_data) = init_data {
let rt = AsyncComputeTaskPool::get();
let mut host = HostState::<G>::default();
let task = rt.spawn(async move {
game.init(&mut host, init_data);
(game, host)
});
info!("Offline game initializing.");
r = false.into();
OfflineHostState::Initializing { task }
} else {
let host = HostState::<G>::default();
info!("Offline game initialized.");
r = true.into();
OfflineHostState::Initialized { game, host }
}
let rt = AsyncComputeTaskPool::get();
let mut host = HostState::<G>::default();
let task = rt.spawn(async move {
game.init(&mut host, init_data);
(game, host)
});
info!("Offline game initializing.");
r = false.into();
OfflineHostState::Initializing { task }
}
OfflineHostState::Initializing { mut task } => {
if let Some((game, host)) = block_on(poll_once(&mut task)) {
Expand All @@ -144,8 +137,8 @@ fn update_offline_game<G: Game, EIn, EOut>(
mut evw_out: EventWriter<EOut>,
)
where
EIn: Event + Clone + Into<G::InputAction>,
EOut: Event + From<(Plids, G::OutEvent)>,
EIn: Event + Clone + Into<<G::Io as GameIo>::InputAction>,
EOut: Event + From<(Plids, <G::Io as GameIo>::OutEvent)>,
{
let plid = q_session.single().0;
let state = &mut q_driver.single_mut().0;
Expand Down Expand Up @@ -223,9 +216,9 @@ where
}

struct HostState<G: Game> {
events: Vec<GameOutput<G>>,
scheds: BTreeMap<Instant, G::SchedEvent>,
cancel: HashSet<G::SchedEvent>,
events: Vec<GameOutput<G::Io>>,
scheds: BTreeMap<Instant, <G::Io as GameIo>::SchedEvent>,
cancel: HashSet<<G::Io as GameIo>::SchedEvent>,
game_over: bool,
}

Expand All @@ -240,14 +233,14 @@ impl<G: Game> Default for HostState<G> {
}
}

impl<G: Game> Host<G> for HostState<G> {
fn msg(&mut self, output: GameOutput<G>) {
impl<G: Game> Host<G::Io> for HostState<G> {
fn msg(&mut self, output: GameOutput<G::Io>) {
self.events.push(output);
}
fn sched(&mut self, time: Instant, event: G::SchedEvent) {
fn sched(&mut self, time: Instant, event: <G::Io as GameIo>::SchedEvent) {
self.scheds.insert(time, event);
}
fn desched_all(&mut self, event: G::SchedEvent) {
fn desched_all(&mut self, event: <G::Io as GameIo>::SchedEvent) {
self.cancel.insert(event);
}
fn game_over(&mut self) {
Expand All @@ -272,7 +265,7 @@ impl<G: Game> HostState<G> {
}

async fn task_host_game<G: Game>(
mut game: Box<G>,
mut game: G,
mut host: HostState<G>,
rx: Receiver<TaskIn<G>>,
tx: Sender<TaskOut<G>>,
Expand Down
12 changes: 6 additions & 6 deletions lib/common/mw_game_minesweeper/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ impl GameMinesweeperBuilder {
self,
map_size: u8,
f_kind: impl Fn(Hex) -> TileKind,
) -> GameMinesweeper {
GameMinesweeper::Hex(
) -> Box<GameMinesweeper> {
Box::new(GameMinesweeper::Hex(
self.with_mapdata_inner(map_size, f_kind)
)
))
}
pub fn with_mapdata_sq(
self,
map_size: u8,
f_kind: impl Fn(Sq) -> TileKind,
) -> GameMinesweeper {
GameMinesweeper::Sq(
) -> Box<GameMinesweeper> {
Box::new(GameMinesweeper::Sq(
self.with_mapdata_inner(map_size, f_kind)
)
))
}
fn with_mapdata_inner<C: Coord>(
self,
Expand Down
10 changes: 5 additions & 5 deletions lib/common/mw_game_minesweeper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,30 +70,30 @@ pub enum GameMinesweeper {
Sq(GameMinesweeperTopo<Sq>),
}

impl Game for GameMinesweeper {
impl Game for Box<GameMinesweeper> {
type Io = MinesweeperIo;
type InitData = MinesweeperInitData;

fn init<H: Host<MinesweeperIo>>(&mut self, host: &mut H, initdata: Box<Self::InitData>) {
match self {
match self.as_mut() {
GameMinesweeper::Hex(game) => game.init(host, initdata),
GameMinesweeper::Sq(game) => game.init(host, initdata),
}
}
fn input<H: Host<MinesweeperIo>>(&mut self, host: &mut H, input: GameInput<MinesweeperIo>) {
match self {
match self.as_mut() {
GameMinesweeper::Hex(game) => game.input(host, input),
GameMinesweeper::Sq(game) => game.input(host, input),
}
}
fn unsched<H: Host<MinesweeperIo>>(&mut self, host: &mut H, event: MinesweeperSchedEvent) {
match self {
match self.as_mut() {
GameMinesweeper::Hex(game) => game.unsched(host, event),
GameMinesweeper::Sq(game) => game.unsched(host, event),
}
}
fn unreliable<H: Host<MinesweeperIo>>(&mut self, host: &mut H) {
match self {
match self.as_mut() {
GameMinesweeper::Hex(game) => game.unreliable(host),
GameMinesweeper::Sq(game) => game.unreliable(host),
}
Expand Down

0 comments on commit 49c7ac1

Please sign in to comment.