From 74cce227a5736796d699c407e0bcdff8ffd480bd Mon Sep 17 00:00:00 2001 From: Aubrey Taylor Date: Sun, 26 Jan 2025 02:34:55 -0600 Subject: [PATCH] start supporting mof properly --- extract.nu | 24 +++++++++++++++++++----- macros/Cargo.toml | 2 +- src/anm_viewer.rs | 2 +- src/game/anm/loaded_file.rs | 20 ++++++++++++++------ src/game/anm/manager/loading.rs | 10 ++++++++-- src/game/anm/manager/rendering.rs | 9 ++++++--- src/game/anm/vm/mod.rs | 4 ++-- src/game/enemy/loaded_file.rs | 16 ++++++++++------ src/game/mod.rs | 16 ++++++++++++---- src/game/snd/bgm/mod.rs | 12 ++++++++---- src/game/snd/mod.rs | 24 ++++++++++++++++-------- src/game/states/gameplay/mod.rs | 17 ++++++++++++----- src/game/states/loading.rs | 12 +++++++----- src/game/states/mod.rs | 6 +++--- src/game/states/title.rs | 21 ++++++++++++++------- src/utils/game.rs | 20 ++++++++++++++++++++ src/utils/mod.rs | 1 + todos.md | 3 +++ 18 files changed, 157 insertions(+), 62 deletions(-) create mode 100644 src/utils/game.rs create mode 100644 todos.md diff --git a/extract.nu b/extract.nu index c60bf79..a6259ab 100644 --- a/extract.nu +++ b/extract.nu @@ -1,14 +1,28 @@ -def main [thdat: path, version: int] { +def main [game_folder: path, version: int] { let game = if $version == 10 { - "mof" + { folder: "mof", version: $version } } else if $version == 11 { - "sa" + { folder: "sa", version: $version } } else { return (error make {msg: "version not supported", label: { text: "expected 10 or 11", span: (metadata $version).span } }) exit 1 } - thdat -C $"assets/($game)" -x $version $thdat + let assets = $"assets/($game.folder)" + let thver = $"th($game.version)" + thdat -C $assets -x $version $"($game_folder)/($thver).dat" + try { + ln -s $"($game_folder)/thbgm.dat" $"($assets)/thbgm.dat" + } catch { } - + let research = $"research/dump/($game.folder)" + let replt = {|ext| str replace $ext $"t($ext)"}; + let dump = {|ext| + ls $assets | get name | where {str ends-with $".($ext)"} | each {path basename} + | each {|name| run-external $"tru($ext)" "decompile" "-g" $game.version $"($assets)/($name)" "-m" $"utils/($thver).($ext)m" | save -f $"($research)/($name | do $replt $ext)"} + }; + + do $dump "anm" + do $dump "ecl" + do $dump "std" } diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 683f3e6..d32ef86 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -9,4 +9,4 @@ proc-macro = true proc-macro2 = "1.0.86" quote = "1.0.36" syn = "2.0.72" -truth = { git = "https://github.com/ExpHP/truth", version = "0.5.2" } +truth = { git = "https://github.com/ExpHP/truth" } diff --git a/src/anm_viewer.rs b/src/anm_viewer.rs index 21cacf1..94cb9ce 100644 --- a/src/anm_viewer.rs +++ b/src/anm_viewer.rs @@ -103,7 +103,7 @@ impl AnmViewer { &mut BinReader::from_reader( &RootEmitter::new_stderr(), "", - Cursor::new(read("assets/title.anm").unwrap()), + // Cursor::new(read("assets/title.anm").unwrap()), ), Game::Th11, true, diff --git a/src/game/anm/loaded_file.rs b/src/game/anm/loaded_file.rs index 5020591..9e7b25a 100644 --- a/src/game/anm/loaded_file.rs +++ b/src/game/anm/loaded_file.rs @@ -4,14 +4,19 @@ use async_std::fs; use bytemuck::{Pod, Zeroable}; use glam::Vec2; use nonoverlapping_interval_tree::NonOverlappingIntervalTree; -use truth::{context::RootEmitter, io::BinReader, AnmFile, Game}; +use truth::{context::RootEmitter, io::BinReader, AnmFile, Game as TruthGame}; use wgpu::{ - naga::FastHashMap, util::DeviceExt, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry, Device, Extent3d, Queue, ShaderStages, Texture, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages + naga::FastHashMap, util::DeviceExt, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, + BindGroupLayoutEntry, Device, Extent3d, Queue, ShaderStages, Texture, TextureDescriptor, TextureDimension, + TextureFormat, TextureUsages, }; use winit::dpi::PhysicalSize; +use crate::utils::game::Game; + use super::{ - image::{produce_image_from_entry, Image}, vm::opcodes::{Instruction, Op} + image::{produce_image_from_entry, Image}, + vm::opcodes::{Instruction, Op}, }; pub struct LoadedEntry { @@ -199,12 +204,15 @@ pub struct LoadedFile { } impl LoadedFile { - pub async fn load(device: &Device, queue: &Queue, size: PhysicalSize, file_name: &str) -> Self { - let file_data = fs::read(Path::new("./assets").join(file_name)).await.expect("failed to load anm file"); + pub async fn load(device: &Device, queue: &Queue, size: PhysicalSize, game: Game, file_name: &str) -> Self { + let file_data = fs::read(game.asset_path(file_name)).await.expect("failed to load anm file"); let file = AnmFile::read_from_stream( &mut BinReader::from_reader(&RootEmitter::new_stderr(), file_name, Cursor::new(file_data)), - Game::Th11, + match game { + Game::Mof => TruthGame::Th10, + Game::Sa => TruthGame::Th11, + }, true, ) .unwrap(); diff --git a/src/game/anm/manager/loading.rs b/src/game/anm/manager/loading.rs index 99f52a7..a8f243f 100644 --- a/src/game/anm/manager/loading.rs +++ b/src/game/anm/manager/loading.rs @@ -3,7 +3,10 @@ use std::sync::Arc; use wgpu::{Device, Queue}; use winit::{dpi::PhysicalSize, window::Window}; -use crate::{game::anm::LoadedFile, utils::soon::Soon}; +use crate::{ + game::anm::LoadedFile, + utils::{game::Game, soon::Soon}, +}; use super::Manager; @@ -13,6 +16,7 @@ impl Manager { device: Arc, queue: Arc, size: PhysicalSize, + game: Game, file_name: impl Into, ) -> Soon> { let file_name: String = file_name.into(); @@ -22,7 +26,7 @@ impl Manager { let sender = self.anm_sender.clone(); Soon::new(async move { - let file = Arc::new(LoadedFile::load(&device, &queue, size, &file_name).await); + let file = Arc::new(LoadedFile::load(&device, &queue, size, game, &file_name).await); sender.send((file_name, file.clone())).unwrap(); @@ -41,6 +45,7 @@ impl Manager { device: &Device, queue: &Queue, window: &Window, + game: Game, file_name: impl Into, ) -> Arc { let file_name = file_name.into(); @@ -52,6 +57,7 @@ impl Manager { device, queue, window.inner_size(), + game, &file_name, ))); diff --git a/src/game/anm/manager/rendering.rs b/src/game/anm/manager/rendering.rs index 7be7340..c0611c9 100644 --- a/src/game/anm/manager/rendering.rs +++ b/src/game/anm/manager/rendering.rs @@ -375,9 +375,12 @@ impl Manager { resolve_target: None, ops: Operations { // load: LoadOp::Clear(Color { - // r: 100. / 255., - // g: 149. / 255., - // b: 237. / 255., + // // r: 100. / 255., + // // g: 149. / 255., + // // b: 237. / 255., + // r: 1.0, + // g: 1.0, + // b: 1.0, // a: 1.0, // }), load: LoadOp::Load, diff --git a/src/game/anm/vm/mod.rs b/src/game/anm/vm/mod.rs index 67d66f6..79bc84e 100644 --- a/src/game/anm/vm/mod.rs +++ b/src/game/anm/vm/mod.rs @@ -204,7 +204,7 @@ impl AnmVm { dst_factor: BlendFactor::OneMinusSrcAlpha, operation: BlendOperation::Add, }, - alpha: BlendComponent::REPLACE, + alpha: BlendComponent::OVER, }, 1 => BlendState { // additive blending @@ -213,7 +213,7 @@ impl AnmVm { dst_factor: BlendFactor::OneMinusSrcAlpha, operation: BlendOperation::Add, }, - alpha: BlendComponent::REPLACE, + alpha: BlendComponent::OVER, }, 3 => BlendState { color: BlendComponent::REPLACE, diff --git a/src/game/enemy/loaded_file.rs b/src/game/enemy/loaded_file.rs index d510a55..ccfa3a5 100644 --- a/src/game/enemy/loaded_file.rs +++ b/src/game/enemy/loaded_file.rs @@ -2,11 +2,11 @@ use std::{io::Cursor, path::Path, sync::Arc}; use async_std::fs; use futures::future::{join3, join_all}; -use truth::{context::RootEmitter, io::BinReader, Game, StackEclFile}; +use truth::{context::RootEmitter, io::BinReader, Game as TruthGame, StackEclFile}; use wgpu::{naga::FastHashMap, Device, Queue}; use winit::dpi::PhysicalSize; -use crate::game::anm; +use crate::{game::anm, utils::game::Game}; use super::vm::opcodes::Instruction; @@ -21,23 +21,27 @@ impl LoadedFile { device: Arc, queue: Arc, size: PhysicalSize, + game: Game, file_name: impl Into + Send, ) -> LoadedFile { let file_name = file_name.into(); - let file_data = fs::read(Path::new("./assets").join(&file_name)).await.expect("failed to load anm file"); + let file_data = fs::read(game.asset_path(&file_name)).await.expect("failed to load anm file"); let file = StackEclFile::read_from_stream( &mut BinReader::from_reader(&RootEmitter::new_stderr(), &file_name, Cursor::new(file_data)), - Game::Th11, + match game { + Game::Mof => TruthGame::Th10, + Game::Sa => TruthGame::Th11, + }, ) .unwrap(); let anm_files = join_all(file.anim_list.into_iter().map(|sp| sp.value).map(|anm| { let (device, queue) = (device.clone(), queue.clone()); - async move { anm::LoadedFile::load(&device, &queue, size, &anm).await } + async move { anm::LoadedFile::load(&device, &queue, size, game, &anm).await } })); let ecl_files = join_all(file.ecli_list.into_iter().map(|sp| sp.value).map(|ecl| { let (device, queue) = (device.clone(), queue.clone()); - async move { LoadedFile::load(device, queue, size, ecl).await } + async move { LoadedFile::load(device, queue, size, game, ecl).await } })); let subs = file.subs.into_iter().map(|(k, v)| (k.value, v)).collect::>(); diff --git a/src/game/mod.rs b/src/game/mod.rs index d076eed..5bb72e6 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -4,7 +4,8 @@ use anm::LoadedFile; use states::GameStateMachine; use crate::{ - engine::{EngineState, UpdateContext}, utils::soon::Soon + engine::{EngineState, UpdateContext}, + utils::{game::Game, soon::Soon}, }; mod anm; @@ -27,17 +28,24 @@ struct GameContext<'a> { } impl GameContext<'_> { - pub fn start_load_anm(&mut self, file_name: impl Into) -> Soon> { + pub fn start_load_anm(&mut self, game: Game, file_name: impl Into) -> Soon> { self.anm_manager.start_load_anm( self.engine.device.clone(), self.engine.queue.clone(), self.engine.window.inner_size(), + game, file_name, ) } - pub fn load_anm(&mut self, file_name: impl Into) -> Arc { - self.anm_manager.load_anm(&self.engine.device, &self.engine.queue, &self.engine.window, file_name) + pub fn load_anm(&mut self, game: Game, file_name: impl Into) -> Arc { + self.anm_manager.load_anm( + &self.engine.device, + &self.engine.queue, + &self.engine.window, + game, + file_name, + ) } } diff --git a/src/game/snd/bgm/mod.rs b/src/game/snd/bgm/mod.rs index 503c916..25229d3 100644 --- a/src/game/snd/bgm/mod.rs +++ b/src/game/snd/bgm/mod.rs @@ -1,19 +1,23 @@ +use std::{rc::Rc, sync::Arc}; + use async_std::fs::read; use format::BgmFormat; use rodio::{static_buffer::StaticSamplesBuffer, Sink, Source}; +use crate::utils::game::Game; + pub mod format; pub struct BgmManager { bgm_format: BgmFormat, bgm_file: &'static [u8], - music_sink: Sink, + music_sink: Arc, } impl BgmManager { - pub(super) async fn new(music_sink: Sink) -> BgmManager { - let bgm_format = BgmFormat::new(read("assets/thbgm.fmt").await.unwrap()); - let bgm_file = read("./thbgm.dat").await.unwrap(); + pub(super) async fn new(music_sink: Arc, game: Game) -> BgmManager { + let bgm_format = BgmFormat::new(read(game.asset_path("thbgm.fmt")).await.unwrap()); + let bgm_file = read(game.asset_path("thbgm.dat")).await.unwrap(); music_sink.set_volume(0.1); Self { diff --git a/src/game/snd/mod.rs b/src/game/snd/mod.rs index df502eb..76d63cd 100644 --- a/src/game/snd/mod.rs +++ b/src/game/snd/mod.rs @@ -2,15 +2,17 @@ use std::sync::Arc; use bgm::BgmManager; use rodio::{ - dynamic_mixer::{mixer, DynamicMixerController}, OutputStream, Sink + dynamic_mixer::{mixer, DynamicMixerController}, + OutputStream, Sink, }; -use crate::utils::soon::Soon; +use crate::utils::{game::Game, soon::Soon}; pub mod bgm; pub struct Manager { - bgm_manager: Soon, + bgm_manager_mof: Soon, + bgm_manager_sa: Soon, _output_stream: OutputStream, _sound_sink: Sink, _sound_controller: Arc>, @@ -20,12 +22,13 @@ impl Manager { pub fn new() -> Self { let (output_stream, stream_handle) = OutputStream::try_default().unwrap(); let sound_sink = Sink::try_new(&stream_handle).unwrap(); - let music_sink = Sink::try_new(&stream_handle).unwrap(); + let music_sink = Arc::new(Sink::try_new(&stream_handle).unwrap()); let (sound_controller, mixer) = mixer::(2, 44100); sound_sink.append(mixer); Self { - bgm_manager: Soon::new(BgmManager::new(music_sink)), + bgm_manager_mof: Soon::new(BgmManager::new(music_sink.clone(), Game::Mof)), + bgm_manager_sa: Soon::new(BgmManager::new(music_sink, Game::Sa)), _output_stream: output_stream, _sound_sink: sound_sink, _sound_controller: sound_controller, @@ -33,10 +36,15 @@ impl Manager { } pub fn is_bgm_manager_loaded(&mut self) -> bool { - self.bgm_manager.is_done() + self.bgm_manager_mof.is_done() && self.bgm_manager_sa.is_done() } - pub fn get_bgm_manager(&mut self) -> &mut BgmManager { - self.bgm_manager.try_borrow_mut().unwrap() + pub fn get_bgm_manager(&mut self, game: Game) -> &mut BgmManager { + match game { + Game::Mof => &mut self.bgm_manager_mof, + Game::Sa => &mut self.bgm_manager_sa, + } + .try_borrow_mut() + .unwrap() } } diff --git a/src/game/states/gameplay/mod.rs b/src/game/states/gameplay/mod.rs index 00a3cdd..6b7081c 100644 --- a/src/game/states/gameplay/mod.rs +++ b/src/game/states/gameplay/mod.rs @@ -1,15 +1,22 @@ use async_std::task::{block_on, spawn}; use sfsm::State; -use crate::game::{enemy::loaded_file::LoadedFile, GameContext}; +use crate::{ + game::{enemy::loaded_file::LoadedFile, GameContext}, + utils::game::Game, +}; -pub struct Gameplay { - -} +pub struct Gameplay {} impl Gameplay { pub fn new(context: &GameContext) -> Self { - block_on(LoadedFile::load(context.engine.device.clone(), context.engine.queue.clone(), context.engine.window.inner_size(), "default.ecl")); + block_on(LoadedFile::load( + context.engine.device.clone(), + context.engine.queue.clone(), + context.engine.window.inner_size(), + Game::Sa, + "default.ecl", + )); Self {} } } diff --git a/src/game/states/loading.rs b/src/game/states/loading.rs index e64b530..3e99e34 100644 --- a/src/game/states/loading.rs +++ b/src/game/states/loading.rs @@ -5,8 +5,10 @@ use sfsm::{State, TransitGuard, Transition}; use crate::{ game::{ - anm::{LoadedFile, Vm, VmLocation}, GameContext - }, utils::soon::Soon + anm::{LoadedFile, Vm, VmLocation}, + GameContext, + }, + utils::{game::Game, soon::Soon}, }; use super::{title::TitleScreen, UPDATE_CONTEXT}; @@ -20,8 +22,8 @@ pub struct Loading { impl Loading { pub fn new(context: &mut GameContext) -> Loading { - let ascii = context.load_anm("ascii.anm"); - let sig_anm = context.load_anm("sig.anm"); + let ascii = context.load_anm(Game::Sa, "ascii.anm"); + let sig_anm = context.load_anm(Game::Sa, "sig.anm"); let sig = context.anm_manager.new_vm(sig_anm, None, 0, VmLocation::new_ui()); let ascii_loading = context.anm_manager.new_vm(ascii.clone(), None, 16, VmLocation::new_ui()); ascii_loading.borrow_mut().origin = Vec3::new(480.0, 392.0, 0.0); @@ -30,7 +32,7 @@ impl Loading { _sig: sig, _ascii_loading: ascii_loading, - title_anm: context.start_load_anm("title.anm").into(), + title_anm: context.start_load_anm(Game::Sa, "title.anm").into(), } } } diff --git a/src/game/states/mod.rs b/src/game/states/mod.rs index bc3155f..143f30d 100644 --- a/src/game/states/mod.rs +++ b/src/game/states/mod.rs @@ -13,7 +13,7 @@ use super::GameContext; pub(super) static UPDATE_CONTEXT: ContextMut = ContextMut::new(); -add_state_machine!(Machine, Gameplay, {Loading, TitleScreen, Gameplay}, { +add_state_machine!(Machine, Loading, {Loading, TitleScreen, Gameplay}, { Loading => TitleScreen, TitleScreen => TitleScreen }); @@ -25,8 +25,8 @@ impl GameStateMachine { UPDATE_CONTEXT.scoped(context, || { let mut machine = GameStateMachine(Machine::new()); - // UPDATE_CONTEXT.with(|context| machine.0.start(Loading::new(context))).unwrap(); - UPDATE_CONTEXT.with(|context| machine.0.start(Gameplay::new(context))).unwrap(); + UPDATE_CONTEXT.with(|context| machine.0.start(Loading::new(context))).unwrap(); + // UPDATE_CONTEXT.with(|context| machine.0.start(Gameplay::new(context))).unwrap(); machine }) diff --git a/src/game/states/title.rs b/src/game/states/title.rs index f19f2cb..f2b8d17 100644 --- a/src/game/states/title.rs +++ b/src/game/states/title.rs @@ -1,8 +1,12 @@ use sfsm::{State, TransitGuard, Transition}; use winit::keyboard::KeyCode; -use crate::game::{ - anm::{Vm, VmLocation}, GameContext +use crate::{ + game::{ + anm::{Vm, VmLocation}, + GameContext, + }, + utils::game::Game, }; use super::{loading::Loading, UPDATE_CONTEXT}; @@ -13,12 +17,14 @@ pub struct TitleScreen { } impl TitleScreen { - fn new(context: &mut GameContext, from_startup: bool) -> Self { - let title = context.load_anm("title.anm"); + fn new(context: &mut GameContext, _: bool) -> Self { + let title = context.load_anm(Game::Mof, "title.anm"); // 79, 83 - let splash = context.anm_manager.new_vm(title.clone(), Some(8), 79, VmLocation::new_ui()); - let logo = context.anm_manager.new_vm(title.clone(), Some(8), 83, VmLocation::new_ui()); + // let splash = context.anm_manager.new_vm(title.clone(), Some(8), 79, VmLocation::new_ui()); + // let logo = context.anm_manager.new_vm(title.clone(), Some(8), 83, VmLocation::new_ui()); + let splash = context.anm_manager.new_vm(title.clone(), Some(8), 88, VmLocation::new_ui()); + let logo = context.anm_manager.new_vm(title.clone(), Some(8), 90, VmLocation::new_ui()); Self { _logo: logo, @@ -40,7 +46,8 @@ impl State for TitleScreen { impl From for TitleScreen { fn from(_: Loading) -> Self { UPDATE_CONTEXT.with(|context| { - context.sound_manager.get_bgm_manager().play_track("th11_00.wav"); + context.sound_manager.get_bgm_manager(Game::Mof).play_track("th10_02.wav"); + // context.sound_manager.get_bgm_manager_sa().play_track("th11_00.wav"); TitleScreen::new(context, true) }) } diff --git a/src/utils/game.rs b/src/utils/game.rs new file mode 100644 index 0000000..dd9cee5 --- /dev/null +++ b/src/utils/game.rs @@ -0,0 +1,20 @@ +use std::path::{Path, PathBuf}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Game { + Mof, + Sa, +} + +impl Game { + fn asset_path_str(&self) -> &'static str { + match self { + Game::Mof => "./assets/mof", + Game::Sa => "./assets/sa", + } + } + + pub fn asset_path>(&self, path: P) -> PathBuf { + Path::new(self.asset_path_str()).join(path) + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 289ab50..529531b 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,2 +1,3 @@ pub mod context; pub mod soon; +pub mod game; diff --git a/todos.md b/todos.md new file mode 100644 index 0000000..6a62c28 --- /dev/null +++ b/todos.md @@ -0,0 +1,3 @@ +- why does the loading screen's blend mode look fucked again? did i not finish fixing that last time i worked on it? +- poke around truth, rerun extract on mof to see warnings, low priority +- start mof title screen