// It would be nice if we could just do this to deep copy a pawn, but there are references to world objects in a saved pawn that can cause // problems, i.e. relationship references to other pawns. So we follow the more explicit technique below to copy the pawn. // Leaving this here to remind us to not bother trying to do this again. //public static Pawn IdealCopy(this Pawn source) { // try { // Pawn copy = UtilityCopy.CopyExposable<Pawn>(source); // copy.ClearCaches(); // return copy; // } // catch (Exception e) { // Logger.Warning("Failed to copy pawn with preferred method. Using backup method instead.\n" + e); // return CopyBackup(source); // } //} public static Pawn Copy(this Pawn source) { PawnHealthState savedHealthState = source.health.State; Pawn result = (Pawn)ThingMaker.MakeThing(source.kindDef.race, null); result.kindDef = source.kindDef; result.SetFactionDirect(source.Faction); PawnComponentsUtility.CreateInitialComponents(result); // Copy gender. result.gender = source.gender; // Copy name; NameTriple nameTriple = source.Name as NameTriple; NameSingle nameSingle = source.Name as NameSingle; if (nameTriple != null) { result.Name = new NameTriple(nameTriple.First, nameTriple.Nick, nameTriple.Last); } else if (nameSingle != null) { result.Name = new NameSingle(nameSingle.Name, nameSingle.Numerical); } // Copy trackers. object[] constructorArgs = new object[] { result }; result.ageTracker = UtilityCopy.CopyExposable(source.ageTracker, constructorArgs); result.story = UtilityCopy.CopyExposable(source.story, constructorArgs); result.skills = UtilityCopy.CopyExposable(source.skills, constructorArgs); result.health = UtilityCopy.CopyExposable(source.health, constructorArgs); result.apparel = UtilityCopy.CopyExposable(source.apparel, constructorArgs); // Copy comps //List<ThingComp> validComps = new List<ThingComp>(); //foreach (var c in source.AllComps) { // PawnCompsSaver saver = new PawnCompsSaver(new List<ThingComp>() { c }, null); // string xml = UtilityCopy.SerializeExposableToString(saver); // XmlDocument doc = new XmlDocument(); // doc.LoadXml(xml); // if (doc.DocumentElement.HasChildNodes) { // validComps.Add(c); // Logger.Debug(c.GetType().FullName + ": \n " + xml); // } // else { // Logger.Debug(c.GetType().FullName + " is empty"); // } //} CopyPawnComps(source, result); // Clear all of the pawn caches. source.ClearCaches(); result.ClearCaches(); return(result); }
public static Pawn Copy(this Pawn source) { PawnHealthState savedHealthState = source.health.State; Pawn result = (Pawn)ThingMaker.MakeThing(source.kindDef.race, null); result.kindDef = source.kindDef; result.SetFactionDirect(source.Faction); PawnComponentsUtility.CreateInitialComponents(result); // Copy gender. result.gender = source.gender; // Copy name; NameTriple nameTriple = source.Name as NameTriple; NameSingle nameSingle = source.Name as NameSingle; if (nameTriple != null) { result.Name = new NameTriple(nameTriple.First, nameTriple.Nick, nameTriple.Last); } else if (nameSingle != null) { result.Name = new NameSingle(nameSingle.Name, nameSingle.Numerical); } // Copy trackers. object[] constructorArgs = new object[] { result }; result.ageTracker = UtilityCopy.CopyExposable(source.ageTracker, constructorArgs); result.story = UtilityCopy.CopyExposable(source.story, constructorArgs); result.skills = UtilityCopy.CopyExposable(source.skills, constructorArgs); result.health = UtilityCopy.CopyExposable(source.health, constructorArgs); result.apparel = UtilityCopy.CopyExposable(source.apparel, constructorArgs); // Copy properties added to pawns by mods. CopyModdedProperties(source, result); // Verify the pawn health state. if (result.health.State != savedHealthState) { Log.Warning("Mismatched health state on copied pawn: " + savedHealthState + " != " + result.health.State + "; Resetting value to match."); result.SetHealthState(savedHealthState); } // Clear all of the pawn caches. source.ClearCaches(); return(result); }
// Given a field name, deep-copies an instance of an IExposable class from a source object to a target object via reflection. // Creates a deep copy by serializing and then deserializing the IExposable instance. The class must be constructable // with no arguments. public static void CopyExposableViaReflection(string fieldName, object source, object target, object[] constructorArgs) { FieldInfo sourceField = source.GetType().GetField(fieldName); FieldInfo targetField = target.GetType().GetField(fieldName); if (sourceField != null && targetField != null) { object value = sourceField.GetValue(source); if (typeof(IExposable).IsAssignableFrom(value.GetType())) { IExposable e = (IExposable)value; IExposable copy = UtilityCopy.CopyExposable(e, constructorArgs); targetField.SetValue(target, copy); } } }
public void PrepareGame() { PrepareColonists(); PrepareWorldPawns(); PrepareRelatedPawns(); // This needs some explaining. We need custom scenario parts to handle animal spawning // and scattered things. However, we don't want the scenario that gets saved with a game // to include any Prepare Carefully-specific parts (because the save would become bound to // the mod). We work around this by creating two copies of the actual scenario. The first // copy includes the customized scenario parts needed to do the spawning. The second contains // vanilla versions of those parts that can safely be saved without forcing a dependency on // the mod. The GenStep_RemovePrepareCarefullyScenario class is responsible for switching out // the actual scenario with the vanilla-friendly version at the end of the map generation process. Scenario actualScenario = UtilityCopy.CopyExposable(Find.Scenario); Scenario vanillaFriendlyScenario = UtilityCopy.CopyExposable(Find.Scenario); Current.Game.Scenario = actualScenario; PrepareCarefully.OriginalScenario = vanillaFriendlyScenario; // Remove equipment scenario parts. ReplaceScenarioParts(actualScenario, vanillaFriendlyScenario); }