public void PerformAction(bool prompt) { try { Overwatch.Log("Cleanup Genealogy"); Dictionary <IMiniSimDescription, IMiniSimDescription> duplicates = new Dictionary <IMiniSimDescription, IMiniSimDescription>(); Dictionary <ulong, IMiniSimDescription> lookup = new Dictionary <ulong, IMiniSimDescription>(); Dictionary <IMiniSimDescription, bool> urnstones = new Dictionary <IMiniSimDescription, bool>(); foreach (SimDescription sim in SimDescription.GetHomelessSimDescriptionsFromUrnstones()) { if (urnstones.ContainsKey(sim)) { continue; } urnstones.Add(sim, true); } Dictionary <IGenealogy, bool> allGenealogies = new Dictionary <IGenealogy, bool>(); List <IGenealogy> geneList = new List <IGenealogy>(); foreach (KeyValuePair <ulong, List <IMiniSimDescription> > ids in SimListing.AllSims <IMiniSimDescription>(null, true, false)) { List <IMiniSimDescription> list = ids.Value; foreach (IMiniSimDescription miniSim in list) { if (miniSim.CASGenealogy == null) { continue; } if (allGenealogies.ContainsKey(miniSim.CASGenealogy)) { continue; } allGenealogies.Add(miniSim.CASGenealogy, true); geneList.Add(miniSim.CASGenealogy); } IMiniSimDescription choice = null; if (list.Count == 1) { choice = list[0]; } else if (list.Count > 1) { List <IMiniSimDescription> choices = new List <IMiniSimDescription>(); foreach (IMiniSimDescription miniSim in list) { SimDescription sim = miniSim as SimDescription; if (sim == null) { continue; } if (sim.Household == Household.ActiveHousehold) { choices.Add(miniSim); } } if (choices.Count >= 1) { choice = choices[0]; Overwatch.Log("Doppleganger Active-Inactive (" + list.Count + "): " + Relationships.GetFullName(choice)); } else { choices.Clear(); foreach (IMiniSimDescription sim in list) { if (urnstones.ContainsKey(sim)) { choices.Add(sim); } } if (choices.Count == 1) { choice = choices[0]; Overwatch.Log("Doppleganger Urnstone (" + list.Count + "): " + Relationships.GetFullName(choice)); } else { choices.Clear(); foreach (IMiniSimDescription sim in list) { Genealogy genealogy = sim.CASGenealogy as Genealogy; if ((genealogy != null) && (object.ReferenceEquals(sim, genealogy.mSim))) { choices.Add(sim); } } if (choices.Count == 1) { choice = choices[0]; Overwatch.Log("Doppleganger Personal Genealogy (" + list.Count + "): " + Relationships.GetFullName(choice)); } else { choices.Clear(); MiniSimDescription miniSim = MiniSimDescription.Find(ids.Key); if ((miniSim != null) && (miniSim.Genealogy != null) && (miniSim.Genealogy.mSim != null)) { foreach (IMiniSimDescription sim in list) { if (object.ReferenceEquals(sim, miniSim.Genealogy.mSim)) { choices.Add(sim); } } } if (choices.Count == 1) { choice = choices[0]; Overwatch.Log("Doppleganger MiniSim Genealogy (" + list.Count + "): " + Relationships.GetFullName(choice)); } else { choices.Clear(); int maxLinks = 0; foreach (IMiniSimDescription sim in list) { if (choice == null) { choice = sim; } else { int numLinks = 0; Genealogy gene = sim.CASGenealogy as Genealogy; if (gene != null) { if (gene.mNaturalParents != null) { numLinks += gene.mNaturalParents.Count; } if (gene.mChildren != null) { numLinks += gene.mChildren.Count; } if (gene.mSiblings != null) { numLinks += gene.mSiblings.Count; } if (maxLinks < numLinks) { maxLinks = numLinks; choice = sim; } } } } Overwatch.Log("Doppleganger By Link Count (" + list.Count + "): " + Relationships.GetFullName(choice)); } } } } } if (choice != null) { lookup.Add(choice.SimDescriptionId, choice); foreach (IMiniSimDescription sim in list) { if (object.ReferenceEquals(sim, choice)) { continue; } duplicates.Add(sim, choice); Genealogy genealogy = ReconcileGenealogy(choice.CASGenealogy as Genealogy, sim.CASGenealogy as Genealogy); if (genealogy != null) { SetGenealogy(choice, genealogy); } } } } int index = 0; while (index < geneList.Count) { Genealogy genealogy = geneList[index] as Genealogy; index++; if (genealogy == null) { continue; } AddToList(geneList, allGenealogies, genealogy.mNaturalParents); AddToList(geneList, allGenealogies, genealogy.mChildren); AddToList(geneList, allGenealogies, genealogy.mSiblings); } Dictionary <string, List <Genealogy> > broken = new Dictionary <string, List <Genealogy> >(); foreach (IGenealogy iGene in geneList) { Genealogy gene = iGene as Genealogy; if (gene == null) { continue; } if ((gene.mMiniSim == null) && (gene.mSim == null)) { if (!string.IsNullOrEmpty(gene.Name)) { List <Genealogy> genes; if (!broken.TryGetValue(gene.Name, out genes)) { genes = new List <Genealogy>(); broken.Add(gene.Name, genes); } genes.Add(gene); } } MiniSimDescription miniSim = gene.mMiniSim as MiniSimDescription; if (miniSim == null) { continue; } if ((MiniSimDescription.sMiniSims != null) && (!MiniSimDescription.sMiniSims.ContainsKey(miniSim.SimDescriptionId))) { MiniSimDescription.sMiniSims.Add(miniSim.SimDescriptionId, miniSim); if (!lookup.ContainsKey(miniSim.SimDescriptionId)) { lookup.Add(miniSim.SimDescriptionId, miniSim); } Overwatch.Log("Genealogy Minisim Added " + Relationships.GetFullName(miniSim)); } } CleanupMiniSimGenealogy(lookup, broken); foreach (IMiniSimDescription sim in lookup.Values) { try { IMiniSimDescription lookupSim = Relationships.Find(sim.SimDescriptionId, lookup); Genealogy genealogy = null; if (lookupSim != null) { genealogy = lookupSim.CASGenealogy as Genealogy; if ((genealogy != null) && (sim.CASGenealogy != null) && (!object.ReferenceEquals(genealogy, sim.CASGenealogy))) { sim.CASGenealogy = genealogy; Overwatch.Log("Lookup Genealogy Replaced: " + Relationships.GetFullName(sim)); } } if (genealogy == null) { genealogy = sim.CASGenealogy as Genealogy; } if (genealogy == null) { MiniSimDescription miniSim = MiniSimDescription.Find(sim.SimDescriptionId); if (miniSim != null) { genealogy = miniSim.mGenealogy; if ((genealogy != null) && (sim.CASGenealogy != null) && (!object.ReferenceEquals(genealogy, sim.CASGenealogy))) { sim.CASGenealogy = genealogy; Overwatch.Log("MiniSim Genealogy Replaced: " + Relationships.GetFullName(sim)); } } } if (genealogy == null) { SimDescription trueSim = sim as SimDescription; if (trueSim != null) { trueSim.Fixup(); genealogy = sim.CASGenealogy as Genealogy; if (genealogy == null) { Overwatch.Log("No SimDesc Genealogy: " + Relationships.GetFullName(sim)); } else { Overwatch.Log("Genealogy Fixup Performed: " + Relationships.GetFullName(sim)); } } else { MiniSimDescription miniSim = sim as MiniSimDescription; if (miniSim != null) { // This minisim may be part of a family tree, so must be uncorrupted genealogy = new Genealogy(miniSim.FullName); Overwatch.Log("MiniSim Genealogy Created: " + Relationships.GetFullName(sim)); } else { Overwatch.Log("No MiniSim Genealogy: " + Relationships.GetFullName(sim)); } } } SetGenealogy(sim, genealogy); } catch (Exception e) { Common.Exception("Phase One: " + Relationships.GetFullName(sim), e); } } foreach (IMiniSimDescription sim in lookup.Values) { try { SimDescription trueSim = sim as SimDescription; if (trueSim != null) { MiniSimDescription miniSim = MiniSimDescription.Find(trueSim.SimDescriptionId); if (miniSim != null) { List <MiniRelationship> relationships = new List <MiniRelationship>(miniSim.MiniRelationships); foreach (MiniRelationship relationship in relationships) { IMiniSimDescription otherSim = MiniSimDescription.Find(relationship.GetOtherSimDescriptionId(sim)); if (otherSim == null) { miniSim.mMiniRelationships.Remove(relationship); } else { Genealogy gene = otherSim.CASGenealogy as Genealogy; if (gene == null) { miniSim.mMiniRelationships.Remove(relationship); } } } } Dictionary <ulong, bool> existingRelations = new Dictionary <ulong, bool>(); Dictionary <SimDescription, Relationship> oldRelations; if (Relationship.sAllRelationships.TryGetValue(trueSim, out oldRelations)) { Dictionary <SimDescription, Relationship> newRelations = new Dictionary <SimDescription, Relationship>(); foreach (KeyValuePair <SimDescription, Relationship> relation in new Dictionary <SimDescription, Relationship>(oldRelations)) { IMiniSimDescription townSim; if (lookup.TryGetValue(relation.Key.SimDescriptionId, out townSim)) { if (!object.ReferenceEquals(townSim, relation.Key)) { Overwatch.Log(Relationships.GetFullName(sim) + " Dropped bad relation for " + Relationships.GetFullName(relation.Key)); Relationships.SafeRemoveRelationship(relation.Value); continue; } } if (existingRelations.ContainsKey(relation.Key.SimDescriptionId)) { Overwatch.Log(Relationships.GetFullName(sim) + " Dropped duplicate relation for " + Relationships.GetFullName(relation.Key)); Relationships.SafeRemoveRelationship(relation.Value); continue; } existingRelations.Add(relation.Key.SimDescriptionId, true); Relationships.RepairRelationship(relation.Value, Overwatch.Log); newRelations.Add(relation.Key, relation.Value); } Relationship.sAllRelationships[trueSim] = newRelations; } /* * MiniSimDescription miniDesc = MiniSimDescription.Find(trueSim.SimDescriptionId); * if (miniDesc != null) * { * for (int i = miniDesc.mMiniRelationships.Count - 1; i >= 0; i--) * { * MiniRelationship relation = miniDesc.mMiniRelationships[i]; * * if (existingRelations.ContainsKey(relation.SimDescriptionId)) * { * miniDesc.mMiniRelationships.RemoveAt(i); * * Overwatch.Log(GetFullName(trueSim) + " Dropped duplicate mini relation"); * } * } * } */ RepairMissingPartner(trueSim); // Legacy repair for an issue with an earlier Phase of Overwatch List <Relationship> relations = new List <Relationship>(Relationship.GetRelationships(trueSim)); foreach (Relationship relation in relations) { if ((relation.LTR.HasInteractionBit(LongTermRelationship.InteractionBits.Divorce)) || (relation.LTR.HasInteractionBit(LongTermRelationship.InteractionBits.BreakUp)) || (relation.LTR.HasInteractionBit(LongTermRelationship.InteractionBits.BreakEngagement)) || (relation.LTR.HasInteractionBit(LongTermRelationship.InteractionBits.Marry)) || (relation.LTR.HasInteractionBit(LongTermRelationship.InteractionBits.Propose)) || (relation.LTR.HasInteractionBit(LongTermRelationship.InteractionBits.MakeCommitment))) { relation.LTR.AddInteractionBit(LongTermRelationship.InteractionBits.HaveBeenPartners); } } } Genealogy genealogy = sim.CASGenealogy as Genealogy; if (genealogy != null) { genealogy.ClearDerivedData(); new Relationships.RepairParents().Perform(sim, Overwatch.Log, lookup); new Relationships.RepairChildren().Perform(sim, Overwatch.Log, lookup); new Relationships.RepairSiblings().Perform(sim, Overwatch.Log, lookup); RepairSpouse(sim, lookup); if ((sim.IsMarried) && (genealogy.mPartnerType != PartnerType.Marriage)) { genealogy.mPartnerType = PartnerType.Marriage; if (genealogy.Spouse != null) { genealogy.Spouse.mPartnerType = PartnerType.Marriage; } Overwatch.Log(Relationships.GetFullName(sim) + " PartnerType Corrected"); } } RepairMiniSim(trueSim); } catch (Exception e) { Common.Exception("Phase Two: " + Relationships.GetFullName(sim), e); } } CleanupMiniSims(lookup); // Must be performed after repairing the genealogy as the mSim is wiped from the genealogy during deletion foreach (KeyValuePair <IMiniSimDescription, IMiniSimDescription> duplicate in duplicates) { CustomAnnihilation(duplicate.Key as SimDescription, duplicate.Value as SimDescription); } } catch (Exception e) { Common.Exception(Name, e); } }
protected static void RepairSpouse(IMiniSimDescription simA, Dictionary <ulong, IMiniSimDescription> lookup) { SimDescription trueSimA = simA as SimDescription; IMiniSimDescription simB = null; Genealogy genealogy = simA.CASGenealogy as Genealogy; if (genealogy.Spouse != null) { simB = Relationships.GetSim(genealogy.Spouse, lookup); } if (trueSimA != null) { if ((simB == null) && (simA.IsMarried)) { simB = trueSimA.Partner; } if (simB == null) { List <Relationship> relations = new List <Relationship>(Relationship.GetRelationships(trueSimA)); foreach (Relationship relation in relations) { if (relation.LTR.CurrentLTR == LongTermRelationshipTypes.Spouse) { simB = relation.GetOtherSimDescription(trueSimA); if (simB != null) { simB = Relationships.Find(simB.SimDescriptionId, lookup); } if (simB is SimDescription) { break; } } } } } SimDescription trueSimB = simB as SimDescription; if ((simA != null) && (simB != null)) { Genealogy geneA = simA.CASGenealogy as Genealogy; Genealogy geneB = simB.CASGenealogy as Genealogy; if ((geneA != null) && (geneB != null)) { if (!object.ReferenceEquals(geneA.Spouse, geneB)) { geneA.mSpouse = geneB; Overwatch.Log("Missing Spouse Link Attached A"); Overwatch.Log(" " + Relationships.GetFullName(geneA) + " - " + Relationships.GetFullName(geneB)); } if (!object.ReferenceEquals(geneB.Spouse, geneA)) { geneB.mSpouse = geneA; Overwatch.Log("Missing Spouse Link Attached B"); Overwatch.Log(" " + Relationships.GetFullName(geneB) + " - " + Relationships.GetFullName(geneA)); } } } if ((trueSimA != null) && (trueSimB != null)) { if (!object.ReferenceEquals(trueSimA.Partner, trueSimB)) { // Don't call Partner, it requires genealogy trueSimA.mPartner = trueSimB; Overwatch.Log("Missing Partner Link Attached A"); Overwatch.Log(" " + Relationships.GetFullName(simA) + " - " + Relationships.GetFullName(simB)); } if (!object.ReferenceEquals(trueSimB.Partner, trueSimA)) { // Don't call Partner, it requires genealogy trueSimB.mPartner = trueSimA; Overwatch.Log("Missing Partner Link Attached B"); Overwatch.Log(" " + Relationships.GetFullName(simB) + " - " + Relationships.GetFullName(simA)); } } }