mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-20 20:55:50 +00:00
Scaffold out model file support, still needs working decoders
This commit is contained in:
@@ -9,14 +9,14 @@ use std::{
|
||||
|
||||
use failure::Fail;
|
||||
|
||||
use rbx_tree::{RbxTree, RbxValue, RbxId};
|
||||
use rbx_tree::{RbxTree, RbxInstance, RbxValue, RbxId};
|
||||
|
||||
use crate::{
|
||||
project::{Project, ProjectNode, InstanceProjectNodeMetadata},
|
||||
message_queue::MessageQueue,
|
||||
imfs::{Imfs, ImfsItem, ImfsFile},
|
||||
path_map::PathMap,
|
||||
rbx_snapshot::{RbxSnapshotInstance, InstanceChanges, reify_root, reconcile_subtree},
|
||||
rbx_snapshot::{RbxSnapshotInstance, InstanceChanges, snapshot_from_tree, reify_root, reconcile_subtree},
|
||||
};
|
||||
|
||||
const INIT_SCRIPT: &str = "init.lua";
|
||||
@@ -235,6 +235,8 @@ enum FileType {
|
||||
ClientScript,
|
||||
StringValue,
|
||||
LocalizationTable,
|
||||
XmlModel,
|
||||
BinaryModel,
|
||||
}
|
||||
|
||||
fn get_trailing<'a>(input: &'a str, trailer: &str) -> Option<&'a str> {
|
||||
@@ -247,21 +249,25 @@ fn get_trailing<'a>(input: &'a str, trailer: &str) -> Option<&'a str> {
|
||||
}
|
||||
|
||||
fn classify_file(file: &ImfsFile) -> Option<(&str, FileType)> {
|
||||
static EXTENSIONS_TO_TYPES: &[(&str, FileType)] = &[
|
||||
(".server.lua", FileType::ServerScript),
|
||||
(".client.lua", FileType::ClientScript),
|
||||
(".lua", FileType::ModuleScript),
|
||||
(".csv", FileType::LocalizationTable),
|
||||
(".txt", FileType::StringValue),
|
||||
(".rbxmx", FileType::XmlModel),
|
||||
(".rbxm", FileType::BinaryModel),
|
||||
];
|
||||
|
||||
let file_name = file.path.file_name()?.to_str()?;
|
||||
|
||||
if let Some(instance_name) = get_trailing(file_name, ".server.lua") {
|
||||
Some((instance_name, FileType::ServerScript))
|
||||
} else if let Some(instance_name) = get_trailing(file_name, ".client.lua") {
|
||||
Some((instance_name, FileType::ClientScript))
|
||||
} else if let Some(instance_name) = get_trailing(file_name, ".lua") {
|
||||
Some((instance_name, FileType::ModuleScript))
|
||||
} else if let Some(instance_name) = get_trailing(file_name, ".csv") {
|
||||
Some((instance_name, FileType::LocalizationTable))
|
||||
} else if let Some(instance_name) = get_trailing(file_name, ".txt") {
|
||||
Some((instance_name, FileType::StringValue))
|
||||
} else {
|
||||
None
|
||||
for (extension, file_type) in EXTENSIONS_TO_TYPES {
|
||||
if let Some(instance_name) = get_trailing(file_name, extension) {
|
||||
return Some((instance_name, *file_type))
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@@ -307,6 +313,16 @@ enum SnapshotError {
|
||||
inner: str::Utf8Error,
|
||||
path: PathBuf,
|
||||
},
|
||||
|
||||
XmlModelDecodeError {
|
||||
inner: rbx_xml::DecodeError,
|
||||
path: PathBuf,
|
||||
},
|
||||
|
||||
BinaryModelDecodeError {
|
||||
inner: rbx_binary::DecodeError,
|
||||
path: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
impl fmt::Display for SnapshotError {
|
||||
@@ -316,10 +332,78 @@ impl fmt::Display for SnapshotError {
|
||||
SnapshotError::Utf8Error { inner, path } => {
|
||||
write!(output, "Invalid UTF-8: {} in path {}", inner, path.display())
|
||||
},
|
||||
SnapshotError::XmlModelDecodeError { inner, path } => {
|
||||
write!(output, "Malformed rbxmx model: {:?} in path {}", inner, path.display())
|
||||
},
|
||||
SnapshotError::BinaryModelDecodeError { inner, path } => {
|
||||
write!(output, "Malformed rbxm model: {:?} in path {}", inner, path.display())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn snapshot_xml_model<'a>(
|
||||
instance_name: Cow<'a, str>,
|
||||
file: &ImfsFile,
|
||||
) -> Result<Option<RbxSnapshotInstance<'a>>, SnapshotError> {
|
||||
let mut temp_tree = RbxTree::new(RbxInstance {
|
||||
name: "Temp".to_owned(),
|
||||
class_name: "Folder".to_owned(),
|
||||
properties: HashMap::new(),
|
||||
});
|
||||
|
||||
let root_id = temp_tree.get_root_id();
|
||||
rbx_xml::decode(&mut temp_tree, root_id, file.contents.as_slice())
|
||||
.map_err(|inner| SnapshotError::XmlModelDecodeError {
|
||||
inner,
|
||||
path: file.path.clone(),
|
||||
})?;
|
||||
|
||||
let root_instance = temp_tree.get_instance(root_id).unwrap();
|
||||
let children = root_instance.get_children_ids();
|
||||
|
||||
match children.len() {
|
||||
0 => Ok(None),
|
||||
1 => {
|
||||
let mut snapshot = snapshot_from_tree(&temp_tree, children[0]).unwrap();
|
||||
snapshot.name = instance_name;
|
||||
Ok(Some(snapshot))
|
||||
},
|
||||
_ => panic!("Rojo doesn't have support for model files with multiple roots yet"),
|
||||
}
|
||||
}
|
||||
|
||||
fn snapshot_binary_model<'a>(
|
||||
instance_name: Cow<'a, str>,
|
||||
file: &ImfsFile,
|
||||
) -> Result<Option<RbxSnapshotInstance<'a>>, SnapshotError> {
|
||||
let mut temp_tree = RbxTree::new(RbxInstance {
|
||||
name: "Temp".to_owned(),
|
||||
class_name: "Folder".to_owned(),
|
||||
properties: HashMap::new(),
|
||||
});
|
||||
|
||||
let root_id = temp_tree.get_root_id();
|
||||
rbx_binary::decode(&mut temp_tree, root_id, file.contents.as_slice())
|
||||
.map_err(|inner| SnapshotError::BinaryModelDecodeError {
|
||||
inner,
|
||||
path: file.path.clone(),
|
||||
})?;
|
||||
|
||||
let root_instance = temp_tree.get_instance(root_id).unwrap();
|
||||
let children = root_instance.get_children_ids();
|
||||
|
||||
match children.len() {
|
||||
0 => Ok(None),
|
||||
1 => {
|
||||
let mut snapshot = snapshot_from_tree(&temp_tree, children[0]).unwrap();
|
||||
snapshot.name = instance_name;
|
||||
Ok(Some(snapshot))
|
||||
},
|
||||
_ => panic!("Rojo doesn't have support for model files with multiple roots yet"),
|
||||
}
|
||||
}
|
||||
|
||||
fn snapshot_instances_from_imfs<'a>(
|
||||
imfs: &'a Imfs,
|
||||
imfs_path: &Path,
|
||||
@@ -344,6 +428,8 @@ fn snapshot_instances_from_imfs<'a>(
|
||||
FileType::ClientScript => "LocalScript",
|
||||
FileType::StringValue => "StringValue",
|
||||
FileType::LocalizationTable => "LocalizationTable",
|
||||
FileType::XmlModel => return snapshot_xml_model(instance_name, file),
|
||||
FileType::BinaryModel => return snapshot_binary_model(instance_name, file),
|
||||
};
|
||||
|
||||
let contents = str::from_utf8(&file.contents)
|
||||
@@ -379,6 +465,7 @@ fn snapshot_instances_from_imfs<'a>(
|
||||
value: table_contents,
|
||||
});
|
||||
},
|
||||
FileType::XmlModel | FileType::BinaryModel => unreachable!(),
|
||||
}
|
||||
|
||||
Ok(Some(RbxSnapshotInstance {
|
||||
|
||||
@@ -65,6 +65,24 @@ pub struct RbxSnapshotInstance<'a> {
|
||||
pub metadata: Option<InstanceProjectNodeMetadata>,
|
||||
}
|
||||
|
||||
pub fn snapshot_from_tree(tree: &RbxTree, id: RbxId) -> Option<RbxSnapshotInstance<'static>> {
|
||||
let instance = tree.get_instance(id)?;
|
||||
|
||||
let mut children = Vec::new();
|
||||
for &child_id in instance.get_children_ids() {
|
||||
children.push(snapshot_from_tree(tree, child_id)?);
|
||||
}
|
||||
|
||||
Some(RbxSnapshotInstance {
|
||||
name: Cow::Owned(instance.name.to_owned()),
|
||||
class_name: Cow::Owned(instance.class_name.to_owned()),
|
||||
properties: instance.properties.clone(),
|
||||
children,
|
||||
source_path: None,
|
||||
metadata: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn reify_root(
|
||||
snapshot: &RbxSnapshotInstance,
|
||||
path_map: &mut PathMap<RbxId>,
|
||||
|
||||
6
test-projects/composing-models/roblox-project.json
Normal file
6
test-projects/composing-models/roblox-project.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "composing-models",
|
||||
"tree": {
|
||||
"$path": "src"
|
||||
}
|
||||
}
|
||||
BIN
test-projects/composing-models/src/Binary.rbxm
Normal file
BIN
test-projects/composing-models/src/Binary.rbxm
Normal file
Binary file not shown.
16
test-projects/composing-models/src/XML.rbxmx
Normal file
16
test-projects/composing-models/src/XML.rbxmx
Normal file
@@ -0,0 +1,16 @@
|
||||
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
|
||||
<Meta name="ExplicitAutoJoints">true</Meta>
|
||||
<External>null</External>
|
||||
<External>nil</External>
|
||||
<Item class="Script" referent="RBX634A9A9988354E4B9D971B2A4DEBD26E">
|
||||
<Properties>
|
||||
<bool name="Disabled">false</bool>
|
||||
<Content name="LinkedSource"><null></null></Content>
|
||||
<string name="Name">Lone Script</string>
|
||||
<string name="ScriptGuid">{C62CD9FB-FF28-4FD9-9712-AD28A1E92C84}</string>
|
||||
<ProtectedString name="Source"><![CDATA[print("Hello world!")
|
||||
]]></ProtectedString>
|
||||
<BinaryString name="Tags"></BinaryString>
|
||||
</Properties>
|
||||
</Item>
|
||||
</roblox>
|
||||
Reference in New Issue
Block a user