В поисках лучшего способа заполнения объектов с помощью JSON.net, используя ссылки - PullRequest
0 голосов
/ 22 октября 2019

Я использую JSON.net в Unity для сохранения игровых данных. Я создал класс Savegame, который содержит все данные, которые я хочу сохранить. Допустим, я получил список персонажей и объект Player, который содержит ссылку на один из этих персонажей. Используя PreserveReferencesHandling, результирующий JSON выглядит ожидаемым образом:

{
  "characters":[
    {
      "$id": "1",
      "name": "char1",
      "reputation": 100
    },
...
  "player": {
    "location": "town1",
      "character": {
        "$ref": "1"
      }
  }
}

Когда я десериализирую Savegame, список персонажей и проигрыватель восстанавливаются и устанавливается ссылка на персонажа. Теперь я мог назначить объект Player из Savegame обратно объекту Player в моем GameManager, где Player используется на протяжении всей игры.

Итак, вкратце: на GameManager.Player ссылается Savegame, который затем сериализуется. После загрузки нового игрока с сохраненными данными в Savegame создается и Savegame.Player присваивается GameManager.Player.

Проблема в том, что каждая часть игры, которая имела ссылку на GameManager.Player, теперьвсе еще ссылаются на старый объект Player, в то время как GameManager.Player теперь содержит новую ссылку на вновь созданного Player (надеюсь, что это имеет смысл).

Так что я мог убедиться, что ссылки на Player не кэшируютсячто я пытаюсь сделать, я мог бы заполнить существующий проигрыватель данными из Savegame. JSON.net предоставляет метод для этого с именем JsonConvert.PopulateObject(string value, object target). Поэтому я проанализировал JSON и вытащил проигрыватель из него, но заполнение персонажа внутри проигрывателя оказалось не очень успешным, потому что в этой части JSON была только ссылка без данных.

Поэтому мой вопрос: какзаполнить объекты этими ссылками при извлечении их из всего контекста?

Упрощенные фрагменты кода ниже.

public class GameManager{
  public static GameManager instance; //singleton

  public List<Character> characters;
  public Player player; //<-- other classes may have a ref to this

  //...
}

public class Character{
  public string name;
  public int reputation;
  //...
}

public class Player{
  public string location;
  public Character character;
  //...
}

public class Savegame{
  public List<Character> characters;
  public Player player;

  public Savegame(){
    characters=GameManager.instance.characters;
    player=GameManager.instance.player;
  }

  public static void Save(){
    string saveJson = JsonConvert.SerializeObject(new Savegame(), Formatting.Indented,
        new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });
        string dest = Path.Combine(Application.persistentDataPath, "gmSave.json");
        File.WriteAllText(dest, saveJson);
  }

  public static void Load(){
    string dest = Path.Combine(Application.persistentDataPath, "gmSave.json");
    string saveJson = File.ReadAllText(dest);
    Savegame savegame = JsonConvert.DeserializeObject<Savegame>(saveJson);
    JObject jo = JObject.Parse(saveJson);    
    JsonConvert.PopulateObject(jo["player"].ToString(), GameManager.instance.player);
  }
}

1 Ответ

0 голосов
/ 28 октября 2019

Используйте JSONUtility вместо этого для простых классов.

Вы не должны заполнять объекты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...