This commit is contained in:
2023-05-06 19:02:24 +02:00
parent d066215cf3
commit 76948c6501
46 changed files with 1031 additions and 85 deletions

View File

@@ -76,7 +76,10 @@ where
"xml" => {
serde_xml_rs::from_str::<UiTag>(String::from_utf8(data).map_err(custom_err)?.as_str())
.map_err(custom_err)
.map(DatafileFile::Ui)
.map(|mut it| {
it.post_process();
DatafileFile::Ui(it)
})
}
"txt" => {
let stem = path

View File

@@ -1,7 +1,7 @@
use serde::de::Error;
use serde::{Deserialize, Deserializer};
#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, Deserialize)]
pub enum UiTag {
Menu(UiMenu),
Image(UiImage),
@@ -11,7 +11,7 @@ pub enum UiTag {
ToggleButton(UiToggleButton),
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, Deserialize)]
pub struct UiMenu {
pub selected: String,
#[serde(rename = "OnBack")]
@@ -20,54 +20,55 @@ pub struct UiMenu {
pub children: Vec<UiTag>,
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, Deserialize)]
pub struct UiImage {
pub texture: String,
#[serde(deserialize_with = "deserialize_vec2")]
pub position: [i32; 2],
#[serde(deserialize_with = "deserialize_vec2")]
pub size: [i32; 2],
#[serde(rename = "fademode")]
#[serde(rename = "fademode", default)]
pub fade_mode: FadeMode,
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, Deserialize)]
pub struct UiTextButton {
pub name: Option<String>,
pub text: String,
#[serde(deserialize_with = "deserialize_vec2")]
pub position: [i32; 2],
#[serde(rename = "halign")]
#[serde(rename = "halign", default)]
pub horizontal_align: HorizontalAlign,
#[serde(rename = "fademode")]
#[serde(rename = "fademode", default)]
pub fade_mode: FadeMode,
#[serde(rename = "OnSelect")]
pub on_select: String,
}
/// This sometimes appears completely empty
#[derive(Debug, Deserialize)]
/// This is a really weird node, sometimes it has children and sometimes, don't ask me why,
/// it appears as a normal tag and then gets closed by an empty tag of this kind.
#[derive(Debug, Clone, Deserialize)]
pub struct UiTextArea {
#[serde(deserialize_with = "deserialize_vec2", default)]
pub position: [i32; 2],
#[serde(deserialize_with = "deserialize_vec2", default)]
pub size: [i32; 2],
#[serde(deserialize_with = "deserialize_vec2_opt", default)]
pub position: Option<[i32; 2]>,
#[serde(deserialize_with = "deserialize_vec2_opt", default)]
pub size: Option<[i32; 2]>,
#[serde(rename = "$value", default)]
pub children: Vec<UiTag>,
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, Deserialize)]
pub struct UiStaticText {
pub text: String,
#[serde(deserialize_with = "deserialize_vec2")]
pub position: [i32; 2],
#[serde(rename = "halign")]
#[serde(rename = "halign", default)]
pub horizontal_align: HorizontalAlign,
#[serde(rename = "fademode")]
#[serde(rename = "fademode", default)]
pub fade_mode: FadeMode,
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, Deserialize)]
pub struct UiToggleButton {
pub name: Option<String>,
pub text: String,
@@ -85,15 +86,49 @@ pub struct UiToggleButton {
pub target_l_offset: [i32; 2],
#[serde(rename = "targetROffset", deserialize_with = "deserialize_vec2")]
pub target_r_offset: [i32; 2],
#[serde(rename = "noSound")]
pub no_sound: Option<bool>,
#[serde(rename = "noSound", default)]
pub no_sound: bool,
#[serde(rename = "OnChange")]
pub on_change: String,
#[serde(rename = "OnSelect")]
pub on_select: String,
}
#[derive(Debug, Deserialize)]
impl UiTag {
pub fn post_process(&mut self) {
if let UiTag::Menu(menu) = self {
let children: Vec<UiTag> = menu.children.drain(..).collect();
let mut area_stack: Vec<Vec<UiTag>> = vec![vec![]];
for mut child in children {
child.post_process();
if let UiTag::TextArea(mut area) = child {
let children = area_stack.pop().unwrap();
let opening_tag = area_stack.last_mut().map(|it| it.last_mut());
if let Some(Some(UiTag::TextArea(opening_tag))) = opening_tag {
opening_tag.children = children;
} else {
area_stack.push(children);
}
if area.position.is_some() && area.size.is_some() {
let children = area.children.drain(..).collect();
area_stack.last_mut().unwrap().push(UiTag::TextArea(area));
area_stack.push(children);
}
} else {
area_stack.last_mut().unwrap().push(child);
}
}
menu.children = area_stack.pop().unwrap();
debug_assert!(area_stack.is_empty());
}
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum HorizontalAlign {
Left,
@@ -101,17 +136,46 @@ pub enum HorizontalAlign {
Right,
}
#[derive(Debug, Deserialize)]
impl Default for HorizontalAlign {
fn default() -> HorizontalAlign {
HorizontalAlign::Left
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum FadeMode {
None,
}
impl Default for FadeMode {
fn default() -> Self {
FadeMode::None
}
}
fn deserialize_vec2_opt<'de, D>(deserializer: D) -> Result<Option<[i32; 2]>, D::Error>
where
D: Deserializer<'de>,
{
if let Some(buf) = Option::<String>::deserialize(deserializer)? {
to_vec2::<D>(buf).map(Some)
} else {
Ok(None)
}
}
fn deserialize_vec2<'de, D>(deserializer: D) -> Result<[i32; 2], D::Error>
where
D: Deserializer<'de>,
{
let buf = String::deserialize(deserializer)?;
to_vec2::<D>(String::deserialize(deserializer)?)
}
fn to_vec2<'de, D>(buf: String) -> Result<[i32; 2], D::Error>
where
D: Deserializer<'de>,
{
let mut values: Vec<Result<i32, D::Error>> = buf
.split(',')
.into_iter()

View File

@@ -177,7 +177,9 @@ impl ResourceFormatLoaderVirtual for DatafileLoader {
.rsplitn(3, '/')
.collect_tuple()
.expect("Illegal path for UI");
let ui = convert_ui(ui, None, base_path);
let mut ui = convert_ui(ui, base_path);
own_children(&mut ui, None);
let mut scene = PackedScene::new();
scene.pack(ui);
@@ -284,3 +286,13 @@ impl ResourceFormatLoaderVirtual for DatafileLoader {
}
}
}
fn own_children(node: &mut Gd<Node>, owner: Option<&mut Gd<Node>>) {
let iter = node.get_children(false);
let owner = owner.unwrap_or(node);
for mut child in iter.iter_shared() {
println!("{:#?}", child);
child.set_owner(owner.share());
own_children(&mut child, Some(owner));
}
}

View File

@@ -1,9 +1,7 @@
use godot::builtin::{Rect2, Vector2, Vector2i};
use godot::engine::{FontFile, Image};
use godot::prelude::utilities::{print_verbose, prints};
use godot::prelude::utilities::prints;
use godot::prelude::{Color, Gd, Share, ToVariant};
use std::ops::Index;
use unicode_segmentation::UnicodeSegmentation;
const CHARSET: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜabcdefghijklmnopqrstuvwxyzäöüß0123456789,;.:!?\
+-*/=<>()[]{}\"$%&#~_^@|¡¿™©®º¹²³ªÀÁÂÃÅÆÇÈÉÊËÌÍÎÏIÐGÑÒÓÔÕŒØSŠÙÚÛÝÞŸŽàáâãåæçèéêëìíî\
@@ -14,13 +12,6 @@ pub fn load_bitmap_font(image: Gd<Image>) -> Gd<FontFile> {
let mut font_file = FontFile::new();
let chroma_key = Color {
r: 0.0,
g: 0.0,
b: 0.0,
a: 0.0,
};
let mut was_empty_column = true;
let mut char_x = 0;
let mut char_width = 0;

View File

@@ -1,6 +1,6 @@
use crate::formats::ui_xml::{HorizontalAlign, UiTag};
use godot::builtin::{Array, Dictionary, GodotString, ToVariant, Vector2};
use godot::engine::control::{LayoutPreset, SizeFlags};
use godot::engine::control::LayoutPreset;
use godot::engine::global::HorizontalAlignment;
use godot::engine::node::InternalMode;
use godot::engine::{load, Button, Control, Label, Node, SpinBox, TextureRect};
@@ -9,12 +9,12 @@ use itertools::Itertools;
const ACTION_META_NAME: &str = "action";
pub fn convert_ui(ui: UiTag, owner: Option<Gd<Node>>, base_path: &str) -> Gd<Node> {
pub fn convert_ui(ui: UiTag, base_path: &str) -> Gd<Node> {
match ui {
UiTag::Menu(menu) => {
let mut gd_menu = Control::new_alloc();
gd_menu.set_anchors_preset(LayoutPreset::PRESET_FULL_RECT, false);
attach_children(&mut gd_menu, owner, menu.children, base_path);
attach_children(&mut gd_menu, menu.children, base_path);
gd_menu.upcast()
}
UiTag::Image(image) => {
@@ -37,10 +37,10 @@ pub fn convert_ui(ui: UiTag, owner: Option<Gd<Node>>, base_path: &str) -> Gd<Nod
}
UiTag::TextArea(area) => {
let mut text_area = Control::new_alloc();
text_area.set_anchors_preset(LayoutPreset::PRESET_FULL_RECT, false);
text_area.set_position(to_vec2(area.position), false);
text_area.set_size(to_vec2(area.size), false);
attach_children(&mut text_area, owner, area.children, base_path);
// text_area.set_anchors_preset(LayoutPreset::PRESET_, false);
text_area.set_position(to_vec2(area.position.unwrap()), false);
text_area.set_size(to_vec2(area.size.unwrap()), false);
attach_children(&mut text_area, area.children, base_path);
text_area.upcast()
}
UiTag::ToggleButton(toggle) => {
@@ -54,10 +54,7 @@ pub fn convert_ui(ui: UiTag, owner: Option<Gd<Node>>, base_path: &str) -> Gd<Nod
}
spin_box.set_meta("text".into(), toggle.text.to_variant());
spin_box.set_meta("target".into(), toggle.target.to_variant());
spin_box.set_meta(
"no_sound".into(),
toggle.no_sound.unwrap_or(false).to_variant(),
);
spin_box.set_meta("no_sound".into(), toggle.no_sound.to_variant());
attach_call_meta(&mut spin_box, toggle.on_change);
spin_box.upcast()
}
@@ -87,22 +84,18 @@ impl Into<HorizontalAlignment> for HorizontalAlign {
}
}
fn attach_children<T>(
node: &mut Gd<T>,
owner: Option<Gd<Node>>,
children: Vec<UiTag>,
base_path: &str,
) where
fn attach_children<T>(node: &mut Gd<T>, children: Vec<UiTag>, base_path: &str)
where
T: Inherits<Node>,
{
let owner_node = owner.unwrap_or_else(|| node.share().upcast());
let mut parent = node.share().upcast();
for child in children {
let mut child = convert_ui(child, Some(owner_node.share()), base_path);
node.share()
.upcast()
.add_child(child.share(), false, InternalMode::INTERNAL_MODE_FRONT);
child.set_owner(owner_node.share());
parent.add_child(
convert_ui(child, base_path),
false,
InternalMode::INTERNAL_MODE_DISABLED,
);
}
}

View File

@@ -66,16 +66,18 @@ fn extract(datafile: &Datafile, file: &mut File) {
}
fn main() {
let file_name = Some(NullString::from("data\\loading\\sprites.txt"));
let file_name = Some(NullString::from(
"data\\menu\\screens\\options_controls.xml",
));
let dat_path = "E:\\Games\\Schatzjäger\\data\\datafile.dat";
let mut file = File::open(dat_path).unwrap();
let dat: Datafile = Datafile::read(&mut file).unwrap();
println!("{:#?}", dat);
extract(&dat, &mut file);
// extract(&dat, &mut file);
/*if let Some(file_name) = file_name {
if let Some(file_name) = file_name {
let target = dat.files.iter().find(|it| it.name == file_name).unwrap();
file.seek(SeekFrom::Start(target.pos as u64)).unwrap();
let mut data = vec![0u8; target.len as usize];
@@ -85,10 +87,12 @@ fn main() {
.extension()
.and_then(OsStr::to_str)
{
Some("xml") => println!(
"{:#?}",
from_str::<UiTag>(String::from_utf8(data).unwrap().as_str())
),
Some("xml") => {
let mut data =
from_str::<UiTag>(String::from_utf8(data).unwrap().as_str()).unwrap();
data.post_process();
println!("{:#?}", data)
}
Some("txt") => {
if false {
/*let decr = decrypt_txt(&mut data);
@@ -124,7 +128,7 @@ fn main() {
Some(ext) => eprintln!("Unknown file extension <{}>", ext),
None => eprintln!("Failed to read"),
}
}*/
}
}
// pub fn decr2()