2014-09-24 45 views
0

我正在尝试为名为Transform的第三方类创建代理。我需要序列化它的一些公共成员,包括对另一个这样的类实例的引用,并公开内部列表Transforms。所以我写了替代品,但我不确定是否可以在替代品的字段上定义[ProtoMember]属性,该属性的类型为Transform。或者他们应该是TransformSurrogate?现在,我的代码是:代理类可以包含对原始类的引用

[ProtoContract(AsReferenceDefault = true)] 
public class TransformSurrogate { 
    [ProtoMember(1)] 
    Vector3 localPosition { get; set; } 
    [ProtoMember(2)] 
    Vector3 localScale { get; set; } 
    [ProtoMember(3)] 
    Quaternion localRotation { get; set; } 
    [ProtoMember(4, AsReference = true)] 
    Transform parent { get; set; } 
    [ProtoMember(5, AsReference = true)] 
    List<Transform> children { get; set; } 

    public static explicit operator TransformSurrogate(Transform transform) { 
     if (transform == null) return null; 
     var surrogate = new TransformSurrogate(); 
     surrogate.localPosition = transform.localPosition; 
     surrogate.localRotation = transform.localRotation; 
     surrogate.localScale = transform.localScale; 
     surrogate.parent = transform.parent; 
     surrogate.children = new List<Transform>(); 
     for (int i = 0; i < transform.childCount; ++i) { 
      surrogate.children.Add(transform.GetChild(i)); 
     } 
     return surrogate; 
    } 

    public static explicit operator Transform(TransformSurrogate surrogate) { 
     if (surrogate == null) return null; 
     var transform = new GameObject().transform; 
     transform.localPosition = surrogate.localPosition; 
     transform.localRotation = surrogate.localRotation; 
     transform.localScale = surrogate.localScale; 
     transform.parent = (Transform) surrogate.parent; 
     foreach (var child in surrogate.children) { 
      child.parent = transform; 
     } 
     return transform; 
    } 
} 

不要太注意Vector3Quaternion班 - 他们很容易序列化的结构。所以我定义自己的RuntimeTypeModelTransform类型是这样的:

Model.Add(typeof(Transform), false).SetSurrogate(typeof(TransformSurrogate)); 

不过,我反序列化过程中得到一个错误,告诉我的Protobuf是无法类之间的转换。我在想,这是因为在代理类中混合了原始类,但我不确定。

+0

在一个依赖于非核心类型的复杂类型的环境中,这很难回答;你有没有用简单的本地类型演示问题的例子? – 2014-09-25 11:09:37

+0

@MarcGravell现在我试图在更简单的环境中对这种情况建模,但是如果您想知道Vector3和Quaternion类型是什么 - 您可以跳过这些,因为它们是简单的结构,并且我已成功将它们序列化。我现在主要关注的只是Transform类。如果有帮助,Transform是Unity3D的内置类型。 – GuardianX 2014-09-25 12:24:31

回答

1

对于某些数据类型是的,它会工作,我现在正在做同样的事情(编写Unity3D转换的代理)。早些时候,我在MeshSurrogate上进行了测试。下面是代码是如何开始......

[ProtoContract(AsReferenceDefault = true)] 
    [ProtoSurrogate(typeof(Mesh))] 
    sealed class MeshSurrogate { 
     [ProtoMember(1)] 
     Matrix4x4[] bindposes; 

     [ProtoMember(2)] 
     BoneWeight[] boneWeights; 

/* Lots more follows */ 

(该ProtoSurrogateAttribute是自...它你所期望的) 它工作得很好,序列化和所有原非代理类型的反序列化领域数据类型。

虽然变换变得更有趣。这是一个潜在的问题 - 据报道,AsReference在替代品方面效果不佳 - https://code.google.com/p/protobuf-net/issues/detail?id=352太糟糕了,因为这是我们Unity系列化战略的核心。

我会更新,如果我得到这个工作。

更新: 事实证明,这是相当复杂的。

我得到的解决方案是,基本上任何继承UnityEngine.Object的东西都会得到一个代理,它包含3个且只有3个成员 - 一个instanceIdBeforeSerialization(通过UnityEngine.Object.GetInstanceID()获得),一个“shell”和一个“数据”。如果在此序列化过程中首次遇到此代理项,则只会填充shell和数据,否则它们将为空。壳负责实例化对象,以及用[OnDeserialized]方法填充它们的数据。当shell创建一个对象时,它将其存储在一个表中,并将其从旧实例ID映射到它的新实例ID,以便当任何代理转换为原始类型时,只需要在表中搜索它的新对象。由于shell早先放置在流中,因此在需要在对象图中引用它们之前,所有对象都至少已初始化。

不幸的是,我不能让Data类直接存储对Unity对象的引用,但这是一个库,所以最大程度的方便是给用户而不是作者。

既然事情已经解决了,看起来这种方法会运作良好。我会看看我的雇主是否会允许它进入资产商店。

更新: 这将在资产商店完成时进行。有很多代理首先添加,因此可能会有一段时间。

相关问题