Skip to content

Instantly share code, notes, and snippets.

@PJB3005
Created August 19, 2020 14:12
Show Gist options
  • Save PJB3005/7fe68f7e96642a0a9363c52006f07102 to your computer and use it in GitHub Desktop.
Save PJB3005/7fe68f7e96642a0a9363c52006f07102 to your computer and use it in GitHub Desktop.
DM Recipe export to JSON
[package]
name = "dm-recipe-export"
version = "0.1.0"
authors = ["Pieter-Jan Briers <[email protected]>"]
edition = "2018"
[dependencies]
dreammaker = { path = "/home/pj/Projects/SpacemanDMM/src/dreammaker/" }
serde_json = "1.0.52"
serde = "1.0.107"
use dreammaker::ast::{Expression, Spanned, Term, FormatTypePath};
use dreammaker::objtree::{ObjectTree, TypeRef, VarValue};
use dreammaker::{constants::{Constant, Pop}, Context};
use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;
use std::ops::Deref;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct MainData {
recipes: HashMap<String, Recipe>
}
#[derive(Serialize, Deserialize)]
struct Recipe {
name: String,
result: String,
reagents: Option<Vec<ReagentData>>,
items: Option<Vec<String>>
}
#[derive(Serialize, Deserialize)]
struct ReagentData {
allowed: Vec<String>,
amount: i32,
}
fn main() {
let context = Context::default();
let path = PathBuf::from("/home/pj/Projects/vgstation13/vgstation13.dme");
let tree = context.parse_environment(&path).unwrap();
let recipes = discover_recipes(&tree);
let json = gen_data(&recipes);
let file = File::create("dump.json").unwrap();
serde_json::to_writer_pretty(file, &json).unwrap();
}
fn discover_recipes(o: &ObjectTree) -> Vec<TypeRef> {
let mut types = Vec::new();
push_children(o.expect("/datum/recipe"), &mut types);
types
}
fn push_children<'a>(t: TypeRef<'a>, v: &mut Vec<TypeRef<'a>>) {
for x in t.children() {
v.push(x);
push_children(x, v);
}
}
fn gen_data(types: &[TypeRef]) -> MainData {
MainData {
recipes: types.iter()
.filter_map(|t| {
println!("{}", t.path);
let value = gen_recipe_data(*t);
match value {
Some(v) => Some((t.path.clone(), v)),
None => None,
}
})
.collect()
}
}
fn gen_recipe_data(t: TypeRef) -> Option<Recipe> {
let result_var = t.get_value("result").unwrap();
let result = match &result_var.constant.as_ref().unwrap() {
Constant::Prefab(p) => format!("{}", p),
_ => return None,
};
let reagents = parse_reagents(t.get_value("reagents").unwrap());
let items = parse_items(t.get_value("items").unwrap());
Some(Recipe {name: t.name.clone(), result, reagents, items })
}
fn parse_reagents(v: &VarValue) -> Option<Vec<ReagentData>> {
let expr_list = match v.expression.as_ref() {
Some(Expression::Base {
term: Spanned {
elem: Term::List(el),
..
},
..
}) => el,
_ => return None,
};
let reagent_list = expr_list.iter()
.map(|e| match e {
Expression::AssignOp { lhs, rhs, .. } => {
let m = (lhs.deref(), rhs.deref());
match m {
(
Expression::Base {
term:
Spanned {
elem: lhs,
..
},
..
},
Expression::Base {
term:
Spanned {
elem: Term::Int(reagent_amount),
..
},
..
},
) => {
(lhs, *reagent_amount)
}
_ => panic!("Unexpected format!"),
}
}
_ => panic!("Unexpected format!"),
});
Some(reagent_list.map(|r| {
let term = r.0;
let amount = r.1;
let allowed = match term {
Term::String(s) => vec![s.clone()],
Term::List(expressions) => {
expressions.iter().map(|e| {
match e {
Expression::Base { term: Spanned {elem: Term::String(s), ..}, ..} => {
s.clone()
},
_ => panic!("Unexpected format!")
}
}).collect()
}
_ => panic!("Unexpected format!")
};
ReagentData { amount, allowed }
}).collect())
}
fn parse_items(v: &VarValue) -> Option<Vec<String>> {
let expr_list = match v.expression.as_ref() {
Some(Expression::Base {
term: Spanned {
elem: Term::List(el),
..
},
..
}) => el,
_ => return None,
};
Some(expr_list.iter()
.map(|e| match e {
Expression::Base {term: Spanned { elem: Term::Prefab(p), ..}, ..} => {
format!("{}", FormatTypePath(&p.path))
},
_ => panic!("Unexpected format!")
}).collect())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment