From fd94cd670150642a7d61803d005339e0916a39d0 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 25 Dec 2023 10:30:27 -0800 Subject: [PATCH] Improved system parser --- content/system.toml | 27 ++++++--- src/content/syntax/system.rs | 104 +++++++++++++++++++++++------------ src/doodad.rs | 5 +- src/system.rs | 3 +- 4 files changed, 93 insertions(+), 46 deletions(-) diff --git a/content/system.toml b/content/system.toml index 904f49f..71eac99 100644 --- a/content/system.toml +++ b/content/system.toml @@ -4,14 +4,25 @@ name = "12 Autumn above" [object.star] sprite = "star::star" -center = [0.0, 0.0] -size = 50 -parallax = 1.0 +position = [0.0, 0.0] +size = 1000 +parallax = 20.0 + [object.earth] sprite = "planet::earth" -center = "star" -radius = 1000 -angle = 0 -size = 100 -parallax = 1.0 +position.center = "star" +position.radius = 4000 +position.angle = 0 +size = 1000 +parallax = 10.0 + + +[object.luna] +sprite = "planet::luna" +position.center = "earth" +position.radius = 1600 +position.angle = 135 +size = 500 +angle = -45 +parallax = 7.8 diff --git a/src/content/syntax/system.rs b/src/content/syntax/system.rs index 3747469..cd0859c 100644 --- a/src/content/syntax/system.rs +++ b/src/content/syntax/system.rs @@ -1,6 +1,6 @@ -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use cgmath::{Deg, Point2}; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use crate::physics::{Pfloat, Polar}; @@ -24,25 +24,37 @@ pub(in crate::content) mod toml { #[derive(Debug, Deserialize)] pub struct Object { pub sprite: String, - pub center: Center, + pub position: Position, pub size: Pfloat, pub parallax: Pfloat, - #[serde(default)] + pub radius: Option, + pub angle: Option, + } + + #[derive(Debug, Deserialize)] + #[serde(untagged)] + pub enum Position { + Polar(PolarCoords), + Cartesian(Coordinates), + } + + #[derive(Debug, Deserialize)] + pub struct PolarCoords { + pub center: Coordinates, pub radius: Pfloat, - #[serde(default)] pub angle: Pfloat, } #[derive(Debug, Deserialize)] #[serde(untagged)] - pub enum Center { + pub enum Coordinates { Label(String), Coords([Pfloat; 2]), } - impl ToString for Center { + impl ToString for Coordinates { fn to_string(&self) -> String { match self { Self::Label(s) => s.to_owned(), @@ -61,25 +73,57 @@ pub struct System { #[derive(Debug)] pub struct Object { pub sprite: String, - pub position: Polar, + pub position: Point2, pub size: Pfloat, pub parallax: Pfloat, + pub angle: Deg, } -fn resolve_center( +fn resolve_coordinates( + objects: &HashMap, + cor: &toml::Coordinates, + mut cycle_detector: HashSet, +) -> Result> { + match cor { + toml::Coordinates::Coords(c) => Ok((*c).into()), + toml::Coordinates::Label(l) => { + if cycle_detector.contains(l) { + bail!( + "Found coordinate cycle: `{}`", + cycle_detector.iter().fold(String::new(), |sum, a| { + if sum.is_empty() { + a.to_string() + } else { + sum + " -> " + a + } + }) + ); + } + cycle_detector.insert(l.to_owned()); + + let p = match objects.get(l) { + Some(p) => p, + None => bail!("Could not resolve coordinate label `{l}`"), + }; + Ok(resolve_position(&objects, &p, cycle_detector) + .with_context(|| format!("In object {:#?}", l))?) + } + } +} + +fn resolve_position( objects: &HashMap, obj: &toml::Object, -) -> Option> { - match &obj.center { - toml::Center::Label(s) => Some( - Polar { - center: resolve_center(&objects, objects.get(s)?)?, - radius: obj.radius, - angle: Deg(obj.angle), - } - .to_cartesian(), - ), - toml::Center::Coords(v) => Some((*v).into()), + cycle_detector: HashSet, +) -> Result> { + match &obj.position { + toml::Position::Cartesian(c) => Ok(resolve_coordinates(objects, c, cycle_detector)?), + toml::Position::Polar(p) => Ok(Polar { + center: resolve_coordinates(&objects, &p.center, cycle_detector)?, + radius: p.radius, + angle: Deg(p.angle), + } + .to_cartesian()), } } @@ -88,26 +132,16 @@ impl System { let mut objects = Vec::new(); for (label, obj) in &value.object { - let center = match resolve_center(&value.object, obj) { - Some(v) => v, - None => { - bail!( - "could not resolve center label `{}` in `object.{}`", - obj.center.to_string(), - label - ); - } - }; + let mut cycle_detector = HashSet::new(); + cycle_detector.insert(label.to_owned()); objects.push(Object { sprite: obj.sprite.clone(), - position: Polar { - center, - radius: obj.radius, - angle: Deg(obj.angle), - }, + position: resolve_position(&value.object, &obj, cycle_detector) + .with_context(|| format!("In object {:#?}", label))?, size: obj.size, parallax: obj.parallax, + angle: Deg(obj.angle.unwrap_or(0.0)), }); } diff --git a/src/doodad.rs b/src/doodad.rs index bcd2491..7db2435 100644 --- a/src/doodad.rs +++ b/src/doodad.rs @@ -7,15 +7,16 @@ pub struct Doodad { pub pos: Point2, pub parallax: Pfloat, pub size: Pfloat, + pub angle: Deg, } impl Spriteable for Doodad { fn get_sprite(&self) -> Sprite { return Sprite { texture: self.sprite.clone(), - pos: self.pos, - angle: Deg(0.0), scale: 1.0, + pos: self.pos, + angle: self.angle, size: self.size, parallax: self.parallax, }; diff --git a/src/system.rs b/src/system.rs index e4ae90c..31623f8 100644 --- a/src/system.rs +++ b/src/system.rs @@ -50,10 +50,11 @@ impl System { for o in &ct.objects { s.bodies.push(Doodad { - pos: o.position.to_cartesian(), + pos: o.position, sprite: SpriteTexture(o.sprite.to_owned()), size: o.size, parallax: o.parallax, + angle: o.angle, }); }