Added system loading from file

master
Mark 2023-12-25 09:01:12 -08:00
parent 50bd3bdb8c
commit 619b8ae797
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
8 changed files with 134 additions and 85 deletions

View File

@ -3,11 +3,15 @@
name = "12 Autumn above" name = "12 Autumn above"
[object.star] [object.star]
sprite = "star::a0" sprite = "star::star"
center = [0.0, 0.0] center = [0.0, 0.0]
size = 50
parallax = 1.0
[object.earth] [object.earth]
sprite = "planet::earth" sprite = "planet::earth"
center = "star" center = "star"
radius = 200 radius = 1000
angle = 14 angle = 0
size = 100
parallax = 1.0

View File

@ -1,24 +1,25 @@
use anyhow::Result; use anyhow::{Context, Result};
use std::path::PathBuf;
use super::{syntax, ContentType}; use super::{syntax, ContentType};
#[derive(Debug)] #[derive(Debug)]
pub struct Content { pub struct Content {
systems: Vec<syntax::System>, pub systems: Vec<syntax::system::System>,
} }
impl Content { impl Content {
pub fn new(cv: Vec<ContentType>) -> Result<Self> { pub fn new(cv: Vec<(PathBuf, ContentType)>) -> Result<Self> {
let mut content = Self { let mut content = Self {
systems: Vec::new(), systems: Vec::new(),
}; };
// TODO: locate bad files
// These methods check intra-file consistency // These methods check intra-file consistency
for c in cv { for (p, c) in cv {
match c { match c {
ContentType::System(v) => content.add_system(v)?, ContentType::System(v) => content
.add_system(v)
.with_context(|| format!("Could not parse {}", p.display()))?,
}; };
} }
@ -26,7 +27,7 @@ impl Content {
} }
fn add_system(&mut self, toml: syntax::system::toml::SystemRoot) -> Result<()> { fn add_system(&mut self, toml: syntax::system::toml::SystemRoot) -> Result<()> {
self.systems.push(syntax::System::parse(toml)?); self.systems.push(syntax::system::System::parse(toml)?);
return Ok(()); return Ok(());
} }
} }

View File

@ -1,4 +1,4 @@
use anyhow::Result; use anyhow::{bail, Result};
use std::{fs::File, io::Read, path::Path}; use std::{fs::File, io::Read, path::Path};
use super::syntax; use super::syntax;
@ -12,12 +12,21 @@ pub enum ContentType {
impl ContentType { impl ContentType {
pub fn try_parse(file_string: &str) -> Result<Option<Self>> { pub fn try_parse(file_string: &str) -> Result<Option<Self>> {
// TODO: More advanced parsing, read the whole top comment // TODO: More advanced parsing, read the whole top comment
let (first, _) = file_string.split_once("\n").unwrap(); let first = match file_string.split_once("\n") {
None => bail!("This file is empty."),
Some((first, _)) => first,
};
let type_spec = first[1..].trim(); // Remove hash let type_spec = first[1..].trim(); // Remove hash
return Ok(match type_spec { let type_spec = if type_spec.starts_with("content type: ") {
"content type: system" => Some(Self::System(toml::from_str(&file_string)?)), type_spec[14..].to_owned()
_ => None, } else {
bail!("No content type specified")
};
return Ok(match &type_spec[..] {
"system" => Some(Self::System(toml::from_str(&file_string)?)),
_ => bail!("Invalid content type `{}`", type_spec),
}); });
} }

View File

@ -4,3 +4,38 @@ mod syntax;
pub use content::Content; pub use content::Content;
pub use contenttype::ContentType; pub use contenttype::ContentType;
pub use syntax::system;
use anyhow::{Context, Result};
use walkdir::WalkDir;
pub fn load_content_dir(path: &str) -> Result<Content> {
let mut raw_content = Vec::new();
for e in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) {
if e.metadata().unwrap().is_file() {
// TODO: better warnings
match e.path().extension() {
Some(t) => {
if t.to_str() != Some("toml") {
println!("[WARNING] {e:#?} is not a toml file, skipping.");
continue;
}
}
None => {
println!("[WARNING] {e:#?} is not a toml file, skipping.");
continue;
}
}
let c = crate::content::ContentType::from_path(e.path())
.with_context(|| format!("Could not load {:#?}", e.path()))?;
match c {
Some(c) => raw_content.push((e.path().to_path_buf(), c)),
None => continue,
}
}
}
return crate::content::Content::new(raw_content);
}

View File

@ -1,3 +1,2 @@
#![allow(dead_code)] #![allow(dead_code)]
pub mod system; pub mod system;
pub use system::System;

View File

@ -1,8 +1,8 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use cgmath::Point2; use cgmath::{Deg, Point2};
use std::collections::HashMap; use std::collections::HashMap;
use crate::physics::Pfloat; use crate::physics::{Pfloat, Polar};
/// Toml file syntax /// Toml file syntax
pub(in crate::content) mod toml { pub(in crate::content) mod toml {
@ -26,6 +26,9 @@ pub(in crate::content) mod toml {
pub sprite: String, pub sprite: String,
pub center: Center, pub center: Center,
pub size: Pfloat,
pub parallax: Pfloat,
#[serde(default)] #[serde(default)]
pub radius: Pfloat, pub radius: Pfloat,
#[serde(default)] #[serde(default)]
@ -38,20 +41,29 @@ pub(in crate::content) mod toml {
Label(String), Label(String),
Coords([Pfloat; 2]), Coords([Pfloat; 2]),
} }
impl ToString for Center {
fn to_string(&self) -> String {
match self {
Self::Label(s) => s.to_owned(),
Self::Coords(v) => format!("{:?}", v),
}
}
}
} }
#[derive(Debug)] #[derive(Debug)]
pub struct System { pub struct System {
name: String, pub name: String,
objects: Vec<Object>, pub objects: Vec<Object>,
} }
#[derive(Debug)] #[derive(Debug)]
struct Object { pub struct Object {
sprite: String, pub sprite: String,
center: Point2<Pfloat>, pub position: Polar,
radius: Pfloat, pub size: Pfloat,
angle: Pfloat, pub parallax: Pfloat,
} }
fn resolve_center( fn resolve_center(
@ -59,8 +71,15 @@ fn resolve_center(
obj: &toml::Object, obj: &toml::Object,
) -> Option<Point2<f32>> { ) -> Option<Point2<f32>> {
match &obj.center { match &obj.center {
toml::Center::Label(s) => resolve_center(&objects, objects.get(s)?), toml::Center::Label(s) => Some(
toml::Center::Coords(v) => Some(Point2::from(*v)), Polar {
center: resolve_center(&objects, objects.get(s)?)?,
radius: obj.radius,
angle: Deg(obj.angle),
}
.to_cartesian(),
),
toml::Center::Coords(v) => Some((*v).into()),
} }
} }
@ -68,22 +87,27 @@ impl System {
pub fn parse(value: toml::SystemRoot) -> Result<Self> { pub fn parse(value: toml::SystemRoot) -> Result<Self> {
let mut objects = Vec::new(); let mut objects = Vec::new();
for (_, obj) in &value.object { for (label, obj) in &value.object {
let center = match resolve_center(&value.object, obj) { let center = match resolve_center(&value.object, obj) {
Some(v) => v, Some(v) => v,
None => { None => {
bail!( bail!(
"Failed to parse content file: could not resolve center label `{:?}`", "could not resolve center label `{}` in `object.{}`",
obj.center obj.center.to_string(),
label
); );
} }
}; };
objects.push(Object { objects.push(Object {
sprite: obj.sprite.clone(), sprite: obj.sprite.clone(),
center, position: Polar {
radius: obj.radius, center,
angle: obj.angle, radius: obj.radius,
angle: Deg(obj.angle),
},
size: obj.size,
parallax: obj.parallax,
}); });
} }

View File

@ -8,8 +8,8 @@ mod system;
use anyhow::Result; use anyhow::Result;
use cgmath::{Deg, Point2}; use cgmath::{Deg, Point2};
use content::Content;
use std::time::Instant; use std::time::Instant;
use walkdir::WalkDir;
use winit::{ use winit::{
event::{ event::{
ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase,
@ -69,10 +69,10 @@ struct Sprite {
/// The size of this sprite, /// The size of this sprite,
/// given as height in world units. /// given as height in world units.
height: Pfloat, size: Pfloat,
/// Scale factor. /// Scale factor.
/// if this is 1, sprite height is exactly self.height. /// if this is 1, sprite height is exactly self.size.
scale: Pfloat, scale: Pfloat,
/// This sprite's rotation /// This sprite's rotation
@ -95,7 +95,7 @@ struct Game {
} }
impl Game { impl Game {
fn new() -> Self { fn new(ct: Content) -> Self {
Game { Game {
last_update: Instant::now(), last_update: Instant::now(),
input: InputStatus::new(), input: InputStatus::new(),
@ -104,7 +104,7 @@ impl Game {
pos: (0.0, 0.0).into(), pos: (0.0, 0.0).into(),
zoom: 500.0, zoom: 500.0,
}, },
system: System::new(), system: System::new(&ct.systems[0]),
} }
} }
@ -128,11 +128,11 @@ impl Game {
} }
if self.input.key_right { if self.input.key_right {
self.player.body.rot(Deg { 0: 35.0 } * t); self.player.body.rot(Deg(35.0) * t);
} }
if self.input.key_left { if self.input.key_left {
self.player.body.rot(Deg { 0: -35.0 } * t); self.player.body.rot(Deg(-35.0) * t);
} }
if self.input.v_scroll != 0.0 { if self.input.v_scroll != 0.0 {
@ -140,6 +140,7 @@ impl Game {
self.input.v_scroll = 0.0; self.input.v_scroll = 0.0;
} }
println!("{:?}", self.player.body.pos);
self.player.body.tick(t); self.player.body.tick(t);
self.camera.pos = self.player.body.pos; self.camera.pos = self.player.body.pos;
@ -163,12 +164,11 @@ impl Game {
} }
} }
pub async fn run() -> Result<()> { async fn run(mut game: Game) -> Result<()> {
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap(); let window = WindowBuilder::new().build(&event_loop).unwrap();
let mut gpu = GPUState::new(window).await?; let mut gpu = GPUState::new(window).await?;
let mut game = Game::new();
gpu.update_starfield_buffer(&game); gpu.update_starfield_buffer(&game);
@ -231,20 +231,10 @@ pub async fn run() -> Result<()> {
} }
fn main() -> Result<()> { fn main() -> Result<()> {
let mut raw_content = Vec::new(); let content = content::load_content_dir("./content")?;
for e in WalkDir::new("content").into_iter().filter_map(|e| e.ok()) { println!("{:?}", content);
if e.metadata().unwrap().is_file() { let game = Game::new(content);
let c = crate::content::ContentType::from_path(e.path())?;
match c {
Some(c) => raw_content.push(c),
None => continue,
}
}
}
let a = crate::content::Content::new(raw_content)?; pollster::block_on(run(game))?;
println!("{:?}", a);
//pollster::block_on(run())?;
return Ok(()); return Ok(());
} }

View File

@ -1,10 +1,8 @@
use crate::{ use crate::{
physics::{Pfloat, Polar}, content, physics::Pfloat, render::SpriteTexture, Doodad, Sprite, Spriteable, STARFIELD_COUNT,
render::SpriteTexture, STARFIELD_PARALLAX_MAX, STARFIELD_PARALLAX_MIN, STARFIELD_SIZE,
Doodad, Sprite, Spriteable, STARFIELD_COUNT, STARFIELD_PARALLAX_MAX, STARFIELD_PARALLAX_MIN,
STARFIELD_SIZE,
}; };
use cgmath::{Deg, Point2, Vector2}; use cgmath::{Point2, Vector2};
use rand::{self, Rng}; use rand::{self, Rng};
pub struct StarfieldStar { pub struct StarfieldStar {
@ -12,8 +10,9 @@ pub struct StarfieldStar {
/// These are relative to the center of a starfield tile. /// These are relative to the center of a starfield tile.
pub pos: Point2<Pfloat>, pub pos: Point2<Pfloat>,
// TODO: z-coordinate?
pub parallax: Pfloat, pub parallax: Pfloat,
pub height: Pfloat, pub size: Pfloat,
/// Color/brightness variation. /// Color/brightness variation.
/// See shader. /// See shader.
@ -26,7 +25,7 @@ pub struct System {
} }
impl System { impl System {
pub fn new() -> Self { pub fn new(ct: &content::system::System) -> Self {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let sz = STARFIELD_SIZE as f32 / 2.0; let sz = STARFIELD_SIZE as f32 / 2.0;
let mut s = System { let mut s = System {
@ -38,7 +37,7 @@ impl System {
y: rng.gen_range(-sz..=sz), y: rng.gen_range(-sz..=sz),
}, },
parallax: rng.gen_range(STARFIELD_PARALLAX_MIN..STARFIELD_PARALLAX_MAX), parallax: rng.gen_range(STARFIELD_PARALLAX_MIN..STARFIELD_PARALLAX_MAX),
height: rng.gen_range(0.2..0.8), // TODO: configurable size: rng.gen_range(0.2..0.8), // TODO: configurable
tint: Vector2 { tint: Vector2 {
x: rng.gen_range(0.0..=1.0), x: rng.gen_range(0.0..=1.0),
y: rng.gen_range(0.0..=1.0), y: rng.gen_range(0.0..=1.0),
@ -47,26 +46,14 @@ impl System {
.collect(), .collect(),
}; };
s.bodies.push(Doodad { for o in &ct.objects {
pos: (0.0, 0.0).into(), s.bodies.push(Doodad {
sprite: SpriteTexture { name: "star::star" }, pos: o.position.to_cartesian(),
parallax: 10.0, sprite: SpriteTexture(o.sprite.to_owned()),
height: 80.0, size: o.size,
}); parallax: o.parallax,
});
s.bodies.push(Doodad { }
pos: Polar {
center: (0.0, 0.0).into(),
radius: 5000.0,
angle: Deg { 0: 31.0 },
}
.to_cartesian(),
sprite: SpriteTexture {
name: "planet::earth",
},
parallax: 5.0,
height: 120.0,
});
return s; return s;
} }