Skip to content

Commit

Permalink
Fix not saving nodes for objects/components when writing, cache field…
Browse files Browse the repository at this point in the history
…less objects to prevent recreating them when Persistent is applied wrongly
  • Loading branch information
NathanKell committed Sep 4, 2022
1 parent 89f77f7 commit 0a10528
Showing 1 changed file with 43 additions and 40 deletions.
83 changes: 43 additions & 40 deletions KSPCommunityFixes/Modding/PersistentIConfigNode.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// - Add support for IConfigNode serialization
// - Add support for Guid serialization
// - Rewrite Object reading and writing for perf, clarity, and reuse
#define DEBUG_PERSISTENTICONFIGNODE
//#define DEBUG_PERSISTENTICONFIGNODE
using HarmonyLib;
using System;
using System.Collections;
Expand Down Expand Up @@ -194,6 +194,7 @@ public class FieldData
public FieldData(Type t, Persistent[] attribs)
{
fieldType = t;
this.attribs = attribs;

int len = attribs.Length;
persistentNames = new string[len];
Expand Down Expand Up @@ -228,20 +229,20 @@ public FieldData(MemberInfo memberInfo, Persistent[] attribs)
SetDataType(true);
}

public bool Read(Value value, object host, int index)
public bool Read(Value value, object host, int attribIndex)
{
if (index >= attribs.Length)
if (attribIndex >= attribs.Length)
{
Debug.LogError($"[KSPCommuntiyFixes] Tried to read value `{value.name} = {value.value}` for field {fieldInfo.Name}, index was {index} but only {attribs.Length} [Persistent] attributes on that field on host object of type {host.GetType().Name}."
Debug.LogError($"[KSPCommunityFixes] Tried to read value `{value.name} = {value.value}` for field {fieldInfo.Name}, index was {attribIndex} but only {attribs.Length} [Persistent] attributes on that field on host object of type {host.GetType().Name}."
+ "\nThis is probably because the value was specified twice in the config. Making that assumption and clamping.");
index = 0;
attribIndex = 0;
}
if (attribs[index].link)
if (attribs[attribIndex].link)
{
if (!isLinkable || !int.TryParse(value.value, out int linkID))
return false;

readLinks.AssignLink(linkID, new ReadFieldList.FieldItem(fieldInfo, attribs[index], host), -1);
readLinks.AssignLink(linkID, new ReadFieldList.FieldItem(fieldInfo, attribs[attribIndex], host), -1);
if (removeAfterUse)
value.name = string.Empty;

Expand All @@ -259,13 +260,13 @@ public bool Read(Value value, object host, int index)
return true;
}

public bool Read(ConfigNode node, object host, int index)
public bool Read(ConfigNode node, object host, int attribIndex)
{
if (index >= attribs.Length)
if (attribIndex >= attribs.Length)
{
Debug.LogError($"[KSPCommuntiyFixes] Tried to read node `{node.name}` for field {fieldInfo.Name}, index was {index} but only {attribs.Length} [Persistent] attributes on that field on host object of type {host.GetType().Name}."
Debug.LogError($"[KSPCommunityFixes] Tried to read node `{node.name}` for field {fieldInfo.Name}, index was {attribIndex} but only {attribs.Length} [Persistent] attributes on that field on host object of type {host.GetType().Name}."
+ "\nThis is probably because the node was specified twice in the config. Making that assumption and clamping.");
index = 0;
attribIndex = 0;
}
int vCount = node._values.values.Count;
int nCount = node._nodes.nodes.Count;
Expand All @@ -288,7 +289,7 @@ public bool Read(ConfigNode node, object host, int index)
{
if (wasNull)
{
MonoBehaviour behv = CreateComponent(host, fieldType, attribs[index], node, out bool success);
MonoBehaviour behv = CreateComponent(host, fieldType, attribs[attribIndex], node, out bool success);
if (behv == null)
return false;
fieldInfo.SetValue(host, behv);
Expand All @@ -307,7 +308,7 @@ public bool Read(ConfigNode node, object host, int index)

Array arr = null;
IList list = null;
if (attribs[index].link)
if (attribs[attribIndex].link)
{
int fieldIndex = 0;

Expand All @@ -316,7 +317,7 @@ public bool Read(ConfigNode node, object host, int index)
{
value = node._values.values[i];

_readLinks.AssignLink(int.Parse(value.value), new ReadFieldList.FieldItem(fieldInfo, attribs[index], host), fieldIndex++);
_readLinks.AssignLink(int.Parse(value.value), new ReadFieldList.FieldItem(fieldInfo, attribs[attribIndex], host), fieldIndex++);
}

if (dataType == DataType.Array)
Expand All @@ -343,7 +344,7 @@ public bool Read(ConfigNode node, object host, int index)
return false;

if (arrayType.dataType == DataType.Component)
return ReadComponentArray(node, host, index);
return ReadComponentArray(node, host, attribIndex);

bool isArr = dataType == DataType.Array;
bool arrReadSuccess = true;
Expand Down Expand Up @@ -390,8 +391,24 @@ public bool Read(ConfigNode node, object host, int index)
return arrReadSuccess;
}

public bool Write(string fieldName, object value, ConfigNode node, int attribIndex, int pass)
public bool Write(object value, ConfigNode node, int attribIndex, int pass)
{
Persistent persistent = attribs[attribIndex];
if (!persistent.isPersistant || (pass != 0 && persistent.pass != 0 && (persistent.pass & pass) == 0))
return true;

string fieldName = persistentNames[attribIndex];
if (persistent.link)
{
if (!isLinkable)
{
Debug.LogWarning("Field: '" + fieldInfo.Name + "' does not reference a PersistentLinkable type");
return false;
}

return WriteValue(fieldName, writeLinks.AssignLink(value), DataType.ValueInt, node);
}

if (dataType >= DataType.FirstValueType && dataType <= DataType.LastValueType)
{
return WriteValue(fieldName, value, dataType, node);
Expand All @@ -415,7 +432,7 @@ public bool Write(string fieldName, object value, ConfigNode node, int attribInd
string itemName = arrayType.persistentNames[attribIndex] ?? "item";
foreach (var item in list)
{
arrayType.Write(itemName, item, subNode, attribIndex, pass);
arrayType.Write(item, subNode, attribIndex, pass);
}
if (subNode.HasData)
node._nodes.nodes.Add(subNode);
Expand All @@ -424,6 +441,8 @@ public bool Write(string fieldName, object value, ConfigNode node, int attribInd
case DataType.Object:
case DataType.Component:
PersistentIConfigNode.ConfigNode_WriteObject_Prefix(value, subNode, pass);
if (subNode.HasData)
node._nodes.nodes.Add(subNode);
return PersistentIConfigNode.WriteSuccess;
}
return false;
Expand Down Expand Up @@ -503,7 +522,7 @@ public static MonoBehaviour CreateComponent(object host, Type fieldType, Persist
return child;
}

private bool ReadComponentArray(ConfigNode node, object host, int index)
private bool ReadComponentArray(ConfigNode node, object host, int attribIndex)
{
int nCount = node._nodes.Count;
List<object> objects = new List<object>();
Expand All @@ -513,7 +532,7 @@ private bool ReadComponentArray(ConfigNode node, object host, int index)
for (int i = 0; i < nCount; ++i)
{
subNode = node.nodes[i];
MonoBehaviour child = CreateComponent(host, arrayType.fieldType, attribs[index], subNode, out bool success);
MonoBehaviour child = CreateComponent(host, arrayType.fieldType, attribs[attribIndex], subNode, out bool success);
if (child == null)
continue;

Expand Down Expand Up @@ -953,26 +972,7 @@ public bool Write(object obj, ConfigNode node, int pass)
int persistentCount = fieldData.attribs.Length;
for (int j = 0; j < persistentCount; j++)
{
Persistent persistent = fieldData.attribs[j];
if (!persistent.isPersistant || (pass != 0 && persistent.pass != 0 && (persistent.pass & pass) == 0))
{
continue;
}

string fieldName = fieldData.persistentNames[j];
if (persistent.link)
{
if (!fieldData.isLinkable)
{
Debug.LogWarning("Field: '" + fieldData.fieldInfo.Name + "' does not reference a PersistentLinkable type");
}
else
{
allSucceeded &= FieldData.WriteValue(fieldName, writeLinks.AssignLink(value), DataType.ValueInt, node);
}
continue;
}
allSucceeded &= fieldData.Write(fieldName, value, node, j, pass);
allSucceeded &= fieldData.Write(value, node, j, pass);
}
}
return allSucceeded;
Expand All @@ -990,7 +990,10 @@ public static TypeCache CreateAndAdd(Type t)
{
var tc = new TypeCache(t);
if (tc._fields.Count == 0)
return null;
{
Debug.LogError($"[KSPCommunityFixes]: No Persistent fields on object of type {t.Name} that is referenced in persistent field, adding as null to TypeCache.");
tc = null;
}

cache[t] = tc;
return tc;
Expand Down

0 comments on commit 0a10528

Please sign in to comment.