diff --git a/server/src/rbx_snapshot.rs b/server/src/rbx_snapshot.rs index 7be71d3b..c3e4fef9 100644 --- a/server/src/rbx_snapshot.rs +++ b/server/src/rbx_snapshot.rs @@ -39,6 +39,7 @@ use crate::{ const INIT_MODULE_NAME: &str = "init.lua"; const INIT_SERVER_NAME: &str = "init.server.lua"; const INIT_CLIENT_NAME: &str = "init.client.lua"; +const INIT_META_NAME: &str = "init.meta.json"; pub struct SnapshotContext { pub plugin_context: Option, @@ -105,6 +106,12 @@ pub enum SnapshotError { path: PathBuf, }, + InitMetaError { + #[fail(cause)] + inner: serde_json::Error, + path: PathBuf, + }, + XmlModelDecodeError { #[fail(cause)] inner: rbx_xml::DecodeError, @@ -152,6 +159,9 @@ impl fmt::Display for SnapshotError { SnapshotError::JsonModelDecodeError { inner, path } => { write!(output, "Malformed .model.json model: {} in path {}", inner, path.display()) }, + SnapshotError::InitMetaError { inner, path } => { + write!(output, "Malformed init.meta.json: {} in path {}", inner, path.display()) + }, SnapshotError::XmlModelDecodeError { inner, path } => { write!(output, "Malformed rbxmx model: {} in path {}", inner, path.display()) }, @@ -299,6 +309,7 @@ fn snapshot_imfs_directory<'source>( let init_path = directory.path.join(INIT_MODULE_NAME); let init_server_path = directory.path.join(INIT_SERVER_NAME); let init_client_path = directory.path.join(INIT_CLIENT_NAME); + let init_meta_path = directory.path.join(INIT_META_NAME); let snapshot_name = instance_name .unwrap_or_else(|| { @@ -327,6 +338,27 @@ fn snapshot_imfs_directory<'source>( } }; + if let Some(ImfsItem::File(file)) = imfs.get(&init_meta_path) { + let meta: InitMeta = serde_json::from_slice(&file.contents) + .map_err(|inner| SnapshotError::InitMetaError { + inner, + path: file.path.to_path_buf(), + })?; + + if let Some(meta_class) = meta.class_name { + snapshot.class_name = Cow::Owned(meta_class); + } + + if let Some(meta_ignore_instances) = meta.ignore_unknown_instances { + snapshot.metadata.ignore_unknown_instances = meta_ignore_instances; + } + + for (key, value) in meta.properties { + let resolved_value = try_resolve_value(&snapshot.class_name, &key, &value)?; + snapshot.properties.insert(key, resolved_value); + } + } + snapshot.metadata.source_path = Some(directory.path.to_owned()); for child_path in &directory.children { @@ -351,6 +383,16 @@ fn snapshot_imfs_directory<'source>( Ok(Some(snapshot)) } +#[derive(Debug, Default, Deserialize)] +#[serde(rename_all = "camelCase")] +struct InitMeta { + class_name: Option, + ignore_unknown_instances: Option, + + #[serde(default = "HashMap::new")] + properties: HashMap, +} + fn snapshot_imfs_file<'source>( context: &SnapshotContext, file: &'source ImfsFile, diff --git a/server/tests/snapshot_snapshots.rs b/server/tests/snapshot_snapshots.rs index 7c3d1e78..4c143f38 100644 --- a/server/tests/snapshot_snapshots.rs +++ b/server/tests/snapshot_snapshots.rs @@ -35,6 +35,7 @@ generate_snapshot_tests!( empty, json_model, localization, + meta_files, multi_partition_game, nested_partitions, single_partition_game, diff --git a/test-projects/meta_files/default.project.json b/test-projects/meta_files/default.project.json new file mode 100644 index 00000000..0eb0c8ea --- /dev/null +++ b/test-projects/meta_files/default.project.json @@ -0,0 +1,6 @@ +{ + "name": "test-model", + "tree": { + "$path": "src" + } +} \ No newline at end of file diff --git a/test-projects/meta_files/expected-snapshot.json b/test-projects/meta_files/expected-snapshot.json new file mode 100644 index 00000000..060c5109 --- /dev/null +++ b/test-projects/meta_files/expected-snapshot.json @@ -0,0 +1,57 @@ +{ + "name": "test-model", + "class_name": "Tool", + "properties": { + "Enabled": { + "Type": "Bool", + "Value": true + } + }, + "children": [ + { + "name": "A", + "class_name": "Folder", + "properties": {}, + "children": [], + "metadata": { + "ignore_unknown_instances": true, + "source_path": "src/A", + "project_definition": null + } + }, + { + "name": "Script", + "class_name": "Script", + "properties": { + "Disabled": { + "Type": "Bool", + "Value": true + }, + "Source": { + "Type": "String", + "Value": "print(\"Hello, world\")" + } + }, + "children": [], + "metadata": { + "ignore_unknown_instances": false, + "source_path": "src/Script", + "project_definition": null + } + } + ], + "metadata": { + "ignore_unknown_instances": false, + "source_path": "src", + "project_definition": [ + "test-model", + { + "class_name": null, + "children": {}, + "properties": {}, + "ignore_unknown_instances": null, + "path": "src" + } + ] + } +} \ No newline at end of file diff --git a/test-projects/meta_files/src/A/init.meta.json b/test-projects/meta_files/src/A/init.meta.json new file mode 100644 index 00000000..1025b06a --- /dev/null +++ b/test-projects/meta_files/src/A/init.meta.json @@ -0,0 +1,3 @@ +{ + "ignoreUnknownInstances": true +} \ No newline at end of file diff --git a/test-projects/meta_files/src/Script/init.meta.json b/test-projects/meta_files/src/Script/init.meta.json new file mode 100644 index 00000000..54f46925 --- /dev/null +++ b/test-projects/meta_files/src/Script/init.meta.json @@ -0,0 +1,5 @@ +{ + "properties": { + "Disabled": true + } +} \ No newline at end of file diff --git a/test-projects/meta_files/src/Script/init.server.lua b/test-projects/meta_files/src/Script/init.server.lua new file mode 100644 index 00000000..2c9b8de6 --- /dev/null +++ b/test-projects/meta_files/src/Script/init.server.lua @@ -0,0 +1 @@ +print("Hello, world") \ No newline at end of file diff --git a/test-projects/meta_files/src/init.meta.json b/test-projects/meta_files/src/init.meta.json new file mode 100644 index 00000000..fa412de2 --- /dev/null +++ b/test-projects/meta_files/src/init.meta.json @@ -0,0 +1,6 @@ +{ + "className": "Tool", + "properties": { + "Enabled": true + } +} \ No newline at end of file