문제

나는 아마도 무언가를 간과하고 있지만, 프로토콜 버퍼를 나중에 확장을 제공하기위한 쉬운 방법으로 씨름하려고 노력하고 있습니다. 조금 불분명 해 보이기 때문에 문제로 직접 뛰어들 것입니다.

다양한 작업을 지원하기 위해 어셈블리를 작성하고 있으며 그 중 하나는 구조화 된 데이터 설명을 포함합니다. 프로토콜 버퍼를 사용하기에 완벽한 시간. 프로토콜 버퍼를 사용하는 기본 클래스를 명시 정화라고합니다. 다음은 제가 생각해 낸 .proto 파일입니다.

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)

저의 목표는 _Statedef 메시지를 나중에 필요한 필드로 연장 할 수 있도록하는 것이 었습니다. 그러나이 확장은 현재 쓰고있는 도서관과 독립적으로 발생합니다.

kagents.dll-> 핸들은 정의 구문 분석 등을 처리합니다.

Kagents.dll->를 참조하는 것들은 필요한 상태를 정의하기 위해 "extend GraphicsStatedef"가있는 protobuff 파일이 있습니다.

"GraphicsStatedef"확장을 정의하면 속성을 사용하여 이러한 필드에 액세스하고 번거로운 "Extendible.appendValue ()"및 getValue () 구문을 피할 수있는 코드가 생성되기를 바랐습니다.

내가 고안 한 한 가지 해결책은 해킹 된 것처럼 보인다.

    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);
        }
    }

누군가가 더 나은 방법을 생각할 수 있다면, 나는 많은 의무가있을 것입니다. =) 또한, 문제에 대한 내 설명이 얼마나 명확하게 나왔는지 잘 모르겠으므로, 내가 제공 할 수있는 설명이나 추가 정보가 있으면 알려주십시오. =))

편집 : 그래서, 이것에 대해 많이 생각하고 나는 문제가 잘못되었다는 것을 깨달았습니다. Statereference는 다양한 게임 테이트 목록을 저장해야합니다. 또한이 상태 참조의 상태를 설명 해야하는 명시 정의를 저장합니다. 현재 상태 버퍼를 다른 클래스 (GraphicsStatedef)로 사로화하려고 노력하고 있습니다.

따라서 언급 정화가 스트림의 컨테이너가되도록 설계를 다시 생각해야하며 "반복 된 statetypes 요구 사항 = 1"필드에 대한 충분한 정보 만 추출해야합니다. 그런 다음 참조 어셈블리에서 나머지 스트림은 각 상태로 사막화 될 수 있습니다.

누구든지 이것에 접근하는 방법에 대한 권장이 있습니까? 몇 가지 아이디어가 공식화되어 있지만 콘크리트는 없으며 다른 사람들의 입력을 좋아합니다.

도움이 되었습니까?

해결책 2

최종 답변 :

며칠 전에 나는 솔루션을 해결했고 다른 사람이 같은 문제에 빠지게 된 경우에만 업데이트하고 있습니다.

전체 문제는 내가 Protobuf-net이 BYTE []를 지원할 수 있다는 사실을 깨닫지 못했다는 사실에서 비롯되었습니다. 그래서 여기 내 해결책이 있습니다.

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());
            }
        }
    }
}

다른 팁

저는 Protobuf-Net의 저자입니다. 직접 제시된대로 시나리오를 다루기 위해 아무것도 추가하지 않았습니다 ( Extensible 코드),하지만 나는 당신이 생각하는 것에 대한 제안에 열려 있습니다. ~해야 한다 하다.

또한 "PROTOC"(코드 생성 전에 .proto를 구문 분석하는 데 사용하는 .proto 컴파일러)를 사용하면 규칙적인 멤버와 확장 된 멤버를 구별 할 수 있는지 확인해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top