public void AddChildToParentChildGroup(CustomParentChildGroup group, CustomParentChildPawn pawn)
 {
     if (!group.Parents.Contains(pawn) && !group.Children.Contains(pawn))
     {
         group.Children.Add(pawn);
     }
 }
 public void RemoveChildFromParentChildGroup(CustomParentChildGroup group, CustomParentChildPawn pawn)
 {
     group.Children.Remove(pawn);
     if (group.Parents.Count == 0 && group.Children.Count == 0)
     {
         PrepareCarefully.Instance.RelationshipManager.RemoveParentChildGroup(group);
     }
 }
        protected void ShowChildDialogForGroup(CustomParentChildGroup group, CustomParentChildPawn selected, Action <CustomParentChildPawn> action)
        {
            CustomParentChildPawn           selectedPawn = selected;
            HashSet <CustomParentChildPawn> disabled     = new HashSet <CustomParentChildPawn>();

            if (group != null)
            {
                disabled.AddRange(group.Parents);
                disabled.AddRange(group.Children);
            }
            rowGroups.Clear();
            rowGroups.Add(new WidgetTable <CustomParentChildPawn> .RowGroup("EdB.PC.AddParentChild.Header.SelectColonist".Translate(), PrepareCarefully.Instance.RelationshipManager.ColonyPawns));
            rowGroups.Add(new WidgetTable <CustomParentChildPawn> .RowGroup("EdB.PC.AddParentChild.Header.SelectHidden".Translate(), PrepareCarefully.Instance.RelationshipManager.HiddenPawns));
            WidgetTable <CustomParentChildPawn> .RowGroup newPawnGroup = new WidgetTable <CustomParentChildPawn> .RowGroup(null, newPawns);

            rowGroups.Add(newPawnGroup);
            DialogSelectParentChildPawn pawnDialog = new DialogSelectParentChildPawn()
            {
                HeaderLabel       = "EdB.PC.AddParentChild.Header.AddChild".Translate(),
                SelectAction      = (CustomParentChildPawn pawn) => { selectedPawn = pawn; },
                RowGroups         = rowGroups,
                DisabledPawns     = disabled,
                ConfirmValidation = () => {
                    if (selectedPawn == null)
                    {
                        return("EdB.PC.AddParentChild.Error.ChildRequired");
                    }
                    else
                    {
                        return(null);
                    }
                },
                CloseAction = () => {
                    // If the user selected a new pawn, replace the pawn in the new pawn list with another one.
                    int index = newPawnGroup.Rows.FirstIndexOf((CustomParentChildPawn p) => {
                        return(p == selectedPawn);
                    });
                    if (index > -1 && index < newPawns.Count)
                    {
                        selectedPawn = ReplaceNewHiddenCharacter(index);
                    }
                    action(selectedPawn);
                }
            };

            Find.WindowStack.Add(pawnDialog);
        }
        private void InitializeParentChildGroupRelationships(List <CustomRelationship> relationships)
        {
            Dictionary <CustomParentChildPawn, CustomParentChildGroup> groupLookup = new Dictionary <CustomParentChildPawn, CustomParentChildGroup>();

            foreach (var relationship in relationships)
            {
                CustomParentChildPawn parent = null;
                CustomParentChildPawn child  = null;
                if (relationship.def == PawnRelationDefOf.Parent)
                {
                    parentChildCustomPawnLookup.TryGetValue(relationship.source, out child);
                    parentChildCustomPawnLookup.TryGetValue(relationship.target, out parent);
                }
                else if (relationship.def == PawnRelationDefOf.Child)
                {
                    parentChildCustomPawnLookup.TryGetValue(relationship.target, out child);
                    parentChildCustomPawnLookup.TryGetValue(relationship.source, out parent);
                }
                if (parent == null)
                {
                    Log.Warning("Could not add relationship because of missing parent");
                    continue;
                }
                if (child == null)
                {
                    Log.Warning("Could not add relationship because of missing child");
                    continue;
                }

                // See if the child has an existing parent/child group.  If not, create the group.
                // If so, just add the parent.
                CustomParentChildGroup group;
                if (!groupLookup.TryGetValue(child, out group))
                {
                    group = new CustomParentChildGroup();
                    group.Children.Add(child);
                    groupLookup.Add(child, group);
                }
                group.Parents.Add(parent);
            }

            SortAndDedupeParentChildGroups(groupLookup.Values);
        }
        private void InitializeParentChildGroupsForStartingPawns(List <Pawn> pawns, List <CustomPawn> correspondingFacades)
        {
            // Create a map so that we can look up custom pawns based on their matching original pawn.
            Dictionary <Pawn, CustomPawn> pawnToFacadeMap = new Dictionary <Pawn, CustomPawn>();
            int pawnCount = pawns.Count;

            for (int i = 0; i < pawns.Count; i++)
            {
                pawnToFacadeMap.Add(pawns[i], correspondingFacades[i]);
            }

            // Go through each pawn and look for a child/parent relationship between it and all other pawns.
            Dictionary <Pawn, CustomParentChildGroup> groupLookup = new Dictionary <Pawn, CustomParentChildGroup>();

            foreach (Pawn child in pawns)
            {
                foreach (var r in child.relations.DirectRelations)
                {
                    //Log.Message("Relationship: " + r.def.defName + ", " + child.LabelShort + " & " + r.otherPawn.LabelShort);
                    if (r.def == PawnRelationDefOf.Parent)
                    {
                        Pawn parent = r.otherPawn;
                        CustomParentChildPawn parentCustomPawn = parentChildPawnLookup[parent];
                        CustomParentChildPawn childCustomPawn  = parentChildPawnLookup[child];

                        // See if the child has an existing parent/child group.  If not, create the group.
                        // If so, just add the parent.
                        CustomParentChildGroup group;
                        if (!groupLookup.TryGetValue(child, out group))
                        {
                            group = new CustomParentChildGroup();
                            group.Children.Add(childCustomPawn);
                            groupLookup.Add(child, group);
                        }
                        group.Parents.Add(parentCustomPawn);
                    }
                }
            }

            SortAndDedupeParentChildGroups(groupLookup.Values);
        }
 public void AddParentChildGroup(CustomParentChildGroup group)
 {
     PrepareCarefully.Instance.RelationshipManager.ParentChildGroups.Add(group);
 }
        protected float DrawNextGroup(float cursor)
        {
            int   parentBoxCount  = 1;
            int   childBoxCount   = 1;
            float widthOfParents  = parentBoxCount * SizePawn.x + (SpacingPawn * (parentBoxCount - 1)) + (PaddingBox * 2);
            float widthOfChildren = SizeChildOffset + (childBoxCount * SizePawn.x) + (SpacingPawn * (childBoxCount - 1)) + (PaddingBox * 2);
            float width           = Mathf.Max(widthOfChildren, widthOfParents);
            float height          = PaddingBox * 2 + SpacingArrow * 2 + SizeArrowBase.y + SizeArrowHead.y + SizePawn.y * 2;
            Rect  rect            = new Rect(cursor, 0, width, height);

            GUI.color = Style.ColorPanelBackgroundItem;
            GUI.DrawTexture(rect, BaseContent.WhiteTex);

            GUI.BeginGroup(rect);
            try {
                Rect parentPawnRect = new Rect(PaddingBox, PaddingBox, SizePawn.x, SizePawn.y);

                GUI.color = ColorParentEmpty;
                GUI.DrawTexture(parentPawnRect, BaseContent.WhiteTex);
                Rect addParentRect = new Rect(parentPawnRect.xMax - PaddingAddButton - SizeAddButton.x, parentPawnRect.y + PaddingAddButton, SizeAddButton.x, SizeAddButton.y);
                Style.SetGUIColorForButton(parentPawnRect);
                GUI.DrawTexture(addParentRect, Textures.TextureButtonAdd);
                if (Widgets.ButtonInvisible(parentPawnRect))
                {
                    ShowParentDialogForGroup(null, null, (CustomParentChildPawn pawn) => {
                        CustomParentChildGroup group = new CustomParentChildGroup();
                        group.Parents.Add(pawn);
                        GroupAdded(group);
                    });
                }

                GUI.color = ColorParentEmpty;
                Rect arrowBaseRect = new Rect(parentPawnRect.MiddleX() - SizeArrowBase.HalfX(), parentPawnRect.yMax, SizeArrowBase.x, SpacingArrow);
                GUI.DrawTexture(arrowBaseRect, BaseContent.WhiteTex);

                GUI.color = ColorChildEmpty;
                Rect  childPawnRect = new Rect(PaddingBox + SizeChildOffset, PaddingBox + SizePawn.y + SizeArrowBase.y + SizeArrowHead.y + SpacingArrow * 2, SizePawn.x, SizePawn.y);
                float arrowBaseLeft = parentPawnRect.MiddleX() - SizeArrowBase.HalfX();
                GUI.DrawTexture(childPawnRect, BaseContent.WhiteTex);
                Rect addChildRect = new Rect(childPawnRect.xMax - PaddingAddButton - SizeAddButton.x, childPawnRect.y + PaddingAddButton, SizeAddButton.x, SizeAddButton.y);
                Style.SetGUIColorForButton(childPawnRect);
                GUI.DrawTexture(addChildRect, Textures.TextureButtonAdd);
                if (Widgets.ButtonInvisible(childPawnRect))
                {
                    ShowChildDialogForGroup(null, null, (CustomParentChildPawn pawn) => {
                        CustomParentChildGroup group = new CustomParentChildGroup();
                        group.Children.Add(pawn);
                        GroupAdded(group);
                    });
                }

                GUI.color     = ColorParentEmpty;
                arrowBaseRect = new Rect(childPawnRect.MiddleX() - SizeArrowBase.HalfX(), childPawnRect.y - SizeArrowHead.y - SpacingArrow, SizeArrowBase.x, SpacingArrow);
                GUI.DrawTexture(arrowBaseRect, BaseContent.WhiteTex);
                float arrowBaseRightChild = arrowBaseRect.xMax;

                Rect arrowHeadRect = new Rect(childPawnRect.MiddleX() - SizeArrowHead.HalfX(), childPawnRect.y - SizeArrowHead.y, SizeArrowHead.x, SizeArrowHead.y);
                GUI.DrawTexture(arrowHeadRect, Textures.TextureArrowDown);

                Rect arrowBaseLineRect = new Rect(arrowBaseLeft, PaddingBox + SizePawn.y + SpacingArrow, arrowBaseRightChild - arrowBaseLeft, SizeArrowBase.y);
                GUI.DrawTexture(arrowBaseLineRect, BaseContent.WhiteTex);
            }
            finally {
                GUI.EndGroup();
            }

            GUI.color = Color.white;
            cursor   += width + SpacingGroup;

            return(cursor);
        }
        protected float DrawGroup(float cursor, CustomParentChildGroup group)
        {
            int   parentBoxCount  = group.Parents.Count + 1;
            int   childBoxCount   = group.Children.Count + 1;
            float widthOfParents  = parentBoxCount * SizePawn.x + (SpacingPawn * (parentBoxCount - 1)) + (PaddingBox * 2);
            float widthOfChildren = SizeChildOffset + (childBoxCount * SizePawn.x) + (SpacingPawn * (childBoxCount - 1)) + (PaddingBox * 2);
            float width           = Mathf.Max(widthOfChildren, widthOfParents);
            float height          = PaddingBox * 2 + SpacingArrow * 2 + SizeArrowBase.y + SizeArrowHead.y + SizePawn.y * 2;
            Rect  rect            = new Rect(cursor, 0, width, height);

            GUI.color = Style.ColorPanelBackgroundItem;
            GUI.DrawTexture(rect, BaseContent.WhiteTex);

            GUI.BeginGroup(rect);
            try {
                Color arrowColor           = group.Parents.Count > 0 ? ColorParent : ColorParentEmpty;
                Rect  firstParentPawnRect  = new Rect(PaddingBox, PaddingBox, SizePawn.x, SizePawn.y);
                Rect  parentPawnRect       = firstParentPawnRect;
                float arrowBaseRightParent = 0;
                foreach (var parent in group.Parents)
                {
                    GUI.color = ColorParent;
                    GUI.DrawTexture(parentPawnRect, BaseContent.WhiteTex);

                    Rect arrowBaseRect = new Rect(parentPawnRect.MiddleX() - SizeArrowBase.HalfX(), parentPawnRect.yMax, SizeArrowBase.x, SpacingArrow);
                    arrowBaseRightParent = arrowBaseRect.xMax;
                    GUI.DrawTexture(arrowBaseRect, BaseContent.WhiteTex);

                    DrawPortrait(parent, parentPawnRect);

                    if (parentPawnRect.Contains(Event.current.mousePosition))
                    {
                        Rect deleteRect = new Rect(parentPawnRect.xMax - PaddingDeleteButton - SizeDeleteButton.x, parentPawnRect.y + PaddingDeleteButton, SizeDeleteButton.x, SizeDeleteButton.y);
                        Style.SetGUIColorForButton(deleteRect);
                        GUI.DrawTexture(deleteRect, Textures.TextureButtonDelete);
                        if (Widgets.ButtonInvisible(deleteRect))
                        {
                            parentsToRemove.Add(new PawnGroupPair(parent, group));
                        }
                    }

                    parentPawnRect.x += SizePawn.x + SpacingPawn;
                }

                // If there's no parent, we still want to draw the arrow that points from the first parent box to the first child.
                // Normally, we would have drawn it when we drew the parent, but since there's aren't any parents, we have to call
                // it out here and draw it separately.
                if (group.Parents.Count == 0)
                {
                    GUI.color = arrowColor;
                    Rect arrowBaseRect = new Rect(parentPawnRect.MiddleX() - SizeArrowBase.HalfX(), parentPawnRect.yMax, SizeArrowBase.x, SpacingArrow);
                    GUI.DrawTexture(arrowBaseRect, BaseContent.WhiteTex);
                    arrowBaseRightParent = arrowBaseRect.x;
                }

                GUI.color = ColorParentEmpty;
                GUI.DrawTexture(parentPawnRect, BaseContent.WhiteTex);
                Rect addParentRect = new Rect(parentPawnRect.xMax - PaddingAddButton - SizeAddButton.x, parentPawnRect.y + PaddingAddButton, SizeAddButton.x, SizeAddButton.y);
                Style.SetGUIColorForButton(parentPawnRect);
                GUI.DrawTexture(addParentRect, Textures.TextureButtonAdd);
                if (Widgets.ButtonInvisible(parentPawnRect))
                {
                    ShowParentDialogForGroup(group, null, (CustomParentChildPawn pawn) => {
                        ParentAddedToGroup(group, pawn);
                    });
                }

                Rect  childPawnRect       = new Rect(PaddingBox + SizeChildOffset, PaddingBox + SizePawn.y + SizeArrowBase.y + SizeArrowHead.y + SpacingArrow * 2, SizePawn.x, SizePawn.y);
                float arrowBaseLeft       = firstParentPawnRect.MiddleX() - SizeArrowBase.HalfX();
                float arrowBaseRightChild = arrowBaseLeft + SizeArrowBase.x;
                foreach (var child in group.Children)
                {
                    GUI.color = ColorChild;
                    GUI.DrawTexture(childPawnRect, BaseContent.WhiteTex);

                    GUI.color = arrowColor;
                    Rect arrowBaseRect = new Rect(childPawnRect.MiddleX() - SizeArrowBase.HalfX(), childPawnRect.y - SizeArrowHead.y - SpacingArrow, SizeArrowBase.x, SpacingArrow);
                    GUI.DrawTexture(arrowBaseRect, BaseContent.WhiteTex);

                    Rect arrowHeadRect = new Rect(childPawnRect.MiddleX() - SizeArrowHead.HalfX(), childPawnRect.y - SizeArrowHead.y, SizeArrowHead.x, SizeArrowHead.y);
                    GUI.DrawTexture(arrowHeadRect, Textures.TextureArrowDown);

                    DrawPortrait(child, childPawnRect);

                    if (childPawnRect.Contains(Event.current.mousePosition))
                    {
                        Rect deleteRect = new Rect(childPawnRect.xMax - PaddingDeleteButton - SizeDeleteButton.x, childPawnRect.y + PaddingDeleteButton, SizeDeleteButton.x, SizeDeleteButton.y);
                        Style.SetGUIColorForButton(deleteRect);
                        GUI.DrawTexture(deleteRect, Textures.TextureButtonDelete);
                        if (Widgets.ButtonInvisible(deleteRect))
                        {
                            childrenToRemove.Add(new PawnGroupPair(child, group));
                        }
                    }

                    childPawnRect.x    += SizePawn.x + SpacingPawn;
                    arrowBaseRightChild = arrowBaseRect.xMax;
                }

                // If there's no children, we still want to draw the arrow that points to the first child.
                // Normally, we would have drawn it when we drew the children, but since there's aren't any children,
                // we have to call it out here and draw it separately.
                if (group.Children.Count == 0)
                {
                    GUI.color = arrowColor;
                    Rect arrowBaseRect = new Rect(childPawnRect.MiddleX() - SizeArrowBase.HalfX(), childPawnRect.y - SizeArrowHead.y - SpacingArrow, SizeArrowBase.x, SpacingArrow);
                    GUI.DrawTexture(arrowBaseRect, BaseContent.WhiteTex);
                    Rect arrowHeadRect = new Rect(childPawnRect.MiddleX() - SizeArrowHead.HalfX(), childPawnRect.y - SizeArrowHead.y, SizeArrowHead.x, SizeArrowHead.y);
                    GUI.DrawTexture(arrowHeadRect, Textures.TextureArrowDown);
                    arrowBaseRightChild = arrowBaseRect.xMax;
                }

                GUI.color = ColorChildEmpty;
                GUI.DrawTexture(childPawnRect, BaseContent.WhiteTex);
                Rect addChildRect = new Rect(childPawnRect.xMax - PaddingAddButton - SizeAddButton.x, childPawnRect.y + PaddingAddButton, SizeAddButton.x, SizeAddButton.y);
                Style.SetGUIColorForButton(childPawnRect);
                GUI.DrawTexture(addChildRect, Textures.TextureButtonAdd);
                if (Widgets.ButtonInvisible(childPawnRect))
                {
                    ShowChildDialogForGroup(group, null, (CustomParentChildPawn pawn) => {
                        ChildAddedToGroup(group, pawn);
                    });
                }

                float arrowBaseRight    = Mathf.Max(arrowBaseRightChild, arrowBaseRightParent);
                Rect  arrowBaseLineRect = new Rect(arrowBaseLeft, PaddingBox + SizePawn.y + SpacingArrow, arrowBaseRight - arrowBaseLeft, SizeArrowBase.y);
                GUI.color = arrowColor;
                GUI.DrawTexture(arrowBaseLineRect, BaseContent.WhiteTex);
            }
            finally {
                GUI.EndGroup();
            }

            GUI.color = Color.white;
            cursor   += width + SpacingGroup;

            return(cursor);
        }
 public PawnGroupPair(CustomParentChildPawn Pawn, CustomParentChildGroup Group)
 {
     this.Pawn  = Pawn;
     this.Group = Group;
 }
 public void RemoveParentChildGroup(CustomParentChildGroup group)
 {
     parentChildGroups.Remove(group);
 }
        public bool Load(PrepareCarefully loadout, string presetName)
        {
            List <SaveRecordPawnV3>             pawns              = new List <SaveRecordPawnV3>();
            List <SaveRecordPawnV3>             hiddenPawns        = new List <SaveRecordPawnV3>();
            List <SaveRecordRelationshipV3>     savedRelationships = new List <SaveRecordRelationshipV3>();
            List <SaveRecordParentChildGroupV3> parentChildGroups  = new List <SaveRecordParentChildGroupV3>();

            Failed = false;
            int  startingPoints = 0;
            bool usePoints      = false;

            try {
                Scribe.loader.InitLoading(PresetFiles.FilePathForSavedPreset(presetName));

                Scribe_Values.Look <bool>(ref usePoints, "usePoints", true, false);
                Scribe_Values.Look <int>(ref startingPoints, "startingPoints", 0, false);
                Scribe_Values.Look <string>(ref ModString, "mods", "", false);

                try {
                    Scribe_Collections.Look <SaveRecordPawnV3>(ref pawns, "colonists", LookMode.Deep, null);
                }
                catch (Exception e) {
                    Messages.Message("EdB.PC.Dialog.Preset.Error.Failed".Translate(), MessageTypeDefOf.ThreatBig);
                    Log.Warning(e.ToString());
                    Log.Warning("Preset was created with the following mods: " + ModString);
                    return(false);
                }

                try {
                    Scribe_Collections.Look <SaveRecordPawnV3>(ref hiddenPawns, "hiddenPawns", LookMode.Deep, null);
                }
                catch (Exception e) {
                    Messages.Message("EdB.PC.Dialog.Preset.Error.Failed".Translate(), MessageTypeDefOf.ThreatBig);
                    Log.Warning(e.ToString());
                    Log.Warning("Preset was created with the following mods: " + ModString);
                    return(false);
                }

                try {
                    Scribe_Collections.Look <SaveRecordRelationshipV3>(ref savedRelationships, "relationships", LookMode.Deep, null);
                }
                catch (Exception e) {
                    Messages.Message("EdB.PC.Dialog.Preset.Error.Failed".Translate(), MessageTypeDefOf.ThreatBig);
                    Log.Warning(e.ToString());
                    Log.Warning("Preset was created with the following mods: " + ModString);
                    return(false);
                }

                try {
                    Scribe_Collections.Look <SaveRecordParentChildGroupV3>(ref parentChildGroups, "parentChildGroups", LookMode.Deep, null);
                }
                catch (Exception e) {
                    Messages.Message("EdB.PC.Dialog.Preset.Error.Failed".Translate(), MessageTypeDefOf.ThreatBig);
                    Log.Warning(e.ToString());
                    Log.Warning("Preset was created with the following mods: " + ModString);
                    return(false);
                }

                List <EquipmentSaveRecord> tempEquipment = new List <EquipmentSaveRecord>();
                Scribe_Collections.Look <EquipmentSaveRecord>(ref tempEquipment, "equipment", LookMode.Deep, null);
                loadout.Equipment.Clear();
                if (tempEquipment != null)
                {
                    List <EquipmentSelection> equipment = new List <EquipmentSelection>(tempEquipment.Count);
                    foreach (var e in tempEquipment)
                    {
                        ThingDef thingDef = DefDatabase <ThingDef> .GetNamedSilentFail(e.def);

                        if (thingDef == null)
                        {
                            string replacementDefName;
                            if (thingDefReplacements.TryGetValue(e.def, out replacementDefName))
                            {
                                thingDef = DefDatabase <ThingDef> .GetNamedSilentFail(replacementDefName);
                            }
                        }
                        ThingDef stuffDef = null;
                        Gender   gender   = Gender.None;
                        if (!string.IsNullOrEmpty(e.stuffDef))
                        {
                            stuffDef = DefDatabase <ThingDef> .GetNamedSilentFail(e.stuffDef);
                        }
                        if (!string.IsNullOrEmpty(e.gender))
                        {
                            try {
                                gender = (Gender)Enum.Parse(typeof(Gender), e.gender);
                            }
                            catch (Exception) {
                                Log.Warning("Failed to load gender value for animal.");
                                Failed = true;
                                continue;
                            }
                        }
                        if (thingDef != null)
                        {
                            if (string.IsNullOrEmpty(e.stuffDef))
                            {
                                EquipmentKey    key    = new EquipmentKey(thingDef, null, gender);
                                EquipmentRecord record = PrepareCarefully.Instance.EquipmentDatabase[key];
                                if (record != null)
                                {
                                    equipment.Add(new EquipmentSelection(record, e.count));
                                }
                                else
                                {
                                    Log.Warning("Could not find equipment in equipment database: " + key);
                                    Failed = true;
                                    continue;
                                }
                            }
                            else
                            {
                                if (stuffDef != null)
                                {
                                    EquipmentKey    key    = new EquipmentKey(thingDef, stuffDef, gender);
                                    EquipmentRecord record = PrepareCarefully.Instance.EquipmentDatabase[key];
                                    if (record == null)
                                    {
                                        string thing = thingDef != null ? thingDef.defName : "null";
                                        string stuff = stuffDef != null ? stuffDef.defName : "null";
                                        Log.Warning(string.Format("Could not load equipment/resource from the preset.  This may be caused by an invalid thing/stuff combination: " + key));
                                        Failed = true;
                                        continue;
                                    }
                                    else
                                    {
                                        equipment.Add(new EquipmentSelection(record, e.count));
                                    }
                                }
                                else
                                {
                                    Log.Warning("Could not load stuff definition \"" + e.stuffDef + "\" for item \"" + e.def + "\"");
                                    Failed = true;
                                }
                            }
                        }
                        else
                        {
                            Log.Warning("Could not load thing definition \"" + e.def + "\"");
                            Failed = true;
                        }
                    }
                    loadout.Equipment.Clear();
                    foreach (var e in equipment)
                    {
                        loadout.Equipment.Add(e);
                    }
                }
                else
                {
                    Messages.Message("EdB.PC.Dialog.Preset.Error.EquipmentFailed".Translate(), MessageTypeDefOf.ThreatBig);
                    Log.Warning("Failed to load equipment from preset");
                    Failed = true;
                }

                //PrepareCarefully.Instance.Config.pointsEnabled = usePoints;
            }
            catch (Exception e) {
                Log.Error("Failed to load preset file");
                throw e;
            }
            finally {
                // I don't fully understand how these cross-references and saveables are resolved, but
                // if we don't clear them out, we get null pointer exceptions.
                HashSet <IExposable> saveables = (HashSet <IExposable>)(typeof(PostLoadIniter).GetField("saveablesToPostLoad", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Scribe.loader.initer));
                if (saveables != null)
                {
                    saveables.Clear();
                }
                List <IExposable> crossReferencingExposables = (List <IExposable>)(typeof(CrossRefHandler).GetField("crossReferencingExposables", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Scribe.loader.crossRefs));
                if (crossReferencingExposables != null)
                {
                    crossReferencingExposables.Clear();
                }
                Scribe.loader.FinalizeLoading();
            }

            List <CustomPawn> allPawns            = new List <CustomPawn>();
            List <CustomPawn> colonistCustomPawns = new List <CustomPawn>();

            try {
                foreach (SaveRecordPawnV3 p in pawns)
                {
                    CustomPawn pawn = LoadPawn(p);
                    if (pawn != null)
                    {
                        allPawns.Add(pawn);
                        colonistCustomPawns.Add(pawn);
                    }
                    else
                    {
                        Messages.Message("EdB.PC.Dialog.Preset.Error.NoCharacter".Translate(), MessageTypeDefOf.ThreatBig);
                        Log.Warning("Preset was created with the following mods: " + ModString);
                    }
                }
            }
            catch (Exception e) {
                Messages.Message("EdB.PC.Dialog.Preset.Error.Failed".Translate(), MessageTypeDefOf.ThreatBig);
                Log.Warning(e.ToString());
                Log.Warning("Preset was created with the following mods: " + ModString);
                return(false);
            }

            List <CustomPawn> hiddenCustomPawns = new List <CustomPawn>();

            try {
                if (hiddenPawns != null)
                {
                    foreach (SaveRecordPawnV3 p in hiddenPawns)
                    {
                        CustomPawn pawn = LoadPawn(p);
                        if (pawn != null)
                        {
                            allPawns.Add(pawn);
                            hiddenCustomPawns.Add(pawn);
                        }
                        else
                        {
                            Log.Warning("Prepare Carefully failed to load a hidden character from the preset");
                        }
                    }
                }
            }
            catch (Exception e) {
                Messages.Message("EdB.PC.Dialog.Preset.Error.Failed".Translate(), MessageTypeDefOf.ThreatBig);
                Log.Warning(e.ToString());
                Log.Warning("Preset was created with the following mods: " + ModString);
                return(false);
            }

            loadout.ClearPawns();
            foreach (CustomPawn p in colonistCustomPawns)
            {
                loadout.AddPawn(p);
            }
            loadout.RelationshipManager.Clear();
            loadout.RelationshipManager.InitializeWithParentChildPawns(colonistCustomPawns, hiddenCustomPawns);

            bool atLeastOneRelationshipFailed          = false;
            List <CustomRelationship> allRelationships = new List <CustomRelationship>();

            if (savedRelationships != null)
            {
                try {
                    foreach (SaveRecordRelationshipV3 r in savedRelationships)
                    {
                        if (string.IsNullOrEmpty(r.source) || string.IsNullOrEmpty(r.target) || string.IsNullOrEmpty(r.relation))
                        {
                            atLeastOneRelationshipFailed = true;
                            Log.Warning("Prepare Carefully failed to load a custom relationship from the preset: " + r);
                            continue;
                        }
                        CustomRelationship relationship = LoadRelationship(r, allPawns);
                        if (relationship == null)
                        {
                            atLeastOneRelationshipFailed = true;
                            Log.Warning("Prepare Carefully failed to load a custom relationship from the preset: " + r);
                        }
                        else
                        {
                            allRelationships.Add(relationship);
                        }
                    }
                }
                catch (Exception e) {
                    Messages.Message("EdB.PC.Dialog.Preset.Error.RelationshipFailed".Translate(), MessageTypeDefOf.ThreatBig);
                    Log.Warning(e.ToString());
                    Log.Warning("Preset was created with the following mods: " + ModString);
                    return(false);
                }
                if (atLeastOneRelationshipFailed)
                {
                    Messages.Message("EdB.PC.Dialog.Preset.Error.RelationshipFailed".Translate(), MessageTypeDefOf.ThreatBig);
                }
            }
            loadout.RelationshipManager.AddRelationships(allRelationships);

            if (parentChildGroups != null)
            {
                foreach (var groupRecord in parentChildGroups)
                {
                    CustomParentChildGroup group = new CustomParentChildGroup();
                    if (groupRecord.parents != null)
                    {
                        foreach (var id in groupRecord.parents)
                        {
                            CustomPawn parent = FindPawnById(id, colonistCustomPawns, hiddenCustomPawns);
                            if (parent != null)
                            {
                                var pawn = loadout.RelationshipManager.FindParentChildPawn(parent);
                                if (pawn != null)
                                {
                                    group.Parents.Add(pawn);
                                }
                                else
                                {
                                    Log.Warning("Prepare Carefully could not load a custom parent relationship because it could not find a matching pawn in the relationship manager.");
                                }
                            }
                            else
                            {
                                Log.Warning("Prepare Carefully could not load a custom parent relationship because it could not find a pawn with the saved identifer.");
                            }
                        }
                    }
                    if (groupRecord.children != null)
                    {
                        foreach (var id in groupRecord.children)
                        {
                            CustomPawn child = FindPawnById(id, colonistCustomPawns, hiddenCustomPawns);
                            if (child != null)
                            {
                                var pawn = loadout.RelationshipManager.FindParentChildPawn(child);
                                if (pawn != null)
                                {
                                    group.Children.Add(pawn);
                                }
                                else
                                {
                                    Log.Warning("Prepare Carefully could not load a custom child relationship because it could not find a matching pawn in the relationship manager.");
                                }
                            }
                            else
                            {
                                Log.Warning("Prepare Carefully could not load a custom child relationship because it could not find a pawn with the saved identifer.");
                            }
                        }
                    }
                    loadout.RelationshipManager.ParentChildGroups.Add(group);
                }
            }
            loadout.RelationshipManager.ReassignHiddenPawnIndices();

            if (Failed)
            {
                Messages.Message(ModString, MessageTypeDefOf.SilentInput);
                Messages.Message("EdB.PC.Dialog.Preset.Error.ThingDefFailed".Translate(), MessageTypeDefOf.ThreatBig);
                Log.Warning("Preset was created with the following mods: " + ModString);
                return(false);
            }

            return(true);
        }