diff --git a/lib/src/maps/elements/level.rs b/lib/src/maps/elements/level.rs index 1e4034f..4835771 100644 --- a/lib/src/maps/elements/level.rs +++ b/lib/src/maps/elements/level.rs @@ -173,6 +173,7 @@ pub struct Background { #[name = "offsetY"] pub offset_y: Float, #[name = "innerText"] + #[rle] pub inner_text: Option, } @@ -199,6 +200,7 @@ pub struct Solids { #[name = "offsetY"] pub offset_y: Float, #[name = "innerText"] + #[rle] pub inner_text: Option, } diff --git a/lib/src/maps/mod.rs b/lib/src/maps/mod.rs index 7a5af76..e8d26c9 100644 --- a/lib/src/maps/mod.rs +++ b/lib/src/maps/mod.rs @@ -62,7 +62,7 @@ pub struct RawMap { } impl RawMap { - fn from_bytes(bytes: Vec) -> Result { + pub fn from_bytes(bytes: Vec) -> Result { let mut reader = MapReader::new(bytes); let check_string = reader.read_string()?; @@ -284,20 +284,20 @@ impl ErasedMapElement for T { // It'll probably be fine because of monomorphization // so Option and Option are different // BUT still doesn't make sense to allow this when parsing dyn elements -impl MapElement for Option { - const NAME: &'static str = T::NAME; +// impl MapElement for Option { +// const NAME: &'static str = T::NAME; - fn from_raw(parser: MapParser) -> Result - where Self: Sized { - Ok(parser.parse_element::().ok()) - } +// fn from_raw(parser: MapParser) -> Result +// where Self: Sized { +// Ok(parser.parse_element::().ok()) +// } - fn to_raw(&self, encoder: &mut MapEncoder) { - if let Some(t) = self { - t.to_raw(encoder) - } - } -} +// fn to_raw(&self, encoder: &mut MapEncoder) { +// if let Some(t) = self { +// t.to_raw(encoder) +// } +// } +// } /// A dynamic element, if a parser for the element was registered it will be parsed into that struct, otherwise it is a [RawMapElement] /// @@ -443,13 +443,7 @@ impl MapManager { } /// Writes the stored map data as binary into the provided writer - /// - /// This makes [ResolvableString]s unresolved so you should run [RawMap::resolve_strings] - /// if you intend to further edit the `RawMap` directly. pub fn write_map(&mut self, writer: &mut impl Write) -> std::io::Result<()> { - // unresolve strings, just in case people are editing the RawMap directly - self.map.unresolve_strings(); - writer.write_all(&self.map.to_bytes()?) } } diff --git a/lib/src/maps/var_types.rs b/lib/src/maps/var_types.rs index 965a1fc..7c6481a 100644 --- a/lib/src/maps/var_types.rs +++ b/lib/src/maps/var_types.rs @@ -28,7 +28,7 @@ impl EncodedVar { EncodedVar::Float(f) => format!("{f}_f32"), EncodedVar::LookupIndex(i) => lookup_table[*i].clone(), EncodedVar::String(s) => s.clone(), - EncodedVar::LengthEncodedString(s) => s.clone(), + EncodedVar::LengthEncodedString(s) => format!("RLE {s}"), } } diff --git a/lib/src/maps/writer.rs b/lib/src/maps/writer.rs index 8d99597..5daa644 100644 --- a/lib/src/maps/writer.rs +++ b/lib/src/maps/writer.rs @@ -99,10 +99,10 @@ impl MapWriter { let mut cur_char = char_iter.next().unwrap(); let mut cur_char_count = 1; - for c in str.chars() { + for c in char_iter { if c != cur_char || cur_char_count == 255 { buf.push(cur_char_count); - buf.push(c as u8); + buf.push(cur_char as u8); cur_char = c; cur_char_count = 1; @@ -111,6 +111,9 @@ impl MapWriter { } } + buf.push(cur_char_count); + buf.push(cur_char as u8); + self.write_short(buf.len() as i16); self.buf.extend(&buf); } diff --git a/macros/src/entity.rs b/macros/src/entity.rs index 99e1100..2b206f6 100644 --- a/macros/src/entity.rs +++ b/macros/src/entity.rs @@ -130,7 +130,7 @@ pub(super) fn entity_derive(input: DeriveInput) -> Result { let encoders = fields.iter().map(|(name, field_type)| match field_type { FieldType::Normal(expr) => quote! {encoder.attribute(#expr, self.#name.clone())}, FieldType::Optional(expr) => quote! {encoder.optional_attribute(#expr, &self.#name)}, - FieldType::Node(true, false) => quote! {encoder.child(&self.#name)}, + FieldType::Node(true, false) => quote! {if let Some(v) = &self.#name { encoder.child(v) }}, FieldType::Node(false, false) => quote! {encoder.child(&self.#name)}, FieldType::Node(_, true) => quote! {encoder.children(&self.#name)}, }); diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 42aaf39..248c190 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -178,7 +178,7 @@ pub fn root_tag( .into() } -#[proc_macro_derive(MapElement, attributes(child, name, dyn_child))] +#[proc_macro_derive(MapElement, attributes(child, name, dyn_child, rle))] pub fn map_element_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); diff --git a/macros/src/map_element.rs b/macros/src/map_element.rs index a07f205..a8c8221 100644 --- a/macros/src/map_element.rs +++ b/macros/src/map_element.rs @@ -3,8 +3,8 @@ use quote::quote; use syn::{spanned::Spanned, Data, DeriveInput, Error, Expr, Meta, Type}; enum FieldType { - Normal(Expr), - Optional(Expr), + Normal(Expr, bool), + Optional(Expr, bool), Child(bool, bool, bool), } @@ -47,7 +47,18 @@ pub(super) fn map_element_derive(input: DeriveInput) -> Result @@ -59,6 +70,13 @@ pub(super) fn map_element_derive(input: DeriveInput) -> Result Result Result Result quote! {#name: parser.get_attribute(#expr)?,}, - FieldType::Optional(expr) => quote! {#name: parser.get_optional_attribute(#expr),}, + FieldType::Normal(expr, _) => quote! {#name: parser.get_attribute(#expr)?,}, + FieldType::Optional(expr, _) => quote! {#name: parser.get_optional_attribute(#expr),}, FieldType::Child(false, true, _) => quote! {#name: parser.parse_element().ok(),}, FieldType::Child(false, false, _) => quote! {#name: parser.parse_element()?,}, FieldType::Child(true, _, false) => quote! {#name: parser.parse_all_elements()?, }, @@ -133,14 +162,15 @@ pub(super) fn map_element_derive(input: DeriveInput) -> Result quote! {encoder.attribute(#expr, self.#name.clone())}, - FieldType::Optional(expr) => quote! {encoder.optional_attribute(#expr, &self.#name)}, - FieldType::Child(false, ..) => quote! {encoder.child(&self.#name)}, + FieldType::Normal(expr, false) => quote! {encoder.attribute(#expr, self.#name.clone())}, + FieldType::Normal(expr, true) => quote! {encoder.attribute(#expr, #celeste_rs::maps::EncodedVar::new_rle_str(&self.#name))}, + FieldType::Optional(expr, false) => quote! {encoder.optional_attribute(#expr, &self.#name)}, + FieldType::Optional(expr, true) => quote! {encoder.optional_attribute(#expr, &self.#name.as_ref().map(#celeste_rs::maps::EncodedVar::new_rle_str))}, + FieldType::Child(false, false, _) => quote! {encoder.child(&self.#name)}, + FieldType::Child(false, true, _) => quote! {if let Some(v) = &self.#name {encoder.child(v);}}, FieldType::Child(true, ..) => quote! {encoder.children(&self.#name)}, }); - let celeste_rs = super::celeste_rs(); - Ok(quote! { impl MapElement for #struct_ident { const NAME: &'static str = #struct_name; diff --git a/macros/src/trigger.rs b/macros/src/trigger.rs index a85203f..347c778 100644 --- a/macros/src/trigger.rs +++ b/macros/src/trigger.rs @@ -130,7 +130,7 @@ pub(super) fn trigger_derive(input: DeriveInput) -> Result { let encoders = fields.iter().map(|(name, field_type)| match field_type { FieldType::Normal(expr) => quote! {encoder.attribute(#expr, self.#name.clone())}, FieldType::Optional(expr) => quote! {encoder.optional_attribute(#expr, &self.#name)}, - FieldType::Node(true, false) => quote! {encoder.child(&self.#name)}, + FieldType::Node(true, false) => quote! {if let Some(v) = &self.#name { encoder.child(v) }}, FieldType::Node(false, false) => quote! {encoder.child(&self.#name)}, FieldType::Node(_, true) => quote! {encoder.children(&self.#name)}, });