mirror of
https://github.com/ALEZ-DEV/Babylonia-terminal.git
synced 2025-12-16 09:28:53 +00:00
game process now run on a separate thread
This commit is contained in:
parent
85bb1e2c59
commit
a2e0b6315f
@ -1,112 +1,11 @@
|
|||||||
use babylonia_terminal_sdk::game_state::GameState;
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use manager::run_game;
|
use relm4::RelmApp;
|
||||||
use relm4::{
|
|
||||||
gtk::{
|
|
||||||
self,
|
|
||||||
prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt, WidgetExt},
|
|
||||||
},
|
|
||||||
loading_widgets::LoadingWidgets,
|
|
||||||
prelude::{AsyncComponent, AsyncComponentParts, SimpleAsyncComponent},
|
|
||||||
view, ComponentParts, RelmWidgetExt, SimpleComponent,
|
|
||||||
};
|
|
||||||
use relm4::{Component, RelmApp};
|
|
||||||
|
|
||||||
mod manager;
|
mod manager;
|
||||||
|
mod ui;
|
||||||
|
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
debug!("Start GUI!");
|
debug!("Start GUI!");
|
||||||
let app = RelmApp::new("moe.celica.BabyloniaTerminal").with_args(vec![]);
|
let app = RelmApp::new("moe.celica.BabyloniaTerminal").with_args(vec![]);
|
||||||
app.run_async::<MainWindow>(None);
|
ui::run(app);
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum MainWindowMsg {
|
|
||||||
RunGame,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MainWindow {
|
|
||||||
game_state: GameState,
|
|
||||||
is_game_running: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MainWindow {
|
|
||||||
fn new(game_state: GameState) -> Self {
|
|
||||||
MainWindow {
|
|
||||||
game_state,
|
|
||||||
is_game_running: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[relm4::component(async)]
|
|
||||||
impl SimpleAsyncComponent for MainWindow {
|
|
||||||
type Input = MainWindowMsg;
|
|
||||||
|
|
||||||
type Output = ();
|
|
||||||
|
|
||||||
type Init = Option<GameState>;
|
|
||||||
|
|
||||||
view! {
|
|
||||||
#[root]
|
|
||||||
gtk::Window {
|
|
||||||
gtk::Box {
|
|
||||||
set_orientation: gtk::Orientation::Vertical,
|
|
||||||
set_spacing: 5,
|
|
||||||
set_margin_all: 5,
|
|
||||||
|
|
||||||
#[name(start_button)]
|
|
||||||
gtk::Button {
|
|
||||||
set_label: "Start game",
|
|
||||||
connect_clicked => MainWindowMsg::RunGame,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn init(
|
|
||||||
game_state: Self::Init,
|
|
||||||
root: Self::Root,
|
|
||||||
sender: relm4::AsyncComponentSender<Self>,
|
|
||||||
) -> AsyncComponentParts<Self> {
|
|
||||||
let model;
|
|
||||||
if game_state.is_none() {
|
|
||||||
model = MainWindow::new(
|
|
||||||
babylonia_terminal_sdk::game_state::GameState::get_current_state()
|
|
||||||
.await
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
model = MainWindow::new(game_state.unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
let widgets = view_output!();
|
|
||||||
|
|
||||||
AsyncComponentParts { model, widgets }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_loading_widgets(root: Self::Root) -> Option<LoadingWidgets> {
|
|
||||||
view! {
|
|
||||||
#[local]
|
|
||||||
root {
|
|
||||||
set_title: Some("Babylonia Terminal"),
|
|
||||||
set_default_width: 700,
|
|
||||||
set_default_height: 300,
|
|
||||||
|
|
||||||
#[name(spinner)]
|
|
||||||
gtk::Spinner {
|
|
||||||
start: (),
|
|
||||||
set_halign: gtk::Align::Center,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(LoadingWidgets::new(root, spinner))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update(&mut self, message: Self::Input, _sender: relm4::AsyncComponentSender<Self>) {
|
|
||||||
match message {
|
|
||||||
MainWindowMsg::RunGame => run_game().await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,14 @@ use babylonia_terminal_sdk::{
|
|||||||
game_manager::GameManager,
|
game_manager::GameManager,
|
||||||
};
|
};
|
||||||
use log::error;
|
use log::error;
|
||||||
use relm4::tokio::sync::OnceCell;
|
use relm4::{
|
||||||
|
tokio::{self, sync::OnceCell},
|
||||||
|
Worker,
|
||||||
|
};
|
||||||
use wincompatlib::prelude::Proton;
|
use wincompatlib::prelude::Proton;
|
||||||
|
|
||||||
|
use crate::ui;
|
||||||
|
|
||||||
static PROTON: OnceCell<Proton> = OnceCell::const_new();
|
static PROTON: OnceCell<Proton> = OnceCell::const_new();
|
||||||
|
|
||||||
pub async fn get_proton() -> Proton {
|
pub async fn get_proton() -> Proton {
|
||||||
@ -31,3 +36,38 @@ pub async fn run_game() {
|
|||||||
|
|
||||||
GameManager::start_game(&proton, game_dir.unwrap(), None, false).await;
|
GameManager::start_game(&proton, game_dir.unwrap(), None, false).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum HandleGameProcessMsg {
|
||||||
|
RunGame,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HandleGameProcess;
|
||||||
|
|
||||||
|
impl Worker for HandleGameProcess {
|
||||||
|
type Init = ();
|
||||||
|
|
||||||
|
type Input = HandleGameProcessMsg;
|
||||||
|
|
||||||
|
type Output = ui::MainWindowMsg;
|
||||||
|
|
||||||
|
fn init(_init: Self::Init, _sender: relm4::ComponentSender<Self>) -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, message: Self::Input, sender: relm4::ComponentSender<Self>) {
|
||||||
|
match message {
|
||||||
|
HandleGameProcessMsg::RunGame => {
|
||||||
|
tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
.block_on(async {
|
||||||
|
sender.output(ui::MainWindowMsg::SetIsGameRunning(true));
|
||||||
|
run_game().await;
|
||||||
|
sender.output(ui::MainWindowMsg::SetIsGameRunning(false));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
118
babylonia-terminal-gui/src/ui/mod.rs
Normal file
118
babylonia-terminal-gui/src/ui/mod.rs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
use std::convert::identity;
|
||||||
|
|
||||||
|
use crate::manager;
|
||||||
|
use babylonia_terminal_sdk::game_state::GameState;
|
||||||
|
|
||||||
|
use relm4::{
|
||||||
|
gtk::{
|
||||||
|
self,
|
||||||
|
prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt, WidgetExt},
|
||||||
|
},
|
||||||
|
loading_widgets::LoadingWidgets,
|
||||||
|
prelude::{AsyncComponentParts, SimpleAsyncComponent},
|
||||||
|
view, Component, RelmApp, RelmWidgetExt, WorkerController,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn run(app: RelmApp<MainWindowMsg>) {
|
||||||
|
app.run_async::<MainWindow>(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum MainWindowMsg {
|
||||||
|
SetIsGameRunning(bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MainWindow {
|
||||||
|
game_handler: WorkerController<manager::HandleGameProcess>,
|
||||||
|
game_state: GameState,
|
||||||
|
is_game_running: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MainWindow {
|
||||||
|
fn new(game_state: GameState, sender: relm4::AsyncComponentSender<Self>) -> Self {
|
||||||
|
MainWindow {
|
||||||
|
game_state,
|
||||||
|
is_game_running: false,
|
||||||
|
game_handler: manager::HandleGameProcess::builder()
|
||||||
|
.detach_worker(())
|
||||||
|
.forward(sender.input_sender(), identity),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[relm4::component(async)]
|
||||||
|
impl SimpleAsyncComponent for MainWindow {
|
||||||
|
type Input = MainWindowMsg;
|
||||||
|
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
type Init = Option<GameState>;
|
||||||
|
|
||||||
|
view! {
|
||||||
|
#[root]
|
||||||
|
gtk::Window {
|
||||||
|
gtk::Box {
|
||||||
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
set_spacing: 5,
|
||||||
|
set_margin_all: 5,
|
||||||
|
|
||||||
|
#[name(start_button)]
|
||||||
|
gtk::Button {
|
||||||
|
#[watch]
|
||||||
|
set_sensitive: !model.is_game_running,
|
||||||
|
set_label: "Start game",
|
||||||
|
connect_clicked[sender = model.game_handler.sender().clone()] => move |_| {
|
||||||
|
sender.send(manager::HandleGameProcessMsg::RunGame).unwrap();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn init(
|
||||||
|
game_state: Self::Init,
|
||||||
|
root: Self::Root,
|
||||||
|
sender: relm4::AsyncComponentSender<Self>,
|
||||||
|
) -> AsyncComponentParts<Self> {
|
||||||
|
let model;
|
||||||
|
if game_state.is_none() {
|
||||||
|
model = MainWindow::new(
|
||||||
|
babylonia_terminal_sdk::game_state::GameState::get_current_state()
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
sender,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
model = MainWindow::new(game_state.unwrap(), sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
let widgets = view_output!();
|
||||||
|
|
||||||
|
AsyncComponentParts { model, widgets }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_loading_widgets(root: Self::Root) -> Option<LoadingWidgets> {
|
||||||
|
view! {
|
||||||
|
#[local]
|
||||||
|
root {
|
||||||
|
set_title: Some("Babylonia Terminal"),
|
||||||
|
set_default_width: 700,
|
||||||
|
set_default_height: 300,
|
||||||
|
|
||||||
|
#[name(spinner)]
|
||||||
|
gtk::Spinner {
|
||||||
|
start: (),
|
||||||
|
set_halign: gtk::Align::Center,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(LoadingWidgets::new(root, spinner))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update(&mut self, message: Self::Input, _sender: relm4::AsyncComponentSender<Self>) {
|
||||||
|
match message {
|
||||||
|
MainWindowMsg::SetIsGameRunning(value) => self.is_game_running = value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user