refactor(vm): fix Reagent code gen

Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
Rachel Powers
2024-09-16 18:01:45 -07:00
parent 08c42a2618
commit 6e80f21046
6 changed files with 199 additions and 92 deletions

View File

@@ -1,4 +1,4 @@
use color_eyre::eyre;
use color_eyre::eyre::{self, Context};
use quote::ToTokens;
use std::collections::BTreeMap;
@@ -98,16 +98,22 @@ fn format_rust(content: impl ToTokens) -> color_eyre::Result<String> {
Ok(prettyplease::unparse(&content))
}
fn prepend_generated_comment_and_format(file_path: &std::path::Path, module: &str) -> color_eyre::Result<()> {
fn prepend_generated_comment_and_format(
file_path: &std::path::Path,
module: &str,
) -> color_eyre::Result<()> {
use std::io::Write;
let tmp_path = file_path.with_extension("rs.tmp");
{
let mut tmp = std::fs::File::create(&tmp_path)?;
let src = syn::parse_file(&std::fs::read_to_string(file_path)?)?;
let src = syn::parse_file(&std::fs::read_to_string(file_path)?)
.with_context(|| format!("Error parsing file {}", file_path.display()))?;
let formated = format_rust(src)?;
let formatted = format_rust(src)?;
write!(&mut tmp, "\
write!(
&mut tmp,
"\
// =================================================\n\
// !! <-----> DO NOT MODIFY <-----> !!\n\
//\n\
@@ -122,7 +128,7 @@ fn prepend_generated_comment_and_format(file_path: &std::path::Path, module: &st
//\n\
// =================================================\n\
\n\
{formated}\
{formatted}\
"
)?;
}

View File

@@ -19,11 +19,11 @@ use stationeers_data::templates::{
InstructionPartType, InternalAtmoInfo, ItemCircuitHolderTemplate, ItemConsumerTemplate,
ItemInfo, ItemLogicMemoryTemplate, ItemLogicTemplate, ItemSlotsTemplate,
ItemSuitCircuitHolderTemplate, ItemSuitLogicTemplate, ItemSuitTemplate, ItemTemplate,
LogicInfo, MemoryInfo, ObjectTemplate, PrefabInfo, Recipe, RecipeGasMix, RecipeRange, SlotInfo,
StructureCircuitHolderTemplate, StructureInfo, StructureLogicDeviceConsumerMemoryTemplate,
StructureLogicDeviceConsumerTemplate, StructureLogicDeviceMemoryTemplate,
StructureLogicDeviceTemplate, StructureLogicTemplate, StructureSlotsTemplate,
StructureTemplate, SuitInfo, ThermalInfo,
LogicInfo, MemoryInfo, ObjectTemplate, PrefabInfo, Reagent, Recipe, RecipeGasMix, RecipeRange,
SlotInfo, StructureCircuitHolderTemplate, StructureInfo,
StructureLogicDeviceConsumerMemoryTemplate, StructureLogicDeviceConsumerTemplate,
StructureLogicDeviceMemoryTemplate, StructureLogicDeviceTemplate, StructureLogicTemplate,
StructureSlotsTemplate, StructureTemplate, SuitInfo, ThermalInfo,
};
#[allow(clippy::too_many_lines)]
@@ -174,9 +174,21 @@ pub fn generate_database(
}
})
.collect();
let reagents = stationpedia
.reagents
.iter()
.map(|(name, reagent)| {
(
name.clone(),
Into::<Reagent>::into(reagent).with_name(name.clone()),
)
})
.collect();
let db: ObjectDatabase = ObjectDatabase {
prefabs,
reagents: stationpedia.reagents.clone(),
reagents,
enums: enums.clone(),
prefabs_by_hash,
structures,
@@ -191,7 +203,7 @@ pub fn generate_database(
.join("www")
.join("src")
.join("ts")
.join("virtualMachine");
.join("database");
if !data_path.exists() {
std::fs::create_dir(&data_path)?;
}
@@ -225,7 +237,15 @@ pub fn generate_database(
let mut prefab_map_file = std::io::BufWriter::new(std::fs::File::create(&prefab_map_path)?);
write_prefab_map(&mut prefab_map_file, &db.prefabs)?;
Ok(vec![prefab_map_path])
let reagent_map_path = workspace
.join("stationeers_data")
.join("src")
.join("database")
.join("reagent_map.rs");
let mut reagent_map_file = std::io::BufWriter::new(std::fs::File::create(&reagent_map_path)?);
write_reagent_map(&mut reagent_map_file, &db.reagents)?;
Ok(vec![prefab_map_path, reagent_map_path])
}
fn write_prefab_map<T: std::io::Write>(
@@ -243,12 +263,17 @@ fn write_prefab_map<T: std::io::Write>(
}
)?;
let enum_tag_regex = regex::Regex::new(r#"templateType:\s"\w+"\.into\(\),"#).unwrap();
let numeric_string_literal_regex = regex::Regex::new(r#""(\d+)"\.into\(\)"#).unwrap();
let entries = prefabs
.values()
.map(|prefab| {
let hash = prefab.prefab().prefab_hash;
let uneval_src = &uneval::to_string(prefab)?;
let obj = syn::parse_str::<syn::Expr>(&enum_tag_regex.replace_all(&uneval_src, ""))?;
let fixed = enum_tag_regex.replace_all(&uneval_src, "");
let fixed = numeric_string_literal_regex.replace_all(&fixed, |captures: &regex::Captures| {
captures[1].to_string()
});
let obj = syn::parse_str::<syn::Expr>(&fixed)?;
let entry = quote! {
map.insert(#hash, #obj.into());
};
@@ -270,9 +295,47 @@ fn write_prefab_map<T: std::io::Write>(
Ok(())
}
fn write_reagent_map<T: std::io::Write>(
writer: &mut BufWriter<T>,
reagents: &BTreeMap<String, Reagent>,
) -> color_eyre::Result<()> {
write!(
writer,
"{}",
quote! {
use crate::templates::Reagent;
}
)?;
let entries = reagents
.values()
.map(|reagent| {
let id = reagent.id;
let uneval_src = &uneval::to_string(reagent)?;
let obj = syn::parse_str::<syn::Expr>(&uneval_src)?;
let entry = quote! {
map.insert(#id, #obj);
};
Ok(entry)
})
.collect::<Result<Vec<_>, color_eyre::Report>>()?;
write!(
writer,
"{}",
quote! {
pub fn build_reagent_database() -> std::collections::BTreeMap<u8, crate::templates::Reagent> {
#[allow(clippy::unreadable_literal)]
let mut map: std::collections::BTreeMap<u8, crate::templates::Reagent> = std::collections::BTreeMap::new();
#(#entries)*
map
}
},
)?;
Ok(())
}
#[allow(clippy::too_many_lines)]
fn generate_templates(pedia: &Stationpedia) -> Vec<ObjectTemplate> {
println!("Generating templates ...");
eprintln!("Generating templates ...");
let mut templates: Vec<ObjectTemplate> = Vec::new();
for page in &pedia.pages {
let prefab = PrefabInfo {
@@ -567,7 +630,6 @@ fn generate_templates(pedia: &Stationpedia) -> Vec<ObjectTemplate> {
thermal_info: thermal.as_ref().map(Into::into),
internal_atmo_info: internal_atmosphere.as_ref().map(Into::into),
}));
// println!("Structure")
}
Page {
item: None,
@@ -591,7 +653,6 @@ fn generate_templates(pedia: &Stationpedia) -> Vec<ObjectTemplate> {
internal_atmo_info: internal_atmosphere.as_ref().map(Into::into),
slots: slot_inserts_to_info(slot_inserts),
}));
// println!("Structure")
}
Page {
item: None,
@@ -624,7 +685,6 @@ fn generate_templates(pedia: &Stationpedia) -> Vec<ObjectTemplate> {
logic,
slots: slot_inserts_to_info(slot_inserts),
}));
// println!("Structure")
}
Page {
item: None,
@@ -660,7 +720,6 @@ fn generate_templates(pedia: &Stationpedia) -> Vec<ObjectTemplate> {
device: device.into(),
},
));
// println!("Structure")
}
Page {
item: None,
@@ -704,7 +763,6 @@ fn generate_templates(pedia: &Stationpedia) -> Vec<ObjectTemplate> {
device: device.into(),
},
));
// println!("Structure")
}
Page {
item: None,
@@ -742,7 +800,6 @@ fn generate_templates(pedia: &Stationpedia) -> Vec<ObjectTemplate> {
fabricator_info: device.fabricator.as_ref().map(Into::into),
},
));
// println!("Structure")
}
Page {
item: None,
@@ -778,7 +835,6 @@ fn generate_templates(pedia: &Stationpedia) -> Vec<ObjectTemplate> {
memory: memory.into(),
},
));
// println!("Structure")
}
Page {
item: None,
@@ -816,7 +872,6 @@ fn generate_templates(pedia: &Stationpedia) -> Vec<ObjectTemplate> {
memory: memory.into(),
},
));
// println!("Structure")
}
_ => panic!(
"\
@@ -851,16 +906,32 @@ fn generate_templates(pedia: &Stationpedia) -> Vec<ObjectTemplate> {
templates
}
fn slot_inserts_to_info(slots: &[stationpedia::SlotInsert]) -> Vec<SlotInfo> {
fn slot_inserts_to_info(slots: &[stationpedia::SlotInsert]) -> BTreeMap<u32, SlotInfo> {
let mut tmp: Vec<_> = slots.into();
tmp.sort_by(|a, b| a.slot_index.cmp(&b.slot_index));
tmp.iter()
.map(|slot| SlotInfo {
name: slot.slot_name.clone(),
typ: slot
.slot_type
.parse()
.unwrap_or_else(|err| panic!("failed to parse slot class: {err}")),
.map(|slot| {
let typ = &slot.slot_type;
if typ == "Proxy" {
(
slot.slot_index,
SlotInfo::Proxy {
name: slot.slot_name.clone(),
index: slot.slot_index,
},
)
} else {
(
slot.slot_index,
SlotInfo::Direct {
name: slot.slot_name.clone(),
class: typ.parse().unwrap_or_else(|err| {
panic!("failed to parse slot class '{typ}': {err}")
}),
index: slot.slot_index,
},
)
}
})
.collect()
}
@@ -877,7 +948,7 @@ fn mode_inserts_to_info(modes: &[stationpedia::ModeInsert]) -> BTreeMap<u32, Str
#[serde(rename_all = "camelCase")]
pub struct ObjectDatabase {
pub prefabs: BTreeMap<String, ObjectTemplate>,
pub reagents: BTreeMap<String, stationpedia::Reagent>,
pub reagents: BTreeMap<String, Reagent>,
pub enums: enums::Enums,
pub prefabs_by_hash: BTreeMap<i32, String>,
pub structures: Vec<String>,
@@ -929,10 +1000,10 @@ impl From<&stationpedia::LogicInfo> for LogicInfo {
.map(|(key, val)| {
(
key.parse().unwrap_or_else(|err| {
panic!("failed to parse logic slot type: {err}")
panic!("failed to parse logic slot type '{key}': {err}")
}),
val.parse().unwrap_or_else(|err| {
panic!("failed to parse memory access: {err}")
panic!("failed to parse memory access '{val}': {err}")
}),
)
})
@@ -946,10 +1017,12 @@ impl From<&stationpedia::LogicInfo> for LogicInfo {
.iter()
.map(|(key, val)| {
(
key.parse()
.unwrap_or_else(|err| panic!("failed to parse logic type: {err}")),
val.parse()
.unwrap_or_else(|err| panic!("failed to parse memory access: {err}")),
key.parse().unwrap_or_else(|err| {
panic!("failed to parse logic type '{key}' : {err}")
}),
val.parse().unwrap_or_else(|err| {
panic!("failed to parse memory access '{val}': {err}")
}),
)
})
.collect(),
@@ -976,20 +1049,14 @@ impl From<&stationpedia::Item> for ItemInfo {
.reagents
.as_ref()
.map(|map| map.iter().map(|(key, val)| (key.clone(), *val)).collect()),
slot_class: item
.slot_class
.parse()
.unwrap_or_else(|err| {
let slot_class = &item.slot_class;
panic!("failed to parse slot class `{slot_class}`: {err}");
}),
sorting_class: item
.sorting_class
.parse()
.unwrap_or_else(|err| {
let sorting_class = &item.sorting_class;
panic!("failed to parse sorting class `{sorting_class}`: {err}");
}),
slot_class: item.slot_class.parse().unwrap_or_else(|err| {
let slot_class = &item.slot_class;
panic!("failed to parse slot class `{slot_class}`: {err}");
}),
sorting_class: item.sorting_class.parse().unwrap_or_else(|err| {
let sorting_class = &item.sorting_class;
panic!("failed to parse sorting class `{sorting_class}`: {err}");
}),
}
}
}
@@ -1001,12 +1068,12 @@ impl From<&stationpedia::Device> for DeviceInfo {
.connection_list
.iter()
.map(|(typ, role)| ConnectionInfo {
typ: typ
.parse()
.unwrap_or_else(|err| panic!("failed to parse connection type `{typ}`: {err}")),
role: role
.parse()
.unwrap_or_else(|err| panic!("failed to parse connection role `{role}`: {err}")),
typ: typ.parse().unwrap_or_else(|err| {
panic!("failed to parse connection type `{typ}`: {err}")
}),
role: role.parse().unwrap_or_else(|err| {
panic!("failed to parse connection role `{role}`: {err}")
}),
})
.collect(),
device_pins_length: value.devices_length,
@@ -1123,6 +1190,19 @@ impl From<&stationpedia::ResourceConsumer> for ConsumerInfo {
}
}
impl From<&stationpedia::Reagent> for Reagent {
fn from(value: &stationpedia::Reagent) -> Self {
Reagent {
id: value.id,
name: String::new(),
hash: value.hash,
unit: value.unit.clone(),
is_organic: value.is_organic,
sources: value.sources.clone().unwrap_or_default(),
}
}
}
impl From<&stationpedia::Fabricator> for FabricatorInfo {
fn from(value: &stationpedia::Fabricator) -> Self {
FabricatorInfo {
@@ -1133,7 +1213,7 @@ impl From<&stationpedia::Fabricator> for FabricatorInfo {
recipes: value
.recipes
.iter()
.map(|(key, val)| (key.clone(), val.into()))
.map(|(prefab, val)| Into::<Recipe>::into(val).with_target(prefab))
.collect(),
}
}
@@ -1142,6 +1222,8 @@ impl From<&stationpedia::Fabricator> for FabricatorInfo {
impl From<&stationpedia::Recipe> for Recipe {
fn from(value: &stationpedia::Recipe) -> Self {
Recipe {
target_prefab: String::new(),
target_prefab_hash: 0,
tier: value
.tier_name
.parse()

View File

@@ -15,7 +15,7 @@ pub fn generate(
enums: &crate::enums::Enums,
workspace: &std::path::Path,
) -> color_eyre::Result<Vec<PathBuf>> {
println!("Writing Enum Listings ...");
eprintln!("Writing Enum Listings ...");
let enums_path = workspace.join("stationeers_data").join("src").join("enums");
if !enums_path.exists() {
std::fs::create_dir(&enums_path)?;
@@ -51,7 +51,7 @@ pub fn generate(
}
write_enum_listing(&mut writer, enm)?;
}
write_enum_aggragate_mod(&mut writer, &enums.basic_enums)?;
write_enum_aggregate_mod(&mut writer, &enums.basic_enums)?;
let mut writer = std::io::BufWriter::new(std::fs::File::create(enums_path.join("prefabs.rs"))?);
write_repr_enum_use_header(&mut writer)?;
@@ -80,7 +80,7 @@ pub fn generate(
}
#[allow(clippy::type_complexity)]
fn write_enum_aggragate_mod<T: std::io::Write>(
fn write_enum_aggregate_mod<T: std::io::Write>(
writer: &mut BufWriter<T>,
enums: &BTreeMap<String, crate::enums::EnumListing>,
) -> color_eyre::Result<()> {

View File

@@ -30,10 +30,14 @@ impl Stationpedia {
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Reagent {
#[serde(rename = "Id")]
pub id: u8,
#[serde(rename = "Hash")]
pub hash: i64,
pub hash: i32,
#[serde(rename = "Unit")]
pub unit: String,
#[serde(rename = "IsOrganic")]
pub is_organic: bool,
#[serde(rename = "Sources")]
pub sources: Option<BTreeMap<String, f64>>,
}