4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Unity] EasySave3 ネストしたデータの保存

Last updated at Posted at 2021-02-07

また備忘です。長文です。reflection使えばprivateもできるかも。コストも読み書きの時だけで安いし。

今回はUnityで大人気の有償アセットEasySave3についてです。
保存できる型はデフォルトで基本の型のほとんどがサポートされています。

が、ネストしたデータやサポートにない独自の型のセーブロードどうすればいいの…ってときです。

大きく分けて対策2個あると思うんです。一長一短ある。
・ネストした型をJSONにパースしてstringに変換後に保存!
 JsonUtility をつかって Unity で JSON を取り扱う方法
・独自のセーブロードタイプクラスを作成(今回はこ↑こ↓)

結論を書くと、自分でES3用のセーブロードタイプクラスを作るのです。

公式のマニュアルに書いてあるのでこちらを参考してください。

・独自クラス作成前セーブデータ(保存できてない)

OldSavedata.dat
	"LanguageDatabase" : {
		"__type" : "Databases.DatabaseObject,Assembly-CSharp",
		"value" : {
			"__type" : "Databases.LanguageDatabase,Assembly-CSharp",
			"_ES3Ref" : "1380498291805822379",
			"_ES3Ref" : "1380498291805822379"
		}
	},

・独自クラス作成後セーブデータ(どやぁ)

NewSavedata.dat
	"LanguageDatabase" : {
		"__type" : "Databases.DatabaseObject,Assembly-CSharp",
		"value" : {
			"__type" : "Databases.LanguageDatabase,Assembly-CSharp",
			"_ES3Ref" : "5303085288931533276",
			"_ES3Ref" : "5303085288931533276",
			"Items" : [
				{
					"Language" : "English",
					"CompoItems" : [
						{
							"Type" : 1,
							"LanguageData" : [
								{
									"ID" : 0,
									"SearchID" : "KeyName",
									"Word" : "Key Name"
								},{
									"ID" : 1,
									"SearchID" : "BindName",
									"Word" : "Bind Key"
								},{
							]
						},{
							"Type" : 2,
							"LanguageData" : [
								{
									"ID" : 60,
									"SearchID" : "TXT_HotKey",
									"Word" : "HotKey"
								},{
									"ID" : 61,
									"SearchID" : "TXT_Video",
									"Word" : "Video"
								},{
						},{
					]
				},{
					"Language" : "日本語",
					"CompoItems" : [
						{
							"Type" : 1,
							"LanguageData" : [
								{
									"ID" : 0,
									"SearchID" : "KeyName",
									"Word" : "名称"
								},{
									"ID" : 1,
									"SearchID" : "BindName",
									"Word" : "設定キー"
								},{
以下略

※SakuraEditorで開くと文字コードがShiftJisでに設定された文字化けするけど、
 UTF-8 Bom付でもう一度開けば文字化けは解消されます。(文字コードは怖いね)

保存対象のデータ構造(Odin使ってます。見にくい人いるかも、とりあえずネストした構造です。)
構造.png
セーブを実行しているコードと、クラス・構造体もペタっとおいておきます。ソロ開発のコードなので好きに見ていきなペッ!

SaveExecute.cs
    ES3.Save(GetType().Name, (LanguageDatabase.Instance)this, dataPath); //SaveData.csのinstanceされたデータ
SaveData.cs
    [System.Serializable] // 保存対象
    public class LanguageDatabase : SingletonDatabase<LanguageDatabase>, IMasterData
    {
        // いろんな項目が多々ある
        public List<LanguageDataList> Items = new List<LanguageDataList>(); //保存されるデータ
        // いろんなメソッドが多々ある
    }
Data.cs
    [System.Serializable] // Serializeなデータ
    public class LanguageDataList
    {
        public string Language;
        public List<LanguageCompoTypeData> CompoItems = new List<LanguageCompoTypeData>();
        public LanguageDataList(string val)
        {
            Language = val;
        }
    }
    [System.Serializable]
    public class LanguageCompoTypeData
    {
        public CompoLangType Type = CompoLangType.None;
        public List<LanguageData> LanguageItems = new List<LanguageData>();
        public LanguageCompoTypeData(CompoLangType type)
        {
            Type = type;
        }
    }
    [System.Serializable]
    public class LanguageData
    {
        public int ID;
        public string SearchID;
        public string Word;
        public string GetWord() { 
            return  @Word;
        }
    }

今回作ったもの(重要)

ネストした個数分タイプを作りました。 ~~#一番下層のタイプはもしかしたらいらないかも(ES3UserType_LanguageData.cs)~~ 独自の型は全部必要なので定義してください。
ES3UserType_LanguageDataList.cs
using Databases;
using System.Collections.Generic;

namespace ES3Types
{
    [UnityEngine.Scripting.Preserve]
	[ES3PropertiesAttribute()]
	public class ES3UserType_LanguageDataList : ES3ObjectType
	{
		public static ES3Type Instance = null;

		public ES3UserType_LanguageDataList() : base(typeof(LanguageDataList)){ Instance = this; priority = 1; }


		protected override void WriteObject(object obj, ES3Writer writer)
		{
			var instance = (LanguageDataList)obj;
			writer.WriteProperty<string>("Language", instance.Language);
			writer.WriteProperty<List<LanguageCompoTypeData>>("CompoItems", instance.CompoItems);
		}

		protected override void ReadObject<T>(ES3Reader reader, object obj)
		{
			var instance = (LanguageDataList)obj;
			foreach(string propertyName in reader.Properties)
			{
				switch(propertyName)
				{
					case "Language":
						instance.Language = reader.Read<string>(); break;
					case "CompoItems":
						instance.CompoItems = reader.Read<List<LanguageCompoTypeData>>(); break;
					default:
						reader.Skip();
						break;
				}
			}
		}

		protected override object ReadObject<T>(ES3Reader reader)
		{
			var instance = new LanguageDataList("Language");
			ReadObject<T>(reader, instance);
			return instance;
		}
	}
}
ES3UserType_LanguageCompoTypeData.cs
namespace ES3Types
{
    [UnityEngine.Scripting.Preserve]
	[ES3PropertiesAttribute()]
	public class ES3UserType_LanguageCompoTypeData : ES3ObjectType
	{
		public static ES3Type Instance = null;

		public ES3UserType_LanguageCompoTypeData() : base(typeof(LanguageCompoTypeData)){ Instance = this; priority = 1; }


		protected override void WriteObject(object obj, ES3Writer writer)
		{
			var instance = (LanguageCompoTypeData)obj;
			writer.WriteProperty<CompoLangType>("Type", instance.Type);
			writer.WriteProperty<List<LanguageData>>("LanguageData", instance.LanguageItems);
		}

		protected override void ReadObject<T>(ES3Reader reader, object obj)
		{
			var instance = (LanguageCompoTypeData)obj;
			foreach(string propertyName in reader.Properties)
			{
				switch(propertyName)
				{
					case "Type":
						instance.Type = reader.Read<CompoLangType>(); break;
					case "LanguageData":
						instance.LanguageItems = reader.Read<List<LanguageData>>(); break;
					default:
						reader.Skip();
						break;
				}
			}
		}

		protected override object ReadObject<T>(ES3Reader reader)
		{
			var instance = new LanguageCompoTypeData(CompoLangType.None);
			ReadObject<T>(reader, instance);
			return instance;
		}
	}
}
ES3UserType_LanguageData.cs
namespace ES3Types
{
    [UnityEngine.Scripting.Preserve]
	[ES3PropertiesAttribute()]
	public class ES3UserType_LanguageData : ES3ObjectType
	{
		public static ES3Type Instance = null;

		public ES3UserType_LanguageData() : base(typeof(LanguageData)){ Instance = this; priority = 1; }


		protected override void WriteObject(object obj, ES3Writer writer)
		{
			var instance = (LanguageData)obj;
			writer.WriteProperty<int>("ID", instance.ID);
			writer.WriteProperty<string>("SearchID", instance.SearchID);
			writer.WriteProperty<string>("Word", instance.Word);
		}

		protected override void ReadObject<T>(ES3Reader reader, object obj)
		{
			var instance = (LanguageData)obj;
			foreach(string propertyName in reader.Properties)
			{
				switch(propertyName)
				{
					case "ID":
						instance.ID = reader.Read<int>(); break;
					case "SearchID":
						instance.SearchID = reader.Read<string>(); break;
					case "Word":
						instance.Word = reader.Read<string>(); break;
					default:
						reader.Skip();
						break;
				}
			}
		}

		protected override object ReadObject<T>(ES3Reader reader)
		{
			var instance = new LanguageData();
			ReadObject<T>(reader, instance);
			return instance;
		}
	}
}

以上です。お疲れ様です。

解説はとくにありません・・・

WriteObjectとReadObjectがそれぞれ対で設定できてればオッケー!
ReadObjectは今回の場合はほとんどいらないかも。一応作ってるけど。

EasySave3のソースコードのぞいてみるとわかるけど、
プリミティブ型⇒Listとか汎用な型⇒Unity謹製型⇒独自型⇒ないならエラー!
ってとこでList構造見つけるまではいいけどListに指定されている型が謎だからできんってなってる。

そこに今回の独自型を作成して、参照を自動的にお願いしているだけです。

https://qiita.com/AllNight/items/cd8d7b6111a9f75afb55
上記の記事で良い感じのデータ定義と、データロードができるようになりました。
公式でぜひ採用してほしいレベル(何)

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?