Unity中使用JsonObject插件动态序列与反序列化对象

原因

游戏的存档是放在客户端的,之前是直接使用的二进制序列化

对象标记[Serializable]标签,然后直接转换成二进制文件

这样操作乍看没问题,但是当上线后需要加入新功能,问题就暴露出来了

玩家此时已经有本地存档了,当我对本地Vo对象加入新属性时候,二进制代码无法和Class进行对应.于是乎就会出现 旧存档无法使用的情况.

解决方案

需要找到一种 可以在Class已经发生更新后,仍旧可以用旧的存档进行反序列化的方法.

能想到的有两种. 一种是Google的Protobuf,一种是Json.

Protobuf只要保证新加入的key是向后延续的,就可以兼容之前的数据.

Json的话,如果用Unity内置的Json类是无法实现的,因为他需要做Json-Objecet的映射.不过JsonObject这个插件可以实现动态解析.

我的选择

Protobuf的话 主要是体积小,一般用于网络传输. 我主要是用于游戏存档.整体存档数据不大.所以JsonObject更适合我.

并且其代码很简洁,后期自己如果有一些特殊需求,扩展起来也会很方便的.

JsonObject

下载地址

Unity AssetsStore
GitHub(推荐)

核心代码

TeamVo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using System.Collections.Generic;
using Code;

public class Team : ICEJsonSerializable
{
private const string TEAM_NAME = "a";
private const string ALL_MEMBER_LIST = "b";
private const string CITY = "c";

public string teamName;
public List<Person> allMembersList;

//New
public string city;

public Team()
{
allMembersList = new List<Person>();
}


public void FromJson(JSONObject _jsonObject)
{
_jsonObject.GetField(ALL_MEMBER_LIST, _obj =>
{
foreach (var menberObj in _obj.list)
{
var person = new Person();
person.FromJson(menberObj);
allMembersList.Add(person);
}
});

_jsonObject.GetField(TEAM_NAME, _obj => { teamName = _obj.str; }, name => { teamName = "NotSet"; });
_jsonObject.GetField(CITY, _obj => { city = _obj.str; }, _notFound => { city = "NotFound"; });
}

public JSONObject ToJsonObject()
{
var returnObj = new JSONObject();

var menberList = new JSONObject(JSONObject.Type.ARRAY);
foreach (var person in allMembersList)
{
menberList.Add(person.ToJsonObject());
}

returnObj.AddField(ALL_MEMBER_LIST, menberList);
returnObj.AddField(TEAM_NAME, teamName);

return returnObj;
}
}
1
2
3
4
5
6
7
8

//序列化方法
var json = team.ToJsonObject();
var str = json.ToString();

//反序列化
var team = new Team();
team.FromJson(new JSONObject(str));

代码说明

序列化部分比较简单,所有Vo对象实现 序列化反序列化接口.然后递归创建JsonObject即可

反序列化JsonObject处理比较好的部分是

_jsonObject.GetField(key,成功回调,失败回调)

也就是取数据使用回调函数

比如像TeamVo中,我第一次序列化时候并不包含city字段. 当我序列化成功后,给TeamVo中加入city字段

再读取之前序列化好的Json(进行反序列化).

1
_jsonObject.GetField(CITY, _obj => { city = _obj.str; }, _notFound => { city = "NotFound"; });

我就可以很轻松的兼容旧的序列化文件.

坚持原创技术分享,您的支持将鼓励我继续创作!