Created
September 18, 2018 20:23
-
-
Save FuzzySlipper/20523cb10a29690346c38fafaf96d21d to your computer and use it in GitHub Desktop.
Runtime CastleDB file reader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
using SimpleJSON; | |
namespace PixelComrades { | |
public class JsonDB { | |
private const string Id = "ID"; | |
private const string EnumProp = "hasIndex"; | |
private JsonParser _parser; | |
private Dictionary<string, List<LoadedDataEntry>> _sheets = new Dictionary<string, List<LoadedDataEntry>>(); | |
public Dictionary<string, List<LoadedDataEntry>> Sheets { get => _sheets; } | |
public JsonParser Parser { get => _parser; } | |
public JsonDB(string input) { | |
if (string.IsNullOrEmpty(input)) { | |
return; | |
} | |
_parser = new JsonParser(input); | |
SetupSheets(); | |
} | |
public void SetupSheets() { | |
for (var s = 0; s < _parser.Sheets.Count; s++) { | |
var sheet = _parser.Sheets[s]; | |
var list = new List<LoadedDataEntry>(); | |
_sheets.Add(sheet.Name, list); | |
for (int r = 0; r < sheet.Rows.Count; r++) { | |
JSONNode line = sheet.Rows[r]; | |
var id = line[0].Value; | |
var entry = new LoadedDataEntry(id, sheet, sheet.Columns.Count); | |
entry.Cells[0] = new LoadedDataCell<string>(Id, entry, id); | |
for (int c = 1; c < sheet.Columns.Count; c++) { | |
entry.Cells[c] = GetColumnData(entry, line[c], sheet.Columns[c]); | |
} | |
list.Add(entry); | |
} | |
if (sheet.HasProp(EnumProp)) { | |
GameData.Enums.Add(sheet.Name, new FakeEnum(sheet)); | |
} | |
} | |
for (var s = 0; s < _parser.Nested.Count; s++) { | |
var nestedSheet = _parser.Nested[s]; | |
var targetSheet = _parser.GetSheetWithName(nestedSheet.NestedParent); | |
var column = targetSheet.GetColumn(nestedSheet.NestedColumn); | |
var entryList = _sheets[targetSheet.Name]; | |
for (int e = 0; e < entryList.Count; e++) { | |
var entry = entryList[e]; | |
var list = entry.Get(column.Name) as LoadedDataList; | |
if (list == null || nestedSheet.Columns.Count == 0) { | |
Debug.Log(string.Format("No list for {0} at {1}", column.Name, entry.ID)); | |
continue; | |
} | |
for (int c = 0; c < nestedSheet.Columns.Count; c++) { | |
var nestedColumn = nestedSheet.Columns[c]; | |
for (int i = 0; i < list.TempData.Count; i++) { | |
var data = list.TempData[i][nestedColumn.Name]; | |
if (data == null) { | |
continue; | |
} | |
list.Value.Add(GetColumnData(entry, data, nestedColumn)); | |
} | |
} | |
list.TempData = null; | |
} | |
} | |
} | |
private LoadedDataCell GetColumnData(LoadedDataEntry owner, JSONNode data, ColumnNode column) { | |
LoadedDataCell cell = null; | |
var typeNum = GetTypeNumFromCastleDBTypeString(column.TypeStr); | |
switch (typeNum) { | |
case "0": | |
case "1": | |
//0 = UniqueIdentifier | |
//1 = Text | |
cell = new LoadedDataCell<string>(column.Name, owner, data.Value); | |
break; | |
case "2": | |
cell = new LoadedDataCell<bool>(column.Name, owner, data.AsBool); | |
break; | |
case "3": | |
cell = new LoadedDataCell<int>(column.Name, owner, data.AsInt); | |
break; | |
case "4": | |
cell = new LoadedDataCell<float>(column.Name, owner, data.AsFloat); | |
break; | |
case "6": | |
cell = new LoadedDataReference(column.Name, owner, GetTypeStrData(column.TypeStr), data.Value, this); | |
break; | |
case "7": | |
case "13": | |
case "14": | |
case "16": | |
//7 = Image | |
//13 = File | |
//14 = Tile | |
//16 = Dynamic | |
cell = new LoadedDataCell<string>(column.Name, owner, data.Value); | |
break; | |
case "9": | |
//Custom type | |
cell = new LoadedDataCell<string>(column.Name, owner, data.Value); | |
break; | |
case "11": | |
//Color | |
if (ColorUtility.TryParseHtmlString((data.AsInt).ToString("X"), out var color)) { | |
cell = new LoadedDataCell<Color>(column.Name, owner, color); | |
} | |
break; | |
case "12": | |
case "15": | |
//12 = Data Layer | |
//16 = Tile Layer | |
cell = new LoadedDataReference(column.Name, owner, GetTypeStrData(column.TypeStr), data.Value, this); | |
break; | |
case "5": | |
case "10": | |
//5 = Enum | |
//10 = Flags Enum | |
var enumMembers = GetEnumValuesFromTypeString(column.TypeStr); | |
cell = new LoadedDataCell<string>(column.Name, owner, enumMembers[data.AsInt]); | |
break; | |
case "8": | |
//List | |
var list = new LoadedDataList(column.Name, owner, new List<LoadedDataCell>()); | |
cell = list; | |
foreach (var item in data) { | |
list.TempData.Add(item); | |
} | |
break; | |
} | |
return cell; | |
} | |
private string GetTypeStrData(string entry) { | |
var index = entry.LastIndexOf(':'); | |
if (index < 0) { | |
for (int i = 0; i < entry.Length; i++) { | |
if (!System.Char.IsDigit(entry[i])) { | |
return entry.Substring(i); | |
} | |
} | |
} | |
return entry.Substring(index + 1); | |
} | |
public static string[] GetEnumValuesFromTypeString(string inputString) { | |
char delimiter1 = ':'; | |
char delimiter2 = ','; | |
string[] init = inputString.Split(delimiter1); | |
string[] enumValues = init[1].Split(delimiter2); | |
return enumValues; | |
} | |
public static string GetTypeNumFromCastleDBTypeString(string inputString) { | |
char delimiter = ':'; | |
string[] typeString = inputString.Split(delimiter); | |
return typeString[0]; | |
} | |
} | |
public class JsonParser { | |
public const string JsonSheets = "sheets"; | |
public const string JsonName = "name"; | |
public const string JsonDisplay = "display"; | |
public const string JsonType = "typeStr"; | |
public const string JsonColumns = "columns"; | |
public const string JsonLines = "lines"; | |
public const string JsonProps = "props"; | |
public List<SheetNode> Sheets { get; protected set; } | |
public List<SheetNode> Nested { get; protected set; } | |
public JsonParser(string text) { | |
var root = JSON.Parse(text); | |
Sheets = new List<SheetNode>(); | |
Nested = new List<SheetNode>(); | |
foreach (var item in root[JsonSheets]) { | |
var sheet = new SheetNode(item.Value); | |
if (sheet.NestedType) { | |
Nested.Add(sheet); | |
} | |
else { | |
Sheets.Add(sheet); | |
} | |
} | |
} | |
public SheetNode GetSheetWithName(string name) { | |
for (var i = 0; i < Sheets.Count; i++) { | |
var item = Sheets[i]; | |
if (item.Name == name) { | |
return item; | |
} | |
} | |
return null; | |
} | |
} | |
public class ColumnNode { | |
public ColumnNode(JSONNode sheetValue) { | |
var value = sheetValue; | |
Name = value[JsonParser.JsonName]; | |
Display = value[JsonParser.JsonDisplay]; | |
TypeStr = value[JsonParser.JsonType]; | |
} | |
public string TypeStr { get; protected set; } | |
public string Name { get; protected set; } | |
public string Display { get; protected set; } | |
} | |
public class SheetNode { | |
public SheetNode(JSONNode sheetValue) { | |
var value = sheetValue; | |
Name = value[JsonParser.JsonName]; | |
char delimit = '@'; | |
var splitString = Name.Split(delimit); | |
if (splitString.Length <= 1) { | |
NestedType = false; | |
} | |
else { | |
NestedParent = splitString[0]; | |
NestedColumn = splitString[1]; | |
NestedType = true; | |
} | |
Columns = new List<ColumnNode>(); | |
Rows = new List<JSONNode>(); | |
Props = value[JsonParser.JsonProps]; | |
foreach (KeyValuePair<string, JSONNode> item in value[JsonParser.JsonColumns]) { | |
Columns.Add(new ColumnNode(item.Value)); | |
} | |
foreach (KeyValuePair<string, JSONNode> item in value[JsonParser.JsonLines]) { | |
Rows.Add(item.Value); | |
} | |
} | |
public string NestedParent { get; } | |
public string NestedColumn { get; } | |
public bool NestedType { get; protected set; } | |
public string Name { get; protected set; } | |
public List<ColumnNode> Columns { get; protected set; } | |
public List<JSONNode> Rows { get; protected set; } | |
public JSONNode Props { get; protected set; } | |
public ColumnNode GetColumn(string name) { | |
for (var i = 0; i < Columns.Count; i++) { | |
var item = Columns[i]; | |
if (item.Name == name) { | |
return item; | |
} | |
} | |
return null; | |
} | |
public bool HasProp(string prop) { | |
var targetProp = Props[prop]; | |
return targetProp != null && targetProp.AsBool; | |
} | |
} | |
public abstract class LoadedDataCell { | |
public abstract System.Object Get { get; } | |
public string ID { get; } | |
public string FullID { get; } | |
protected LoadedDataCell(string id, LoadedDataEntry owner) { | |
ID = id; | |
FullID = string.Format("{0}.{1}", owner.ID, id); | |
} | |
} | |
public class LoadedDataCell<T> : LoadedDataCell { | |
public T Value { get;} | |
public System.Type Type { get; } | |
public override System.Object Get { get { return Value; } } | |
public LoadedDataCell(string id, LoadedDataEntry owner, T value) : base(id, owner) { | |
Value = value; | |
Type = typeof(T); | |
} | |
} | |
public class LoadedDataList : LoadedDataCell<List<LoadedDataCell>> { | |
public List<JSONNode> TempData = new List<JSONNode>(); | |
public LoadedDataList(string id, LoadedDataEntry owner, List<LoadedDataCell> value) : base(id, owner, value) {} | |
} | |
public class LoadedDataReference : LoadedDataCell { | |
public string TargetSheet { get; } | |
public string TargetID { get; } | |
private JsonDB _db; | |
private LoadedDataEntry _entry; | |
public override System.Object Get { get { return Value != null ? _entry.FullID : string.Format("Missing {0} at {1}", TargetID, TargetSheet); } } | |
public LoadedDataEntry Value { | |
get { | |
if (_entry != null) { | |
return _entry; | |
} | |
var list = _db.Sheets[TargetSheet]; | |
for (int i = 0; i < list.Count; i++) { | |
if (list[i].ID == TargetID) { | |
_entry = list[i]; | |
break; | |
} | |
} | |
return _entry; | |
} | |
} | |
public LoadedDataReference(string id, LoadedDataEntry owner, string targetSheet, string targetId, JsonDB db) : base(id, owner) { | |
TargetSheet = targetSheet; | |
TargetID = targetId; | |
_db = db; | |
} | |
} | |
public class LoadedDataEntry { | |
public LoadedDataCell[] Cells; | |
public string ID { get; } | |
public string FullID { get; } | |
public LoadedDataEntry(string id, SheetNode owner, int cnt) { | |
Cells = new LoadedDataCell[cnt]; | |
ID = id; | |
FullID = string.Format("{0}.{1}", owner.Name, id); | |
} | |
public LoadedDataCell Get(string label) { | |
for (int i = 0; i < Cells.Length; i++) { | |
if (Cells[i].ID == label) { | |
return Cells[i]; | |
} | |
} | |
return null; | |
} | |
public T Get<T>(string field) { | |
var cell = Get(field); | |
if (cell == null) { | |
return default(T); | |
} | |
if (cell is LoadedDataCell<T> typeCell) { | |
return typeCell.Value; | |
} | |
return (T) cell.Get; | |
} | |
public T TryGet<T>(string field, T defaultValue) { | |
var cell = Get(field); | |
if (cell == null) { | |
return defaultValue; | |
} | |
if (cell is LoadedDataCell<T> typeCell) { | |
return typeCell.Value; | |
} | |
return (T) cell.Get; | |
} | |
} | |
public class FakeEnum { | |
private const string JsonName = "Name"; | |
private const string JsonDescription = "Description"; | |
private const string JsonValue = "Value"; | |
private string[] _ids; | |
private string[] _fullIds; | |
private string[] _names; | |
private string[] _descriptions; | |
private int[] _associatedValues; | |
public string TypeName { get; } | |
public string[] Ids { get => _ids; } | |
public string[] FullIds { get => _fullIds; } | |
public string[] Names { get => _names; } | |
public string[] Descriptions { get => _descriptions; } | |
public int[] AssociatedValues { get => _associatedValues; } | |
public int Length { get { return _ids.Length; } } | |
public int Count { get { return _ids.Length; } } | |
public string this[int index] { get { return _ids[index]; } } | |
public string GetDescriptionAt(int index) { | |
return _descriptions[index]; | |
} | |
public string GetID(int index) { | |
return _ids[index]; | |
} | |
public string GetID(string key) { | |
if (TryParse(key, out var index)) { | |
return _ids[index]; | |
} | |
return ""; | |
} | |
public int GetAssociatedValue(int index) { | |
return _associatedValues[index]; | |
} | |
public FakeEnum(SheetNode sheet) { | |
TypeName = sheet.Name; | |
_ids = new string[sheet.Rows.Count]; | |
_fullIds = new string[sheet.Rows.Count]; | |
_names = new string[sheet.Rows.Count]; | |
_descriptions = new string[sheet.Rows.Count]; | |
_associatedValues = new int[sheet.Rows.Count]; | |
for (int r = 0; r < sheet.Rows.Count; r++) { | |
JSONNode line = sheet.Rows[r]; | |
_ids[r] = line[0].Value; | |
_fullIds[r] = string.Format("{0}.{1}", TypeName, _ids[r]); | |
var name = line[JsonName]; | |
_names[r] = name != null ? name.Value : _ids[r]; | |
var description = line[JsonDescription]; | |
_descriptions[r] = description != null ? description.Value : _ids[r]; | |
var value = line[JsonValue]; | |
_associatedValues[r] = value != null ? value.AsInt : r; | |
} | |
} | |
public bool TryParse(string text, out int index) { | |
index = -1; | |
for (int i = 0; i < _ids.Length; i++) { | |
if (text.CompareCaseInsensitive(_ids[i]) || | |
text.CompareCaseInsensitive(_names[i]) || | |
text.CompareCaseInsensitive(_fullIds[i])) { | |
index = i; | |
return true; | |
} | |
} | |
return false; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment