public static bool MovePawnToColony(Pawn pawn, Pawn inviter, Map destination) { Map map = destination; if (map.ParentFaction != Faction.OfPlayer) { if (inviter.IsCaravanMember() || PawnUtility.IsTravelingInTransportPodWorldObject(pawn) || inviter.Map.ParentFaction != Faction.OfPlayer) { map = Find.AnyPlayerHomeMap; } else { map = inviter.Map; } } if (!TryFindEntryCell(map, out IntVec3 cell)) { return(false); } if (pawn.apparel.AnyApparelLocked) { var req = PawnGenerationRequest.MakeDefault(); req.Tile = inviter.Map.Tile; PawnApparelGenerator.GenerateStartingApparelFor(pawn, req); } GenSpawn.Spawn(pawn, cell, map, WipeMode.Vanish); Letters.SendJoinLetter(pawn, inviter, map); return(true); }
public WorldPawnSituation GetSituation(Pawn p) { if (!this.Contains(p)) { return(WorldPawnSituation.None); } if (p.Dead || p.Destroyed) { return(WorldPawnSituation.Dead); } if (PawnUtility.IsFactionLeader(p)) { return(WorldPawnSituation.FactionLeader); } if (PawnUtility.IsKidnappedPawn(p)) { return(WorldPawnSituation.Kidnapped); } if (p.IsCaravanMember()) { return(WorldPawnSituation.CaravanMember); } if (PawnUtility.IsTravelingInTransportPodWorldObject(p)) { return(WorldPawnSituation.InTravelingTransportPod); } if (PawnUtility.ForSaleBySettlement(p)) { return(WorldPawnSituation.ForSaleBySettlement); } return(WorldPawnSituation.Free); }
private bool ShouldMothball(Pawn p) { if (DefPreventingMothball(p) == null && !p.IsCaravanMember()) { return(!PawnUtility.IsTravelingInTransportPodWorldObject(p)); } return(false); }
private bool ShouldAutoTendTo(Pawn pawn) { if (!pawn.Dead && !pawn.Destroyed && pawn.IsHashIntervalTick(7500) && !pawn.IsCaravanMember()) { return(!PawnUtility.IsTravelingInTransportPodWorldObject(pawn)); } return(false); }
public WorldPawnSituation GetSituation(Pawn p) { if (!Contains(p)) { return(WorldPawnSituation.None); } if (p.Dead || p.Destroyed) { return(WorldPawnSituation.Dead); } if (PawnUtility.IsFactionLeader(p)) { return(WorldPawnSituation.FactionLeader); } if (PawnUtility.IsKidnappedPawn(p)) { return(WorldPawnSituation.Kidnapped); } if (p.IsBorrowedByAnyFaction()) { return(WorldPawnSituation.Borrowed); } if (p.IsCaravanMember()) { return(WorldPawnSituation.CaravanMember); } if (PawnUtility.IsTravelingInTransportPodWorldObject(p)) { return(WorldPawnSituation.InTravelingTransportPod); } if (PawnUtility.ForSaleBySettlement(p)) { return(WorldPawnSituation.ForSaleBySettlement); } if (QuestUtility.IsReservedByQuestOrQuestBeingGenerated(p)) { return(WorldPawnSituation.ReservedByQuest); } if (p.teleporting) { return(WorldPawnSituation.Teleporting); } return(WorldPawnSituation.Free); }
public static bool Prefix(Pawn member, ref bool free) { if (member.Faction == Faction.OfPlayer) { return(true); } if (PawnUtility.IsTravelingInTransportPodWorldObject(member)) { return(false); // Fired in pod? Don't trigger } var compGuest = member.CompGuest(); if (compGuest == null || !compGuest.rescued || member.guest == null || PawnUtility.IsTravelingInTransportPodWorldObject(member)) { return(true); } free = true; Traverse.Create(member.guest).Field("hostFactionInt").SetValue(Faction.OfPlayer); // Settings this makes the reward work compGuest.rescued = false; // Turn back off return(true); }
private string GetCriticalPawnReason(Pawn pawn) { if (pawn.Discarded) { return(null); } if (PawnUtility.EverBeenColonistOrTameAnimal(pawn) && pawn.RaceProps.Humanlike) { return("Colonist"); } if (PawnGenerator.IsBeingGenerated(pawn)) { return("Generating"); } if (PawnUtility.IsFactionLeader(pawn)) { return("FactionLeader"); } if (PawnUtility.IsKidnappedPawn(pawn)) { return("Kidnapped"); } if (pawn.IsCaravanMember()) { return("CaravanMember"); } if (PawnUtility.IsTravelingInTransportPodWorldObject(pawn)) { return("TransportPod"); } if (PawnUtility.ForSaleBySettlement(pawn)) { return("ForSale"); } if (Find.WorldPawns.ForcefullyKeptPawns.Contains(pawn)) { return("ForceKept"); } if (pawn.SpawnedOrAnyParentSpawned) { return("Spawned"); } if (!pawn.Corpse.DestroyedOrNull()) { return("CorpseExists"); } if (pawn.RaceProps.Humanlike && Current.ProgramState == ProgramState.Playing) { if (Find.PlayLog.AnyEntryConcerns(pawn)) { return("InPlayLog"); } if (Find.BattleLog.AnyEntryConcerns(pawn)) { return("InBattleLog"); } } if (Current.ProgramState == ProgramState.Playing && Find.TaleManager.AnyActiveTaleConcerns(pawn)) { return("InActiveTale"); } if (QuestUtility.IsReservedByQuestOrQuestBeingGenerated(pawn)) { return("ReservedByQuest"); } return(null); }
private static void ExecuteTicks() { if (mapPreTickComplete && plantMaterialsCount > 0) { int index = Interlocked.Decrement(ref plantMaterialsCount); while (index >= 0) { try { WindManager_Patch.plantMaterials[index].SetFloat(ShaderPropertyIDs.SwayHead, plantSwayHead); } catch (Exception ex) { Log.Error("Exception ticking " + WindManager_Patch.plantMaterials[index].ToStringSafe() + ": " + ex); } index = Interlocked.Decrement(ref plantMaterialsCount); } if (index == -1) { Interlocked.Increment(ref listsFullyProcessed); } } else if (tickListNormalComplete && thingListNormalTicks > 0) { int index = Interlocked.Decrement(ref thingListNormalTicks); while (index >= 0) { Thing thing = thingListNormal[index]; if (!thing.Destroyed) { try { thing.Tick(); } catch (Exception ex) { string text = thing.Spawned ? (" (at " + thing.Position + ")") : ""; if (Prefs.DevMode) { Log.Error("Exception ticking " + thing.ToStringSafe() + text + ": " + ex); } else { Log.ErrorOnce("Exception ticking " + thing.ToStringSafe() + text + ". Suppressing further errors. Exception: " + ex, thing.thingIDNumber ^ 0x22627165); } } } index = Interlocked.Decrement(ref thingListNormalTicks); } if (index == -1) { Interlocked.Increment(ref listsFullyProcessed); } } else if (tickListRareComplete && thingListRareTicks > 0) { int index = Interlocked.Decrement(ref thingListRareTicks); while (index >= 0) { Thing thing = thingListRare[index]; if (!thing.Destroyed) { try { thing.TickRare(); } catch (Exception ex) { string text = thing.Spawned ? (" (at " + thing.Position + ")") : ""; if (Prefs.DevMode) { Log.Error("Exception ticking " + thing.ToStringSafe() + text + ": " + ex); } else { Log.ErrorOnce("Exception ticking " + thing.ToStringSafe() + text + ". Suppressing further errors. Exception: " + ex, thing.thingIDNumber ^ 0x22627165); } } } index = Interlocked.Decrement(ref thingListRareTicks); } if (index == -1) { Interlocked.Increment(ref listsFullyProcessed); } } else if (tickListLongComplete && thingListLongTicks > 0) { int index = Interlocked.Decrement(ref thingListLongTicks); while (index >= 0) { Thing thing = thingListLong[index]; if (!thing.Destroyed) { try { thing.TickLong(); } catch (Exception ex) { string text = thing.Spawned ? (" (at " + thing.Position + ")") : ""; if (Prefs.DevMode) { Log.Error("Exception ticking " + thing.ToStringSafe() + text + ": " + ex); } else { Log.ErrorOnce("Exception ticking " + thing.ToStringSafe() + text + ". Suppressing further errors. Exception: " + ex, thing.thingIDNumber ^ 0x22627165); } } } index = Interlocked.Decrement(ref thingListLongTicks); } if (index == -1) { Interlocked.Increment(ref listsFullyProcessed); } } else if (worldTickComplete && worldPawnsTicks > 0) { int index = Interlocked.Decrement(ref worldPawnsTicks); while (index >= 0) { Pawn pawn = worldPawnsAlive[index]; try { pawn.Tick(); } catch (Exception ex) { Log.ErrorOnce("Exception ticking world pawn " + pawn.ToStringSafe() + ". Suppressing further errors. " + (object)ex, pawn.thingIDNumber ^ 1148571423, false); } try { if (!pawn.Dead && !pawn.Destroyed && (pawn.IsHashIntervalTick(7500) && !pawn.IsCaravanMember()) && !PawnUtility.IsTravelingInTransportPodWorldObject(pawn)) { TendUtility.DoTend(null, pawn, null); } } catch (Exception ex) { Log.ErrorOnce("Exception tending to a world pawn " + pawn.ToStringSafe() + ". Suppressing further errors. " + (object)ex, pawn.thingIDNumber ^ 8765780, false); } index = Interlocked.Decrement(ref worldPawnsTicks); } if (index == -1) { Interlocked.Increment(ref listsFullyProcessed); } } else if (worldTickComplete && worldObjectsTicks > 0) { int index = Interlocked.Decrement(ref worldObjectsTicks); while (index >= 0) { try { worldObjects[index].Tick(); } catch (Exception ex) { Log.Error("Exception ticking " + worldObjects[index].ToStringSafe() + ": " + ex); } index = Interlocked.Decrement(ref worldObjectsTicks); } if (index == -1) { Interlocked.Increment(ref listsFullyProcessed); } } else if (worldTickComplete && allFactionsTicks > 0) { int index = Interlocked.Decrement(ref allFactionsTicks); while (index >= 0) { try { allFactions[index].FactionTick(); } catch (Exception ex) { Log.Error("Exception ticking " + allFactions[index].ToStringSafe() + ": " + ex); } index = Interlocked.Decrement(ref allFactionsTicks); } if (index == -1) { Interlocked.Increment(ref listsFullyProcessed); } } else if (mapPostTickComplete && steadyEnvironmentEffectsTicksCompleted < totalSteadyEnvironmentEffectsTicks) { int ticketIndex = Interlocked.Increment(ref steadyEnvironmentEffectsTicksCompleted) - 1; int steadyEnvironmentEffectsIndex = 0; while (ticketIndex < totalSteadyEnvironmentEffectsTicks) { int index = ticketIndex; while (ticketIndex >= steadyEnvironmentEffectsStructures[steadyEnvironmentEffectsIndex].steadyEnvironmentEffectsTicks) { steadyEnvironmentEffectsIndex++; } if (steadyEnvironmentEffectsIndex > 0) { index = ticketIndex - steadyEnvironmentEffectsStructures[steadyEnvironmentEffectsIndex - 1].steadyEnvironmentEffectsTicks; } int cycleIndex = (steadyEnvironmentEffectsStructures[steadyEnvironmentEffectsIndex].steadyEnvironmentEffectsCycleIndexOffset - index) % steadyEnvironmentEffectsStructures[steadyEnvironmentEffectsIndex].steadyEnvironmentEffectsArea; IntVec3 c = steadyEnvironmentEffectsStructures[steadyEnvironmentEffectsIndex].steadyEnvironmentEffectsCellsInRandomOrder.Get(cycleIndex); try { SteadyEnvironmentEffects_Patch.DoCellSteadyEffects( steadyEnvironmentEffectsStructures[steadyEnvironmentEffectsIndex].steadyEnvironmentEffects, c); } catch (Exception ex) { Log.Error("Exception ticking steadyEnvironmentEffectsCells " + index.ToStringSafe() + ": " + ex); } //Interlocked.Increment(ref SteadyEnvironmentEffects_Patch.cycleIndex(steadyEnvironmentEffectsInstance)); ticketIndex = Interlocked.Increment(ref steadyEnvironmentEffectsTicksCompleted) - 1; } if (ticketIndex == totalSteadyEnvironmentEffectsTicks) { Interlocked.Increment(ref listsFullyProcessed); } } else if (mapPostTickComplete && wildPlantSpawnerTicksCompleted < wildPlantSpawnerTicksCount) { int ticketIndex = Interlocked.Increment(ref wildPlantSpawnerTicksCompleted) - 1; int wildPlantSpawnerIndex = 0; WildPlantSpawnerStructure wildPlantSpawner; int index; while (ticketIndex < wildPlantSpawnerTicksCount) { index = ticketIndex; while (ticketIndex >= wildPlantSpawners[wildPlantSpawnerIndex].WildPlantSpawnerTicks) { wildPlantSpawnerIndex++; } if (wildPlantSpawnerIndex > 0) { index = ticketIndex - wildPlantSpawners[wildPlantSpawnerIndex - 1].WildPlantSpawnerTicks; } try { wildPlantSpawner = wildPlantSpawners[wildPlantSpawnerIndex]; int cycleIndex = (wildPlantSpawner.WildPlantSpawnerCycleIndexOffset - index) % wildPlantSpawner.WildPlantSpawnerArea; IntVec3 intVec = wildPlantSpawner.WildPlantSpawnerCellsInRandomOrder.Get(cycleIndex); if ((wildPlantSpawner.WildPlantSpawnerCycleIndexOffset - index) > wildPlantSpawner.WildPlantSpawnerArea) { Interlocked.Add(ref wildPlantSpawner.DesiredPlants2Tmp1000, 1000 * (int)WildPlantSpawner_Patch.GetDesiredPlantsCountAt2( wildPlantSpawner.WildPlantSpawnerMap, intVec, intVec, wildPlantSpawner.WildPlantSpawnerCurrentPlantDensity)); if (intVec.GetTerrain(wildPlantSpawners[wildPlantSpawnerIndex].WildPlantSpawnerMap).fertility > 0f) { Interlocked.Increment(ref wildPlantSpawner.FertilityCells2Tmp); } float mtb = WildPlantSpawner_Patch.GoodRoofForCavePlant2( wildPlantSpawner.WildPlantSpawnerMap, intVec) ? 130f : wildPlantSpawner.WildPlantSpawnerMap.Biome.wildPlantRegrowDays; if (Rand.Chance(wildPlantSpawner.WildPlantSpawnerChance) && Rand.MTBEventOccurs(mtb, 60000f, 10000) && WildPlantSpawner_Patch.CanRegrowAt2(wildPlantSpawner.WildPlantSpawnerMap, intVec)) { wildPlantSpawner.WildPlantSpawnerInstance.CheckSpawnWildPlantAt(intVec, wildPlantSpawner.WildPlantSpawnerCurrentPlantDensity, wildPlantSpawner.DesiredPlantsTmp1000 / 1000.0f); } } else { Interlocked.Add(ref wildPlantSpawner.DesiredPlantsTmp1000, 1000 * (int)WildPlantSpawner_Patch.GetDesiredPlantsCountAt2( wildPlantSpawner.WildPlantSpawnerMap, intVec, intVec, wildPlantSpawner.WildPlantSpawnerCurrentPlantDensity)); if (intVec.GetTerrain(wildPlantSpawner.WildPlantSpawnerMap).fertility > 0f) { Interlocked.Increment(ref wildPlantSpawner.FertilityCellsTmp); } float mtb = WildPlantSpawner_Patch.GoodRoofForCavePlant2(wildPlantSpawner.WildPlantSpawnerMap, intVec) ? 130f : wildPlantSpawner.WildPlantSpawnerMap.Biome.wildPlantRegrowDays; if (Rand.Chance(wildPlantSpawner.WildPlantSpawnerChance) && Rand.MTBEventOccurs(mtb, 60000f, 10000) && WildPlantSpawner_Patch.CanRegrowAt2(wildPlantSpawner.WildPlantSpawnerMap, intVec)) { wildPlantSpawner.WildPlantSpawnerInstance.CheckSpawnWildPlantAt(intVec, wildPlantSpawner.WildPlantSpawnerCurrentPlantDensity, wildPlantSpawner.DesiredPlants); } } if (ticketIndex == wildPlantSpawners[wildPlantSpawnerIndex].WildPlantSpawnerTicks - 1) { if ((wildPlantSpawner.WildPlantSpawnerCycleIndexOffset - index) > wildPlantSpawner.WildPlantSpawnerArea) { WildPlantSpawner_Patch.calculatedWholeMapNumDesiredPlants(wildPlantSpawner.WildPlantSpawnerInstance) = wildPlantSpawner.DesiredPlantsTmp1000 / 1000.0f; WildPlantSpawner_Patch.calculatedWholeMapNumDesiredPlantsTmp(wildPlantSpawner.WildPlantSpawnerInstance) = wildPlantSpawner.DesiredPlants2Tmp1000 / 1000.0f; WildPlantSpawner_Patch.calculatedWholeMapNumNonZeroFertilityCells(wildPlantSpawner.WildPlantSpawnerInstance) = wildPlantSpawner.FertilityCellsTmp; WildPlantSpawner_Patch.calculatedWholeMapNumNonZeroFertilityCellsTmp(wildPlantSpawner.WildPlantSpawnerInstance) = wildPlantSpawner.FertilityCells2Tmp; } else { WildPlantSpawner_Patch.calculatedWholeMapNumDesiredPlantsTmp(wildPlantSpawner.WildPlantSpawnerInstance) = wildPlantSpawner.DesiredPlantsTmp1000 / 1000.0f; WildPlantSpawner_Patch.calculatedWholeMapNumNonZeroFertilityCells(wildPlantSpawner.WildPlantSpawnerInstance) = wildPlantSpawner.FertilityCellsTmp; } if (index == -1) { Interlocked.Increment(ref listsFullyProcessed); } } } catch (Exception ex) { Log.Error("Exception ticking WildPlantSpawner: " + ex); } ticketIndex = Interlocked.Increment(ref wildPlantSpawnerTicksCompleted) - 1; } if (ticketIndex == wildPlantSpawnerTicksCount) { Interlocked.Increment(ref listsFullyProcessed); } } else if (mapPostTickComplete && totalTradeShipTicksCompleted < totalTradeShipTicks) { int ticketIndex = Interlocked.Increment(ref totalTradeShipTicksCompleted) - 1; int totalTradeShipIndex = 0; while (ticketIndex < totalTradeShipTicks) { int index = ticketIndex; while (ticketIndex >= tradeShips[totalTradeShipIndex].TradeShipTicks) { totalTradeShipIndex++; } if (totalTradeShipIndex > 0) { index = ticketIndex - tradeShips[totalTradeShipIndex - 1].TradeShipTicks; } Pawn pawn = tradeShips[totalTradeShipIndex].TradeShipThings[index] as Pawn; if (pawn != null) { try { pawn.Tick(); } catch (Exception ex) { Log.Error("Exception ticking Pawn: " + pawn.ToStringSafe() + " " + ex); } if (pawn.Dead) { lock (tradeShips[totalTradeShipIndex].TradeShipThings) { tradeShips[totalTradeShipIndex].TradeShipThings.Remove(pawn); } } } ticketIndex = Interlocked.Increment(ref totalTradeShipTicksCompleted) - 1; } if (ticketIndex == totalTradeShipTicks) { Interlocked.Increment(ref listsFullyProcessed); } } else if (worldTickComplete && WorldComponentTicks > 0) { int index = Interlocked.Decrement(ref WorldComponentTicks); while (index >= 0) { //try //{ WorldComponent wc = WorldComponents[index]; if (null != wc) { lock (wc) { try { wc.WorldComponentTick(); } catch (Exception ex) { Log.Error("Exception ticking World Component: " + wc.ToStringSafe() + ex); } } } //} //catch (Exception ex) //{ // Log.Error(ex.ToString()); //} index = Interlocked.Decrement(ref WorldComponentTicks); } if (index == -1) { Interlocked.Increment(ref listsFullyProcessed); } } /* * while(drawQueue.TryDequeue(out Thing drawThing)) * { * IntVec3 position = drawThing.Position; * if ((cellRect.Contains(position) || drawThing.def.drawOffscreen) && (!fogGrid[cellIndices.CellToIndex(position)] || drawThing.def.seeThroughFog) && (drawThing.def.hideAtSnowDepth >= 1.0 || snowGrid.GetDepth(position) <= (double)drawThing.def.hideAtSnowDepth)) * { * try * { * drawThing.Draw(); * } * catch (Exception ex) * { * Log.Error("Exception drawing " + (object)drawThing + ": " + ex.ToString(), false); * } * } * } */ }
/// <summary> /// GC().The best way to shrink Rimworld saves,I think. /// </summary> /// <param name="verbose">Determine if GC() should log details very very verbosely</param> /// <returns>Count of disposed World pawns</returns> public int GC(bool verbose = false) { /* * TODO Log * 1.talelog by interest -X * 2.animal - deconstruct relation -Done * 3.deeperclean?remove hediffs -X * 5.correct verbose log -Done * 6.yield return "status" -X * 7.UI compability -Done * 8.Filth cleaner -Done * 9.Fix:Faction Leader -Done * 10.Fix:Faction Relations -Done * 12.Warp->Wrap -Done */ /* * TODO A18 * 4.adjustable GC depth -X * 11.GC boostup -Done * 13.remake GC System -Done * 13.Keyed in Float menu items -Done * 14.help contents -Done * 15.Optimize Cleanser frame -Done * 16.Optimize Floatmenu System -Done * 17.Debug only options -Done */ /* * TODO 1.0 * 18.Clean snow -Done * 19.whole-map clean -Done * 20.remake log -Done * 21.Mod framework -Done * 22.settings -Done * 23.MuteGC -Done * 24.MuteCL -Done * 25.remake FloatMenuUtil -Done * 26.timer of gc -X * 27.toolbox integration -Done * 28.MainButtonDef into xml -Done * 29.try catch -Done * 30.Find.CurrentMap==null check -Done * 31.MainButtonWorker -Done * 32.Messages.Message(str,historical) settings -Done * 33.AvoidGrid rework -Done * 34.Faction rework & cleanup -Done * 35.Close letter stack -Done */ if (Current.ProgramState != ProgramState.Playing) { Verse.Log.Error("You must be kidding me...GC a save without loading one?"); return(0); } /*Initialization*/ Verse.Log.Message("[GC Log] Pre-Initializing GC..."); this.reference = Find.WorldPawns.AllPawnsAliveOrDead.ToList(); this.allFlags.Clear(); this.verbose = verbose; if (verbose) { allFlagsCounter.Clear(); allFlagsCounter.Add(Flags.None, 0); for (int j = 0; j < FlagsCountNotNull; j++) { allFlagsCounter.Add((Flags)(1 << j), 0); } } /*Generate EntryPoints from Map Pawns*/ Verse.Log.Message("[GC Log] Generating EntryPoints from Map Pawns..."); List <Pawn> mapPawnEntryPoints; DiagnoseMapPawns(out mapPawnEntryPoints); if (verbose) { Verse.Log.Message("[GC Log][Verbose] " + allPawnsCounter.Count().ToString() + " Map Pawns marked during diagnosis"); } /*Reset counters*/ allPawnsCounter.Clear(); if (verbose) { allFlagsCounter.Clear(); allFlagsCounter.Add(Flags.None, 0); for (int j = 0; j < FlagsCountNotNull; j++) { allFlagsCounter.Add((Flags)(1 << j), 0); } } /*Generate a list of pawns concerned by used Tales*/ Verse.Log.Message("[GC Log] Collecting Pawns concerned by Used Tales..."); List <Pawn> allUsedTalePawns; CleanserUtil.InitUsedTalePawns(out allUsedTalePawns); /*Diagnosis:marking entries on WorldPawns.*/ Verse.Log.Message("[GC Log] Running diagnosis on WorldPawns..."); foreach (Pawn p in reference) { if (p.IsColonist) { addFlag(p, Flags.Colonist | Flags.RelationLvl2); } if (p.IsPrisonerOfColony) { addFlag(p, Flags.Prisoner | Flags.RelationLvl2); } if (PawnUtility.IsFactionLeader(p)) { addFlag(p, Flags.KeptWorldPawn | Flags.FactionLeader | Flags.RelationLvl1); } if (PawnUtility.IsKidnappedPawn(p)) { addFlag(p, Flags.KeptWorldPawn | Flags.RelationLvl2); } if (p.Corpse != null) { addFlag(p, Flags.CorpseOwner | Flags.RelationLvl1); } if (allUsedTalePawns.Contains(p)) { addFlag(p, Flags.TaleEntryOwner | Flags.RelationLvl0); } if (p.InContainerEnclosed) { addFlag(p, Flags.KeptWorldPawn | Flags.RelationLvl0); } if (p.Spawned) { addFlag(p, Flags.RelationLvl0); } if (p.IsPlayerControlledCaravanMember()) { addFlag(p, Flags.KeptWorldPawn | Flags.RelationLvl2); } if (PawnUtility.IsTravelingInTransportPodWorldObject(p)) { addFlag(p, Flags.KeptWorldPawn | Flags.RelationLvl2); } //Patch:A18 new entry if (PawnUtility.ForSaleBySettlement(p)) { addFlag(p, Flags.OnSale | Flags.RelationLvl0); } if (verbose) { Verse.Log.Message("[worldPawn] " + p.LabelShort + " [flag] " + markedFlagsString(p)); } } if (verbose) { Verse.Log.Message("[GC Log][Verbose] " + allPawnsCounter.Count().ToString() + " World Pawns marked during diagnosis"); } int i; /*Expansion 1:Expand relation network from map pawns.*/ Verse.Log.Message("[GC Log] Expanding Relation networks through Map Pawn Entry Points..."); for (i = mapPawnEntryPoints.Count - 1; i > -1; i--) { if (containsFlag(mapPawnEntryPoints[i], Flags.RelationLvl2)) { expandRelation(mapPawnEntryPoints[i], Flags.RelationLvl1); mapPawnEntryPoints.RemoveAt(i); } } for (i = mapPawnEntryPoints.Count - 1; i > -1; i--) { if (containsFlag(mapPawnEntryPoints[i], Flags.RelationLvl1)) { expandRelation(mapPawnEntryPoints[i], Flags.RelationLvl0); mapPawnEntryPoints.RemoveAt(i); } } /*Its unnecessary to process RelationLvl0 in mapPawnEntryPoints, * for they are not related to any world pawns. */ /*Expansion 2:Expand relation network from world pawns.*/ Verse.Log.Message("[GC Log] Expanding Relation networks on marked World Pawns..."); for (i = reference.Count - 1; i > -1; i--) { if (containsFlag(reference[i], Flags.RelationLvl2)) { expandRelation(reference[i], Flags.RelationLvl1); reference.RemoveAt(i); } } for (i = reference.Count - 1; i > -1; i--) { if (containsFlag(reference[i], Flags.RelationLvl1)) { expandRelation(reference[i], Flags.RelationLvl0); reference.RemoveAt(i); } } for (i = reference.Count - 1; i > -1; i--) { if (containsFlag(reference[i], Flags.RelationLvl0)) { reference.RemoveAt(i); } } int a = 0; /*VerboseMode:counting addFlag() calls.*/ if (verbose) { foreach (KeyValuePair <Pawn, int> p in allPawnsCounter) { a += p.Value; } Verse.Log.Message("[GC Log][Verbose] " + allPawnsCounter.Count().ToString() + " World Pawns marked during Expanding"); if (debug) { Verse.Log.Message("addFlag() called " + a + " times"); } } /*Posfix:remove UsedTalePawns.*/ Verse.Log.Message("[GC Log] Excluding Pawns concerned by Used Tales..."); foreach (Pawn p in allUsedTalePawns) { reference.Remove(p); } /*GC Core:dispose all pawns left in reference list.*/ Verse.Log.Message("[GC Log] Disposing World Pawns..."); a = reference.Count; Pawn pawn; for (i = reference.Count - 1; i > -1; i--) { pawn = reference[i]; //Patch:Mysterious WorldPawn.missing //Update:This patch is disabled due to safety concerns. //if(Find.WorldPawns.Contains(pawn)) Find.WorldPawns.RemovePawn(pawn); if (!pawn.Destroyed) { pawn.Destroy(DestroyMode.Vanish); } if (!pawn.Discarded) { pawn.Discard(true); } } /*VerboseMode:Finalize output*/ if (verbose) { string s = "[GC Log][Verbose] Flag calls stat:"; allFlagsCounter.Remove(Flags.None); foreach (KeyValuePair <Flags, int> pair in allFlagsCounter) { s += "\n " + pair.Key.ToString() + " : " + pair.Value; } Verse.Log.Message(s); } Verse.Log.Message("[GC Log] GC() completed with " + a + " World Pawns disposed"); return(a); }
/// <summary> /// Manual finalizer for WorldPawnCleaner.GC(). /// Deconstruct all animal families on map and discard the redundant members. /// </summary> /// <returns>The count of discarded members.</returns> public static int DeconstructAnimalFamily() { List <Pawn> worldpawns = new List <Pawn>(); foreach (Pawn p in Find.WorldPawns.AllPawnsAliveOrDead) { worldpawns.Add(p); } List <Pawn> queue = new List <Pawn>(); List <Pawn> pawnlist = new List <Pawn>(); foreach (Map map in Find.Maps) { foreach (Pawn p in map.mapPawns.AllPawns) { if ((p.records.GetAsInt(RecordDefOf.TimeAsColonistOrColonyAnimal) > 0) && !(p.RaceProps.Humanlike)) { pawnlist.Add(p); } } } foreach (Pawn p in pawnlist) { //Patch:null relationship on robots. if (p.relations != null) { foreach (Pawn p2 in expandRelation(p)) { if (worldpawns.Contains(p2) && (!p2.Spawned) && (!p2.IsPlayerControlledCaravanMember()) && (!PawnUtility.IsTravelingInTransportPodWorldObject(p2)) //Patch:Corpses remained on maps. && (p.Corpse == null) ) { queue.Add(p2); worldpawns.Remove(p2); } } } } //Patch:2nd Pawn of a used Tale_DoublePawn will raise Scribe Warnings if discarded List <Pawn> allUsedTaleOwner; CleanserUtil.InitUsedTalePawns(out allUsedTaleOwner); foreach (Pawn pawn in allUsedTaleOwner) { queue.Remove(pawn); } int a = queue.Count; foreach (Pawn pawn in queue) { Find.WorldPawns.RemovePawn(pawn); if (!pawn.Destroyed) { pawn.Destroy(DestroyMode.Vanish); } if (!pawn.Discarded) { pawn.Discard(true); } } Find.WindowStack.WindowOfType <UserInterface>().Notify_PawnsCountDirty(); return(a); }
//candidate for reverse patch public static void WorldPawnsListTick() { while (true) { int index = Interlocked.Decrement(ref worldPawnsTicks); if (index < 0) { return; } Pawn pawn = worldPawnsAlive[index]; try { pawn.Tick(); } catch (Exception ex) { Log.ErrorOnce("Exception ticking world pawn " + pawn.ToStringSafe() + ". Suppressing further errors. " + ex, pawn.thingIDNumber ^ 1148571423); } try { if (!pawn.Dead && !pawn.Destroyed && (pawn.IsHashIntervalTick(7500) && !pawn.IsCaravanMember()) && !PawnUtility.IsTravelingInTransportPodWorldObject(pawn)) { TendUtility.DoTend(null, pawn, null); } } catch (Exception ex) { Log.ErrorOnce("Exception tending to a world pawn " + pawn.ToStringSafe() + ". Suppressing further errors. " + ex, pawn.thingIDNumber ^ 8765780); } } }