mod parser;
mod types;
#[allow(unused_imports)]
pub use types::{ExtResource, GodotScene, SceneNode, SubResource};
use anyhow::{Context, Result};
use std::fs;
use std::path::Path;
impl GodotScene {
pub fn load(path: &Path) -> Result<Self> {
let content =
fs::read_to_string(path).with_context(|| format!("Failed to read scene file: {}", path.display()))?;
Self::parse(&content)
}
pub fn save(&self, path: &Path) -> Result<()> {
let content = self.to_string();
fs::write(path, content).with_context(|| format!("Failed to write scene file: {}", path.display()))?;
Ok(())
}
#[allow(clippy::inherent_to_string)]
pub fn to_string(&self) -> String {
let mut output = String::new();
let uid_part = self.uid.as_ref().map(|u| format!(" uid=\"{}\"", u)).unwrap_or_default();
output.push_str(&format!(
"[gd_scene load_steps={} format={}{}]\n\n",
self.load_steps, self.format_version, uid_part
));
for (i, res) in self.ext_resources.iter().enumerate() {
output.push_str(&format!(
"[ext_resource type=\"{}\" path=\"{}\" id=\"{}\"]\n",
res.resource_type, res.path, res.id
));
if i == self.ext_resources.len() - 1 {
output.push('\n');
}
}
for res in &self.sub_resources {
output.push_str(&format!(
"[sub_resource type=\"{}\" id=\"{}\"]\n",
res.resource_type, res.id
));
for (key, value) in &res.properties {
output.push_str(&format!("{} = {}\n", key, value));
}
output.push('\n');
}
for node in &self.nodes {
self.write_node(&mut output, node);
}
output
}
fn write_node(&self, output: &mut String, node: &SceneNode) {
output.push_str("[node");
output.push_str(&format!(" name=\"{}\"", node.name));
output.push_str(&format!(" type=\"{}\"", node.node_type));
if let Some(parent) = &node.parent {
output.push_str(&format!(" parent=\"{}\"", parent));
}
if let Some(instance) = &node.instance {
output.push_str(&format!(" instance=ExtResource(\"{}\")", instance));
}
output.push_str("]\n");
if let Some(script) = &node.script {
output.push_str(&format!("script = {}\n", script));
}
for (key, value) in &node.properties {
output.push_str(&format!("{} = {}\n", key, value));
}
output.push('\n');
}
pub fn add_ext_resource(&mut self, resource_type: &str, path: &str) -> String {
let id = (self.ext_resources.len() + 1).to_string();
self.ext_resources.push(ExtResource {
id: id.clone(),
resource_type: resource_type.to_string(),
path: path.to_string(),
});
self.load_steps += 1;
id
}
pub fn add_node(&mut self, node: SceneNode) {
self.nodes.push(node);
}
pub fn find_node(&self, name: &str) -> Option<&SceneNode> {
self.nodes.iter().find(|n| n.name == name)
}
pub fn find_node_mut(&mut self, name: &str) -> Option<&mut SceneNode> {
self.nodes.iter_mut().find(|n| n.name == name)
}
}