Skip to content

Commit

Permalink
Vanilla maps can now roundtrip
Browse files Browse the repository at this point in the history
  • Loading branch information
maddymakesgames committed Aug 26, 2024
1 parent 6adc548 commit ea1003f
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 36 deletions.
2 changes: 2 additions & 0 deletions lib/src/maps/elements/level.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ pub struct Background {
#[name = "offsetY"]
pub offset_y: Float,
#[name = "innerText"]
#[rle]
pub inner_text: Option<String>,
}

Expand All @@ -199,6 +200,7 @@ pub struct Solids {
#[name = "offsetY"]
pub offset_y: Float,
#[name = "innerText"]
#[rle]
pub inner_text: Option<String>,
}

Expand Down
32 changes: 13 additions & 19 deletions lib/src/maps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub struct RawMap {
}

impl RawMap {
fn from_bytes(bytes: Vec<u8>) -> Result<Self, MapReadError> {
pub fn from_bytes(bytes: Vec<u8>) -> Result<Self, MapReadError> {
let mut reader = MapReader::new(bytes);

let check_string = reader.read_string()?;
Expand Down Expand Up @@ -284,20 +284,20 @@ impl<T: MapElement> ErasedMapElement for T {
// It'll probably be fine because of monomorphization
// so Option<u8> and Option<u16> are different
// BUT still doesn't make sense to allow this when parsing dyn elements
impl<T: MapElement> MapElement for Option<T> {
const NAME: &'static str = T::NAME;
// impl<T: MapElement> MapElement for Option<T> {
// const NAME: &'static str = T::NAME;

fn from_raw(parser: MapParser) -> Result<Self, MapElementParsingError>
where Self: Sized {
Ok(parser.parse_element::<T>().ok())
}
// fn from_raw(parser: MapParser) -> Result<Self, MapElementParsingError>
// where Self: Sized {
// Ok(parser.parse_element::<T>().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]
///
Expand Down Expand Up @@ -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()?)
}
}
2 changes: 1 addition & 1 deletion lib/src/maps/var_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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}"),
}
}

Expand Down
7 changes: 5 additions & 2 deletions lib/src/maps/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion macros/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ pub(super) fn entity_derive(input: DeriveInput) -> Result<TokenStream, Error> {
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)},
});
Expand Down
2 changes: 1 addition & 1 deletion macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
52 changes: 41 additions & 11 deletions macros/src/map_element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}

Expand Down Expand Up @@ -47,7 +47,18 @@ pub(super) fn map_element_derive(input: DeriveInput) -> Result<TokenStream, Erro
let mut found_dyn_child = false;

for field in &struct_data.fields {
let mut found_rle = false;
let mut found_attr = false;

for attr in &field.attrs {
if let Meta::Path(path) = &attr.meta {
if path.is_ident("rle") {
found_attr = true;
found_rle = true;
}
}
}

for attr in &field.attrs {
match &attr.meta {
Meta::Path(path) =>
Expand All @@ -59,6 +70,13 @@ pub(super) fn map_element_derive(input: DeriveInput) -> Result<TokenStream, Erro
));
}

if found_rle {
return Err(Error::new(
path.span(),
"Can't have both rle and child on a field",
));
}

found_attr = true;
found_child = true;

Expand All @@ -85,9 +103,18 @@ pub(super) fn map_element_derive(input: DeriveInput) -> Result<TokenStream, Erro
"dyn_child field must be the only child field",
));
}

if found_rle {
return Err(Error::new(
path.span(),
"Can't have both rle and child on a field",
));
}

found_attr = true;
found_child = true;
found_dyn_child = true;

fields.push((
field.ident.clone().unwrap(),
FieldType::Child(true, false, true),
Expand All @@ -101,12 +128,12 @@ pub(super) fn map_element_derive(input: DeriveInput) -> Result<TokenStream, Erro
if p.path.segments.first().is_some_and(|p| p.ident == "Option") {
fields.push((
field.ident.clone().unwrap(),
FieldType::Optional(name_value.value.clone()),
FieldType::Optional(name_value.value.clone(), found_rle),
))
} else {
fields.push((
field.ident.clone().unwrap(),
FieldType::Normal(name_value.value.clone()),
FieldType::Normal(name_value.value.clone(), found_rle),
))
}
}
Expand All @@ -123,24 +150,27 @@ pub(super) fn map_element_derive(input: DeriveInput) -> Result<TokenStream, Erro
}
}

let celeste_rs = super::celeste_rs();

let parsers = fields.iter().map(|(name, field_type)| match field_type {
FieldType::Normal(expr) => 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()?, },
FieldType::Child(true, _, true) => quote! {#name: parser.parse_any_element()?, },
});

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::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;
Expand Down
2 changes: 1 addition & 1 deletion macros/src/trigger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ pub(super) fn trigger_derive(input: DeriveInput) -> Result<TokenStream, Error> {
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)},
});
Expand Down

0 comments on commit ea1003f

Please sign in to comment.