Como lidar com as alterações de versão ao salvar ativos?


9

Estou trabalhando em um RPG há algum tempo e uso duas técnicas diferentes de serialização.

  • Inimigos, armas, itens são salvos como XML.
  • Mapas e eventos são salvos como "binário controlado" (cada classe obtém um método de salvar / carregar e decide o que deseja salvar / carregar).

Mas comecei a questionar minha escolha de mapas e eventos. Minhas preocupações:

  • Criei um editor de mapas, mas ainda sinto falta de poder mudar pequenas coisas, apenas abrindo o arquivo.
  • As mudanças atrapalham tanto. Digamos que eu queira adicionar uma variável a uma classe, se eu não carregar / salvar todos os mapas novamente, eles serão quebrados mais tarde.

É difícil contornar a primeira preocupação sem alterar minha técnica. Pensei em mudar para JSON, mas é muito trabalhoso. Também acho que fica feio com os atributos [DataContract] e [DataMember] em todos os lugares.

Isso me deixa com a minha segunda preocupação e eu me pergunto como posso lidar com isso? Você cria um pequeno programa que percorre todos os mapas e os salva novamente com a nova variável? Porque eu começo a pegar alguns mapas agora e ainda o faço manualmente. Isso me faz pensar duas vezes toda vez que quero fazer algumas alterações, pois cria muito trabalho extra.

Respostas:


5

Existem várias maneiras de lidar com o problema de controle de versão; você pode fazer isso tendo uma função de carregamento por versão, pode tentar automatizar o processo, descrevendo (via atributos geralmente) a transformação da estrutura do ativo ao longo do tempo, pode fazer verificações específicas da versão nas funções de carregamento / gravação, etc. .

Eu gosto da abordagem "descreva as alterações", mas acho que tentar fazê-lo por meio de atributos fica rapidamente difícil . Eu usaria funções em vez disso; implemente uma função que transforma dados na versão Nem dados na versão N + 1para toda a sua versão apropriada. No carregamento, verifique a versão com a mais recente e, se não estiver, execute os dados através de todas as funções de versão apropriadas. Sempre salve a versão mais recente.

Isso funciona melhor se você fizer a transformação quando os dados ainda estiverem em um formato de valor-chave de tempo de execução. Isso significa que você provavelmente desejará implementar uma representação para seus dados que é uma abordagem de "bolsa de propriedades de tempo de execução", porque não é possível usar o formulário de valor-chave subjacente de JSON ou XML se você tiver seu próprio formato binário. Se você não fizer isso, também precisará manter as definições de classe antigas, o que fica feio. Ser capaz de ter seus ativos nesse formato ruim de propriedade também é tremendamente útil para o desenvolvimento de editores de jogos.

Durante o desenvolvimento, à medida que você repete os dados, ele naturalmente flui para a versão mais recente e, eventualmente, você pode excluir as funções antigas de controle de versão. Essa é mais ou menos a mesma abordagem de alto nível que usamos para versão de recursos artísticos (como os mapas) em Guild Wars 2.


Agora, tudo dito, acho útil apoiar a serialização de texto e binária para ativos. Durante o desenvolvimento, mantenha todos os seus dados em um formato legível por humanos com base em XML ou JSON. Isso pode aumentar muito sua capacidade de iteração, porque você não precisa criar ferramentas tão complexas para editar os dados. Você pode voltar a fazer ajustes rápidos simples à mão.

Segundo, supondo que você ainda queira um formato binário para distribuir o jogo (que pode melhorar o tamanho ou o tempo de IO do arquivo, por isso é um desejo válido), projete suas APIs de serialização e desserialização para lidar com o controle de versão. O controle de versão ainda é útil em um contexto de remessa, porque, em algum momento, você pode querer enviar atualizações ou correções de bugs. Existem alguns documentos que descrevem os recursos de versão da serialização .NET e da serialização do Boost que você pode achar interessante. Se você estiver indo para suportar texto e formatos binários, certifique-se de testá-los de vez em quando (ou testes de build automatizado para fazê-lo, melhor ainda).


Obrigado pelo comentário, me deu algumas idéias de como continuar.
user1776562

1

Use uma linguagem de marcação com pares atributo-valor como XML ou JSON.

O analisador pode simplesmente ignorar quaisquer atributos que não entende ou usar padrões para outros que não encontrar, o que facilita bastante a compatibilidade com versões anteriores e posteriores. Além disso, o formato é legível por humanos, para que você possa editá-lo facilmente com um editor de texto.

Ao usar uma linguagem estabelecida como XML ou JSON, você também perceberá que muitas linguagens de script o suportam; portanto, quando você ainda precisar escrever um script para editar um grande número de arquivos, será muito mais fácil fazê-lo.

A desvantagem da maioria dessas línguas é que elas são bastante detalhadas. Isso significa que os arquivos resultantes são muito maiores do que precisariam em um formato binário otimizado. Atualmente, o tamanho do arquivo não importa muito na maioria das situações. Mas naqueles onde isso importa, o tamanho do arquivo geralmente pode ser reduzido significativamente, compactando o arquivo com um algoritmo padrão, como o zip.

As linguagens de marcação geralmente não permitem acesso aleatório, a menos que todo o documento seja lido no disco rígido e analisado. Mas, na prática, isso não importa muito, porque os discos rígidos são mais rápidos com leituras sequenciais. A busca aleatória várias vezes em diferentes partes do mesmo arquivo geralmente pode ser muito mais lenta do que apenas ler o arquivo de uma só vez, mesmo quando isso significa que você lê mais dados do que precisa.


1

Você pode usar o protobuf. https://code.google.com/p/protobuf/ Oferece as vantagens do json / xml, que você pode estendê-lo facilmente e ser compatível com versões anteriores, além da vantagem de ser binário. O fluxo de trabalho é que você cria uma descrição do formato de dados no idioma do protobuf e gera o código fonte para serialização e desserialização. A fonte pode ser gerada para vários idiomas. Além disso, é uma grande vantagem que você tenha uma especificação clara dos seus dados serializados, em contraste com o json, onde a especificação é feita implicitamente na leitura / gravação.


Parece legal, mas eu uso c #, isso parece ser para c ++, python e java.
user1776562

Existe uma versão c #. Eu não testei pessoalmente, mas há um.
Arne
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.