some more UI
This commit is contained in:
parent
165a9fc139
commit
4d6e23980e
53
Cargo.lock
generated
53
Cargo.lock
generated
@ -737,6 +737,12 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
@ -1433,6 +1439,16 @@ dependencies = [
|
||||
"wasi 0.14.2+wasi-0.2.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gl_generator"
|
||||
version = "0.14.0"
|
||||
@ -1774,9 +1790,24 @@ checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
"color_quant",
|
||||
"gif",
|
||||
"image-webp",
|
||||
"num-traits",
|
||||
"png",
|
||||
"tiff",
|
||||
"zune-core",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image-webp"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2727,6 +2758,12 @@ version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.30.0"
|
||||
@ -3416,6 +3453,7 @@ dependencies = [
|
||||
"egui_extras",
|
||||
"env_logger",
|
||||
"hex",
|
||||
"image",
|
||||
"keyvalues-parser",
|
||||
"log",
|
||||
"regex",
|
||||
@ -4626,6 +4664,21 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
|
||||
|
||||
[[package]]
|
||||
name = "zune-jpeg"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028"
|
||||
dependencies = [
|
||||
"zune-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "4.2.0"
|
||||
|
12
Cargo.toml
12
Cargo.toml
@ -24,6 +24,18 @@ egui-modal = { path = "./egui-modal" }
|
||||
chrono-humanize = "0.2.3"
|
||||
chrono = "0.4.40"
|
||||
egui_extras = "0.31.1"
|
||||
image = { version = "0.25.6", default-features = false, features = ["gif", "jpeg", "png", "webp", "bmp"] }
|
||||
|
||||
[workspace]
|
||||
members = ["egui-modal"]
|
||||
|
||||
[profile.special]
|
||||
inherits = "release"
|
||||
opt-level = 3
|
||||
strip = true
|
||||
lto = "fat"
|
||||
debug-assertions = false
|
||||
overflow-checks = false
|
||||
panic = "abort"
|
||||
incremental = false
|
||||
debug = false
|
||||
|
@ -15,7 +15,7 @@
|
||||
inherit overlays;
|
||||
};
|
||||
native-deps = with pkgs; [
|
||||
pkg-config pipewire lld clang libclang alsa-lib openssl zlib libxkbcommon libGL wayland mangohud
|
||||
pkg-config pipewire lld clang libclang alsa-lib openssl zlib libxkbcommon libGL wayland mangohud upx
|
||||
];
|
||||
in
|
||||
pkgs.mkShell {
|
||||
|
@ -1,16 +1,18 @@
|
||||
use std::{f32::consts::E, path::PathBuf, sync::Arc, thread, time::Duration};
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use crossbeam_channel::Receiver;
|
||||
use egui::{mutex::Mutex};
|
||||
use egui::mutex::Mutex;
|
||||
use log::{debug, info};
|
||||
|
||||
use crate::{config::{self, ConfigProvider}, omori_locator};
|
||||
use crate::{config::{self, ConfigProvider}, mod_builder::ModConfiguration, omori_locator};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum UiState {
|
||||
Loading,
|
||||
KeyRequired(String),
|
||||
PickGame(Result<PathBuf, String>, Vec<(PathBuf, u64)>),
|
||||
PickPlaytest(Vec<(PathBuf, u64)>),
|
||||
Configure(ModConfiguration),
|
||||
Error(String)
|
||||
}
|
||||
|
||||
@ -22,7 +24,8 @@ pub struct UiStateHolder {
|
||||
pub enum UiEvent {
|
||||
SetKey(Vec<u8>),
|
||||
UsePath(PathBuf),
|
||||
UseSteamPath
|
||||
UseSteamPath,
|
||||
UseConfiguration(ModConfiguration)
|
||||
}
|
||||
|
||||
pub struct AppThread {
|
||||
@ -36,9 +39,11 @@ impl AppThread {
|
||||
fn commit(&self, s: UiState) {
|
||||
let mut state = self.ui_state.state.lock();
|
||||
*state = s;
|
||||
drop(state);
|
||||
self.context.request_repaint();
|
||||
}
|
||||
|
||||
fn get_key(&mut self, reason: String) -> anyhow::Result<Vec<u8>> {
|
||||
fn get_key(&self, reason: String) -> anyhow::Result<Vec<u8>> {
|
||||
self.commit(UiState::KeyRequired(reason));
|
||||
loop {
|
||||
match self.ui_event_channel.recv()? {
|
||||
@ -51,7 +56,7 @@ impl AppThread {
|
||||
}
|
||||
}
|
||||
|
||||
fn pick_game(&mut self, provider: &mut ConfigProvider) -> anyhow::Result<PathBuf> {
|
||||
fn pick_game(&self, provider: &mut ConfigProvider) -> anyhow::Result<PathBuf> {
|
||||
let steam_location = match omori_locator::get_omori_path() {
|
||||
Ok(l) => Ok(l),
|
||||
Err(e) => Err(String::from(format!("{:#}", e)))
|
||||
@ -77,6 +82,38 @@ impl AppThread {
|
||||
}
|
||||
}
|
||||
|
||||
fn pick_playtest(&self, provider: &mut ConfigProvider) -> anyhow::Result<PathBuf> {
|
||||
let playtest_history = provider.get_playtest_paths()?;
|
||||
self.commit(UiState::PickPlaytest(playtest_history.clone()));
|
||||
|
||||
loop {
|
||||
match self.ui_event_channel.recv()? {
|
||||
UiEvent::UsePath(path) => {
|
||||
provider.set_playtest_path_used(&path)?;
|
||||
self.commit(UiState::Loading);
|
||||
return Ok(path);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_bundling(&self, provider: &mut ConfigProvider, path: &PathBuf) -> anyhow::Result<ModConfiguration> {
|
||||
let configuration = provider.get_configuration_for_playtest(path);
|
||||
self.commit(UiState::Configure(configuration));
|
||||
|
||||
loop {
|
||||
match self.ui_event_channel.recv()? {
|
||||
UiEvent::UseConfiguration(config) => {
|
||||
provider.set_configuration_for_playtest(&path, &config)?;
|
||||
self.commit(UiState::Loading);
|
||||
return Ok(config);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(state_holder: &UiStateHolder, context: &egui::Context, ui_event_channel: &Receiver<UiEvent>) -> AppThread {
|
||||
AppThread {
|
||||
ui_state: state_holder.clone(),
|
||||
@ -105,6 +142,12 @@ impl AppThread {
|
||||
let game_path = self.pick_game(&mut config_provider)?;
|
||||
info!("Will use {:?}", game_path);
|
||||
|
||||
let playtest_path = self.pick_playtest(&mut config_provider)?;
|
||||
info!("Playtest {:?}", playtest_path);
|
||||
|
||||
let config = self.configure_bundling(&mut config_provider, &playtest_path)?;
|
||||
info!("Config {:?}", config);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,34 @@
|
||||
use std::{fs::{self, File}, path::PathBuf, time::{Instant, SystemTime}};
|
||||
use std::{fs::{self, File}, path::PathBuf, time::SystemTime};
|
||||
|
||||
use anyhow::Context;
|
||||
use egui::ahash::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde;
|
||||
|
||||
use crate::{mod_builder::ModConfiguration, omori_locator};
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
struct Config {
|
||||
key: Option<Vec<u8>>,
|
||||
|
||||
#[serde(default)]
|
||||
recently_used_game_paths: HashMap<PathBuf, u64>
|
||||
recently_used_game_paths: HashMap<PathBuf, u64>,
|
||||
|
||||
#[serde(default)]
|
||||
recently_used_playtest_paths: HashMap<PathBuf, u64>,
|
||||
|
||||
#[serde(default)]
|
||||
configuration_history: HashMap<PathBuf, ModConfiguration>
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self { key: Default::default(), recently_used_game_paths: Default::default() }
|
||||
Self {
|
||||
key: Default::default(),
|
||||
recently_used_game_paths: Default::default(),
|
||||
recently_used_playtest_paths: Default::default(),
|
||||
configuration_history: Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,12 +83,61 @@ impl ConfigProvider {
|
||||
let mut paths: Vec<(&PathBuf, &u64)> = self.config.recently_used_game_paths.iter().collect();
|
||||
paths.sort_by(|a, b| a.1.cmp(b.1).reverse());
|
||||
|
||||
Ok(paths.iter().map(|v| (v.0.clone(), *v.1)).collect())
|
||||
Ok(paths
|
||||
.iter()
|
||||
.filter(|p| omori_locator::validate_omori_installation(p.0))
|
||||
.map(|v| (v.0.clone(), *v.1))
|
||||
.collect()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_game_path_used(&mut self, which: &PathBuf) -> anyhow::Result<()> {
|
||||
let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs();
|
||||
self.config.recently_used_game_paths.insert(which.clone(), current_time);
|
||||
self.config.recently_used_game_paths = self.config.recently_used_game_paths
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|p| omori_locator::validate_omori_installation(&p.0))
|
||||
.collect();
|
||||
self.commit()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_playtest_paths(&self) -> anyhow::Result<Vec<(PathBuf, u64)>> {
|
||||
let mut paths: Vec<(&PathBuf, &u64)> = self.config.recently_used_playtest_paths.iter().collect();
|
||||
paths.sort_by(|a, b| a.1.cmp(b.1).reverse());
|
||||
|
||||
Ok(paths
|
||||
.iter()
|
||||
.filter(|p| omori_locator::validate_playtest(p.0))
|
||||
.map(|v| (v.0.clone(), *v.1))
|
||||
.collect()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_playtest_path_used(&mut self, which: &PathBuf) -> anyhow::Result<()> {
|
||||
let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs();
|
||||
self.config.recently_used_playtest_paths.insert(which.clone(), current_time);
|
||||
self.config.recently_used_playtest_paths = self.config.recently_used_playtest_paths
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|p| omori_locator::validate_playtest(&p.0))
|
||||
.collect();
|
||||
self.commit()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_configuration_for_playtest(&self, which: &PathBuf) -> ModConfiguration {
|
||||
match self.config.configuration_history.get(which) {
|
||||
Some(v) => v.clone(),
|
||||
None => Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_configuration_for_playtest(&mut self, which: &PathBuf, config: &ModConfiguration) -> anyhow::Result<()> {
|
||||
self.config.configuration_history.insert(which.clone(), config.clone());
|
||||
self.commit()?;
|
||||
|
||||
Ok(())
|
||||
|
181
src/main.rs
181
src/main.rs
@ -1,16 +1,18 @@
|
||||
mod omori_locator;
|
||||
mod app_logic;
|
||||
mod config;
|
||||
mod mod_builder;
|
||||
|
||||
use std::{sync::Arc, thread, time::{Duration, SystemTime}};
|
||||
use std::{process::exit, sync::Arc, thread, time::SystemTime, default::Default};
|
||||
|
||||
use app_logic::{AppThread, UiEvent, UiState, UiStateHolder};
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use eframe::egui;
|
||||
use egui::{mutex::{Mutex, RwLock}, Align, Layout, RichText, ThemePreference};
|
||||
use egui_alignments::{center_horizontal, center_vertical, top_horizontal, Aligner};
|
||||
use egui::{mutex::Mutex, Align, Layout, RichText, TextStyle, ThemePreference};
|
||||
use egui_alignments::{center_vertical, top_horizontal};
|
||||
use egui_extras::{Column, TableBuilder};
|
||||
use egui_modal::Modal;
|
||||
use mod_builder::ModConfiguration;
|
||||
use sha2::Digest;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
@ -30,6 +32,7 @@ fn main() -> anyhow::Result<()> {
|
||||
viewport: egui::ViewportBuilder::default()
|
||||
.with_min_inner_size([640.0, 480.0]),
|
||||
..Default::default()
|
||||
|
||||
};
|
||||
|
||||
let app_state = UiStateHolder {
|
||||
@ -60,7 +63,9 @@ fn main() -> anyhow::Result<()> {
|
||||
struct Application {
|
||||
state: UiStateHolder,
|
||||
sender: Sender<UiEvent>,
|
||||
key_input: String
|
||||
key_input: String,
|
||||
configuration: ModConfiguration,
|
||||
did_fill_configuration: bool
|
||||
}
|
||||
|
||||
impl Application {
|
||||
@ -68,7 +73,9 @@ impl Application {
|
||||
Application {
|
||||
sender,
|
||||
state,
|
||||
key_input: "".to_string()
|
||||
key_input: "".to_string(),
|
||||
configuration: Default::default(),
|
||||
did_fill_configuration: false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,10 +83,15 @@ impl Application {
|
||||
const GAME_KEY_HASH: &[u8; 32] = include_bytes!("keyhash");
|
||||
|
||||
impl eframe::App for Application {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {
|
||||
exit(0); // TODO: Prompt the user to maybe please consider not actually exiting the app while it's working
|
||||
}
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
let state = self.state.state.lock();
|
||||
let state = state.clone();
|
||||
|
||||
ctx.request_repaint_after_secs(10.0);
|
||||
|
||||
match state {
|
||||
UiState::Loading => {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
@ -154,7 +166,7 @@ impl eframe::App for Application {
|
||||
invalid_path_modal.button(ui, "OK");
|
||||
});
|
||||
});
|
||||
egui::TopBottomPanel::top("key_prompt_title_bar").show(ctx, |ui| {
|
||||
egui::TopBottomPanel::top("game_prompt_title_bar").show(ctx, |ui| {
|
||||
ui.with_layout(Layout::top_down(Align::Center), |ui| {
|
||||
ui.label(RichText::new("Select your base game").size(32.0));
|
||||
});
|
||||
@ -200,7 +212,8 @@ impl eframe::App for Application {
|
||||
TableBuilder::new(ui)
|
||||
.striped(true)
|
||||
.column(Column::remainder())
|
||||
.column(Column::auto())
|
||||
.column(Column::auto().at_least(100.0))
|
||||
.sense(egui::Sense::hover() | egui::Sense::click())
|
||||
.body(|body| {
|
||||
body.rows(20.0, others.len(), |mut row| {
|
||||
let item = &others[row.index()];
|
||||
@ -211,13 +224,26 @@ impl eframe::App for Application {
|
||||
let dt = chrono::Duration::from(chrono::TimeDelta::seconds(dt as i64));
|
||||
|
||||
row.col(|ui| {
|
||||
ui.with_layout(Layout::right_to_left(Align::Center).with_main_align(Align::Min).with_main_justify(true), |ui| {
|
||||
ui.label(format!("{}", item.0.display()));
|
||||
});
|
||||
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.with_layout(Layout::right_to_left(Align::Center).with_main_align(Align::Max), |ui| {
|
||||
ui.label(format!("{}", chrono_humanize::HumanTime::from(dt)));
|
||||
});
|
||||
});
|
||||
if row.response().clicked() {
|
||||
if omori_locator::validate_omori_installation(&item.0) {
|
||||
self.sender.send(UiEvent::UsePath(item.0.clone())).expect("Failed to send");
|
||||
} else {
|
||||
invalid_path_modal.open();
|
||||
}
|
||||
}
|
||||
if row.response().hovered() {
|
||||
ctx.set_cursor_icon(egui::CursorIcon::PointingHand);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
@ -226,7 +252,144 @@ impl eframe::App for Application {
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
UiState::PickPlaytest(playtest_history) => {
|
||||
let invalid_path_modal = Modal::new(ctx, "invalid_playtest_modal");
|
||||
invalid_path_modal.show(|ui| {
|
||||
invalid_path_modal.title(ui, "Invalid path");
|
||||
invalid_path_modal.frame(ui, |ui| {
|
||||
invalid_path_modal.body(ui, "Please pick a valid, Oneloader-generated playtest.");
|
||||
});
|
||||
invalid_path_modal.buttons(ui, |ui| {
|
||||
invalid_path_modal.button(ui, "OK");
|
||||
});
|
||||
});
|
||||
egui::TopBottomPanel::top("playtest_prompt_title_bar").show(ctx, |ui| {
|
||||
ui.with_layout(Layout::top_down(Align::Center), |ui| {
|
||||
ui.label(RichText::new("Select your playtest").size(32.0));
|
||||
});
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.with_layout(Layout::right_to_left(Align::Min).with_main_justify(true).with_main_align(Align::Center), |ui| {
|
||||
if ui.button(RichText::new("Pick playtest").size(16.0)).clicked() {
|
||||
match rfd::FileDialog::new().pick_folder() {
|
||||
Some(path) => {
|
||||
if omori_locator::validate_playtest(&path) {
|
||||
self.sender.send(UiEvent::UsePath(path)).expect("Failed to send");
|
||||
} else {
|
||||
invalid_path_modal.open();
|
||||
}
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if playtest_history.len() > 0 {
|
||||
ui.label("History of playtests");
|
||||
ui.separator();
|
||||
TableBuilder::new(ui)
|
||||
.striped(true)
|
||||
.column(Column::remainder())
|
||||
.column(Column::auto().at_least(100.0))
|
||||
.sense(egui::Sense::hover() | egui::Sense::click())
|
||||
.body(|body| {
|
||||
body.rows(20.0, playtest_history.len(), |mut row| {
|
||||
let item = &playtest_history[row.index()];
|
||||
let dt =
|
||||
(item.1 as i64) -
|
||||
(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).expect("Failed to get the time").as_secs() as i64);
|
||||
|
||||
let dt = chrono::Duration::from(chrono::TimeDelta::seconds(dt as i64));
|
||||
|
||||
row.col(|ui| {
|
||||
ui.with_layout(Layout::right_to_left(Align::Center).with_main_align(Align::Min).with_main_justify(true), |ui| {
|
||||
ui.label(format!("{}", item.0.display()));
|
||||
});
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.with_layout(Layout::right_to_left(Align::Center).with_main_align(Align::Max), |ui| {
|
||||
ui.label(format!("{}", chrono_humanize::HumanTime::from(dt)));
|
||||
});
|
||||
});
|
||||
if row.response().clicked() {
|
||||
if omori_locator::validate_playtest(&item.0) {
|
||||
self.sender.send(UiEvent::UsePath(item.0.clone())).expect("Failed to send");
|
||||
} else {
|
||||
invalid_path_modal.open();
|
||||
}
|
||||
}
|
||||
if row.response().hovered() {
|
||||
ctx.set_cursor_icon(egui::CursorIcon::PointingHand);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
ui.label("Any playtests you've used before will be remembered here.");
|
||||
}
|
||||
});
|
||||
},
|
||||
UiState::Configure(initial_configuration) => {
|
||||
if !self.did_fill_configuration {
|
||||
self.did_fill_configuration = true;
|
||||
self.configuration = initial_configuration;
|
||||
}
|
||||
|
||||
let mut font = TextStyle::Body.resolve(&ctx.style());
|
||||
font.size = 16.0;
|
||||
|
||||
egui::TopBottomPanel::top("configure_title_bar").show(ctx, |ui| {
|
||||
ui.with_layout(Layout::top_down(Align::Center), |ui| {
|
||||
ui.label(RichText::new("Configure your mod").size(32.0));
|
||||
});
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
top_horizontal(ui, |ui| {
|
||||
TableBuilder::new(ui)
|
||||
.column(Column::auto().at_least(100.0))
|
||||
.column(Column::exact(300.0))
|
||||
.body(|mut body| {
|
||||
body.row(24.0, |mut row| {
|
||||
row.col(|ui| {
|
||||
ui.label(RichText::new("Mod ID").size(16.0));
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.add(egui::TextEdit::singleline(&mut self.configuration.mod_id).font(font.clone()));
|
||||
});
|
||||
});
|
||||
body.row(24.0, |mut row| {
|
||||
row.col(|ui| {
|
||||
ui.label(RichText::new("Mod Name").size(16.0));
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.add(egui::TextEdit::singleline(&mut self.configuration.mod_name).font(font.clone()));
|
||||
});
|
||||
});
|
||||
body.row(24.0, |mut row| {
|
||||
row.col(|ui| {
|
||||
ui.label(RichText::new("Mod Description").size(16.0));
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.add(egui::TextEdit::singleline(&mut self.configuration.mod_description).font(font.clone()));
|
||||
});
|
||||
});
|
||||
body.row(24.0, |mut row| {
|
||||
row.col(|ui| {
|
||||
ui.label(RichText::new("Mod Version").size(16.0));
|
||||
});
|
||||
row.col(|ui| {
|
||||
ui.add(egui::TextEdit::singleline(&mut self.configuration.mod_version).font(font.clone()));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
19
src/mod_builder.rs
Normal file
19
src/mod_builder.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct ModConfiguration {
|
||||
pub mod_id: String,
|
||||
pub mod_name: String,
|
||||
pub mod_description: String,
|
||||
pub mod_version: String,
|
||||
|
||||
pub include_audio: bool,
|
||||
pub include_data: bool,
|
||||
pub include_fonts: bool,
|
||||
pub include_icon: bool,
|
||||
pub include_img: bool,
|
||||
pub include_plugins: bool,
|
||||
pub include_languages: bool,
|
||||
pub include_maps: bool,
|
||||
pub include_movies: bool
|
||||
}
|
@ -144,7 +144,7 @@ pub fn get_omori_key() -> anyhow::Result<Vec<u8>> {
|
||||
}
|
||||
|
||||
|
||||
const EXPECTED_PATHS: [&str; 32] = [
|
||||
const EXPECTED_PATHS_BASE: [&str; 32] = [
|
||||
"index.html",
|
||||
"editor.json",
|
||||
"audio/bgm/AMB_forest.rpgmvo",
|
||||
@ -181,7 +181,43 @@ const EXPECTED_PATHS: [&str; 32] = [
|
||||
|
||||
pub fn validate_omori_installation(base: &PathBuf) -> bool {
|
||||
info!("Validating {:?}", base);
|
||||
for path in EXPECTED_PATHS {
|
||||
for path in EXPECTED_PATHS_BASE {
|
||||
trace!("Checking {path}");
|
||||
let mut real = base.clone();
|
||||
real.push(path);
|
||||
|
||||
if let Ok(r) = fs::exists(&real) {
|
||||
if !r { return false; }
|
||||
} else { return false; }
|
||||
}
|
||||
info!("Validation passed");
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
const EXPECTED_PATHS_PLAYTEST: [&str; 17] = [
|
||||
"index.html",
|
||||
"Game.rpgproject",
|
||||
"img",
|
||||
"img/pictures",
|
||||
"audio",
|
||||
"audio/bgm",
|
||||
"js",
|
||||
"languages",
|
||||
"js/plugins",
|
||||
"js/plugins/Omori BASE.js",
|
||||
"package.json",
|
||||
"data/Actors.json",
|
||||
"data/System.json",
|
||||
"data/Atlas.yaml",
|
||||
"data/Troops.json",
|
||||
"img/system/Window.png",
|
||||
"img/atlases/battleATLAS.png",
|
||||
];
|
||||
|
||||
pub fn validate_playtest(base: &PathBuf) -> bool {
|
||||
info!("Validating {:?}", base);
|
||||
for path in EXPECTED_PATHS_PLAYTEST {
|
||||
trace!("Checking {path}");
|
||||
let mut real = base.clone();
|
||||
real.push(path);
|
||||
|
Loading…
x
Reference in New Issue
Block a user