2014-09-24 44 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對象的引用,但這是一個庫,所以最大程度的方便是給用戶而不是作者。

既然事情已經解決了,看起來這種方法會運作良好。我會看看我的僱主是否會允許它進入資產商店。

更新: 這將在資產商店完成時進行。有很多代理首先添加,因此可能會有一段時間。

相關問題