Question

I want to use protobuf-net in my game engine and i come across this task - how can i efficiently differentiate between storage and runtime types?

Basically, the way data is stored on disk will have different format and use then the one loaded at runtime.

Simplified example: I have serialized some GPU related data into byte[], using a class something like this:

[ProtoContract(UseProtoMembersOnly=true)]
public sealed class StoredData
{
    [ProtoMember(1)]
    public byte[] GpuData;
}

Then i would have a runtime implementation of this class, where i would upload that byte buffer to graphics card and therefore would have completely different type, something like "class GraphicsBuffer" not "byte[]".

Also, when serializing the runtime type 'GraphicsBuffer' i would want to serialize completely different message as well - for example a path on disk or name of StoredData to deserialize.

That all boils down to:

How do i interchange types used for serialization while having ability to define callback to convert between those types? So that (for example)

1.When i Serialize SoredData, a StoredData is written

2.When i Deserialize GraphicsBuffer, StoredData is deserialized and converted to GraphicsBuffer

3.When i Serialize GraphicsBuffer, a 'buffer path message' of that buffer is serialized

4.When i Deserialize 'buffer path message', 'buffer path message' is deserialized, then StoredData is found and deserialized using that message, while deserialization of StoredData yields GraphicsBuffer created from information in StoredData.

I hope this makes some sense!

Was it helpful?

Solution

I think that the answer to all of these questions is "surrogates". For example:

// needs to be done once only, before any serialization/deserialization is done
RuntimeTypeModel.Default.Add(typeof(GraphicsBuffer), false)
    .SetSurrogate(typeof(StoredData));

with:

[ProtoContract(UseProtoMembersOnly= true)]
public sealed class StoredData
{
    [ProtoMember(1)]
    public byte[] GpuData;

    public static explicit operator GraphicsBuffer(StoredData value)
    {
        if (value == null) return null;
        throw new NotImplementedException("Your conversion code here");
    }
    public static explicit operator StoredData(GraphicsBuffer value)
    {
        if (value == null) return null;
        throw new NotImplementedException("Your conversion code here");
    }
}

Note to self: I should make this possible via attributes so you don't need to manipulate the model at runtime.

Now, whenever the model encounters a GraphicsBuffer, it will use the conversion operators to/from StoredData, and run the serialization/deserialization code on the StoredData instance.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top