もくじへ
ScriptableObjectを生成する
DataSetの設定が終わったら、Actions領域の「Create ScriptableObject and Importer」ボタンをクリックします。
これはGroup単位で1つのファイルとなっているので、Group配下に複数のデータセットがある場合には、全てのDataSetを作成し終わってからでも問題ありません。
というわけで、続けてExpTableのDataSetの設定を行い、再度出力してみます。
ExpTableの設定は以下としました。
このとき出力されるソースコードの場所は最初にSettingで指定した場所になります。
ScriptableObject Class Path:ScriptableObjectクラスの出力先
Importer Path : インポーターのパス
ScriptableObjectクラス 出力例
using System;
using UnityEngine;
using CatHut;
[CreateAssetMenu(fileName = "Player", menuName = "CatHut/ScriptableObjects/Player")]
public class Player : ScriptableObject
{
public enum JOB
{
NONE = 0,
HERO,
KNIGHT,
HEALER,
FIGHTER
}
[SerializeField] private SerializableDictionary<string, Character> _CharacterData;
public SerializableDictionary<string, Character> CharacterData { get => _CharacterData; set => _CharacterData = value; }
[SerializeField] private SerializableDictionary<string, ExpTable> _ExpTableData;
public SerializableDictionary<string, ExpTable> ExpTableData { get => _ExpTableData; set => _ExpTableData = value; }
[Serializable]
public class Character : MasterDataBase
{
[SerializeField] private string _id;
public string id { get => _id; set => _id = value; }
[SerializeField] private String _Name;
[SerializeField] private JOB _Job;
[SerializeField] private Int32 _Hp;
[SerializeField] private Int32 _Mp;
[SerializeField] private Int32 _Atk;
[SerializeField] private Int32 _Def;
public String Name { get => _Name; set => _Name = value; }
public JOB Job { get => _Job; set => _Job = value; }
public Int32 Hp { get => _Hp; set => _Hp = value; }
public Int32 Mp { get => _Mp; set => _Mp = value; }
public Int32 Atk { get => _Atk; set => _Atk = value; }
public Int32 Def { get => _Def; set => _Def = value; }
}
[Serializable]
public class ExpTable : MasterDataBase
{
[SerializeField] private string _id;
public string id { get => _id; set => _id = value; }
[SerializeField] private Int32 _Lv;
[SerializeField] private Int32 _Exp;
public Int32 Lv { get => _Lv; set => _Lv = value; }
public Int32 Exp { get => _Exp; set => _Exp = value; }
}
}
intがInt32となっていますが、これは内部的には同じものなのでコードで使うときにもintとして使用可能なもので、キャストも不要です。
また、少し長いですが、Importerは下記のようなものが出力されます。
それぞれの型をConvertしながらScriptableObjectのインスタンスに値を格納します。
Importer 出力例
using System;
using System.IO;
using UnityEngine;
using System.Collections.Generic;
namespace CatHut
{
public class PlayerImporter : IDataImporter
{
private readonly RawDataGroup _group;
private readonly Player _instance;
public PlayerImporter(RawDataGroup group)
{
if (group == null)
throw new ArgumentNullException(nameof(group));
_group = group;
_instance = ScriptableObject.CreateInstance<Player>();
_instance.CharacterData = new SerializableDictionary<string, Player.Character>();
_instance.ExpTableData = new SerializableDictionary<string, Player.ExpTable>();
}
public ScriptableObject Import()
{
var CharacterDataSet = _group.GetDataSet("Character");
if (CharacterDataSet == null)
throw new InvalidOperationException("Required dataset 'Character' not found");
if (CharacterDataSet.Header == null)
throw new InvalidOperationException("Header information is missing for dataset 'Character'");
ImportCharacterData(CharacterDataSet);
var ExpTableDataSet = _group.GetDataSet("ExpTable");
if (ExpTableDataSet == null)
throw new InvalidOperationException("Required dataset 'ExpTable' not found");
if (ExpTableDataSet.Header == null)
throw new InvalidOperationException("Header information is missing for dataset 'ExpTable'");
ImportExpTableData(ExpTableDataSet);
return _instance;
}
private void ImportCharacterData(RawDataSet dataSet)
{
var header = dataSet.Header;
foreach (var path in dataSet.DataVersions.GetRegisteredPaths())
{
var csvData = dataSet.DataVersions.GetVersion(path);
if (csvData == null)
throw new InvalidOperationException($"Failed to get CSV data for path: {path}");
dataSet.SetColumnIndex(csvData);
int errorCount = 0;
for (int rowIndex = 1; rowIndex < csvData.RowCount; rowIndex++)
{
var entry = new Player.Character();
bool hasRowError = false;
foreach (var variable in header.VariableDic)
{
if (variable.Value.ColumnIndex >= csvData.ColumnCount)
{
throw new InvalidOperationException(
$"Column index out of range. Variable: {variable.Key}, " +
$"Index: {variable.Value.ColumnIndex}, " +
$"Available columns: {csvData.ColumnCount}");
}
var value = csvData.GetValue(rowIndex, variable.Value.ColumnIndex);
switch (variable.Key)
{
case "id":
if (!MasterDataEditorCommon.TryConvert<string>(value, out var convertedid))
{
Debug.LogError($"[{csvData.FilePath}] Failed to convert value '{value}' to string for column 'id' at row {rowIndex}");
hasRowError = true;
}
else
{
entry.id = convertedid;
}
break;
case "Name":
if (!MasterDataEditorCommon.TryConvert<string>(value, out var convertedName))
{
Debug.LogError($"[{csvData.FilePath}] Failed to convert value '{value}' to string for column 'Name' at row {rowIndex}");
hasRowError = true;
}
else
{
entry.Name = convertedName;
}
break;
case "Job":
if (!MasterDataEditorCommon.TryConvert<Player.JOB>(value, out var convertedJob))
{
Debug.LogError($"[{csvData.FilePath}] Failed to convert value '{value}' to Tables[JOB] for column 'Job' at row {rowIndex}");
hasRowError = true;
}
else
{
entry.Job = convertedJob;
}
break;
case "Hp":
if (!MasterDataEditorCommon.TryConvert<int>(value, out var convertedHp))
{
Debug.LogError($"[{csvData.FilePath}] Failed to convert value '{value}' to int for column 'Hp' at row {rowIndex}");
hasRowError = true;
}
else
{
entry.Hp = convertedHp;
}
break;
case "Mp":
if (!MasterDataEditorCommon.TryConvert<int>(value, out var convertedMp))
{
Debug.LogError($"[{csvData.FilePath}] Failed to convert value '{value}' to int for column 'Mp' at row {rowIndex}");
hasRowError = true;
}
else
{
entry.Mp = convertedMp;
}
break;
case "Atk":
if (!MasterDataEditorCommon.TryConvert<int>(value, out var convertedAtk))
{
Debug.LogError($"[{csvData.FilePath}] Failed to convert value '{value}' to int for column 'Atk' at row {rowIndex}");
hasRowError = true;
}
else
{
entry.Atk = convertedAtk;
}
break;
case "Def":
if (!MasterDataEditorCommon.TryConvert<int>(value, out var convertedDef))
{
Debug.LogError($"[{csvData.FilePath}] Failed to convert value '{value}' to int for column 'Def' at row {rowIndex}");
hasRowError = true;
}
else
{
entry.Def = convertedDef;
}
break;
}
}
if (!hasRowError)
{
if (_instance.CharacterData.ContainsKey(entry.id))
{
Debug.LogError($"[{csvData.FilePath}] Duplicate key found. Value: {entry.id}, Row: {rowIndex}");
hasRowError = true;
errorCount++;
}
else
{
_instance.CharacterData[entry.id] = entry;
}
}
}
if (errorCount > 0)
{
Debug.LogError($"Found {errorCount} errors in file: {csvData.FilePath}");
}
}
}
private void ImportExpTableData(RawDataSet dataSet)
{
var header = dataSet.Header;
foreach (var path in dataSet.DataVersions.GetRegisteredPaths())
{
var csvData = dataSet.DataVersions.GetVersion(path);
if (csvData == null)
throw new InvalidOperationException($"Failed to get CSV data for path: {path}");
dataSet.SetColumnIndex(csvData);
int errorCount = 0;
for (int rowIndex = 1; rowIndex < csvData.RowCount; rowIndex++)
{
var entry = new Player.ExpTable();
bool hasRowError = false;
foreach (var variable in header.VariableDic)
{
if (variable.Value.ColumnIndex >= csvData.ColumnCount)
{
throw new InvalidOperationException(
$"Column index out of range. Variable: {variable.Key}, " +
$"Index: {variable.Value.ColumnIndex}, " +
$"Available columns: {csvData.ColumnCount}");
}
var value = csvData.GetValue(rowIndex, variable.Value.ColumnIndex);
switch (variable.Key)
{
case "id":
if (!MasterDataEditorCommon.TryConvert<string>(value, out var convertedid))
{
Debug.LogError($"[{csvData.FilePath}] Failed to convert value '{value}' to string for column 'id' at row {rowIndex}");
hasRowError = true;
}
else
{
entry.id = convertedid;
}
break;
case "Lv":
if (!MasterDataEditorCommon.TryConvert<int>(value, out var convertedLv))
{
Debug.LogError($"[{csvData.FilePath}] Failed to convert value '{value}' to int for column 'Lv' at row {rowIndex}");
hasRowError = true;
}
else
{
entry.Lv = convertedLv;
}
break;
case "Exp":
if (!MasterDataEditorCommon.TryConvert<int>(value, out var convertedExp))
{
Debug.LogError($"[{csvData.FilePath}] Failed to convert value '{value}' to int for column 'Exp' at row {rowIndex}");
hasRowError = true;
}
else
{
entry.Exp = convertedExp;
}
break;
}
}
if (!hasRowError)
{
if (_instance.ExpTableData.ContainsKey(entry.id))
{
Debug.LogError($"[{csvData.FilePath}] Duplicate key found. Value: {entry.id}, Row: {rowIndex}");
hasRowError = true;
errorCount++;
}
else
{
_instance.ExpTableData[entry.id] = entry;
}
}
}
if (errorCount > 0)
{
Debug.LogError($"Found {errorCount} errors in file: {csvData.FilePath}");
}
}
}
}
}
ここまででデータの読み込みが可能になるので、次は実際にデータを作成し、読み込みを行ってみます。
コメント