mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-25 04:54:07 +00:00
Track metadata in tree snapshot tests
This commit is contained in:
parent
2ed3388e93
commit
78ef26d56c
9 changed files with 999 additions and 469 deletions
68
server/tests/snapshot_snapshots.rs
Normal file
68
server/tests/snapshot_snapshots.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
mod test_util;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
use librojo::{
|
||||||
|
imfs::Imfs,
|
||||||
|
project::Project,
|
||||||
|
rbx_snapshot::{SnapshotContext, snapshot_project_tree},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::test_util::{
|
||||||
|
snapshot::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
macro_rules! generate_snapshot_tests {
|
||||||
|
($($name: ident),*) => {
|
||||||
|
$(
|
||||||
|
paste::item! {
|
||||||
|
#[test]
|
||||||
|
fn [<snapshot_ $name>]() {
|
||||||
|
let _ = env_logger::try_init();
|
||||||
|
|
||||||
|
let tests_folder = Path::new(env!("CARGO_MANIFEST_DIR")).join("../test-projects");
|
||||||
|
let project_folder = tests_folder.join(stringify!($name));
|
||||||
|
run_snapshot_test(&project_folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_snapshot_tests!(
|
||||||
|
empty,
|
||||||
|
multi_partition_game,
|
||||||
|
nested_partitions,
|
||||||
|
single_partition_game,
|
||||||
|
single_partition_model,
|
||||||
|
transmute_partition
|
||||||
|
);
|
||||||
|
|
||||||
|
fn run_snapshot_test(path: &Path) {
|
||||||
|
println!("Running snapshot from project: {}", path.display());
|
||||||
|
|
||||||
|
let project = Project::load_fuzzy(path)
|
||||||
|
.expect("Couldn't load project file for snapshot test");
|
||||||
|
|
||||||
|
let mut imfs = Imfs::new();
|
||||||
|
imfs.add_roots_from_project(&project)
|
||||||
|
.expect("Could not add IMFS roots to snapshot project");
|
||||||
|
|
||||||
|
let context = SnapshotContext {
|
||||||
|
plugin_context: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut snapshot = snapshot_project_tree(&context, &imfs, &project)
|
||||||
|
.expect("Could not generate snapshot for snapshot test");
|
||||||
|
|
||||||
|
if let Some(snapshot) = snapshot.as_mut() {
|
||||||
|
anonymize_snapshot(path, snapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
match read_expected_snapshot(path) {
|
||||||
|
Some(expected_snapshot) => assert_eq!(snapshot, expected_snapshot),
|
||||||
|
None => write_expected_snapshot(path, &snapshot),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,194 +0,0 @@
|
||||||
mod test_util;
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
collections::HashMap,
|
|
||||||
fs,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
sync::Arc,
|
|
||||||
thread,
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use log::error;
|
|
||||||
use tempfile::{tempdir, TempDir};
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
|
|
||||||
use librojo::{
|
|
||||||
imfs::Imfs,
|
|
||||||
project::Project,
|
|
||||||
live_session::LiveSession,
|
|
||||||
rbx_snapshot::{SnapshotContext, snapshot_project_tree},
|
|
||||||
visualize::{VisualizeRbxTree, graphviz_to_svg},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::test_util::{
|
|
||||||
copy_recursive,
|
|
||||||
snapshot::*,
|
|
||||||
tree::{read_tree_by_name, write_tree_by_name, trees_equal},
|
|
||||||
};
|
|
||||||
|
|
||||||
macro_rules! generate_snapshot_tests {
|
|
||||||
($($name: ident),*) => {
|
|
||||||
$(
|
|
||||||
paste::item! {
|
|
||||||
#[test]
|
|
||||||
fn [<snapshot_ $name>]() {
|
|
||||||
let _ = env_logger::try_init();
|
|
||||||
|
|
||||||
let tests_folder = Path::new(env!("CARGO_MANIFEST_DIR")).join("../test-projects");
|
|
||||||
let project_folder = tests_folder.join(stringify!($name));
|
|
||||||
run_snapshot_test(&project_folder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
generate_snapshot_tests!(
|
|
||||||
empty,
|
|
||||||
multi_partition_game,
|
|
||||||
nested_partitions,
|
|
||||||
single_partition_game,
|
|
||||||
single_partition_model,
|
|
||||||
transmute_partition
|
|
||||||
);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn multi_partition_game() {
|
|
||||||
let _ = env_logger::try_init();
|
|
||||||
let source_path = project_path("multi_partition_game");
|
|
||||||
|
|
||||||
let (dir, live_session) = start_session(&source_path);
|
|
||||||
tree_step("initial", &live_session, &source_path);
|
|
||||||
|
|
||||||
let added_path = dir.path().join("a/added");
|
|
||||||
fs::create_dir_all(&added_path)
|
|
||||||
.expect("Couldn't create directory");
|
|
||||||
thread::sleep(Duration::from_millis(250));
|
|
||||||
|
|
||||||
tree_step("with_dir", &live_session, &source_path);
|
|
||||||
|
|
||||||
let moved_path = dir.path().join("b/added");
|
|
||||||
fs::rename(&added_path, &moved_path)
|
|
||||||
.expect("Couldn't rename directory");
|
|
||||||
thread::sleep(Duration::from_millis(250));
|
|
||||||
|
|
||||||
tree_step("with_moved_dir", &live_session, &source_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find the path to the given test project relative to the manifest.
|
|
||||||
fn project_path(name: &str) -> PathBuf {
|
|
||||||
let mut path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../test-projects");
|
|
||||||
path.push(name);
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Starts a new LiveSession for the project located at the given file path.
|
|
||||||
fn start_session(source_path: &Path) -> (TempDir, LiveSession) {
|
|
||||||
let dir = tempdir()
|
|
||||||
.expect("Couldn't create temporary directory");
|
|
||||||
|
|
||||||
copy_recursive(&source_path, dir.path())
|
|
||||||
.expect("Couldn't copy project to temporary directory");
|
|
||||||
|
|
||||||
let project = Arc::new(Project::load_fuzzy(dir.path())
|
|
||||||
.expect("Couldn't load project from temp directory"));
|
|
||||||
|
|
||||||
let live_session = LiveSession::new(Arc::clone(&project))
|
|
||||||
.expect("Couldn't start live session");
|
|
||||||
|
|
||||||
(dir, live_session)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Marks a 'step' in the test, which will snapshot the session's current
|
|
||||||
/// RbxTree object and compare it against the saved snapshot if it exists.
|
|
||||||
fn tree_step(step: &str, live_session: &LiveSession, source_path: &Path) {
|
|
||||||
let rbx_session = live_session.rbx_session.lock().unwrap();
|
|
||||||
let tree = rbx_session.get_tree();
|
|
||||||
|
|
||||||
match read_tree_by_name(source_path, step) {
|
|
||||||
Some(expected) => match trees_equal(&expected, tree) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
error!("Trees at step '{}' were not equal.\n{}", step, e);
|
|
||||||
|
|
||||||
let expected_gv = format!("{}", VisualizeRbxTree {
|
|
||||||
tree: &expected,
|
|
||||||
metadata: &HashMap::new(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let actual_gv = format!("{}", VisualizeRbxTree {
|
|
||||||
tree: rbx_session.get_tree(),
|
|
||||||
metadata: &HashMap::new(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let output_dir = PathBuf::from("failed-snapshots");
|
|
||||||
fs::create_dir_all(&output_dir)
|
|
||||||
.expect("Could not create failed-snapshots directory");
|
|
||||||
|
|
||||||
let expected_basename = format!("{}-{}-expected", live_session.root_project().name, step);
|
|
||||||
let actual_basename = format!("{}-{}-actual", live_session.root_project().name, step);
|
|
||||||
|
|
||||||
let mut expected_out = output_dir.join(expected_basename);
|
|
||||||
let mut actual_out = output_dir.join(actual_basename);
|
|
||||||
|
|
||||||
match (graphviz_to_svg(&expected_gv), graphviz_to_svg(&actual_gv)) {
|
|
||||||
(Some(expected_svg), Some(actual_svg)) => {
|
|
||||||
expected_out.set_extension("svg");
|
|
||||||
actual_out.set_extension("svg");
|
|
||||||
|
|
||||||
fs::write(&expected_out, expected_svg)
|
|
||||||
.expect("Couldn't write expected SVG");
|
|
||||||
|
|
||||||
fs::write(&actual_out, actual_svg)
|
|
||||||
.expect("Couldn't write actual SVG");
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
expected_out.set_extension("gv");
|
|
||||||
actual_out.set_extension("gv");
|
|
||||||
|
|
||||||
fs::write(&expected_out, expected_gv)
|
|
||||||
.expect("Couldn't write expected GV");
|
|
||||||
|
|
||||||
fs::write(&actual_out, actual_gv)
|
|
||||||
.expect("Couldn't write actual GV");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
error!("Output at {} and {}", expected_out.display(), actual_out.display());
|
|
||||||
|
|
||||||
panic!("Tree mismatch at step '{}'", step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
write_tree_by_name(source_path, step, tree);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_snapshot_test(path: &Path) {
|
|
||||||
println!("Running snapshot from project: {}", path.display());
|
|
||||||
|
|
||||||
let project = Project::load_fuzzy(path)
|
|
||||||
.expect("Couldn't load project file for snapshot test");
|
|
||||||
|
|
||||||
let mut imfs = Imfs::new();
|
|
||||||
imfs.add_roots_from_project(&project)
|
|
||||||
.expect("Could not add IMFS roots to snapshot project");
|
|
||||||
|
|
||||||
let context = SnapshotContext {
|
|
||||||
plugin_context: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut snapshot = snapshot_project_tree(&context, &imfs, &project)
|
|
||||||
.expect("Could not generate snapshot for snapshot test");
|
|
||||||
|
|
||||||
if let Some(snapshot) = snapshot.as_mut() {
|
|
||||||
anonymize_snapshot(path, snapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
match read_expected_snapshot(path) {
|
|
||||||
Some(expected_snapshot) => assert_eq!(snapshot, expected_snapshot),
|
|
||||||
None => write_expected_snapshot(path, &snapshot),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::fs::{create_dir, copy};
|
use std::fs::{create_dir, copy};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use std::{
|
||||||
use librojo::{
|
use librojo::{
|
||||||
project::ProjectNode,
|
project::ProjectNode,
|
||||||
snapshot_reconciler::RbxSnapshotInstance,
|
snapshot_reconciler::RbxSnapshotInstance,
|
||||||
|
rbx_session::MetadataPerInstance,
|
||||||
};
|
};
|
||||||
|
|
||||||
const SNAPSHOT_EXPECTED_NAME: &str = "expected-snapshot.json";
|
const SNAPSHOT_EXPECTED_NAME: &str = "expected-snapshot.json";
|
||||||
|
|
@ -19,15 +20,7 @@ const SNAPSHOT_EXPECTED_NAME: &str = "expected-snapshot.json";
|
||||||
/// We also need to sort children, since Rojo tends to enumerate the filesystem
|
/// We also need to sort children, since Rojo tends to enumerate the filesystem
|
||||||
/// in an unpredictable order.
|
/// in an unpredictable order.
|
||||||
pub fn anonymize_snapshot(project_folder_path: &Path, snapshot: &mut RbxSnapshotInstance) {
|
pub fn anonymize_snapshot(project_folder_path: &Path, snapshot: &mut RbxSnapshotInstance) {
|
||||||
match snapshot.metadata.source_path.as_mut() {
|
anonymize_metadata(project_folder_path, &mut snapshot.metadata);
|
||||||
Some(path) => *path = anonymize_path(project_folder_path, path),
|
|
||||||
None => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
match snapshot.metadata.project_definition.as_mut() {
|
|
||||||
Some((_, project_node)) => anonymize_project_node(project_folder_path, project_node),
|
|
||||||
None => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
snapshot.children.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
snapshot.children.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||||
|
|
||||||
|
|
@ -36,6 +29,18 @@ pub fn anonymize_snapshot(project_folder_path: &Path, snapshot: &mut RbxSnapshot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn anonymize_metadata(project_folder_path: &Path, metadata: &mut MetadataPerInstance) {
|
||||||
|
match metadata.source_path.as_mut() {
|
||||||
|
Some(path) => *path = anonymize_path(project_folder_path, path),
|
||||||
|
None => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
match metadata.project_definition.as_mut() {
|
||||||
|
Some((_, project_node)) => anonymize_project_node(project_folder_path, project_node),
|
||||||
|
None => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn anonymize_project_node(project_folder_path: &Path, project_node: &mut ProjectNode) {
|
pub fn anonymize_project_node(project_folder_path: &Path, project_node: &mut ProjectNode) {
|
||||||
match project_node.path.as_mut() {
|
match project_node.path.as_mut() {
|
||||||
Some(path) => *path = anonymize_path(project_folder_path, path),
|
Some(path) => *path = anonymize_path(project_folder_path, path),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! Defines a mechanism to compare two RbxTree objects and generate a useful
|
//! Defines a mechanism to compare two RbxTree objects and generate a useful
|
||||||
//! diff if they aren't the same. These methods ignore IDs, which are randomly
|
//! diff if they aren't the same. These methods ignore IDs, which are randomly
|
||||||
//! generated whenever a tree is constructed anyways. This makes matching up
|
//! generated whenever a tree is constructed anyways. This makes matching up
|
||||||
//! pairs of instances that should be the same pretty difficult.
|
//! pairs of instances that should be the same potentially difficult.
|
||||||
//!
|
//!
|
||||||
//! It relies on a couple different ideas:
|
//! It relies on a couple different ideas:
|
||||||
//! - Instances with the same name and class name are matched as the same
|
//! - Instances with the same name and class name are matched as the same
|
||||||
|
|
@ -12,26 +12,131 @@
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
collections::HashSet,
|
collections::{HashMap, HashSet},
|
||||||
path::Path,
|
|
||||||
fs::{self, File},
|
|
||||||
fmt,
|
fmt,
|
||||||
|
fs::{self, File},
|
||||||
|
hash::Hash,
|
||||||
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use log::error;
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
use rbx_dom_weak::{RbxId, RbxTree};
|
use rbx_dom_weak::{RbxId, RbxTree};
|
||||||
|
|
||||||
pub fn read_tree_by_name(path: &Path, identifier: &str) -> Option<RbxTree> {
|
use librojo::{
|
||||||
|
rbx_session::MetadataPerInstance,
|
||||||
|
live_session::LiveSession,
|
||||||
|
visualize::{VisualizeRbxTree, graphviz_to_svg},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::snapshot::anonymize_metadata;
|
||||||
|
|
||||||
|
/// Marks a 'step' in the test, which will snapshot the session's current
|
||||||
|
/// RbxTree object and compare it against the saved snapshot if it exists.
|
||||||
|
pub fn tree_step(step: &str, live_session: &LiveSession, source_path: &Path) {
|
||||||
|
let rbx_session = live_session.rbx_session.lock().unwrap();
|
||||||
|
let tree = rbx_session.get_tree();
|
||||||
|
|
||||||
|
let project_folder = live_session.root_project().folder_location();
|
||||||
|
let metadata = rbx_session.get_all_instance_metadata()
|
||||||
|
.iter()
|
||||||
|
.map(|(key, meta)| {
|
||||||
|
let mut meta = meta.clone();
|
||||||
|
anonymize_metadata(project_folder, &mut meta);
|
||||||
|
(*key, meta)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let tree_with_metadata = TreeWithMetadata {
|
||||||
|
tree: Cow::Borrowed(&tree),
|
||||||
|
metadata: Cow::Owned(metadata),
|
||||||
|
};
|
||||||
|
|
||||||
|
match read_tree_by_name(source_path, step) {
|
||||||
|
Some(expected) => match trees_equal(&expected, &tree_with_metadata) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Trees at step '{}' were not equal.\n{}", step, e);
|
||||||
|
|
||||||
|
let expected_gv = format!("{}", VisualizeRbxTree {
|
||||||
|
tree: &expected.tree,
|
||||||
|
metadata: &expected.metadata,
|
||||||
|
});
|
||||||
|
|
||||||
|
let actual_gv = format!("{}", VisualizeRbxTree {
|
||||||
|
tree: &tree_with_metadata.tree,
|
||||||
|
metadata: &tree_with_metadata.metadata,
|
||||||
|
});
|
||||||
|
|
||||||
|
let output_dir = PathBuf::from("failed-snapshots");
|
||||||
|
fs::create_dir_all(&output_dir)
|
||||||
|
.expect("Could not create failed-snapshots directory");
|
||||||
|
|
||||||
|
let expected_basename = format!("{}-{}-expected", live_session.root_project().name, step);
|
||||||
|
let actual_basename = format!("{}-{}-actual", live_session.root_project().name, step);
|
||||||
|
|
||||||
|
let mut expected_out = output_dir.join(expected_basename);
|
||||||
|
let mut actual_out = output_dir.join(actual_basename);
|
||||||
|
|
||||||
|
match (graphviz_to_svg(&expected_gv), graphviz_to_svg(&actual_gv)) {
|
||||||
|
(Some(expected_svg), Some(actual_svg)) => {
|
||||||
|
expected_out.set_extension("svg");
|
||||||
|
actual_out.set_extension("svg");
|
||||||
|
|
||||||
|
fs::write(&expected_out, expected_svg)
|
||||||
|
.expect("Couldn't write expected SVG");
|
||||||
|
|
||||||
|
fs::write(&actual_out, actual_svg)
|
||||||
|
.expect("Couldn't write actual SVG");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
expected_out.set_extension("gv");
|
||||||
|
actual_out.set_extension("gv");
|
||||||
|
|
||||||
|
fs::write(&expected_out, expected_gv)
|
||||||
|
.expect("Couldn't write expected GV");
|
||||||
|
|
||||||
|
fs::write(&actual_out, actual_gv)
|
||||||
|
.expect("Couldn't write actual GV");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error!("Output at {} and {}", expected_out.display(), actual_out.display());
|
||||||
|
|
||||||
|
panic!("Tree mismatch at step '{}'", step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
write_tree_by_name(source_path, step, &tree_with_metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_cow_map<K: Clone + Eq + Hash, V: Clone>() -> Cow<'static, HashMap<K, V>> {
|
||||||
|
Cow::Owned(HashMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
struct TreeWithMetadata<'a> {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub tree: Cow<'a, RbxTree>,
|
||||||
|
|
||||||
|
#[serde(default = "new_cow_map")]
|
||||||
|
pub metadata: Cow<'a, HashMap<RbxId, MetadataPerInstance>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_tree_by_name(path: &Path, identifier: &str) -> Option<TreeWithMetadata<'static>> {
|
||||||
let mut file_path = path.join(identifier);
|
let mut file_path = path.join(identifier);
|
||||||
file_path.set_extension("tree.json");
|
file_path.set_extension("tree.json");
|
||||||
|
|
||||||
let contents = fs::read(&file_path).ok()?;
|
let contents = fs::read(&file_path).ok()?;
|
||||||
let tree: RbxTree = serde_json::from_slice(&contents)
|
let tree: TreeWithMetadata = serde_json::from_slice(&contents)
|
||||||
.expect("Could not deserialize tree");
|
.expect("Could not deserialize tree");
|
||||||
|
|
||||||
Some(tree)
|
Some(tree)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_tree_by_name(path: &Path, identifier: &str, tree: &RbxTree) {
|
fn write_tree_by_name(path: &Path, identifier: &str, tree: &TreeWithMetadata) {
|
||||||
let mut file_path = path.join(identifier);
|
let mut file_path = path.join(identifier);
|
||||||
file_path.set_extension("tree.json");
|
file_path.set_extension("tree.json");
|
||||||
|
|
||||||
|
|
@ -43,7 +148,7 @@ pub fn write_tree_by_name(path: &Path, identifier: &str, tree: &RbxTree) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TreeMismatch {
|
struct TreeMismatch {
|
||||||
pub path: Cow<'static, str>,
|
pub path: Cow<'static, str>,
|
||||||
pub detail: Cow<'static, str>,
|
pub detail: Cow<'static, str>,
|
||||||
}
|
}
|
||||||
|
|
@ -74,27 +179,38 @@ impl fmt::Display for TreeMismatch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trees_equal(left_tree: &RbxTree, right_tree: &RbxTree) -> Result<(), TreeMismatch> {
|
fn trees_equal(
|
||||||
let left_id = left_tree.get_root_id();
|
left_tree: &TreeWithMetadata,
|
||||||
let right_id = right_tree.get_root_id();
|
right_tree: &TreeWithMetadata,
|
||||||
|
) -> Result<(), TreeMismatch> {
|
||||||
|
let left_id = left_tree.tree.get_root_id();
|
||||||
|
let right_id = right_tree.tree.get_root_id();
|
||||||
|
|
||||||
basic_equal(left_tree, left_id, right_tree, right_id)?;
|
instances_equal(left_tree, left_id, right_tree, right_id)
|
||||||
properties_equal(left_tree, left_id, right_tree, right_id)?;
|
|
||||||
|
|
||||||
children_equal(left_tree, left_id, right_tree, right_id)
|
|
||||||
.map_err(|e| {
|
|
||||||
let left_instance = left_tree.get_instance(left_id)
|
|
||||||
.expect("ID did not exist in left tree");
|
|
||||||
|
|
||||||
e.add_parent(&left_instance.name)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn basic_equal(left_tree: &RbxTree, left_id: RbxId, right_tree: &RbxTree, right_id: RbxId) -> Result<(), TreeMismatch> {
|
fn instances_equal(
|
||||||
let left_instance = left_tree.get_instance(left_id)
|
left_tree: &TreeWithMetadata,
|
||||||
|
left_id: RbxId,
|
||||||
|
right_tree: &TreeWithMetadata,
|
||||||
|
right_id: RbxId,
|
||||||
|
) -> Result<(), TreeMismatch> {
|
||||||
|
basic_equal(left_tree, left_id, right_tree, right_id)?;
|
||||||
|
properties_equal(left_tree, left_id, right_tree, right_id)?;
|
||||||
|
children_equal(left_tree, left_id, right_tree, right_id)?;
|
||||||
|
metadata_equal(left_tree, left_id, right_tree, right_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basic_equal(
|
||||||
|
left_tree: &TreeWithMetadata,
|
||||||
|
left_id: RbxId,
|
||||||
|
right_tree: &TreeWithMetadata,
|
||||||
|
right_id: RbxId,
|
||||||
|
) -> Result<(), TreeMismatch> {
|
||||||
|
let left_instance = left_tree.tree.get_instance(left_id)
|
||||||
.expect("ID did not exist in left tree");
|
.expect("ID did not exist in left tree");
|
||||||
|
|
||||||
let right_instance = right_tree.get_instance(right_id)
|
let right_instance = right_tree.tree.get_instance(right_id)
|
||||||
.expect("ID did not exist in right tree");
|
.expect("ID did not exist in right tree");
|
||||||
|
|
||||||
if left_instance.name != right_instance.name {
|
if left_instance.name != right_instance.name {
|
||||||
|
|
@ -112,11 +228,16 @@ fn basic_equal(left_tree: &RbxTree, left_id: RbxId, right_tree: &RbxTree, right_
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn properties_equal(left_tree: &RbxTree, left_id: RbxId, right_tree: &RbxTree, right_id: RbxId) -> Result<(), TreeMismatch> {
|
fn properties_equal(
|
||||||
let left_instance = left_tree.get_instance(left_id)
|
left_tree: &TreeWithMetadata,
|
||||||
|
left_id: RbxId,
|
||||||
|
right_tree: &TreeWithMetadata,
|
||||||
|
right_id: RbxId,
|
||||||
|
) -> Result<(), TreeMismatch> {
|
||||||
|
let left_instance = left_tree.tree.get_instance(left_id)
|
||||||
.expect("ID did not exist in left tree");
|
.expect("ID did not exist in left tree");
|
||||||
|
|
||||||
let right_instance = right_tree.get_instance(right_id)
|
let right_instance = right_tree.tree.get_instance(right_id)
|
||||||
.expect("ID did not exist in right tree");
|
.expect("ID did not exist in right tree");
|
||||||
|
|
||||||
let mut visited = HashSet::new();
|
let mut visited = HashSet::new();
|
||||||
|
|
@ -147,7 +268,7 @@ fn properties_equal(left_tree: &RbxTree, left_id: RbxId, right_tree: &RbxTree, r
|
||||||
|
|
||||||
if left_value != Some(right_value) {
|
if left_value != Some(right_value) {
|
||||||
let message = format!(
|
let message = format!(
|
||||||
"Property {} was {:?} on left and {:?} on right",
|
"Property {}:\n\tLeft: {:?}\n\tRight: {:?}",
|
||||||
key,
|
key,
|
||||||
left_value,
|
left_value,
|
||||||
Some(right_value),
|
Some(right_value),
|
||||||
|
|
@ -160,11 +281,16 @@ fn properties_equal(left_tree: &RbxTree, left_id: RbxId, right_tree: &RbxTree, r
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children_equal(left_tree: &RbxTree, left_id: RbxId, right_tree: &RbxTree, right_id: RbxId) -> Result<(), TreeMismatch> {
|
fn children_equal(
|
||||||
let left_instance = left_tree.get_instance(left_id)
|
left_tree: &TreeWithMetadata,
|
||||||
|
left_id: RbxId,
|
||||||
|
right_tree: &TreeWithMetadata,
|
||||||
|
right_id: RbxId,
|
||||||
|
) -> Result<(), TreeMismatch> {
|
||||||
|
let left_instance = left_tree.tree.get_instance(left_id)
|
||||||
.expect("ID did not exist in left tree");
|
.expect("ID did not exist in left tree");
|
||||||
|
|
||||||
let right_instance = right_tree.get_instance(right_id)
|
let right_instance = right_tree.tree.get_instance(right_id)
|
||||||
.expect("ID did not exist in right tree");
|
.expect("ID did not exist in right tree");
|
||||||
|
|
||||||
let left_children = left_instance.get_children_ids();
|
let left_children = left_instance.get_children_ids();
|
||||||
|
|
@ -175,15 +301,34 @@ fn children_equal(left_tree: &RbxTree, left_id: RbxId, right_tree: &RbxTree, rig
|
||||||
}
|
}
|
||||||
|
|
||||||
for (left_child_id, right_child_id) in left_children.iter().zip(right_children) {
|
for (left_child_id, right_child_id) in left_children.iter().zip(right_children) {
|
||||||
basic_equal(left_tree, *left_child_id, right_tree, *right_child_id)
|
instances_equal(left_tree, *left_child_id, right_tree, *right_child_id)
|
||||||
.map_err(|e| e.add_parent(&left_instance.name))?;
|
|
||||||
|
|
||||||
properties_equal(left_tree, *left_child_id, right_tree, *right_child_id)
|
|
||||||
.map_err(|e| e.add_parent(&left_instance.name))?;
|
|
||||||
|
|
||||||
children_equal(left_tree, *left_child_id, right_tree, *right_child_id)
|
|
||||||
.map_err(|e| e.add_parent(&left_instance.name))?;
|
.map_err(|e| e.add_parent(&left_instance.name))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn metadata_equal(
|
||||||
|
left_tree: &TreeWithMetadata,
|
||||||
|
left_id: RbxId,
|
||||||
|
right_tree: &TreeWithMetadata,
|
||||||
|
right_id: RbxId,
|
||||||
|
) -> Result<(), TreeMismatch> {
|
||||||
|
let left_meta = left_tree.metadata.get(&left_id);
|
||||||
|
let right_meta = right_tree.metadata.get(&right_id);
|
||||||
|
|
||||||
|
if left_meta != right_meta {
|
||||||
|
let left_instance = left_tree.tree.get_instance(left_id)
|
||||||
|
.expect("Left instance didn't exist in tree");
|
||||||
|
|
||||||
|
let message = format!(
|
||||||
|
"Metadata mismatch:\n\tLeft: {:?}\n\tRight: {:?}",
|
||||||
|
left_meta,
|
||||||
|
right_meta,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(TreeMismatch::new(&left_instance.name, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
68
server/tests/tree_snapshots.rs
Normal file
68
server/tests/tree_snapshots.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
mod test_util;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fs,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
sync::Arc,
|
||||||
|
thread,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use tempfile::{tempdir, TempDir};
|
||||||
|
|
||||||
|
use librojo::{
|
||||||
|
live_session::LiveSession,
|
||||||
|
project::Project,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::test_util::{
|
||||||
|
copy_recursive,
|
||||||
|
tree::tree_step,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multi_partition_game() {
|
||||||
|
let _ = env_logger::try_init();
|
||||||
|
let source_path = project_path("multi_partition_game");
|
||||||
|
|
||||||
|
let (dir, live_session) = start_session(&source_path);
|
||||||
|
tree_step("initial", &live_session, &source_path);
|
||||||
|
|
||||||
|
let added_path = dir.path().join("a/added");
|
||||||
|
fs::create_dir_all(&added_path)
|
||||||
|
.expect("Couldn't create directory");
|
||||||
|
thread::sleep(Duration::from_millis(250));
|
||||||
|
|
||||||
|
tree_step("with_dir", &live_session, &source_path);
|
||||||
|
|
||||||
|
let moved_path = dir.path().join("b/added");
|
||||||
|
fs::rename(&added_path, &moved_path)
|
||||||
|
.expect("Couldn't rename directory");
|
||||||
|
thread::sleep(Duration::from_millis(250));
|
||||||
|
|
||||||
|
tree_step("with_moved_dir", &live_session, &source_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find the path to the given test project relative to the manifest.
|
||||||
|
fn project_path(name: &str) -> PathBuf {
|
||||||
|
let mut path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../test-projects");
|
||||||
|
path.push(name);
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Starts a new LiveSession for the project located at the given file path.
|
||||||
|
fn start_session(source_path: &Path) -> (TempDir, LiveSession) {
|
||||||
|
let dir = tempdir()
|
||||||
|
.expect("Couldn't create temporary directory");
|
||||||
|
|
||||||
|
copy_recursive(&source_path, dir.path())
|
||||||
|
.expect("Couldn't copy project to temporary directory");
|
||||||
|
|
||||||
|
let project = Arc::new(Project::load_fuzzy(dir.path())
|
||||||
|
.expect("Couldn't load project from temp directory"));
|
||||||
|
|
||||||
|
let live_session = LiveSession::new(Arc::clone(&project))
|
||||||
|
.expect("Couldn't start live session");
|
||||||
|
|
||||||
|
(dir, live_session)
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,6 @@
|
||||||
{
|
{
|
||||||
"instances": {
|
"instances": {
|
||||||
"6a7e0c50-e85d-4abc-863b-48db75038c65": {
|
"8d44bb30-db3c-4366-a6c5-633bd1441885": {
|
||||||
"Name": "foo",
|
|
||||||
"ClassName": "StringValue",
|
|
||||||
"Properties": {
|
|
||||||
"Value": {
|
|
||||||
"Type": "String",
|
|
||||||
"Value": "Hello world, from a/foo.txt"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Id": "6a7e0c50-e85d-4abc-863b-48db75038c65",
|
|
||||||
"Children": [],
|
|
||||||
"Parent": "a27d1480-d3d6-424b-86e9-faf9cf387ae8"
|
|
||||||
},
|
|
||||||
"7abdb15d-9899-414a-baf0-7874c56f8b2a": {
|
|
||||||
"Name": "main",
|
"Name": "main",
|
||||||
"ClassName": "ModuleScript",
|
"ClassName": "ModuleScript",
|
||||||
"Properties": {
|
"Properties": {
|
||||||
|
|
@ -22,67 +9,43 @@
|
||||||
"Value": "-- hello, from a/main.lua"
|
"Value": "-- hello, from a/main.lua"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Id": "7abdb15d-9899-414a-baf0-7874c56f8b2a",
|
"Id": "8d44bb30-db3c-4366-a6c5-633bd1441885",
|
||||||
"Children": [],
|
"Children": [],
|
||||||
"Parent": "a27d1480-d3d6-424b-86e9-faf9cf387ae8"
|
"Parent": "1aafa29b-bdca-40a0-a677-7ead327b84ce"
|
||||||
},
|
},
|
||||||
"f147da62-b6dc-4833-985a-36941e47de82": {
|
"b1c9928c-bf11-427f-90eb-b672c811d859": {
|
||||||
"Name": "multi_partition_game",
|
|
||||||
"ClassName": "DataModel",
|
|
||||||
"Properties": {},
|
|
||||||
"Id": "f147da62-b6dc-4833-985a-36941e47de82",
|
|
||||||
"Children": [
|
|
||||||
"7be3f86d-f8ce-4c6b-88cb-03db03a3fd57",
|
|
||||||
"fe1dd5ab-3255-47e3-a2b4-8c7181ab715e"
|
|
||||||
],
|
|
||||||
"Parent": null
|
|
||||||
},
|
|
||||||
"fe1dd5ab-3255-47e3-a2b4-8c7181ab715e": {
|
|
||||||
"Name": "ReplicatedStorage",
|
|
||||||
"ClassName": "ReplicatedStorage",
|
|
||||||
"Properties": {},
|
|
||||||
"Id": "fe1dd5ab-3255-47e3-a2b4-8c7181ab715e",
|
|
||||||
"Children": [
|
|
||||||
"a27d1480-d3d6-424b-86e9-faf9cf387ae8",
|
|
||||||
"6ce9c44a-0e66-4aaf-97e7-086407aed226"
|
|
||||||
],
|
|
||||||
"Parent": "f147da62-b6dc-4833-985a-36941e47de82"
|
|
||||||
},
|
|
||||||
"7be3f86d-f8ce-4c6b-88cb-03db03a3fd57": {
|
|
||||||
"Name": "HttpService",
|
|
||||||
"ClassName": "HttpService",
|
|
||||||
"Properties": {
|
|
||||||
"HttpEnabled": {
|
|
||||||
"Type": "Bool",
|
|
||||||
"Value": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Id": "7be3f86d-f8ce-4c6b-88cb-03db03a3fd57",
|
|
||||||
"Children": [],
|
|
||||||
"Parent": "f147da62-b6dc-4833-985a-36941e47de82"
|
|
||||||
},
|
|
||||||
"a27d1480-d3d6-424b-86e9-faf9cf387ae8": {
|
|
||||||
"Name": "Ack",
|
|
||||||
"ClassName": "Folder",
|
|
||||||
"Properties": {},
|
|
||||||
"Id": "a27d1480-d3d6-424b-86e9-faf9cf387ae8",
|
|
||||||
"Children": [
|
|
||||||
"6a7e0c50-e85d-4abc-863b-48db75038c65",
|
|
||||||
"7abdb15d-9899-414a-baf0-7874c56f8b2a"
|
|
||||||
],
|
|
||||||
"Parent": "fe1dd5ab-3255-47e3-a2b4-8c7181ab715e"
|
|
||||||
},
|
|
||||||
"6ce9c44a-0e66-4aaf-97e7-086407aed226": {
|
|
||||||
"Name": "Bar",
|
"Name": "Bar",
|
||||||
"ClassName": "Folder",
|
"ClassName": "Folder",
|
||||||
"Properties": {},
|
"Properties": {},
|
||||||
"Id": "6ce9c44a-0e66-4aaf-97e7-086407aed226",
|
"Id": "b1c9928c-bf11-427f-90eb-b672c811d859",
|
||||||
"Children": [
|
"Children": [
|
||||||
"8e0006d3-9f03-4ed4-9cb6-81abe23a4754"
|
"8d690a2a-e987-4c86-b9ac-18e6d3a98503"
|
||||||
],
|
],
|
||||||
"Parent": "fe1dd5ab-3255-47e3-a2b4-8c7181ab715e"
|
"Parent": "9f141826-14c2-492b-b360-2558712f0c08"
|
||||||
},
|
},
|
||||||
"8e0006d3-9f03-4ed4-9cb6-81abe23a4754": {
|
"645ba594-4482-441f-9f41-5bb9c444405b": {
|
||||||
|
"Name": "multi_partition_game",
|
||||||
|
"ClassName": "DataModel",
|
||||||
|
"Properties": {},
|
||||||
|
"Id": "645ba594-4482-441f-9f41-5bb9c444405b",
|
||||||
|
"Children": [
|
||||||
|
"b1298bcc-e370-44a6-9ef4-fbefa290124c",
|
||||||
|
"9f141826-14c2-492b-b360-2558712f0c08"
|
||||||
|
],
|
||||||
|
"Parent": null
|
||||||
|
},
|
||||||
|
"9f141826-14c2-492b-b360-2558712f0c08": {
|
||||||
|
"Name": "ReplicatedStorage",
|
||||||
|
"ClassName": "ReplicatedStorage",
|
||||||
|
"Properties": {},
|
||||||
|
"Id": "9f141826-14c2-492b-b360-2558712f0c08",
|
||||||
|
"Children": [
|
||||||
|
"1aafa29b-bdca-40a0-a677-7ead327b84ce",
|
||||||
|
"b1c9928c-bf11-427f-90eb-b672c811d859"
|
||||||
|
],
|
||||||
|
"Parent": "645ba594-4482-441f-9f41-5bb9c444405b"
|
||||||
|
},
|
||||||
|
"8d690a2a-e987-4c86-b9ac-18e6d3a98503": {
|
||||||
"Name": "something",
|
"Name": "something",
|
||||||
"ClassName": "ModuleScript",
|
"ClassName": "ModuleScript",
|
||||||
"Properties": {
|
"Properties": {
|
||||||
|
|
@ -91,10 +54,189 @@
|
||||||
"Value": "-- b/something.lua"
|
"Value": "-- b/something.lua"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Id": "8e0006d3-9f03-4ed4-9cb6-81abe23a4754",
|
"Id": "8d690a2a-e987-4c86-b9ac-18e6d3a98503",
|
||||||
"Children": [],
|
"Children": [],
|
||||||
"Parent": "6ce9c44a-0e66-4aaf-97e7-086407aed226"
|
"Parent": "b1c9928c-bf11-427f-90eb-b672c811d859"
|
||||||
|
},
|
||||||
|
"b1298bcc-e370-44a6-9ef4-fbefa290124c": {
|
||||||
|
"Name": "HttpService",
|
||||||
|
"ClassName": "HttpService",
|
||||||
|
"Properties": {
|
||||||
|
"HttpEnabled": {
|
||||||
|
"Type": "Bool",
|
||||||
|
"Value": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root_id": "f147da62-b6dc-4833-985a-36941e47de82"
|
"Id": "b1298bcc-e370-44a6-9ef4-fbefa290124c",
|
||||||
|
"Children": [],
|
||||||
|
"Parent": "645ba594-4482-441f-9f41-5bb9c444405b"
|
||||||
|
},
|
||||||
|
"54f2f276-964f-4c60-87d8-5fb2209c97c9": {
|
||||||
|
"Name": "foo",
|
||||||
|
"ClassName": "StringValue",
|
||||||
|
"Properties": {
|
||||||
|
"Value": {
|
||||||
|
"Type": "String",
|
||||||
|
"Value": "Hello world, from a/foo.txt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Id": "54f2f276-964f-4c60-87d8-5fb2209c97c9",
|
||||||
|
"Children": [],
|
||||||
|
"Parent": "1aafa29b-bdca-40a0-a677-7ead327b84ce"
|
||||||
|
},
|
||||||
|
"1aafa29b-bdca-40a0-a677-7ead327b84ce": {
|
||||||
|
"Name": "Ack",
|
||||||
|
"ClassName": "Folder",
|
||||||
|
"Properties": {},
|
||||||
|
"Id": "1aafa29b-bdca-40a0-a677-7ead327b84ce",
|
||||||
|
"Children": [
|
||||||
|
"54f2f276-964f-4c60-87d8-5fb2209c97c9",
|
||||||
|
"8d44bb30-db3c-4366-a6c5-633bd1441885"
|
||||||
|
],
|
||||||
|
"Parent": "9f141826-14c2-492b-b360-2558712f0c08"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root_id": "645ba594-4482-441f-9f41-5bb9c444405b",
|
||||||
|
"metadata": {
|
||||||
|
"645ba594-4482-441f-9f41-5bb9c444405b": {
|
||||||
|
"ignore_unknown_instances": true,
|
||||||
|
"source_path": null,
|
||||||
|
"project_definition": [
|
||||||
|
"multi_partition_game",
|
||||||
|
{
|
||||||
|
"class_name": "DataModel",
|
||||||
|
"children": {
|
||||||
|
"HttpService": {
|
||||||
|
"class_name": "HttpService",
|
||||||
|
"children": {},
|
||||||
|
"properties": {
|
||||||
|
"HttpEnabled": {
|
||||||
|
"Type": "Bool",
|
||||||
|
"Value": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
},
|
||||||
|
"ReplicatedStorage": {
|
||||||
|
"class_name": "ReplicatedStorage",
|
||||||
|
"children": {
|
||||||
|
"Ack": {
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "a"
|
||||||
|
},
|
||||||
|
"Bar": {
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"1aafa29b-bdca-40a0-a677-7ead327b84ce": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "a",
|
||||||
|
"project_definition": [
|
||||||
|
"Ack",
|
||||||
|
{
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "a"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"b1c9928c-bf11-427f-90eb-b672c811d859": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "b",
|
||||||
|
"project_definition": [
|
||||||
|
"Bar",
|
||||||
|
{
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "b"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"54f2f276-964f-4c60-87d8-5fb2209c97c9": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "a/foo.txt",
|
||||||
|
"project_definition": null
|
||||||
|
},
|
||||||
|
"9f141826-14c2-492b-b360-2558712f0c08": {
|
||||||
|
"ignore_unknown_instances": true,
|
||||||
|
"source_path": null,
|
||||||
|
"project_definition": [
|
||||||
|
"ReplicatedStorage",
|
||||||
|
{
|
||||||
|
"class_name": "ReplicatedStorage",
|
||||||
|
"children": {
|
||||||
|
"Ack": {
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "a"
|
||||||
|
},
|
||||||
|
"Bar": {
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"8d44bb30-db3c-4366-a6c5-633bd1441885": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "a/main.lua",
|
||||||
|
"project_definition": null
|
||||||
|
},
|
||||||
|
"b1298bcc-e370-44a6-9ef4-fbefa290124c": {
|
||||||
|
"ignore_unknown_instances": true,
|
||||||
|
"source_path": null,
|
||||||
|
"project_definition": [
|
||||||
|
"HttpService",
|
||||||
|
{
|
||||||
|
"class_name": "HttpService",
|
||||||
|
"children": {},
|
||||||
|
"properties": {
|
||||||
|
"HttpEnabled": {
|
||||||
|
"Type": "Bool",
|
||||||
|
"Value": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"8d690a2a-e987-4c86-b9ac-18e6d3a98503": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "b/something.lua",
|
||||||
|
"project_definition": null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,19 +1,6 @@
|
||||||
{
|
{
|
||||||
"instances": {
|
"instances": {
|
||||||
"6a7e0c50-e85d-4abc-863b-48db75038c65": {
|
"8d44bb30-db3c-4366-a6c5-633bd1441885": {
|
||||||
"Name": "foo",
|
|
||||||
"ClassName": "StringValue",
|
|
||||||
"Properties": {
|
|
||||||
"Value": {
|
|
||||||
"Type": "String",
|
|
||||||
"Value": "Hello world, from a/foo.txt"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Id": "6a7e0c50-e85d-4abc-863b-48db75038c65",
|
|
||||||
"Children": [],
|
|
||||||
"Parent": "a27d1480-d3d6-424b-86e9-faf9cf387ae8"
|
|
||||||
},
|
|
||||||
"7abdb15d-9899-414a-baf0-7874c56f8b2a": {
|
|
||||||
"Name": "main",
|
"Name": "main",
|
||||||
"ClassName": "ModuleScript",
|
"ClassName": "ModuleScript",
|
||||||
"Properties": {
|
"Properties": {
|
||||||
|
|
@ -22,76 +9,43 @@
|
||||||
"Value": "-- hello, from a/main.lua"
|
"Value": "-- hello, from a/main.lua"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Id": "7abdb15d-9899-414a-baf0-7874c56f8b2a",
|
"Id": "8d44bb30-db3c-4366-a6c5-633bd1441885",
|
||||||
"Children": [],
|
"Children": [],
|
||||||
"Parent": "a27d1480-d3d6-424b-86e9-faf9cf387ae8"
|
"Parent": "1aafa29b-bdca-40a0-a677-7ead327b84ce"
|
||||||
},
|
},
|
||||||
"f147da62-b6dc-4833-985a-36941e47de82": {
|
"b1c9928c-bf11-427f-90eb-b672c811d859": {
|
||||||
"Name": "multi_partition_game",
|
|
||||||
"ClassName": "DataModel",
|
|
||||||
"Properties": {},
|
|
||||||
"Id": "f147da62-b6dc-4833-985a-36941e47de82",
|
|
||||||
"Children": [
|
|
||||||
"7be3f86d-f8ce-4c6b-88cb-03db03a3fd57",
|
|
||||||
"fe1dd5ab-3255-47e3-a2b4-8c7181ab715e"
|
|
||||||
],
|
|
||||||
"Parent": null
|
|
||||||
},
|
|
||||||
"b3cc71c5-a558-4fce-a795-cd955ba73c38": {
|
|
||||||
"Name": "added",
|
|
||||||
"ClassName": "Folder",
|
|
||||||
"Properties": {},
|
|
||||||
"Id": "b3cc71c5-a558-4fce-a795-cd955ba73c38",
|
|
||||||
"Children": [],
|
|
||||||
"Parent": "a27d1480-d3d6-424b-86e9-faf9cf387ae8"
|
|
||||||
},
|
|
||||||
"fe1dd5ab-3255-47e3-a2b4-8c7181ab715e": {
|
|
||||||
"Name": "ReplicatedStorage",
|
|
||||||
"ClassName": "ReplicatedStorage",
|
|
||||||
"Properties": {},
|
|
||||||
"Id": "fe1dd5ab-3255-47e3-a2b4-8c7181ab715e",
|
|
||||||
"Children": [
|
|
||||||
"a27d1480-d3d6-424b-86e9-faf9cf387ae8",
|
|
||||||
"6ce9c44a-0e66-4aaf-97e7-086407aed226"
|
|
||||||
],
|
|
||||||
"Parent": "f147da62-b6dc-4833-985a-36941e47de82"
|
|
||||||
},
|
|
||||||
"7be3f86d-f8ce-4c6b-88cb-03db03a3fd57": {
|
|
||||||
"Name": "HttpService",
|
|
||||||
"ClassName": "HttpService",
|
|
||||||
"Properties": {
|
|
||||||
"HttpEnabled": {
|
|
||||||
"Type": "Bool",
|
|
||||||
"Value": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Id": "7be3f86d-f8ce-4c6b-88cb-03db03a3fd57",
|
|
||||||
"Children": [],
|
|
||||||
"Parent": "f147da62-b6dc-4833-985a-36941e47de82"
|
|
||||||
},
|
|
||||||
"a27d1480-d3d6-424b-86e9-faf9cf387ae8": {
|
|
||||||
"Name": "Ack",
|
|
||||||
"ClassName": "Folder",
|
|
||||||
"Properties": {},
|
|
||||||
"Id": "a27d1480-d3d6-424b-86e9-faf9cf387ae8",
|
|
||||||
"Children": [
|
|
||||||
"6a7e0c50-e85d-4abc-863b-48db75038c65",
|
|
||||||
"7abdb15d-9899-414a-baf0-7874c56f8b2a",
|
|
||||||
"b3cc71c5-a558-4fce-a795-cd955ba73c38"
|
|
||||||
],
|
|
||||||
"Parent": "fe1dd5ab-3255-47e3-a2b4-8c7181ab715e"
|
|
||||||
},
|
|
||||||
"6ce9c44a-0e66-4aaf-97e7-086407aed226": {
|
|
||||||
"Name": "Bar",
|
"Name": "Bar",
|
||||||
"ClassName": "Folder",
|
"ClassName": "Folder",
|
||||||
"Properties": {},
|
"Properties": {},
|
||||||
"Id": "6ce9c44a-0e66-4aaf-97e7-086407aed226",
|
"Id": "b1c9928c-bf11-427f-90eb-b672c811d859",
|
||||||
"Children": [
|
"Children": [
|
||||||
"8e0006d3-9f03-4ed4-9cb6-81abe23a4754"
|
"8d690a2a-e987-4c86-b9ac-18e6d3a98503"
|
||||||
],
|
],
|
||||||
"Parent": "fe1dd5ab-3255-47e3-a2b4-8c7181ab715e"
|
"Parent": "9f141826-14c2-492b-b360-2558712f0c08"
|
||||||
},
|
},
|
||||||
"8e0006d3-9f03-4ed4-9cb6-81abe23a4754": {
|
"645ba594-4482-441f-9f41-5bb9c444405b": {
|
||||||
|
"Name": "multi_partition_game",
|
||||||
|
"ClassName": "DataModel",
|
||||||
|
"Properties": {},
|
||||||
|
"Id": "645ba594-4482-441f-9f41-5bb9c444405b",
|
||||||
|
"Children": [
|
||||||
|
"b1298bcc-e370-44a6-9ef4-fbefa290124c",
|
||||||
|
"9f141826-14c2-492b-b360-2558712f0c08"
|
||||||
|
],
|
||||||
|
"Parent": null
|
||||||
|
},
|
||||||
|
"9f141826-14c2-492b-b360-2558712f0c08": {
|
||||||
|
"Name": "ReplicatedStorage",
|
||||||
|
"ClassName": "ReplicatedStorage",
|
||||||
|
"Properties": {},
|
||||||
|
"Id": "9f141826-14c2-492b-b360-2558712f0c08",
|
||||||
|
"Children": [
|
||||||
|
"1aafa29b-bdca-40a0-a677-7ead327b84ce",
|
||||||
|
"b1c9928c-bf11-427f-90eb-b672c811d859"
|
||||||
|
],
|
||||||
|
"Parent": "645ba594-4482-441f-9f41-5bb9c444405b"
|
||||||
|
},
|
||||||
|
"8d690a2a-e987-4c86-b9ac-18e6d3a98503": {
|
||||||
"Name": "something",
|
"Name": "something",
|
||||||
"ClassName": "ModuleScript",
|
"ClassName": "ModuleScript",
|
||||||
"Properties": {
|
"Properties": {
|
||||||
|
|
@ -100,10 +54,203 @@
|
||||||
"Value": "-- b/something.lua"
|
"Value": "-- b/something.lua"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Id": "8e0006d3-9f03-4ed4-9cb6-81abe23a4754",
|
"Id": "8d690a2a-e987-4c86-b9ac-18e6d3a98503",
|
||||||
"Children": [],
|
"Children": [],
|
||||||
"Parent": "6ce9c44a-0e66-4aaf-97e7-086407aed226"
|
"Parent": "b1c9928c-bf11-427f-90eb-b672c811d859"
|
||||||
|
},
|
||||||
|
"b1298bcc-e370-44a6-9ef4-fbefa290124c": {
|
||||||
|
"Name": "HttpService",
|
||||||
|
"ClassName": "HttpService",
|
||||||
|
"Properties": {
|
||||||
|
"HttpEnabled": {
|
||||||
|
"Type": "Bool",
|
||||||
|
"Value": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root_id": "f147da62-b6dc-4833-985a-36941e47de82"
|
"Id": "b1298bcc-e370-44a6-9ef4-fbefa290124c",
|
||||||
|
"Children": [],
|
||||||
|
"Parent": "645ba594-4482-441f-9f41-5bb9c444405b"
|
||||||
|
},
|
||||||
|
"46353305-8818-48fe-94fd-80cf0c5d974c": {
|
||||||
|
"Name": "added",
|
||||||
|
"ClassName": "Folder",
|
||||||
|
"Properties": {},
|
||||||
|
"Id": "46353305-8818-48fe-94fd-80cf0c5d974c",
|
||||||
|
"Children": [],
|
||||||
|
"Parent": "1aafa29b-bdca-40a0-a677-7ead327b84ce"
|
||||||
|
},
|
||||||
|
"54f2f276-964f-4c60-87d8-5fb2209c97c9": {
|
||||||
|
"Name": "foo",
|
||||||
|
"ClassName": "StringValue",
|
||||||
|
"Properties": {
|
||||||
|
"Value": {
|
||||||
|
"Type": "String",
|
||||||
|
"Value": "Hello world, from a/foo.txt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Id": "54f2f276-964f-4c60-87d8-5fb2209c97c9",
|
||||||
|
"Children": [],
|
||||||
|
"Parent": "1aafa29b-bdca-40a0-a677-7ead327b84ce"
|
||||||
|
},
|
||||||
|
"1aafa29b-bdca-40a0-a677-7ead327b84ce": {
|
||||||
|
"Name": "Ack",
|
||||||
|
"ClassName": "Folder",
|
||||||
|
"Properties": {},
|
||||||
|
"Id": "1aafa29b-bdca-40a0-a677-7ead327b84ce",
|
||||||
|
"Children": [
|
||||||
|
"54f2f276-964f-4c60-87d8-5fb2209c97c9",
|
||||||
|
"8d44bb30-db3c-4366-a6c5-633bd1441885",
|
||||||
|
"46353305-8818-48fe-94fd-80cf0c5d974c"
|
||||||
|
],
|
||||||
|
"Parent": "9f141826-14c2-492b-b360-2558712f0c08"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root_id": "645ba594-4482-441f-9f41-5bb9c444405b",
|
||||||
|
"metadata": {
|
||||||
|
"b1c9928c-bf11-427f-90eb-b672c811d859": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "b",
|
||||||
|
"project_definition": [
|
||||||
|
"Bar",
|
||||||
|
{
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "b"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"54f2f276-964f-4c60-87d8-5fb2209c97c9": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "a/foo.txt",
|
||||||
|
"project_definition": null
|
||||||
|
},
|
||||||
|
"8d44bb30-db3c-4366-a6c5-633bd1441885": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "a/main.lua",
|
||||||
|
"project_definition": null
|
||||||
|
},
|
||||||
|
"9f141826-14c2-492b-b360-2558712f0c08": {
|
||||||
|
"ignore_unknown_instances": true,
|
||||||
|
"source_path": null,
|
||||||
|
"project_definition": [
|
||||||
|
"ReplicatedStorage",
|
||||||
|
{
|
||||||
|
"class_name": "ReplicatedStorage",
|
||||||
|
"children": {
|
||||||
|
"Ack": {
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "a"
|
||||||
|
},
|
||||||
|
"Bar": {
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"b1298bcc-e370-44a6-9ef4-fbefa290124c": {
|
||||||
|
"ignore_unknown_instances": true,
|
||||||
|
"source_path": null,
|
||||||
|
"project_definition": [
|
||||||
|
"HttpService",
|
||||||
|
{
|
||||||
|
"class_name": "HttpService",
|
||||||
|
"children": {},
|
||||||
|
"properties": {
|
||||||
|
"HttpEnabled": {
|
||||||
|
"Type": "Bool",
|
||||||
|
"Value": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"46353305-8818-48fe-94fd-80cf0c5d974c": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "a/added",
|
||||||
|
"project_definition": null
|
||||||
|
},
|
||||||
|
"1aafa29b-bdca-40a0-a677-7ead327b84ce": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "a",
|
||||||
|
"project_definition": [
|
||||||
|
"Ack",
|
||||||
|
{
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "a"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"8d690a2a-e987-4c86-b9ac-18e6d3a98503": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "b/something.lua",
|
||||||
|
"project_definition": null
|
||||||
|
},
|
||||||
|
"645ba594-4482-441f-9f41-5bb9c444405b": {
|
||||||
|
"ignore_unknown_instances": true,
|
||||||
|
"source_path": null,
|
||||||
|
"project_definition": [
|
||||||
|
"multi_partition_game",
|
||||||
|
{
|
||||||
|
"class_name": "DataModel",
|
||||||
|
"children": {
|
||||||
|
"HttpService": {
|
||||||
|
"class_name": "HttpService",
|
||||||
|
"children": {},
|
||||||
|
"properties": {
|
||||||
|
"HttpEnabled": {
|
||||||
|
"Type": "Bool",
|
||||||
|
"Value": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
},
|
||||||
|
"ReplicatedStorage": {
|
||||||
|
"class_name": "ReplicatedStorage",
|
||||||
|
"children": {
|
||||||
|
"Ack": {
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "a"
|
||||||
|
},
|
||||||
|
"Bar": {
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,19 +1,6 @@
|
||||||
{
|
{
|
||||||
"instances": {
|
"instances": {
|
||||||
"6a7e0c50-e85d-4abc-863b-48db75038c65": {
|
"8d44bb30-db3c-4366-a6c5-633bd1441885": {
|
||||||
"Name": "foo",
|
|
||||||
"ClassName": "StringValue",
|
|
||||||
"Properties": {
|
|
||||||
"Value": {
|
|
||||||
"Type": "String",
|
|
||||||
"Value": "Hello world, from a/foo.txt"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Id": "6a7e0c50-e85d-4abc-863b-48db75038c65",
|
|
||||||
"Children": [],
|
|
||||||
"Parent": "a27d1480-d3d6-424b-86e9-faf9cf387ae8"
|
|
||||||
},
|
|
||||||
"7abdb15d-9899-414a-baf0-7874c56f8b2a": {
|
|
||||||
"Name": "main",
|
"Name": "main",
|
||||||
"ClassName": "ModuleScript",
|
"ClassName": "ModuleScript",
|
||||||
"Properties": {
|
"Properties": {
|
||||||
|
|
@ -22,76 +9,44 @@
|
||||||
"Value": "-- hello, from a/main.lua"
|
"Value": "-- hello, from a/main.lua"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Id": "7abdb15d-9899-414a-baf0-7874c56f8b2a",
|
"Id": "8d44bb30-db3c-4366-a6c5-633bd1441885",
|
||||||
"Children": [],
|
"Children": [],
|
||||||
"Parent": "a27d1480-d3d6-424b-86e9-faf9cf387ae8"
|
"Parent": "1aafa29b-bdca-40a0-a677-7ead327b84ce"
|
||||||
},
|
},
|
||||||
"f147da62-b6dc-4833-985a-36941e47de82": {
|
"b1c9928c-bf11-427f-90eb-b672c811d859": {
|
||||||
"Name": "multi_partition_game",
|
|
||||||
"ClassName": "DataModel",
|
|
||||||
"Properties": {},
|
|
||||||
"Id": "f147da62-b6dc-4833-985a-36941e47de82",
|
|
||||||
"Children": [
|
|
||||||
"7be3f86d-f8ce-4c6b-88cb-03db03a3fd57",
|
|
||||||
"fe1dd5ab-3255-47e3-a2b4-8c7181ab715e"
|
|
||||||
],
|
|
||||||
"Parent": null
|
|
||||||
},
|
|
||||||
"fe1dd5ab-3255-47e3-a2b4-8c7181ab715e": {
|
|
||||||
"Name": "ReplicatedStorage",
|
|
||||||
"ClassName": "ReplicatedStorage",
|
|
||||||
"Properties": {},
|
|
||||||
"Id": "fe1dd5ab-3255-47e3-a2b4-8c7181ab715e",
|
|
||||||
"Children": [
|
|
||||||
"a27d1480-d3d6-424b-86e9-faf9cf387ae8",
|
|
||||||
"6ce9c44a-0e66-4aaf-97e7-086407aed226"
|
|
||||||
],
|
|
||||||
"Parent": "f147da62-b6dc-4833-985a-36941e47de82"
|
|
||||||
},
|
|
||||||
"7be3f86d-f8ce-4c6b-88cb-03db03a3fd57": {
|
|
||||||
"Name": "HttpService",
|
|
||||||
"ClassName": "HttpService",
|
|
||||||
"Properties": {
|
|
||||||
"HttpEnabled": {
|
|
||||||
"Type": "Bool",
|
|
||||||
"Value": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Id": "7be3f86d-f8ce-4c6b-88cb-03db03a3fd57",
|
|
||||||
"Children": [],
|
|
||||||
"Parent": "f147da62-b6dc-4833-985a-36941e47de82"
|
|
||||||
},
|
|
||||||
"141f9e9a-8ffb-43df-9532-c438d321b7c7": {
|
|
||||||
"Name": "added",
|
|
||||||
"ClassName": "Folder",
|
|
||||||
"Properties": {},
|
|
||||||
"Id": "141f9e9a-8ffb-43df-9532-c438d321b7c7",
|
|
||||||
"Children": [],
|
|
||||||
"Parent": "6ce9c44a-0e66-4aaf-97e7-086407aed226"
|
|
||||||
},
|
|
||||||
"a27d1480-d3d6-424b-86e9-faf9cf387ae8": {
|
|
||||||
"Name": "Ack",
|
|
||||||
"ClassName": "Folder",
|
|
||||||
"Properties": {},
|
|
||||||
"Id": "a27d1480-d3d6-424b-86e9-faf9cf387ae8",
|
|
||||||
"Children": [
|
|
||||||
"6a7e0c50-e85d-4abc-863b-48db75038c65",
|
|
||||||
"7abdb15d-9899-414a-baf0-7874c56f8b2a"
|
|
||||||
],
|
|
||||||
"Parent": "fe1dd5ab-3255-47e3-a2b4-8c7181ab715e"
|
|
||||||
},
|
|
||||||
"6ce9c44a-0e66-4aaf-97e7-086407aed226": {
|
|
||||||
"Name": "Bar",
|
"Name": "Bar",
|
||||||
"ClassName": "Folder",
|
"ClassName": "Folder",
|
||||||
"Properties": {},
|
"Properties": {},
|
||||||
"Id": "6ce9c44a-0e66-4aaf-97e7-086407aed226",
|
"Id": "b1c9928c-bf11-427f-90eb-b672c811d859",
|
||||||
"Children": [
|
"Children": [
|
||||||
"8e0006d3-9f03-4ed4-9cb6-81abe23a4754",
|
"8d690a2a-e987-4c86-b9ac-18e6d3a98503",
|
||||||
"141f9e9a-8ffb-43df-9532-c438d321b7c7"
|
"a8566e76-0495-45a3-a713-1c59ab39453b"
|
||||||
],
|
],
|
||||||
"Parent": "fe1dd5ab-3255-47e3-a2b4-8c7181ab715e"
|
"Parent": "9f141826-14c2-492b-b360-2558712f0c08"
|
||||||
},
|
},
|
||||||
"8e0006d3-9f03-4ed4-9cb6-81abe23a4754": {
|
"645ba594-4482-441f-9f41-5bb9c444405b": {
|
||||||
|
"Name": "multi_partition_game",
|
||||||
|
"ClassName": "DataModel",
|
||||||
|
"Properties": {},
|
||||||
|
"Id": "645ba594-4482-441f-9f41-5bb9c444405b",
|
||||||
|
"Children": [
|
||||||
|
"b1298bcc-e370-44a6-9ef4-fbefa290124c",
|
||||||
|
"9f141826-14c2-492b-b360-2558712f0c08"
|
||||||
|
],
|
||||||
|
"Parent": null
|
||||||
|
},
|
||||||
|
"9f141826-14c2-492b-b360-2558712f0c08": {
|
||||||
|
"Name": "ReplicatedStorage",
|
||||||
|
"ClassName": "ReplicatedStorage",
|
||||||
|
"Properties": {},
|
||||||
|
"Id": "9f141826-14c2-492b-b360-2558712f0c08",
|
||||||
|
"Children": [
|
||||||
|
"1aafa29b-bdca-40a0-a677-7ead327b84ce",
|
||||||
|
"b1c9928c-bf11-427f-90eb-b672c811d859"
|
||||||
|
],
|
||||||
|
"Parent": "645ba594-4482-441f-9f41-5bb9c444405b"
|
||||||
|
},
|
||||||
|
"8d690a2a-e987-4c86-b9ac-18e6d3a98503": {
|
||||||
"Name": "something",
|
"Name": "something",
|
||||||
"ClassName": "ModuleScript",
|
"ClassName": "ModuleScript",
|
||||||
"Properties": {
|
"Properties": {
|
||||||
|
|
@ -100,10 +55,202 @@
|
||||||
"Value": "-- b/something.lua"
|
"Value": "-- b/something.lua"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Id": "8e0006d3-9f03-4ed4-9cb6-81abe23a4754",
|
"Id": "8d690a2a-e987-4c86-b9ac-18e6d3a98503",
|
||||||
"Children": [],
|
"Children": [],
|
||||||
"Parent": "6ce9c44a-0e66-4aaf-97e7-086407aed226"
|
"Parent": "b1c9928c-bf11-427f-90eb-b672c811d859"
|
||||||
|
},
|
||||||
|
"b1298bcc-e370-44a6-9ef4-fbefa290124c": {
|
||||||
|
"Name": "HttpService",
|
||||||
|
"ClassName": "HttpService",
|
||||||
|
"Properties": {
|
||||||
|
"HttpEnabled": {
|
||||||
|
"Type": "Bool",
|
||||||
|
"Value": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root_id": "f147da62-b6dc-4833-985a-36941e47de82"
|
"Id": "b1298bcc-e370-44a6-9ef4-fbefa290124c",
|
||||||
|
"Children": [],
|
||||||
|
"Parent": "645ba594-4482-441f-9f41-5bb9c444405b"
|
||||||
|
},
|
||||||
|
"54f2f276-964f-4c60-87d8-5fb2209c97c9": {
|
||||||
|
"Name": "foo",
|
||||||
|
"ClassName": "StringValue",
|
||||||
|
"Properties": {
|
||||||
|
"Value": {
|
||||||
|
"Type": "String",
|
||||||
|
"Value": "Hello world, from a/foo.txt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Id": "54f2f276-964f-4c60-87d8-5fb2209c97c9",
|
||||||
|
"Children": [],
|
||||||
|
"Parent": "1aafa29b-bdca-40a0-a677-7ead327b84ce"
|
||||||
|
},
|
||||||
|
"a8566e76-0495-45a3-a713-1c59ab39453b": {
|
||||||
|
"Name": "added",
|
||||||
|
"ClassName": "Folder",
|
||||||
|
"Properties": {},
|
||||||
|
"Id": "a8566e76-0495-45a3-a713-1c59ab39453b",
|
||||||
|
"Children": [],
|
||||||
|
"Parent": "b1c9928c-bf11-427f-90eb-b672c811d859"
|
||||||
|
},
|
||||||
|
"1aafa29b-bdca-40a0-a677-7ead327b84ce": {
|
||||||
|
"Name": "Ack",
|
||||||
|
"ClassName": "Folder",
|
||||||
|
"Properties": {},
|
||||||
|
"Id": "1aafa29b-bdca-40a0-a677-7ead327b84ce",
|
||||||
|
"Children": [
|
||||||
|
"54f2f276-964f-4c60-87d8-5fb2209c97c9",
|
||||||
|
"8d44bb30-db3c-4366-a6c5-633bd1441885"
|
||||||
|
],
|
||||||
|
"Parent": "9f141826-14c2-492b-b360-2558712f0c08"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root_id": "645ba594-4482-441f-9f41-5bb9c444405b",
|
||||||
|
"metadata": {
|
||||||
|
"645ba594-4482-441f-9f41-5bb9c444405b": {
|
||||||
|
"ignore_unknown_instances": true,
|
||||||
|
"source_path": null,
|
||||||
|
"project_definition": [
|
||||||
|
"multi_partition_game",
|
||||||
|
{
|
||||||
|
"class_name": "DataModel",
|
||||||
|
"children": {
|
||||||
|
"HttpService": {
|
||||||
|
"class_name": "HttpService",
|
||||||
|
"children": {},
|
||||||
|
"properties": {
|
||||||
|
"HttpEnabled": {
|
||||||
|
"Type": "Bool",
|
||||||
|
"Value": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
},
|
||||||
|
"ReplicatedStorage": {
|
||||||
|
"class_name": "ReplicatedStorage",
|
||||||
|
"children": {
|
||||||
|
"Ack": {
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "a"
|
||||||
|
},
|
||||||
|
"Bar": {
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"1aafa29b-bdca-40a0-a677-7ead327b84ce": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "a",
|
||||||
|
"project_definition": [
|
||||||
|
"Ack",
|
||||||
|
{
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "a"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"a8566e76-0495-45a3-a713-1c59ab39453b": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "b/added",
|
||||||
|
"project_definition": null
|
||||||
|
},
|
||||||
|
"8d690a2a-e987-4c86-b9ac-18e6d3a98503": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "b/something.lua",
|
||||||
|
"project_definition": null
|
||||||
|
},
|
||||||
|
"8d44bb30-db3c-4366-a6c5-633bd1441885": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "a/main.lua",
|
||||||
|
"project_definition": null
|
||||||
|
},
|
||||||
|
"9f141826-14c2-492b-b360-2558712f0c08": {
|
||||||
|
"ignore_unknown_instances": true,
|
||||||
|
"source_path": null,
|
||||||
|
"project_definition": [
|
||||||
|
"ReplicatedStorage",
|
||||||
|
{
|
||||||
|
"class_name": "ReplicatedStorage",
|
||||||
|
"children": {
|
||||||
|
"Ack": {
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "a"
|
||||||
|
},
|
||||||
|
"Bar": {
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"b1c9928c-bf11-427f-90eb-b672c811d859": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "b",
|
||||||
|
"project_definition": [
|
||||||
|
"Bar",
|
||||||
|
{
|
||||||
|
"class_name": null,
|
||||||
|
"children": {},
|
||||||
|
"properties": {},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": "b"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"54f2f276-964f-4c60-87d8-5fb2209c97c9": {
|
||||||
|
"ignore_unknown_instances": false,
|
||||||
|
"source_path": "a/foo.txt",
|
||||||
|
"project_definition": null
|
||||||
|
},
|
||||||
|
"b1298bcc-e370-44a6-9ef4-fbefa290124c": {
|
||||||
|
"ignore_unknown_instances": true,
|
||||||
|
"source_path": null,
|
||||||
|
"project_definition": [
|
||||||
|
"HttpService",
|
||||||
|
{
|
||||||
|
"class_name": "HttpService",
|
||||||
|
"children": {},
|
||||||
|
"properties": {
|
||||||
|
"HttpEnabled": {
|
||||||
|
"Type": "Bool",
|
||||||
|
"Value": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ignore_unknown_instances": null,
|
||||||
|
"path": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue