Implement Syncback to support converting Roblox files to a Rojo project (#937)

This is a very large commit.
Consider checking the linked PR for more information.
This commit is contained in:
Micah
2025-11-19 09:21:33 -08:00
committed by GitHub
parent 071b6e7e23
commit 9b5a07191b
239 changed files with 5325 additions and 225 deletions

View File

@@ -62,6 +62,10 @@ pub struct InstanceMetadata {
/// Indicates the ID used for Ref properties pointing to this Instance.
pub specified_id: Option<RojoRef>,
/// The Middleware that was used to create this Instance. Should generally
/// not be `None` except if the snapshotting process is not completed.
pub middleware: Option<Middleware>,
}
impl InstanceMetadata {
@@ -72,6 +76,7 @@ impl InstanceMetadata {
relevant_paths: Vec::new(),
context: InstanceContext::default(),
specified_id: None,
middleware: None,
}
}
@@ -109,6 +114,13 @@ impl InstanceMetadata {
..self
}
}
pub fn middleware(self, middleware: Middleware) -> Self {
Self {
middleware: Some(middleware),
..self
}
}
}
impl Default for InstanceMetadata {
@@ -215,22 +227,40 @@ impl PathIgnoreRule {
}
}
/// Represents where a particular Instance or InstanceSnapshot came from.
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub enum InstigatingSource {
/// The path the Instance was made from.
Path(#[serde(serialize_with = "path_serializer::serialize_absolute")] PathBuf),
ProjectNode(
#[serde(serialize_with = "path_serializer::serialize_absolute")] PathBuf,
String,
Box<ProjectNode>,
Option<String>,
),
/// The node in a Project that the Instance was made from.
ProjectNode {
#[serde(serialize_with = "path_serializer::serialize_absolute")]
path: PathBuf,
name: String,
node: ProjectNode,
parent_class: Option<String>,
},
}
impl InstigatingSource {
pub fn path(&self) -> &Path {
match self {
Self::Path(path) => path.as_path(),
Self::ProjectNode { path, .. } => path.as_path(),
}
}
}
impl fmt::Debug for InstigatingSource {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InstigatingSource::Path(path) => write!(formatter, "Path({})", path.display()),
InstigatingSource::ProjectNode(path, name, node, parent_class) => write!(
InstigatingSource::ProjectNode {
name,
node,
path,
parent_class,
} => write!(
formatter,
"ProjectNode({}: {:?}) from path {} and parent class {:?}",
name,

View File

@@ -14,5 +14,6 @@ metadata:
context:
emit_legacy_scripts: true
specified_id: ~
middleware: ~
children: []

View File

@@ -12,5 +12,6 @@ metadata:
context:
emit_legacy_scripts: true
specified_id: ~
middleware: ~
children: []

View File

@@ -14,5 +14,6 @@ metadata:
context:
emit_legacy_scripts: true
specified_id: ~
middleware: ~
children: []

View File

@@ -12,5 +12,6 @@ metadata:
context:
emit_legacy_scripts: true
specified_id: ~
middleware: ~
children: []

View File

@@ -13,6 +13,7 @@ added_instances:
context:
emit_legacy_scripts: true
specified_id: ~
middleware: ~
name: New
class_name: Folder
properties: {}

View File

@@ -73,6 +73,13 @@ impl RojoTree {
self.inner.root_ref()
}
/// Returns the root Instance of this tree.
#[inline]
pub fn root(&self) -> InstanceWithMeta<'_> {
self.get_instance(self.get_root_id())
.expect("RojoTrees should have a root")
}
pub fn get_instance(&self, id: Ref) -> Option<InstanceWithMeta<'_>> {
if let Some(instance) = self.inner.get_by_ref(id) {
let metadata = self.metadata_map.get(&id).unwrap();
@@ -322,6 +329,10 @@ impl<'a> InstanceWithMeta<'a> {
pub fn metadata(&self) -> &'a InstanceMetadata {
self.metadata
}
pub fn inner(&self) -> &Instance {
self.instance
}
}
/// RojoTree's equivalent of `&'a mut Instance`.
@@ -371,6 +382,14 @@ impl InstanceWithMetaMut<'_> {
pub fn metadata(&self) -> &InstanceMetadata {
self.metadata
}
pub fn inner(&self) -> &Instance {
self.instance
}
pub fn inner_mut(&mut self) -> &mut Instance {
self.instance
}
}
#[cfg(test)]