mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 05:51:39 +00:00
Implement live syncback fixes addressing multiple issues
- Added explicit encoding for Workspace attributes and tags in `encodeService.lua` to prevent data loss during syncback. - Filtered non-serializable properties, including `ClockTime`, in `build_dom_from_chunks` to ensure accurate data handling. - Resolved a leak of `Rojo_Ref_CurrentCamera` by filtering deferred referents after camera destruction in `syncback_loop`. - Truncated float values to f32 precision in `UnresolvedValue::from_variant` to match rbxl storage format, improving data consistency. These changes enhance the reliability and accuracy of the live syncback process, addressing critical issues identified in previous implementations.
This commit is contained in:
parent
a75a1443c0
commit
7dc4f52793
6 changed files with 180 additions and 5 deletions
|
|
@ -164,6 +164,9 @@ fn build_dom_from_chunks(payload: SyncbackPayload) -> anyhow::Result<WeakDom> {
|
|||
for chunk in &payload.services {
|
||||
let mut builder = InstanceBuilder::new(&chunk.class_name);
|
||||
for (key, value) in &chunk.properties {
|
||||
if !crate::syncback::should_property_serialize(&chunk.class_name, key) {
|
||||
continue;
|
||||
}
|
||||
builder = builder.with_property(key.as_str(), value.clone());
|
||||
}
|
||||
let service_ref = dom.insert(root_ref, builder);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,68 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::REF_PATH_ATTRIBUTE_PREFIX;
|
||||
|
||||
/// Truncates float components of Variant types to f32 precision, matching the
|
||||
/// rbxl binary format which stores most float properties as Float32.
|
||||
fn truncate_variant(v: Variant) -> Variant {
|
||||
#[inline]
|
||||
fn t(v: f32) -> f32 {
|
||||
v as f64 as f32
|
||||
}
|
||||
|
||||
match v {
|
||||
Variant::CFrame(cf) => Variant::CFrame(CFrame {
|
||||
position: Vector3::new(t(cf.position.x), t(cf.position.y), t(cf.position.z)),
|
||||
orientation: Matrix3::new(
|
||||
Vector3::new(
|
||||
t(cf.orientation.x.x),
|
||||
t(cf.orientation.x.y),
|
||||
t(cf.orientation.x.z),
|
||||
),
|
||||
Vector3::new(
|
||||
t(cf.orientation.y.x),
|
||||
t(cf.orientation.y.y),
|
||||
t(cf.orientation.y.z),
|
||||
),
|
||||
Vector3::new(
|
||||
t(cf.orientation.z.x),
|
||||
t(cf.orientation.z.y),
|
||||
t(cf.orientation.z.z),
|
||||
),
|
||||
),
|
||||
}),
|
||||
Variant::OptionalCFrame(Some(cf)) => Variant::OptionalCFrame(Some(CFrame {
|
||||
position: Vector3::new(t(cf.position.x), t(cf.position.y), t(cf.position.z)),
|
||||
orientation: Matrix3::new(
|
||||
Vector3::new(
|
||||
t(cf.orientation.x.x),
|
||||
t(cf.orientation.x.y),
|
||||
t(cf.orientation.x.z),
|
||||
),
|
||||
Vector3::new(
|
||||
t(cf.orientation.y.x),
|
||||
t(cf.orientation.y.y),
|
||||
t(cf.orientation.y.z),
|
||||
),
|
||||
Vector3::new(
|
||||
t(cf.orientation.z.x),
|
||||
t(cf.orientation.z.y),
|
||||
t(cf.orientation.z.z),
|
||||
),
|
||||
),
|
||||
})),
|
||||
Variant::Vector3(v) => Variant::Vector3(Vector3::new(t(v.x), t(v.y), t(v.z))),
|
||||
Variant::Vector2(v) => Variant::Vector2(Vector2::new(t(v.x), t(v.y))),
|
||||
Variant::UDim(u) => Variant::UDim(rbx_dom_weak::types::UDim::new(t(u.scale), u.offset)),
|
||||
Variant::UDim2(u) => Variant::UDim2(rbx_dom_weak::types::UDim2::new(
|
||||
rbx_dom_weak::types::UDim::new(t(u.x.scale), u.x.offset),
|
||||
rbx_dom_weak::types::UDim::new(t(u.y.scale), u.y.offset),
|
||||
)),
|
||||
Variant::Float32(n) => Variant::Float32(n as f64 as f32),
|
||||
Variant::Float64(n) => Variant::Float64(n as f32 as f64),
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
/// A user-friendly version of `Variant` that supports specifying ambiguous
|
||||
/// values. Ambiguous values need a reflection database to be resolved to a
|
||||
/// usable value.
|
||||
|
|
@ -41,6 +103,7 @@ impl UnresolvedValue {
|
|||
/// Creates an `UnresolvedValue` from a variant, using a class and property
|
||||
/// name to potentially allow for ambiguous Enum variants.
|
||||
pub fn from_variant(variant: Variant, class_name: &str, prop_name: &str) -> Self {
|
||||
let variant = truncate_variant(variant);
|
||||
let descriptor = find_descriptor(class_name, prop_name);
|
||||
if descriptor.is_some() {
|
||||
// We can only use an ambiguous syntax if the property is known
|
||||
|
|
@ -116,6 +179,7 @@ impl UnresolvedValue {
|
|||
/// Creates an `UnresolvedValue` from a variant, only returning ambiguous
|
||||
/// values if they're able to be resolved in a context-free environment.
|
||||
pub fn from_variant_unambiguous(variant: Variant) -> Self {
|
||||
let variant = truncate_variant(variant);
|
||||
match variant {
|
||||
Variant::String(str) => Self::Ambiguous(AmbiguousValue::String(str)),
|
||||
Variant::Float64(number) => Self::Ambiguous(AmbiguousValue::Number(number)),
|
||||
|
|
|
|||
|
|
@ -207,18 +207,21 @@ pub fn syncback_loop_with_stats(
|
|||
.unwrap_or(false);
|
||||
if !sync_current_camera {
|
||||
log::debug!("Removing CurrentCamera from new DOM");
|
||||
let mut camera_ref = None;
|
||||
let mut workspace_ref = None;
|
||||
let mut camera_target = None;
|
||||
for child_ref in new_tree.root().children() {
|
||||
let inst = new_tree.get_by_ref(*child_ref).unwrap();
|
||||
if inst.class == "Workspace" {
|
||||
camera_ref = inst.properties.get(&ustr("CurrentCamera"));
|
||||
workspace_ref = Some(*child_ref);
|
||||
camera_target = inst.properties.get(&ustr("CurrentCamera")).cloned();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(Variant::Ref(camera_ref)) = camera_ref {
|
||||
if new_tree.get_by_ref(*camera_ref).is_some() {
|
||||
new_tree.destroy(*camera_ref);
|
||||
if let (Some(ws_ref), Some(Variant::Ref(cam_ref))) = (workspace_ref, camera_target) {
|
||||
if new_tree.get_by_ref(cam_ref).is_some() {
|
||||
new_tree.destroy(cam_ref);
|
||||
}
|
||||
deferred_referents.remove_ref(ws_ref, "CurrentCamera");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -149,6 +149,17 @@ pub struct RefLinks {
|
|||
pub placeholder_to_source_and_target: HashMap<String, (Ref, Ref)>,
|
||||
}
|
||||
|
||||
impl RefLinks {
|
||||
pub fn remove_ref(&mut self, source: Ref, prop_name: &str) {
|
||||
if let Some(links) = self.path_links.get_mut(&source) {
|
||||
links.retain(|link| link.name.as_str() != prop_name);
|
||||
}
|
||||
if let Some(links) = self.id_links.get_mut(&source) {
|
||||
links.retain(|link| link.name.as_str() != prop_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct PathRefLink {
|
||||
name: Ustr,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue