Skip to content

Instantly share code, notes, and snippets.

@lbmaian
Last active August 12, 2019 11:42
Show Gist options
  • Save lbmaian/9dd0739c078105792e23c85a2e5cde36 to your computer and use it in GitHub Desktop.
Save lbmaian/9dd0739c078105792e23c85a2e5cde36 to your computer and use it in GitHub Desktop.
Rimworld generic backstory def loading
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;
using UnityEngine;
using Verse;
namespace RimWorld
{
// Allows loading of backstories defined via <BackstoryDef> with optional <defName> (and optional <bodyTypeMale>/<bodyTypeFemale>)
public class BackstoryDef : Def
{
private Backstory backstory;
public void LoadDataFromXmlCustom(XmlNode xmlRoot)
{
XmlNode defNameNode = xmlRoot.SelectSingleNode("defName");
if (defNameNode != null)
{
defName = defNameNode.InnerText;
xmlRoot.RemoveChild(defNameNode); // need to remove, since Backstory doesn't have a defName field
}
backstory = DirectXmlToObject.ObjectFromXml<Backstory>(xmlRoot, doPostLoad: true);
if (defName == Def.DefaultDefName && backstory != null)
{
// The defName needs to default to backstory.identifier, but that is only calculated in Backstory.ResolveReferences().
// Furthermore, defName cannot be Def.DefaultDefName, or else DefDatabase.AddAllInMods() will coerce it with a warning before ResolveReferences() is called.
// Copying the backstory.identifier calculation logic here, which doesn't depend on any references.
int num = Mathf.Abs(GenText.StableStringHash(backstory.baseDesc) % 100);
string s = backstory.title.Replace('-', ' ');
s = GenText.CapitalizedNoSpaces(s);
defName = GenText.RemoveNonAlphanumeric(s) + num.ToString();
}
}
public override void ResolveReferences()
{
if (backstory != null)
{
if (backstory.slot == BackstorySlot.Adulthood && GetPrivateStringFieldValue(backstory, "bodyTypeGlobal").NullOrEmpty())
{
SetPrivateStringFieldValueIfNull(backstory, "bodyTypeMale", DefDatabase<BodyTypeDef>.GetNamedSilentFail("Male")?.defName ?? "Male");
SetPrivateStringFieldValueIfNull(backstory, "bodyTypeFemale", DefDatabase<BodyTypeDef>.GetNamedSilentFail("Female")?.defName ?? "Female");
}
backstory.ResolveReferences();
backstory.identifier = defName;
BackstoryDatabase.AddBackstory(backstory); // like BackstoryDatabase.ReloadAllBackstories, add even if there are any config errors
//Log.Message("Added custom backstory: " + defName);
}
}
private static string GetPrivateStringFieldValue<T>(T obj, String fieldName)
{
return (string)typeof(T).GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj);
}
private static void SetPrivateStringFieldValueIfNull<T>(T obj, String fieldName, object value)
{
FieldInfo field = typeof(T).GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
if (((string)field.GetValue(obj)).NullOrEmpty())
field.SetValue(obj, value);
}
public override IEnumerable<string> ConfigErrors()
{
foreach (string error in base.ConfigErrors())
yield return error;
if (backstory != null)
foreach (string error in backstory.ConfigErrors(ignoreNoSpawnCategories: false))
yield return error;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment