-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor List/Hashset as well to have generic Collection helpers to l…
…oad/save this data. Refactor helpers to have shared base dict of types and to use hashcodes explicitly for perf.
- Loading branch information
1 parent
0a1093a
commit 02d91c0
Showing
5 changed files
with
269 additions
and
192 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using KSPCommunityFixes.Modding; | ||
using UnityEngine; | ||
|
||
namespace ROUtils.DataTypes | ||
{ | ||
public abstract class PersistenceHelper | ||
{ | ||
protected static readonly Dictionary<int, Type> _TypeCache = new Dictionary<int, Type>(); | ||
|
||
protected const int VERSION = 3; | ||
protected int _version; // will be set on load | ||
|
||
/// <summary> | ||
/// Returns a type from a type name and its hash (fuly qualified name preferred). | ||
/// If the type can't be found or the baseType isn't assignable from the found type, | ||
/// the base type is used. Successfully found types are cached. | ||
/// </summary> | ||
/// <param name="typeName"></param> | ||
/// <param name="hash"></param> | ||
/// <param name="baseType"></param> | ||
/// <returns></returns> | ||
public static Type GetTypeFromString(string typeName, int hash, Type baseType) | ||
{ | ||
if (!_TypeCache.TryGetValue(hash, out var cachedType)) | ||
{ | ||
cachedType = HarmonyLib.AccessTools.TypeByName(typeName); | ||
_TypeCache[hash] = cachedType; | ||
} | ||
|
||
if (cachedType != null && baseType.IsAssignableFrom(cachedType)) | ||
return cachedType; | ||
|
||
return baseType; | ||
} | ||
} | ||
|
||
public abstract class ICollectionPersistence<T> : PersistenceHelper, IConfigNode | ||
{ | ||
protected static readonly Type _Type = typeof(T); | ||
|
||
protected ICollection<T> _coll; | ||
|
||
public ICollectionPersistence(ICollection<T> coll) { _coll = coll; } | ||
|
||
public abstract void Load(ConfigNode node); | ||
|
||
public abstract void Save(ConfigNode node); | ||
} | ||
|
||
public class ICollectionPersistenceNode<T> : ICollectionPersistence<T> where T : IConfigNode | ||
{ | ||
protected static readonly string _TypeName = typeof(T).Name; | ||
protected static readonly int _TypeHash = _TypeName.GetHashCode(); | ||
protected static readonly int _DefaultNodeNameHash = "ITEM".GetHashCode(); | ||
|
||
public ICollectionPersistenceNode(ICollection<T> coll) : base(coll) { } | ||
|
||
public override void Load(ConfigNode node) | ||
{ | ||
_coll.Clear(); | ||
int version = 1; | ||
node.TryGetValue("version", ref version); | ||
|
||
foreach (ConfigNode n in node.nodes) | ||
{ | ||
T item; | ||
int hash = n.name.GetHashCode(); | ||
if (version == 1 || hash == _DefaultNodeNameHash || hash == _TypeHash) | ||
{ | ||
item = Activator.CreateInstance<T>(); | ||
} | ||
else | ||
{ | ||
item = (T)Activator.CreateInstance(GetTypeFromString(n.name, hash, _Type)); | ||
} | ||
item.Load(n); | ||
_coll.Add(item); | ||
} | ||
version = VERSION; | ||
} | ||
|
||
public override void Save(ConfigNode node) | ||
{ | ||
node.AddValue("version", _version); | ||
foreach (var item in _coll) | ||
{ | ||
var type = item.GetType(); | ||
ConfigNode n = new ConfigNode(type == _Type ? _TypeName : type.FullName); | ||
item.Save(n); | ||
node.AddNode(n); | ||
} | ||
} | ||
} | ||
|
||
public class ICollectionPersistenceParseable<T> : ICollectionPersistence<T> where T : class | ||
{ | ||
private enum ParseableType | ||
{ | ||
INVALID, | ||
ProtoCrewMember, | ||
} | ||
|
||
private static ParseableType GetParseableType() | ||
{ | ||
if (_Type == typeof(ProtoCrewMember)) | ||
return ParseableType.ProtoCrewMember; | ||
|
||
return ParseableType.INVALID; | ||
} | ||
|
||
private static readonly ParseableType _ParseType = GetParseableType(); | ||
|
||
protected static readonly string _TypeName = typeof(T).Name; | ||
protected static readonly int _TypeHash = _TypeName.GetHashCode(); | ||
protected static readonly int _DefaultNodeNameHash = "ITEM".GetHashCode(); | ||
|
||
public ICollectionPersistenceParseable(ICollection<T> coll) : base(coll) { } | ||
|
||
private T FromValue(ConfigNode.Value v) | ||
{ | ||
switch (_ParseType) | ||
{ | ||
case ParseableType.ProtoCrewMember: | ||
return HighLogic.CurrentGame.CrewRoster[v.value] as T; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private ConfigNode.Value ToValue(T item) | ||
{ | ||
switch (_ParseType) | ||
{ | ||
case ParseableType.ProtoCrewMember: | ||
return new ConfigNode.Value("item", item.ToString()); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
public override void Load(ConfigNode node) | ||
{ | ||
_coll.Clear(); | ||
foreach (ConfigNode.Value v in node.values) | ||
{ | ||
T item = FromValue(v); | ||
if (item != null) | ||
_coll.Add(item); | ||
} | ||
} | ||
|
||
public override void Save(ConfigNode node) | ||
{ | ||
foreach (var item in _coll) | ||
{ | ||
var v = ToValue(item); | ||
if (v != null) | ||
node.values.Add(v); | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// NOTE: This does not have constraints because string is supported | ||
/// but string is not a valuetype | ||
/// </summary> | ||
public class ICollectionPersistenceValueType<T> : ICollectionPersistence<T> | ||
{ | ||
protected static readonly DataType _DataType = FieldData.ValueDataType(_Type); | ||
|
||
public ICollectionPersistenceValueType(ICollection<T> coll) : base(coll) { } | ||
|
||
public override void Load(ConfigNode node) | ||
{ | ||
_coll.Clear(); | ||
foreach (ConfigNode.Value v in node.values) | ||
{ | ||
T item = (T)FieldData.ReadValue(v.value, _DataType, _Type); | ||
_coll.Add(item); | ||
} | ||
} | ||
|
||
public override void Save(ConfigNode node) | ||
{ | ||
foreach (var item in _coll) | ||
{ | ||
string value = FieldData.WriteValue(item, _DataType); | ||
node.AddValue("item", value); | ||
} | ||
} | ||
} | ||
} |
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
Oops, something went wrong.