Pregunta

Quizás estoy pasando por alto algo, pero estoy tratando de luchar con los buffers de protocolo en un método fácil para proporcionar extensiones más adelante. Eso parece un poco poco claro, así que saltaré directamente al problema.

Estoy escribiendo un ensamblaje para apoyar varias tareas, una de las cuales incluye describir datos estructurados. Momento perfecto para usar tampones de protocolo. La clase principal para usar tampones de protocolo se llama StateFinition. Aquí está el archivo .proto que se me ocurrió:

package Kannon.State;
message StateDefinition {
    enum StateTypes {
        GRAPHICS = 0;
        AUDIO = 1;
        MIND = 2;
        PHYSICS = 3;
        NETWORK = 4;
        GENERIC = 5;
    }
    repeated StateTypes requiredStates = 1; 
    optional GraphicsStateDef Graphics = 2;
    optional AudioStateDef Audio = 3;
         (etc)
}

message GraphicsStateDef {
    extensions 100 to max;
}

message AudioStateDef {
    extensions 100 to max;
}
    (etc)

Mi objetivo era permitir que esos mensajes _STATATEF se extendieran más tarde con lo que necesitaría los campos. Sin embargo, esta extensión ocurriría independientemente de la biblioteca que estoy escribiendo actualmente.

Kagents.dll -> maneja el análisis de la definición y tal.

Algo que hace referencia a Kagents.dll -> tiene un archivo ProtoBuff con "Extender GraphicSstateFeF" para definir el estado necesario.

Esperaba que definir la "extender gráficos segmentos" generara un código que me permitiera usar propiedades para acceder a estos campos y evitar el engorroso "extensible.appendValue ()" y sintax de getValue ().

Una solución que ideé, que parece hackish, es definir una clase en la DLL de referencia con métodos de extensión, como así:

    public static class GraphicsExt
    {
        enum Fields
        {
            someValue = 1,
            someOtherValue = 2
        }

        public static Int32 someValue(this State.GraphicsStateDef def)
        {
            return Extensible.GetValue(def, Fields.someValue);
        }
        public static void someValue(this State.graphicsStateDef def, Int32 value)
        {
            Extensible.AppendValue(def, fields.someValue, value);
        }
    }

Si alguien puede pensar en una mejor manera, estaría muy obligado. =) Además, no estoy seguro de cómo salió mi descripción del problema, por lo que si hay alguna aclaración o información más que pueda proporcionar, hágamelo saber. =)

Editar: Entonces, después de pensar mucho en esto y darme cuenta de que me estoy acercando al problema mal. Se supone que StateReference almacena una lista de diferentes Gamestate. Además, almacena una definición declarada, que debería describir el estado de esta referencia del estado. Actualmente, estoy tratando de deserializar los buffers de estado en diferentes clases (gráficos Statedef), cuando realmente debería estar deserializando los objetos de estado.

Por lo tanto, necesito repensar el diseño de tal manera que StateFinition se convierta en un contenedor para la transmisión y extrae suficiente información para el campo "Estatetypes requeridos requeridos = 1". Luego, en la asamblea de referencia, el resto de la corriente puede deserializarse en los estados respectivos.

¿Alguien tiene recomendaciones sobre cómo abordar esto? Algunas ideas están formulando, pero nada concreto, y me encantaría la opinión de los demás.

¿Fue útil?

Solución 2

Respuesta final:

Muy bien, entonces, hace unos días me decidí por una solución y solo estoy actualizando esto en caso de que alguien más corra el mismo problema.

Todo el problema surgió del hecho de que no me di cuenta de ProtoBuf-Net podría soportar el byte []. Entonces, aquí está mi solución:

namespace Kannon.State
{
    /// <summary>
    /// ReferenceDefinition describes the layout of the reference in general.
    /// It tells what states it should have, and stores the stream buffers for later serialization.
    /// </summary>
    [ProtoBuf.ProtoContract]
    public class ReferenceDefinition
    {
        /// <summary>
        /// There are several built in state types, as well as rudimentary support for a "Generic" state.
        /// </summary>
        public enum StateType
        {
            Graphics=0,
            Audio,
            Mind,
            Physics,
            Network,
            Generic
        }

        /// <summary>
        /// Represents what states should be present in the ReferenceDefinition
        /// </summary>
        [ProtoBuf.ProtoMember(1)]
        List<StateType> m_StatesPresent = new List<StateType>();

        /// <summary>
        /// Represent a list of StateDefinitions, which hold the buffers for each different type of state.
        /// </summary>
        [ProtoBuf.ProtoMember(2)]
        List<StateDefinition> m_StateDefinition = new List<StateDefinition>();

        /// <summary>
        /// Add a state, mapped to a type, to this reference definition.
        /// </summary>
        /// <param name="type">Type of state to add</param>
        /// <param name="def">State definition to add.</param>
        public void AddState(StateType type, StateDefinition def)
        {
            // Enforce only 1 of each type, except for Generic, which can have as many as it wants.
            if (m_StatesPresent.Contains(type) && type != StateType.Generic)
                return;
            m_StatesPresent.Add(type);
            m_StateDefinition.Add(def);
        }
    }

    /// <summary>
    /// Represents a definition of some gamestate, storing protobuffered data to be remapped to the state.
    /// </summary>
    [ProtoBuf.ProtoContract]
    public class StateDefinition
    {
        /// <summary>
        /// Name of the state
        /// </summary>
        [ProtoBuf.ProtoMember(1)]
        string m_StateName;
        /// <summary>
        /// Byte array to store the "data" for later serialization.
        /// </summary>
        [ProtoBuf.ProtoMember(2)]
        byte[] m_Buffer;

        /// <summary>
        /// Constructor for the state definition, protected to enforce the Pack and Unpack functionality to keep things safe.
        /// </summary>
        /// <param name="name">Name of the state type.</param>
        /// <param name="buff">byte buffer to build state off of</param>
        protected StateDefinition(String name, byte[] buff)
        {
            m_StateName = name;
            m_Buffer = buff;
        }

        /// <summary>
        /// Unpack a StateDefinition into a GameState
        /// </summary>
        /// <typeparam name="T">Gamestate type to unpack into.  Must define Protobuf Contracts.</typeparam>
        /// <param name="def">State Definition to unpack.</param>
        /// <returns>The unpacked state data.</returns>
        public static T Unpack<T>(StateDefinition def) where T:GameState
        {
            // Make sure we're unpacking into the right state type.
            if (typeof(T).Name == def.m_StateName)
                return ProtoBuf.Serializer.Deserialize<T>(new MemoryStream(def.m_Buffer));
            else
                // Otherwise, return the equivalent of Null.
                return default(T);
        }

        /// <summary>
        /// Pack a state type into a State Definition
        /// </summary>
        /// <typeparam name="T">Gamestate to package up.  Upst define protobuf contracts.</typeparam>
        /// <param name="state">State to pack up.</param>
        /// <returns>A state definition serialized from the passed in state.</returns>
        public static StateDefinition Pack<T>(T state) where T:GameState
        {
            // Using a memory stream, to make sure Garbage Collection knows what's going on.
            using (MemoryStream s = new MemoryStream())
            {
                ProtoBuf.Serializer.Serialize<T>(s, state);
                // Uses typeof(T).Name to do semi-enforcement of type safety.  Not the best, but it works.
                return new StateDefinition(typeof(T).Name, s.ToArray());
            }
        }
    }
}

Otros consejos

Soy el autor de ProtoBuf-Net. No he agregado nada para abordar el escenario como se presenta directamente (aparte del Extensible código), pero estoy abierto a sugerencias sobre lo que crees debería hacer.

También necesitaría verificar si "Protoc" (el compilador .proto que uso para analizar .proto antes de la generación de códigos) me permite distinguir entre miembros regulares y extendidos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top