1use crate::prelude::*;
11use alloc::collections::BTreeMap;
12use core::fmt::Debug;
13
14use shuyi_assets::ContentError;
15use shuyi_assets::audio::AudioManifest;
16use shuyi_assets::bundle::Bundle;
17use shuyi_assets::font::{FontAtlasDef, FontAtlasRon};
18use shuyi_assets::format::Formats;
19use shuyi_assets::image::ImageTable;
20use shuyi_assets::keymap::{ActionSet, KeymapDef, KeymapRon};
21use shuyi_assets::lang::{English, Lang};
22use shuyi_assets::palette::{PaletteDef, PaletteRon};
23use shuyi_assets::ron::Ron;
24
25use crate::ctx::GameData;
26use crate::frame::{ConsoleSpec, EngineColor};
27use crate::text::check_key_placeholders;
28
29pub const ENGLISH_RON: &str = "en.ron";
31pub const KEYMAP_RON: &str = "keymap.ron";
33pub const PALETTE_RON: &str = "palette.ron";
35pub const FONT_RON: &str = "font/atlas.ron";
37pub const FONT_PNG: &str = "font/atlas.png";
39
40pub const BASIC_GLYPHS: &str = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~·…─│┌┐└┘├┤┬┴┼═║╔╗╚╝▓▲▼◄►";
43
44pub type Own<T> = fn(&Bundle) -> Result<T, Vec<ContentError>>;
47
48#[derive(Debug)]
52pub struct BasicData<A: ActionSet, T: Debug + 'static = ()> {
53 lang: Lang,
54 keymap: KeymapDef<A>,
55 audio: AudioManifest,
56 palette: PaletteDef,
57 console: ConsoleSpec,
58 pub font: FontAtlasDef,
60 pub images: ImageTable,
62 pub bundle: Bundle,
64 pub own: T,
66}
67
68fn gather<T>(errors: &mut Vec<ContentError>, loaded: Result<T, Vec<ContentError>>) -> Option<T> {
70 loaded.map_err(|e| errors.extend(e)).ok()
71}
72
73impl<A: ActionSet, T: Debug + 'static> BasicData<A, T> {
74 pub fn formats() -> Formats {
78 let mut formats = Formats::standard();
79 let colors: Vec<&str> = EngineColor::ALL.iter().map(|c| c.name()).collect();
80 let _ = formats.replace(PaletteRon::requiring(colors));
83 let _ = formats.replace(FontAtlasRon::requiring(BASIC_GLYPHS));
84 let _ = formats.register(KeymapRon::<A>::new());
85 let _ = formats.register(Ron::<English>::new());
86 formats
87 }
88
89 pub fn load(
93 bundle: Bundle,
94 console: ConsoleSpec,
95 own: Own<T>,
96 ) -> Result<Self, Vec<ContentError>> {
97 let formats = Self::formats();
98 let mut errors = Vec::new();
99 let english = gather(
100 &mut errors,
101 formats
102 .load::<English>(&bundle, ENGLISH_RON)
103 .and_then(|english| {
104 check_key_placeholders::<A>(&bundle, ENGLISH_RON, &english.0).map(|()| english)
105 }),
106 );
107 let keymap = gather(
108 &mut errors,
109 formats.load::<KeymapDef<A>>(&bundle, KEYMAP_RON),
110 );
111 let palette = gather(
112 &mut errors,
113 formats.load::<PaletteDef>(&bundle, PALETTE_RON),
114 );
115 let font = gather(&mut errors, formats.load::<FontAtlasDef>(&bundle, FONT_RON));
116 let images = gather(
117 &mut errors,
118 ImageTable::load_with(&bundle, &formats, &[FONT_PNG]),
119 );
120 let own = gather(&mut errors, own(&bundle));
121 match (english, keymap, palette, font, images, own) {
122 (Some(english), Some(keymap), Some(palette), Some(font), Some(images), Some(own)) => {
123 Ok(Self {
124 lang: Lang::new(english.0, BTreeMap::new()),
125 keymap,
126 audio: AudioManifest::default(),
127 palette,
128 console,
129 font,
130 images,
131 bundle,
132 own,
133 })
134 }
135 _ => Err(errors),
136 }
137 }
138}
139
140impl<A: ActionSet, T: Debug + 'static> GameData for BasicData<A, T> {
141 type Action = A;
142 type Colors = EngineColor;
143 type Voice = ();
144 type Settings = ();
145
146 fn lang(&self) -> &Lang {
147 &self.lang
148 }
149
150 fn keymap_def(&self) -> &KeymapDef<A> {
151 &self.keymap
152 }
153
154 fn audio_manifest(&self) -> &AudioManifest {
155 &self.audio
156 }
157
158 fn palette_def(&self) -> &PaletteDef {
159 &self.palette
160 }
161
162 fn console(&self) -> ConsoleSpec {
163 self.console
164 }
165}
166
167#[cfg(test)]
168mod tests;