can now install the game from the GUI

This commit is contained in:
ALEZ-DEV 2024-06-09 23:06:19 +02:00
parent ac52edbb4d
commit 9188860db3
9 changed files with 378 additions and 45 deletions

View File

@ -79,6 +79,9 @@ impl GameComponent {
match v {
Some(str) => {
if str == "done" {
if let Ok(size) = current_size {
progress.done();
}
break;
}
}

View File

@ -6,6 +6,7 @@ import './screens/screens.dart';
import './screens/setup_screen.dart';
import './providers/providers.dart';
import './models/error_reporter.dart';
import './models/game.dart';
class BabyloniaLauncher extends StatelessWidget {
BabyloniaLauncher(
@ -105,17 +106,20 @@ class _MenuState extends State<Menu> {
),
);
return Scaffold(
drawer: Drawer(
child: ListView(
children: items,
return ChangeNotifierProvider(
create: (context) => Game(),
child: Scaffold(
drawer: Drawer(
child: ListView(
children: items,
),
),
appBar: AppBar(
title: const Text("Babylonia Terminal"),
centerTitle: true,
),
body: Screens.getCurrent(_selectedIndex),
),
appBar: AppBar(
title: const Text("Babylonia Terminal"),
centerTitle: true,
),
body: Screens.getCurrent(_selectedIndex),
);
}
}

View File

@ -2,7 +2,6 @@ import 'dart:convert';
import 'dart:io';
import 'package:babylonia_terminal_launcher/models/config.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import './../providers/providers.dart';

View File

@ -0,0 +1,58 @@
import 'package:babylonia_terminal_launcher/messages/steps/game.pb.dart';
import 'package:fixnum/fixnum.dart';
import 'package:flutter/material.dart';
import './../providers/providers.dart';
enum GameInstallationState {
idle,
checkingFile,
downloading,
patching,
}
class Game with ChangeNotifier {
GameInstallationState gameInstallationState = GameInstallationState.idle;
Int64 currentProgress = Int64(0);
Int64 maxProgress = Int64(0);
Future startInstallation(GameStateProvider gameState) async {
StartGameInstallation().sendSignalToRust();
gameInstallationState = GameInstallationState.checkingFile;
notifyListeners();
//final downloadStream = NotifyGameStartDownloading.rustSignalStream;
//await for (final _ in downloadStream) {
// gameInstallationState = GameInstallationState.downloading;
// notifyListeners();
// break;
//}
final downloadProgresStream = GameInstallationProgress.rustSignalStream;
await for (final rustSignal in downloadProgresStream) {
if (gameInstallationState == GameInstallationState.checkingFile) {
gameInstallationState = GameInstallationState.downloading;
}
currentProgress = rustSignal.message.current;
maxProgress = rustSignal.message.max;
print("progress current : $currentProgress / $maxProgress");
notifyListeners();
if (currentProgress >= maxProgress) {
break;
}
}
print("patching game...");
gameInstallationState = GameInstallationState.patching;
notifyListeners();
final successStream = NotifyGameSuccessfullyInstalled.rustSignalStream;
await for (final _ in successStream) {
gameState.updateGameState();
break;
}
}
}

View File

@ -1,9 +1,11 @@
import 'package:babylonia_terminal_launcher/messages/game_state.pb.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../widgets/background_widget.dart';
import '../widgets/serious_lee_widget.dart';
import '../widgets/simple_button.dart';
import '../widgets/steps/game_steps_widget.dart';
import './../providers/providers.dart';
import './../models/settings.dart';
import './../models/background.dart';
@ -16,44 +18,41 @@ class HomeScreen extends StatelessWidget {
return Stack(
children: [
const ShowBackground(),
SizedBox(
child: Padding(
padding: const EdgeInsets.all(50.0),
child: Row(
children: [
const Expanded(
child: SizedBox(),
),
const Expanded(
child: SizedBox(),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 600,
maxHeight: 50,
),
child: SimpleButton(
onPressed: () async {
Provider.of<GameStateProvider>(context,
listen: false)
.updateGameState();
},
child: const Center(
child: Text("Download"),
Provider.of<GameStateProvider>(context).gameState !=
States.GameInstalled
? const GameSteps()
: Padding(
padding: const EdgeInsets.all(50.0),
child: Row(
children: [
const Expanded(
child: SizedBox(),
),
const Expanded(
child: SizedBox(),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 600,
maxHeight: 50,
),
child: SimpleButton(
onPressed: () async {},
child: const Center(
child: Text("Play"),
),
),
),
),
],
),
],
),
),
],
),
],
),
),
),
),
],
);
}

View File

@ -0,0 +1,145 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:yaru/yaru.dart';
import './../../models/game.dart';
import './../simple_button.dart';
import './../gtk_spinner_widget.dart';
import './../../providers/providers.dart';
class GameSteps extends StatelessWidget {
const GameSteps({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(50.0),
child: Builder(builder: (context) {
switch (Provider.of<Game>(context).gameInstallationState) {
case GameInstallationState.idle:
return const _InstallGame();
case GameInstallationState.checkingFile:
return const _CheckingFileGame();
case GameInstallationState.downloading:
return const _DownloadingGame();
case GameInstallationState.patching:
return const _PatchingGame();
}
}),
);
}
}
class _InstallGame extends StatelessWidget {
const _InstallGame({super.key});
@override
Widget build(BuildContext context) {
return Row(
children: [
const Expanded(
child: SizedBox(),
),
const Expanded(
child: SizedBox(),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 600,
maxHeight: 50,
),
child: SimpleButton(
onPressed: () async {
Provider.of<Game>(context, listen: false).startInstallation(
Provider.of<GameStateProvider>(context, listen: false),
);
},
child: const Center(
child: Text("Download"),
),
),
),
],
),
),
],
);
}
}
class _CheckingFileGame extends StatelessWidget {
const _CheckingFileGame({super.key});
@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.only(bottom: 40.0),
child: Align(
alignment: Alignment.bottomCenter,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GtkSpinner(),
Text("Checking files... (This can take a while)"),
],
),
),
);
}
}
class _DownloadingGame extends StatelessWidget {
const _DownloadingGame({super.key});
@override
Widget build(BuildContext context) {
final provider = Provider.of<Game>(context);
final pourcent =
(provider.currentProgress.toInt() / provider.maxProgress.toInt()) * 100;
final currentGb = provider.currentProgress.toInt() / 1024 / 1024 / 1024;
final maxGb = provider.maxProgress.toInt() / 1024 / 1024 / 1024;
return Padding(
padding: const EdgeInsets.only(bottom: 40.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Text(
"${currentGb.toStringAsFixed(2)} / ${maxGb.toStringAsFixed(2)} Gb (${pourcent.toStringAsFixed(2)}%)",
),
),
YaruLinearProgressIndicator(
value: pourcent / 100,
),
],
),
);
}
}
class _PatchingGame extends StatelessWidget {
const _PatchingGame({super.key});
@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.only(bottom: 40.0),
child: Align(
alignment: Alignment.bottomCenter,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GtkSpinner(),
Text("Patching game"),
],
),
),
);
}
}

View File

@ -0,0 +1,20 @@
syntax = "proto3";
package game;
// [RINF:RUST-SIGNAL]
message GameInstallationProgress {
uint64 current = 1;
uint64 max = 2;
}
// [RINF:DART-SIGNAL]
message StartGameInstallation {}
// [RINF:RUST-SIGNAL]
message NotifyGameStartDownloading {}
// [RINF:RUST-SIGNAL]
message NotifyGameStartPatching {}
// [RINF:RUST-SIGNAL]
message NotifyGameSuccessfullyInstalled {}

View File

@ -0,0 +1,103 @@
use std::thread;
use babylonia_terminal_sdk::{
components::proton_component::ProtonComponent, game_manager::GameManager, game_state::GameState,
};
use rinf::debug_print;
use tokio_with_wasm::tokio;
use crate::messages::{
error::ReportError,
steps::game::{
GameInstallationProgress, NotifyGameStartDownloading, NotifyGameStartPatching,
NotifyGameSuccessfullyInstalled, StartGameInstallation,
},
};
pub async fn listen_game_installation() {
let mut receiver = StartGameInstallation::get_dart_signal_receiver();
while let Some(_) = receiver.recv().await {
thread::spawn(move || {
debug_print!("start downloading game...");
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(async {
let game_dir = GameState::get_config().await.config_dir;
match GameManager::install_game(
game_dir.clone(),
InstallationReporter::create(),
)
.await
{
Err(e) => ReportError {
error_message: format!("Failed to install game : {}", e),
}
.send_signal_to_dart(),
Ok(_) => {
NotifyGameStartPatching {}.send_signal_to_dart();
debug_print!("start patching game...");
match GameManager::patch_game(game_dir).await {
Err(e) => ReportError {
error_message: format!("Failed to install game : {}", e),
}
.send_signal_to_dart(),
Ok(_) => NotifyGameSuccessfullyInstalled {}.send_signal_to_dart(),
}
}
}
})
});
}
}
struct DownloadReporterPrivate {
max_progress: Option<u64>,
}
struct InstallationReporter {
private: std::sync::Mutex<Option<DownloadReporterPrivate>>,
}
impl InstallationReporter {
pub fn create() -> std::sync::Arc<Self> {
std::sync::Arc::new(Self {
private: std::sync::Mutex::new(None),
})
}
}
impl downloader::progress::Reporter for InstallationReporter {
fn setup(&self, max_progress: Option<u64>, _: &str) {
let private = DownloadReporterPrivate { max_progress };
let mut guard = self.private.lock().unwrap();
*guard = Some(private);
}
fn progress(&self, current: u64) {
if let Some(p) = self.private.lock().unwrap().as_mut() {
GameInstallationProgress {
current,
max: p.max_progress.unwrap(),
}
.send_signal_to_dart();
}
}
fn set_message(&self, _: &str) {}
fn done(&self) {
if let Some(p) = self.private.lock().unwrap().as_mut() {
GameInstallationProgress {
current: p.max_progress.unwrap(),
max: p.max_progress.unwrap(),
}
.send_signal_to_dart();
}
let mut guard = self.private.lock().unwrap();
*guard = None;
}
}

View File

@ -4,6 +4,7 @@ mod config;
mod dependencies;
mod dxvk;
mod fonts;
mod game;
mod game_state;
mod github;
mod messages;
@ -25,4 +26,5 @@ async fn main() {
tokio::spawn(dxvk::listen_dxvk_installation());
tokio::spawn(fonts::listen_fonts_installation());
tokio::spawn(dependencies::listen_dependecies_installation());
tokio::spawn(game::listen_game_installation());
}