根据向量相似度分析,与 'Source, Toils_Haul, StartCarryThing, Toil' 最相关的代码定义如下: --- **文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI\Toils_Haul.txt` ```csharp public class Toils_Haul { public static bool ErrorCheckForCarry(Pawn pawn, Thing haulThing, bool canTakeFromInventory = false) { if (!haulThing.SpawnedOrAnyParentSpawned || (!canTakeFromInventory && !haulThing.Spawned)) { Log.Message(pawn?.ToString() + " tried to start carry " + haulThing?.ToString() + " which isn't spawned."); pawn.jobs.EndCurrentJob(JobCondition.Incompletable); return true; } if (haulThing.stackCount == 0) { Log.Message(pawn?.ToString() + " tried to start carry " + haulThing?.ToString() + " which had stackcount 0."); pawn.jobs.EndCurrentJob(JobCondition.Incompletable); return true; } if (pawn.jobs.curJob.count <= 0) { Log.Error("Invalid count: " + pawn.jobs.curJob.count + ", setting to 1. Job was " + pawn.jobs.curJob); pawn.jobs.curJob.count = 1; } return false; } public static Toil StartCarryThing(TargetIndex haulableInd, bool putRemainderInQueue = false, bool subtractNumTakenFromJobCount = false, bool failIfStackCountLessThanJobCount = false, bool reserve = true, bool canTakeFromInventory = false) { Toil toil = ToilMaker.MakeToil("StartCarryThing"); toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; Thing thing = curJob.GetTarget(haulableInd).Thing; if (!ErrorCheckForCarry(actor, thing, canTakeFromInventory)) { if (curJob.count == 0) { throw new Exception($"StartCarryThing job had count = {curJob.count}. Job: {curJob}"); } int num = actor.carryTracker.AvailableStackSpace(thing.def); if (num <= 0) { int num2 = actor.carryTracker.MaxStackSpaceEver(thing.def); int num3 = 0; if (actor.carryTracker.CarriedThing != null) { num3 = actor.carryTracker.CarriedThing.stackCount; } throw new Exception($"StartCarryThing got availableStackSpace {num} (haulTarg {thing}, Job: {curJob}, maximum: {num2}, carrying: {num3})"); } if (failIfStackCountLessThanJobCount && thing.stackCount < curJob.count) { actor.jobs.curDriver.EndJobWith(JobCondition.Incompletable); } else { int num4 = Mathf.Min(curJob.count, num, thing.stackCount); if (num4 <= 0) { int num5 = actor.carryTracker.MaxStackSpaceEver(thing.def); int num6 = 0; if (actor.carryTracker.CarriedThing != null) { num6 = actor.carryTracker.CarriedThing.stackCount; } throw new Exception($"StartCarryThing zero or negative desiredNumToTake ({num4}), curJob.count: {curJob.count}, availableStackSpace: {num} (maximum: {num5}, carrying: {num6}), haulTarg.stackCount: {thing.stackCount}"); } int stackCount = thing.stackCount; int num7 = actor.carryTracker.TryStartCarry(thing, num4, reserve); if (num7 == 0) { actor.jobs.EndCurrentJob(JobCondition.Incompletable); } if (num7 < stackCount) { int num8 = curJob.count - num7; if (putRemainderInQueue && num8 > 0) { curJob.GetTargetQueue(haulableInd).Insert(0, thing); Job job = curJob; if (job.countQueue == null) { job.countQueue = new List(); } curJob.countQueue.Insert(0, num8); } else if (actor.Map.reservationManager.ReservedBy(thing, actor, curJob)) { actor.Map.reservationManager.Release(thing, actor, curJob); } } if (subtractNumTakenFromJobCount) { curJob.count -= num7; } curJob.SetTarget(haulableInd, actor.carryTracker.CarriedThing); actor.records.Increment(RecordDefOf.ThingsHauled); } } }; return toil; } public static Toil StoreThingJob(TargetIndex thingIndex) { Toil toil = ToilMaker.MakeToil("StoreThingJob"); toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.CurJob; Thing thing = curJob.GetTarget(thingIndex).Thing; Job job = HaulAIUtility.HaulToStorageJob(actor, thing, curJob.playerForced); if (job != null) { actor.jobs.TryTakeOrderedJob(job, JobTag.Misc); } }; return toil; } public static Toil DropCarriedThing() { Toil toil = ToilMaker.MakeToil("DropCarriedThing"); toil.initAction = delegate { Pawn actor = toil.actor; Thing resultingThing; if (actor.carryTracker.CarriedThing == null) { Log.Error(actor?.ToString() + " tried to drop carried thing but is not carrying anything."); } else if (!actor.carryTracker.TryDropCarriedThing(actor.Position, ThingPlaceMode.Direct, out resultingThing)) { actor.jobs.EndCurrentJob(JobCondition.Incompletable); } }; return toil; } public static Toil JumpIfAlsoCollectingNextTargetInQueue(Toil gotoGetTargetToil, TargetIndex ind) { Toil toil = ToilMaker.MakeToil("JumpIfAlsoCollectingNextTargetInQueue"); toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; List targetQueue = curJob.GetTargetQueue(ind); if (!targetQueue.NullOrEmpty() && curJob.count > 0) { if (actor.carryTracker.CarriedThing == null) { Log.Error("JumpToAlsoCollectTargetInQueue run on " + actor?.ToString() + " who is not carrying something."); } else if (actor.carryTracker.AvailableStackSpace(actor.carryTracker.CarriedThing.def) > 0) { for (int i = 0; i < targetQueue.Count; i++) { if (!GenAI.CanUseItemForWork(actor, targetQueue[i].Thing)) { actor.jobs.EndCurrentJob(JobCondition.Incompletable); break; } if (targetQueue[i].Thing.def == actor.carryTracker.CarriedThing.def) { curJob.SetTarget(ind, targetQueue[i].Thing); targetQueue.RemoveAt(i); actor.jobs.curDriver.JumpToToil(gotoGetTargetToil); break; } } } } }; return toil; } public static Toil CheckForGetOpportunityDuplicate(Toil getHaulTargetToil, TargetIndex haulableInd, TargetIndex storeCellInd, bool takeFromValidStorage = false, Predicate extraValidator = null) { Toil toil = ToilMaker.MakeToil("CheckForGetOpportunityDuplicate"); toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; if (actor.carryTracker.CarriedThing.def.stackLimit != 1 && !actor.carryTracker.Full && curJob.count > 0) { Thing thing = GenClosest.ClosestThingReachable(actor.Position, actor.Map, ThingRequest.ForGroup(ThingRequestGroup.HaulableAlways), PathEndMode.ClosestTouch, TraverseParms.For(actor), 8f, DupeValidator); if (thing != null) { curJob.SetTarget(haulableInd, thing); actor.jobs.curDriver.JumpToToil(getHaulTargetToil); } } bool DupeValidator(Thing t) { if (!t.Spawned) { return false; } if (t.def != actor.carryTracker.CarriedThing.def) { return false; } if (!t.CanStackWith(actor.carryTracker.CarriedThing)) { return false; } if (t.IsForbidden(actor)) { return false; } if (!t.IsSociallyProper(actor, forPrisoner: false, animalsCare: true)) { return false; } if (takeFromValidStorage && storeCellInd != 0 && curJob.GetTarget(storeCellInd).Cell.TryGetSlotGroup(actor.Map, out var group) && t.TryGetValidStoragePriority(out var priority) && (int)priority >= (int)group.Settings.Priority) { return false; } if (storeCellInd != 0 && !curJob.GetTarget(storeCellInd).Cell.IsValidStorageFor(actor.Map, t)) { return false; } if (!actor.CanReserve(t)) { return false; } if (extraValidator != null && !extraValidator(t)) { return false; } return true; } }; return toil; } public static Toil CarryHauledThingToCell(TargetIndex squareIndex, PathEndMode pathEndMode = PathEndMode.ClosestTouch) { Toil toil = ToilMaker.MakeToil("CarryHauledThingToCell"); toil.initAction = delegate { IntVec3 cell3 = toil.actor.jobs.curJob.GetTarget(squareIndex).Cell; toil.actor.pather.StartPath(cell3, pathEndMode); }; toil.defaultCompleteMode = ToilCompleteMode.PatherArrival; toil.AddEndCondition(delegate { Pawn actor2 = toil.actor; IntVec3 cell2 = actor2.jobs.curJob.GetTarget(squareIndex).Cell; CompPushable compPushable2 = actor2.carryTracker.CarriedThing.TryGetComp(); if (compPushable2 != null) { Vector3 v = actor2.Position.ToVector3() + compPushable2.drawPos; if (new IntVec3(v) == cell2) { return JobCondition.Succeeded; } } return JobCondition.Ongoing; }); toil.AddFailCondition(delegate { Pawn actor = toil.actor; IntVec3 cell = actor.jobs.curJob.GetTarget(squareIndex).Cell; if (actor.carryTracker.CarriedThing == null) { return true; } if (actor.jobs.curJob.haulMode == HaulMode.ToCellStorage && !cell.IsValidStorageFor(actor.Map, actor.carryTracker.CarriedThing)) { return true; } CompPushable compPushable = actor.carryTracker.CarriedThing.TryGetComp(); return (compPushable != null && !compPushable.canBePushed) ? true : false; }); return toil; } public static Toil PlaceCarriedThingInCellFacing(TargetIndex facingTargetInd) { Toil toil = ToilMaker.MakeToil("PlaceCarriedThingInCellFacing"); toil.initAction = delegate { Pawn actor = toil.actor; if (actor.carryTracker.CarriedThing == null) { Log.Error(actor?.ToString() + " tried to place hauled thing in facing cell but is not hauling anything."); } else { LocalTargetInfo target = actor.CurJob.GetTarget(facingTargetInd); IntVec3 intVec = ((!target.HasThing) ? target.Cell : target.Thing.OccupiedRect().ClosestCellTo(actor.Position)); IntVec3 dropLoc = actor.Position + Pawn_RotationTracker.RotFromAngleBiased((actor.Position - intVec).AngleFlat).FacingCell; if (!actor.carryTracker.TryDropCarriedThing(dropLoc, ThingPlaceMode.Direct, out var _)) { actor.jobs.EndCurrentJob(JobCondition.Incompletable); } } }; return toil; } public static Toil PlaceHauledThingInCell(TargetIndex cellInd, Toil nextToilOnPlaceFailOrIncomplete, bool storageMode, bool tryStoreInSameStorageIfSpotCantHoldWholeStack = false) { Toil toil = ToilMaker.MakeToil("PlaceHauledThingInCell"); toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; IntVec3 cell = curJob.GetTarget(cellInd).Cell; if (actor.carryTracker.CarriedThing == null) { Log.Error(actor?.ToString() + " tried to place hauled thing in cell but is not hauling anything."); } else { SlotGroup slotGroup = actor.Map.haulDestinationManager.SlotGroupAt(cell); if (slotGroup != null && slotGroup.Settings.AllowedToAccept(actor.carryTracker.CarriedThing)) { actor.Map.designationManager.TryRemoveDesignationOn(actor.carryTracker.CarriedThing, DesignationDefOf.Haul); } Action placedAction = null; if (curJob.def == JobDefOf.DoBill || curJob.def == JobDefOf.RecolorApparel || curJob.def == JobDefOf.RefuelAtomic || curJob.def == JobDefOf.RearmTurretAtomic) { placedAction = delegate(Thing th, int added) { HaulAIUtility.UpdateJobWithPlacedThings(curJob, th, added); }; } if (!actor.carryTracker.TryDropCarriedThing(cell, ThingPlaceMode.Direct, out var _, placedAction)) { if (storageMode) { IntVec3 storeCell; if (nextToilOnPlaceFailOrIncomplete != null && ((tryStoreInSameStorageIfSpotCantHoldWholeStack && StoreUtility.TryFindBestBetterStoreCellForIn(actor.carryTracker.CarriedThing, actor, actor.Map, StoragePriority.Unstored, actor.Faction, curJob.bill.GetSlotGroup(), out var foundCell)) || StoreUtility.TryFindBestBetterStoreCellFor(actor.carryTracker.CarriedThing, actor, actor.Map, StoragePriority.Unstored, actor.Faction, out foundCell))) { if (actor.CanReserve(foundCell)) { actor.Reserve(foundCell, actor.CurJob); } actor.CurJob.SetTarget(cellInd, foundCell); actor.jobs.curDriver.JumpToToil(nextToilOnPlaceFailOrIncomplete); } else if (HaulAIUtility.CanHaulAside(actor, actor.carryTracker.CarriedThing, out storeCell)) { curJob.SetTarget(cellInd, storeCell); curJob.count = int.MaxValue; curJob.haulOpportunisticDuplicates = false; curJob.haulMode = HaulMode.ToCellNonStorage; if (nextToilOnPlaceFailOrIncomplete != null) { actor.jobs.curDriver.JumpToToil(nextToilOnPlaceFailOrIncomplete); } } else { Log.Warning($"Incomplete haul for {actor}: Could not find anywhere to put {actor.carryTracker.CarriedThing} near {actor.Position}. Destroying. This should be very uncommon!"); actor.carryTracker.CarriedThing.Destroy(); } } else if (nextToilOnPlaceFailOrIncomplete != null) { actor.jobs.curDriver.JumpToToil(nextToilOnPlaceFailOrIncomplete); } } } }; return toil; } public static Toil CarryHauledThingToContainer() { Toil gotoDest = ToilMaker.MakeToil("CarryHauledThingToContainer"); gotoDest.initAction = delegate { gotoDest.actor.pather.StartPath(gotoDest.actor.jobs.curJob.targetB.Thing, PathEndMode.Touch); }; gotoDest.AddFailCondition(delegate { Thing thing = gotoDest.actor.jobs.curJob.targetB.Thing; if (thing.Destroyed || (!gotoDest.actor.jobs.curJob.ignoreForbidden && thing.IsForbidden(gotoDest.actor))) { return true; } ThingOwner thingOwner = thing.TryGetInnerInteractableThingOwner(); return (thingOwner != null && !thingOwner.CanAcceptAnyOf(gotoDest.actor.carryTracker.CarriedThing)) ? true : false; }); gotoDest.defaultCompleteMode = ToilCompleteMode.PatherArrival; return gotoDest; } public static Toil DepositHauledThingInContainer(TargetIndex containerInd, TargetIndex reserveForContainerInd, Action onDeposited = null) { Toil toil = ToilMaker.MakeToil("DepositHauledThingInContainer"); toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; if (actor.carryTracker.CarriedThing == null) { Log.Error(actor?.ToString() + " tried to place hauled thing in container but is not hauling anything."); } else { Thing thing = curJob.GetTarget(containerInd).Thing; ThingOwner thingOwner = thing.TryGetInnerInteractableThingOwner(); if (thingOwner != null) { int num = actor.carryTracker.CarriedThing.stackCount; if (thing is IHaulEnroute haulEnroute) { ThingDef def = actor.carryTracker.CarriedThing.def; num = Mathf.Min(haulEnroute.GetSpaceRemainingWithEnroute(def, actor), num); if (reserveForContainerInd != 0) { Thing thing2 = curJob.GetTarget(reserveForContainerInd).Thing; if (!thing2.DestroyedOrNull() && thing2 != haulEnroute && thing2 is IHaulEnroute enroute) { int spaceRemainingWithEnroute = enroute.GetSpaceRemainingWithEnroute(def, actor); num = Mathf.Min(num, actor.carryTracker.CarriedThing.stackCount - spaceRemainingWithEnroute); } } } Thing carriedThing = actor.carryTracker.CarriedThing; int num2 = actor.carryTracker.innerContainer.TryTransferToContainer(carriedThing, thingOwner, num); if (num2 != 0) { if (thing is IHaulEnroute container) { thing.Map.enrouteManager.ReleaseFor(container, actor); } if (thing is INotifyHauledTo notifyHauledTo) { notifyHauledTo.Notify_HauledTo(actor, carriedThing, num2); } if (thing is ThingWithComps thingWithComps) { foreach (ThingComp allComp in thingWithComps.AllComps) { if (allComp is INotifyHauledTo notifyHauledTo2) { notifyHauledTo2.Notify_HauledTo(actor, carriedThing, num2); } } } if (curJob.def == JobDefOf.DoBill) { HaulAIUtility.UpdateJobWithPlacedThings(curJob, carriedThing, num2); } onDeposited?.Invoke(); } } else if (curJob.GetTarget(containerInd).Thing.def.Minifiable) { actor.carryTracker.innerContainer.ClearAndDestroyContents(); } else { Log.Error("Could not deposit hauled thing in container: " + curJob.GetTarget(containerInd).Thing); } } }; return toil; } public static Toil JumpToCarryToNextContainerIfPossible(Toil carryToContainerToil, TargetIndex primaryTargetInd) { Toil toil = ToilMaker.MakeToil("JumpToCarryToNextContainerIfPossible"); toil.debugName = "Jump carry if possible"; toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; if (actor.carryTracker.CarriedThing != null && curJob.targetQueueB != null && curJob.targetQueueB.Count > 0) { if (TryGetNextDestinationFromQueue(primaryTargetInd, TargetIndex.B, actor.carryTracker.CarriedThing.def, curJob, actor, out var nextTarget)) { curJob.targetQueueB.RemoveAll((LocalTargetInfo target) => target.Thing == nextTarget); curJob.targetB = nextTarget; curJob.targetC = nextTarget; actor.jobs.curDriver.JumpToToil(carryToContainerToil); } } }; return toil; } public static bool TryGetNextDestinationFromQueue(TargetIndex primaryIndex, TargetIndex destIndex, ThingDef stuff, Job job, Pawn actor, out Thing target) { Thing primaryTarget = job.GetTarget(primaryIndex).Thing; target = null; if (actor.carryTracker?.CarriedThing == null) { return false; } bool hasSpareItems = actor.carryTracker.CarriedThing.stackCount > 0; if (primaryTarget != null && primaryTarget.Spawned && primaryTarget is IHaulEnroute enroute) { int spaceRemainingWithEnroute = enroute.GetSpaceRemainingWithEnroute(stuff, actor); hasSpareItems = actor.carryTracker.CarriedThing.stackCount > spaceRemainingWithEnroute; } target = GenClosest.ClosestThing_Global_Reachable(actor.Position, actor.Map, from x in job.GetTargetQueue(destIndex) select x.Thing, PathEndMode.Touch, TraverseParms.For(actor), 99999f, Validator); return target != null; bool Validator(Thing th) { if (!(th is IHaulEnroute enroute2)) { return false; } if (enroute2.GetSpaceRemainingWithEnroute(stuff, actor) <= 0) { return false; } if (th != primaryTarget && !hasSpareItems) { return false; } return true; } } public static Toil TakeToInventory(TargetIndex ind, int count) { return TakeToInventory(ind, count, null, null); } private static Toil TakeToInventory(TargetIndex ind, int? count, Func countGetter, Func countGetterPassingThing) { Toil takeThing = ToilMaker.MakeToil("TakeToInventory"); takeThing.initAction = delegate { Pawn actor = takeThing.actor; Thing thing = actor.CurJob.GetTarget(ind).Thing; if (!ErrorCheckForCarry(actor, thing)) { int num = Mathf.Min(count ?? countGetterPassingThing?.Invoke(thing) ?? countGetter(), thing.stackCount); if (actor.CurJob.checkEncumbrance) { num = Math.Min(num, MassUtility.CountToPickUpUntilOverEncumbered(actor, thing)); } if (num <= 0) { actor.jobs.curDriver.ReadyForNextToil(); } else { actor.inventory.GetDirectlyHeldThings().TryAdd(thing.SplitOff(num)); if (thing.def.ingestible != null && (int)thing.def.ingestible.preferability <= 5) { actor.mindState.lastInventoryRawFoodUseTick = Find.TickManager.TicksGame; } thing.def.soundPickup.PlayOneShot(new TargetInfo(actor.Position, actor.Map)); } } }; return takeThing; } public static Toil TakeToInventory(TargetIndex ind, Func countGetter) { return TakeToInventory(ind, null, countGetter, null); } public static Toil TakeToInventory(TargetIndex ind, Func countGetter) { return TakeToInventory(ind, null, null, countGetter); } public static Toil TakeFromOtherInventory(Thing item, ThingOwner taker, ThingOwner holder, int count = -1, TargetIndex indexToSet = TargetIndex.None) { Toil toil = ToilMaker.MakeToil("TakeFromOtherInventory"); toil.initAction = delegate { if (!holder.Contains(item)) { toil.actor.jobs.EndCurrentJob(JobCondition.Incompletable); } else { count = ((count < 0) ? toil.actor.jobs.curJob.count : count); holder.TryTransferToContainer(item, taker, Mathf.Min(item.stackCount, count), out var resultingTransferredItem); if (resultingTransferredItem == null) { Log.Warning($"Taker {toil.actor.Label} unable to take count {count} of thing {item.Label} from holder's inventory"); toil.actor.jobs.EndCurrentJob(JobCondition.Incompletable); } else if (indexToSet != 0) { toil.actor.jobs.curJob.SetTarget(indexToSet, resultingTransferredItem); } } }; return toil; } public static Toil CheckItemCarriedByOtherPawn(Thing item, TargetIndex targetPawnIfCarried = TargetIndex.None, Toil jumpIfCarriedByOther = null) { Toil toil = ToilMaker.MakeToil("CheckItemCarriedByOtherPawn"); toil.initAction = delegate { Pawn pawn = (item?.ParentHolder as Pawn_InventoryTracker)?.pawn; if (pawn != null && pawn != toil.actor) { if (targetPawnIfCarried != 0) { toil.actor.jobs.curJob.SetTarget(targetPawnIfCarried, pawn); } if (jumpIfCarriedByOther != null) { toil.actor.jobs.curDriver.JumpToToil(jumpIfCarriedByOther); } } }; toil.defaultCompleteMode = ToilCompleteMode.Instant; toil.atomicWithPrevious = true; return toil; } } ``` --- **文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI\JobDriver_HaulToContainer.txt` **相似度:** 0.6036 ```csharp public class JobDriver_HaulToContainer : JobDriver, IBuildableDriver { private Effecter graveDigEffect; protected const TargetIndex CarryThingIndex = TargetIndex.A; public const TargetIndex DestIndex = TargetIndex.B; protected const TargetIndex PrimaryDestIndex = TargetIndex.C; protected const int DiggingEffectInterval = 80; public Thing ThingToCarry => (Thing)job.GetTarget(TargetIndex.A); public Thing Container => (Thing)job.GetTarget(TargetIndex.B); public ThingDef ThingDef => ThingToCarry.def; protected virtual int Duration { get { if (Container == null || !(Container is Building building)) { return 0; } return building.HaulToContainerDuration(ThingToCarry); } } protected virtual EffecterDef WorkEffecter => null; protected virtual SoundDef WorkSustainer => null; public bool TryGetBuildableRect(out CellRect rect) { if (Container is Blueprint) { rect = Container.OccupiedRect(); return true; } rect = default(CellRect); return false; } public override string GetReport() { Thing thing = ((pawn.CurJob != job || pawn.carryTracker.CarriedThing == null) ? base.TargetThingA : pawn.carryTracker.CarriedThing); if (thing == null || !job.targetB.HasThing) { return "ReportHaulingUnknown".Translate(); } return ((job.GetTarget(TargetIndex.B).Thing is Building_Grave) ? "ReportHaulingToGrave" : "ReportHaulingTo").Translate(thing.Label, job.targetB.Thing.LabelShort.Named("DESTINATION"), thing.Named("THING")); } public override bool TryMakePreToilReservations(bool errorOnFailed) { if (!pawn.Reserve(job.GetTarget(TargetIndex.A), job, 1, -1, null, errorOnFailed)) { return false; } if (Container.Isnt()) { if (!pawn.Reserve(job.GetTarget(TargetIndex.B), job, 1, 1, null, errorOnFailed)) { return false; } pawn.ReserveAsManyAsPossible(job.GetTargetQueue(TargetIndex.B), job); } UpdateEnrouteTrackers(); pawn.ReserveAsManyAsPossible(job.GetTargetQueue(TargetIndex.A), job); return true; } protected virtual void ModifyPrepareToil(Toil toil) { } private bool TryReplaceWithFrame(TargetIndex index) { Thing thing = GetActor().jobs.curJob.GetTarget(index).Thing; Building edifice = thing.Position.GetEdifice(pawn.Map); if (edifice != null && thing is Blueprint_Build blueprint_Build && edifice is Frame frame && frame.BuildDef == blueprint_Build.BuildDef) { job.SetTarget(TargetIndex.B, frame); return true; } return false; } protected override IEnumerable MakeNewToils() { this.FailOnDestroyedOrNull(TargetIndex.A); this.FailOn(delegate { Thing thing = GetActor().jobs.curJob.GetTarget(TargetIndex.B).Thing; Thing thing2 = GetActor().jobs.curJob.GetTarget(TargetIndex.C).Thing; if (thing == null) { return true; } if (thing2 != null && thing2.Destroyed && !TryReplaceWithFrame(TargetIndex.C)) { job.SetTarget(TargetIndex.C, null); } if (!thing.Spawned || (thing.Destroyed && !TryReplaceWithFrame(TargetIndex.B))) { if (job.targetQueueB.NullOrEmpty()) { return true; } if (!Toils_Haul.TryGetNextDestinationFromQueue(TargetIndex.C, TargetIndex.B, ThingDef, job, pawn, out var nextTarget)) { return true; } job.targetQueueB.RemoveAll((LocalTargetInfo target) => target.Thing == nextTarget); job.targetB = nextTarget; } ThingOwner thingOwner = Container.TryGetInnerInteractableThingOwner(); if (thingOwner != null && !thingOwner.CanAcceptAnyOf(ThingToCarry)) { return true; } return (Container is IHaulDestination haulDestination && !haulDestination.Accepts(ThingToCarry)) ? true : false; }); this.FailOnForbidden(TargetIndex.B); this.FailOn(() => EnterPortalUtility.WasLoadingCanceled(Container)); this.FailOn(() => TransporterUtility.WasLoadingCanceled(Container)); this.FailOn(() => CompBiosculpterPod.WasLoadingCanceled(Container)); this.FailOn(() => Building_SubcoreScanner.WasLoadingCancelled(Container)); Toil getToHaulTarget = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch, canGotoSpawnedParent: true).FailOn(() => ThingToCarry.ParentHolder is MinifiedThing).FailOnSelfAndParentsDespawnedOrNull(TargetIndex.A); Toil uninstallIfMinifiable = Toils_Construct.UninstallIfMinifiable(TargetIndex.A).FailOnSomeonePhysicallyInteracting(TargetIndex.A).FailOn(() => ThingToCarry.ParentHolder is MinifiedThing) .FailOnSelfAndParentsDespawnedOrNull(TargetIndex.A) .FailOnDestroyedOrNull(TargetIndex.A); Toil startCarryingThing = Toils_Haul.StartCarryThing(TargetIndex.A, putRemainderInQueue: false, subtractNumTakenFromJobCount: true, failIfStackCountLessThanJobCount: false, reserve: true, canTakeFromInventory: true); Toil jumpIfAlsoCollectingNextTarget = Toils_Haul.JumpIfAlsoCollectingNextTargetInQueue(getToHaulTarget, TargetIndex.A); Toil carryToContainer = Toils_Haul.CarryHauledThingToContainer(); yield return Toils_Jump.JumpIf(jumpIfAlsoCollectingNextTarget, () => pawn.IsCarryingThing(ThingToCarry)); yield return getToHaulTarget; yield return uninstallIfMinifiable; yield return startCarryingThing; yield return jumpIfAlsoCollectingNextTarget; yield return carryToContainer; yield return Toils_Goto.MoveOffTargetBlueprint(TargetIndex.B); Toil toil = Toils_General.Wait(Duration, TargetIndex.B); toil.WithProgressBarToilDelay(TargetIndex.B); EffecterDef workEffecter = WorkEffecter; if (workEffecter != null) { toil.WithEffect(workEffecter, TargetIndex.B); } SoundDef workSustainer = WorkSustainer; if (workSustainer != null) { toil.PlaySustainerOrSound(workSustainer); } Thing destThing = job.GetTarget(TargetIndex.B).Thing; toil.tickIntervalAction = delegate(int delta) { if (pawn.IsHashIntervalTick(80, delta) && destThing is Building_Grave && graveDigEffect == null) { graveDigEffect = EffecterDefOf.BuryPawn.Spawn(); graveDigEffect.Trigger(destThing, destThing); } }; toil.tickAction = delegate { graveDigEffect?.EffectTick(destThing, destThing); }; ModifyPrepareToil(toil); yield return toil; yield return Toils_Construct.MakeSolidThingFromBlueprintIfNecessary(TargetIndex.B, TargetIndex.C); yield return Toils_Haul.DepositHauledThingInContainer(TargetIndex.B, TargetIndex.C); yield return Toils_Haul.JumpToCarryToNextContainerIfPossible(carryToContainer, TargetIndex.C); } private void UpdateEnrouteTrackers() { int count = job.count; TryReserveEnroute(base.TargetThingC, ref count); if (base.TargetB != base.TargetC) { TryReserveEnroute(base.TargetThingB, ref count); } if (job.targetQueueB == null) { return; } foreach (LocalTargetInfo item in job.targetQueueB) { if (!base.TargetC.HasThing || !(item == base.TargetThingC)) { TryReserveEnroute(item.Thing, ref count); } } } private void TryReserveEnroute(Thing thing, ref int count) { if (thing is IHaulEnroute container && !thing.DestroyedOrNull()) { UpdateTracker(container, ref count); } } private void UpdateTracker(IHaulEnroute container, ref int count) { if (!ThingToCarry.DestroyedOrNull()) { if (job.playerForced && container.GetSpaceRemainingWithEnroute(ThingDef) == 0) { container.Map.enrouteManager.InterruptEnroutePawns(container, pawn); } int num = Mathf.Min(count, container.GetSpaceRemainingWithEnroute(ThingDef)); if (num > 0) { container.Map.enrouteManager.AddEnroute(container, pawn, base.TargetThingA.def, num); } count -= num; } } } ``` --- **文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\JobDriver_PrepareCaravan_GatherItems.txt` **相似度:** 0.5905 ```csharp public class JobDriver_PrepareCaravan_GatherItems : JobDriver { private int pickedUpFirstItemTicks = -1; private int toilLoops; private PrepareCaravanGatherState gatherState; private const TargetIndex ToHaulInd = TargetIndex.A; private const TargetIndex CarrierInd = TargetIndex.B; private const int MaxTicksGatherItems = 7500; private const int LoopBackstop = 500; public Thing ToHaul => job.GetTarget(TargetIndex.A).Thing; public Pawn Carrier => (Pawn)job.GetTarget(TargetIndex.B).Thing; private List Transferables => ((LordJob_FormAndSendCaravan)job.lord.LordJob).transferables; private TransferableOneWay Transferable { get { TransferableOneWay transferableOneWay = TransferableUtility.TransferableMatchingDesperate(ToHaul, Transferables, TransferAsOneMode.PodsOrCaravanPacking); if (transferableOneWay != null) { return transferableOneWay; } throw new InvalidOperationException("Could not find any matching transferable."); } } public override bool TryMakePreToilReservations(bool errorOnFailed) { return pawn.Reserve(ToHaul, job, 1, -1, null, errorOnFailed); } protected override IEnumerable MakeNewToils() { if (gatherState == PrepareCaravanGatherState.Unset) { gatherState = ((pawn.IsFormingCaravan() && (!MassUtility.IsOverEncumbered(pawn) || pawn.inventory.HasAnyUnpackedCaravanItems)) ? PrepareCaravanGatherState.Haul : PrepareCaravanGatherState.Carry); } if (gatherState == PrepareCaravanGatherState.Carry) { return MakeNewToilsCarry(); } return MakeNewToilsHaulInInventory(); } private IEnumerable MakeNewToilsCarry() { this.FailOn(() => !base.Map.lordManager.lords.Contains(job.lord)); Toil reserve = Toils_Reserve.Reserve(TargetIndex.A).FailOnDestroyedOrNull(TargetIndex.A); yield return reserve; bool inInventory = HaulAIUtility.IsInHaulableInventory(ToHaul); yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch, inInventory); yield return DetermineNumToHaul(); yield return Toils_Haul.StartCarryThing(TargetIndex.A, putRemainderInQueue: false, subtractNumTakenFromJobCount: true, failIfStackCountLessThanJobCount: false, reserve: true, inInventory); yield return AddCarriedThingToTransferables(); yield return Toils_Haul.CheckForGetOpportunityDuplicate(reserve, TargetIndex.A, TargetIndex.None, takeFromValidStorage: true, (Thing x) => Transferable.things.Contains(x)); Toil findCarrier = FindCarrier(); yield return findCarrier; yield return Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.Touch).JumpIf(() => !IsUsableCarrier(Carrier, pawn, allowColonists: true), findCarrier); yield return Toils_General.Wait(25).JumpIf(() => !IsUsableCarrier(Carrier, pawn, allowColonists: true), findCarrier).WithProgressBarToilDelay(TargetIndex.B); yield return PlaceTargetInCarrierInventory(); } private IEnumerable MakeNewToilsHaulInInventory() { this.FailOn(() => !base.Map.lordManager.lords.Contains(job.lord)); bool inInventory = HaulAIUtility.IsInHaulableInventory(ToHaul); Toil reserve = Toils_Reserve.Reserve(TargetIndex.A).FailOnDestroyedOrNull(TargetIndex.A); Toil findCarrier = FindCarrier(); yield return reserve; yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch, inInventory).JumpIf(IsFinishedCollectingItems, findCarrier); yield return DetermineNumToHaul(findCarrier); yield return Toils_Haul.StartCarryThing(TargetIndex.A, putRemainderInQueue: false, subtractNumTakenFromJobCount: true, failIfStackCountLessThanJobCount: false, reserve: true, inInventory); yield return AddCarriedThingToTransferables(); yield return Toils_General.Wait(25).WithProgressBarToilDelay(TargetIndex.B); yield return HaulCaravanItemInInventory(reserve); yield return findCarrier; yield return Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.Touch).JumpIf(() => !IsUsableCarrier(Carrier, pawn, allowColonists: true), findCarrier); yield return Toils_General.Wait(25).JumpIf(() => !IsUsableCarrier(Carrier, pawn, allowColonists: true), findCarrier).WithProgressBarToilDelay(TargetIndex.B); yield return AddHauledItemsToCarrier(findCarrier); } private Toil DetermineNumToHaul(Toil findCarrier = null) { Toil toil = ToilMaker.MakeToil("DetermineNumToHaul"); toil.initAction = delegate { int num = GatherItemsForCaravanUtility.CountLeftToTransfer(pawn, Transferable, job.lord); if (pawn.carryTracker.CarriedThing != null) { num -= pawn.carryTracker.CarriedThing.stackCount; } if (num <= 0) { if (findCarrier == null || !pawn.inventory.HasAnyUnpackedCaravanItems) { pawn.jobs.EndCurrentJob(JobCondition.Succeeded); } else { pawn.jobs.curDriver.JumpToToil(findCarrier); } } else { job.count = num; } }; toil.defaultCompleteMode = ToilCompleteMode.Instant; toil.atomicWithPrevious = true; return toil; } private Toil AddCarriedThingToTransferables() { Toil toil = ToilMaker.MakeToil("AddCarriedThingToTransferables"); toil.initAction = delegate { TransferableOneWay transferable = Transferable; if (!transferable.things.Contains(pawn.carryTracker.CarriedThing)) { transferable.things.Add(pawn.carryTracker.CarriedThing); } }; toil.defaultCompleteMode = ToilCompleteMode.Instant; toil.atomicWithPrevious = true; return toil; } private Toil FindCarrier() { Toil toil = ToilMaker.MakeToil("FindCarrier"); toil.initAction = delegate { Pawn pawn = FindBestCarrier(onlyAnimals: true); if (pawn == null) { bool flag = base.pawn.GetLord() == job.lord; if (flag && !MassUtility.IsOverEncumbered(base.pawn)) { pawn = base.pawn; } else { pawn = FindBestCarrier(onlyAnimals: false); if (pawn == null) { if (flag) { pawn = base.pawn; } else { IEnumerable source = job.lord.ownedPawns.Where((Pawn x) => IsUsableCarrier(x, base.pawn, allowColonists: true)); if (!source.Any()) { EndJobWith(JobCondition.Incompletable); return; } pawn = source.RandomElement(); } } } } job.SetTarget(TargetIndex.B, pawn); }; return toil; } private bool IsFinishedCollectingItems() { if (!MassUtility.IsOverEncumbered(pawn)) { if (pickedUpFirstItemTicks > -1) { return Find.TickManager.TicksGame > pickedUpFirstItemTicks + 7500; } return false; } return true; } private Toil HaulCaravanItemInInventory(Toil reserve) { Toil toil = ToilMaker.MakeToil("HaulCaravanItemInInventory"); toil.initAction = delegate { if (pickedUpFirstItemTicks == -1) { pickedUpFirstItemTicks = Find.TickManager.TicksGame; } Transferable.AdjustTo(Mathf.Max(Transferable.CountToTransfer - pawn.carryTracker.CarriedThing.stackCount, 0)); pawn.inventory.AddHauledCaravanItem(pawn.carryTracker.CarriedThing); if (!IsFinishedCollectingItems()) { SetNewHaulTargetAndJumpToReserve(reserve); } }; return toil; } private void SetNewHaulTargetAndJumpToReserve(Toil reserve) { if (CheckToilLoopBackstop()) { Thing thing = GatherItemsForCaravanUtility.FindThingToHaul(pawn, pawn.GetLord()); if (thing != null) { job.SetTarget(TargetIndex.A, thing); pawn.jobs.curDriver.JumpToToil(reserve); } } } private Toil AddHauledItemsToCarrier(Toil findCarrier) { Toil toil = ToilMaker.MakeToil("AddHauledItemsToCarrier"); toil.initAction = delegate { if (Carrier == pawn) { pawn.inventory.ClearHaulingCaravanCache(); } else { pawn.inventory.TransferCaravanItemsToCarrier(Carrier.inventory); if (pawn.inventory.HasAnyUnpackedCaravanItems && CheckToilLoopBackstop()) { pawn.jobs.curDriver.JumpToToil(findCarrier); } } }; return toil; } private bool CheckToilLoopBackstop() { if (++toilLoops > 500) { Log.Error("Prepare caravan gather items job for pawn " + pawn.Label + " looped through toils too many times"); EndJobWith(JobCondition.Errored); return false; } return true; } private Toil PlaceTargetInCarrierInventory() { Toil toil = ToilMaker.MakeToil("PlaceTargetInCarrierInventory"); toil.initAction = delegate { Pawn_CarryTracker carryTracker = pawn.carryTracker; Thing carriedThing = carryTracker.CarriedThing; if (carryTracker.innerContainer.Count == 0) { carryTracker.pawn.Drawer.renderer.SetAllGraphicsDirty(); } Transferable.AdjustTo(Mathf.Max(Transferable.CountToTransfer - carriedThing.stackCount, 0)); carryTracker.innerContainer.TryTransferToContainer(carriedThing, Carrier.inventory.innerContainer, carriedThing.stackCount, out var resultingTransferredItem); CompForbiddable compForbiddable = resultingTransferredItem?.TryGetComp(); if (compForbiddable != null) { compForbiddable.Forbidden = false; } }; return toil; } public static bool IsUsableCarrier(Pawn p, Pawn forPawn, bool allowColonists) { if (!p.IsFormingCaravan()) { return false; } if (p == forPawn) { return true; } if (p.DestroyedOrNull() || !p.Spawned || p.inventory.UnloadEverything || !forPawn.CanReach(p, PathEndMode.Touch, Danger.Deadly)) { return false; } if (allowColonists && p.IsColonist) { return true; } if ((p.RaceProps.packAnimal || p.HostFaction == Faction.OfPlayer) && !p.IsBurning() && !p.Downed) { return !MassUtility.IsOverEncumbered(p); } return false; } private float GetCarrierScore(Pawn p) { float lengthHorizontal = (p.Position - pawn.Position).LengthHorizontal; float num = MassUtility.EncumbrancePercent(p); return 1f - num - lengthHorizontal / 10f * 0.2f; } private Pawn FindBestCarrier(bool onlyAnimals) { Lord lord = job.lord; Pawn pawn = null; float num = 0f; if (lord != null) { for (int i = 0; i < lord.ownedPawns.Count; i++) { Pawn pawn2 = lord.ownedPawns[i]; if (pawn2 != base.pawn && (!onlyAnimals || pawn2.RaceProps.Animal) && IsUsableCarrier(pawn2, base.pawn, allowColonists: false)) { float carrierScore = GetCarrierScore(pawn2); if (pawn == null || carrierScore > num) { pawn = pawn2; num = carrierScore; } } } } return pawn; } public override void ExposeData() { base.ExposeData(); Scribe_Values.Look(ref pickedUpFirstItemTicks, "pickedUpFirstItemTicks", 0); Scribe_Values.Look(ref toilLoops, "toilLoops", 0); Scribe_Values.Look(ref gatherState, "gatherState", PrepareCaravanGatherState.Unset); } } ``` --- **文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\JobDriver_CarryToCryptosleepCasket.txt` **相似度:** 0.5506 ```csharp public class JobDriver_CarryToCryptosleepCasket : JobDriver { private const TargetIndex TakeeInd = TargetIndex.A; private const TargetIndex DropPodInd = TargetIndex.B; protected Pawn Takee => (Pawn)job.GetTarget(TargetIndex.A).Thing; protected Building_CryptosleepCasket DropPod => (Building_CryptosleepCasket)job.GetTarget(TargetIndex.B).Thing; public override bool TryMakePreToilReservations(bool errorOnFailed) { if (pawn.Reserve(Takee, job, 1, -1, null, errorOnFailed)) { return pawn.Reserve(DropPod, job, 1, -1, null, errorOnFailed); } return false; } protected override IEnumerable MakeNewToils() { this.FailOnDestroyedOrNull(TargetIndex.A); this.FailOnDestroyedOrNull(TargetIndex.B); this.FailOnAggroMentalState(TargetIndex.A); this.FailOn(() => !DropPod.Accepts(Takee)); Toil goToTakee = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.OnCell).FailOnDestroyedNullOrForbidden(TargetIndex.A).FailOnDespawnedNullOrForbidden(TargetIndex.B) .FailOn(() => DropPod.GetDirectlyHeldThings().Count > 0) .FailOn(() => !pawn.CanReach(Takee, PathEndMode.OnCell, Danger.Deadly)) .FailOnSomeonePhysicallyInteracting(TargetIndex.A); Toil startCarryingTakee = Toils_Haul.StartCarryThing(TargetIndex.A); Toil goToThing = Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.InteractionCell); yield return Toils_Jump.JumpIf(goToThing, () => pawn.IsCarryingPawn(Takee)); yield return goToTakee; yield return startCarryingTakee; yield return goToThing; Toil toil = Toils_General.Wait(500, TargetIndex.B); toil.FailOnCannotTouch(TargetIndex.B, PathEndMode.InteractionCell); toil.WithProgressBarToilDelay(TargetIndex.B); yield return toil; Toil toil2 = ToilMaker.MakeToil("MakeNewToils"); toil2.initAction = delegate { DropPod.TryAcceptThing(Takee); }; toil2.defaultCompleteMode = ToilCompleteMode.Instant; yield return toil2; } public override object[] TaleParameters() { return new object[2] { pawn, Takee }; } } ``` --- **文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI\JobDriver_HaulToAtomizer.txt` **相似度:** 0.5312 ```csharp public class JobDriver_HaulToAtomizer : JobDriver { private const TargetIndex AtomizerInd = TargetIndex.A; private const TargetIndex WastepackInd = TargetIndex.B; private const TargetIndex ChargerCellInd = TargetIndex.C; public override bool TryMakePreToilReservations(bool errorOnFailed) { pawn.ReserveAsManyAsPossible(job.GetTargetQueue(TargetIndex.B), job); return pawn.Reserve(job.GetTarget(TargetIndex.A), job, 1, -1, null, errorOnFailed); } protected override IEnumerable MakeNewToils() { this.FailOnDespawnedNullOrForbidden(TargetIndex.A); AddEndCondition(() => (base.TargetThingA.TryGetComp().SpaceLeft > 0) ? JobCondition.Ongoing : JobCondition.Succeeded); Toil clearQueue = Toils_JobTransforms.ClearDespawnedNullOrForbiddenQueuedTargets(TargetIndex.B); yield return clearQueue; yield return Toils_JobTransforms.SucceedOnNoTargetInQueue(TargetIndex.B); yield return Toils_JobTransforms.ExtractNextTargetFromQueue(TargetIndex.B); yield return Toils_Reserve.Reserve(TargetIndex.B); yield return Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.ClosestTouch).FailOnSomeonePhysicallyInteracting(TargetIndex.B); yield return Toils_Haul.StartCarryThing(TargetIndex.B, putRemainderInQueue: false, subtractNumTakenFromJobCount: true); yield return Toils_Haul.CheckForGetOpportunityDuplicate(clearQueue, TargetIndex.B, TargetIndex.None, takeFromValidStorage: true); yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell); yield return Toils_Haul.DepositHauledThingInContainer(TargetIndex.A, TargetIndex.B); yield return Toils_Jump.Jump(clearQueue); } } ``` --- **文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI\JobDriver_PickupToHold.txt` **相似度:** 0.5219 ```csharp public class JobDriver_PickupToHold : JobDriver { private const TargetIndex HeldItemInd = TargetIndex.A; public static bool TryMakePreToilReservations(JobDriver driver, bool errorOnFailed) { driver.pawn.Map.pawnDestinationReservationManager.Reserve(driver.pawn, driver.job, driver.job.GetTarget(TargetIndex.A).Cell); return driver.pawn.Reserve(driver.job.GetTarget(TargetIndex.A), driver.job, 1, -1, null, errorOnFailed); } public static IEnumerable Toils(JobDriver driver, TargetIndex HeldItem = TargetIndex.A, bool subtractNumTakenFromJobCount = true) { driver.FailOn(() => !driver.GetActor().health.capacities.CapableOf(PawnCapacityDefOf.Manipulation)); driver.FailOnDestroyedOrNull(HeldItem); driver.FailOnForbidden(HeldItem); Toil end = Toils_General.Label(); yield return Toils_Jump.JumpIf(end, () => driver.GetActor().IsCarryingThing(driver.GetActor().CurJob.GetTarget(HeldItem).Thing)); yield return Toils_Goto.GotoThing(HeldItem, PathEndMode.ClosestTouch).FailOnSomeonePhysicallyInteracting(HeldItem); yield return Toils_Haul.StartCarryThing(HeldItem, putRemainderInQueue: false, subtractNumTakenFromJobCount); yield return end; } public override bool TryMakePreToilReservations(bool errorOnFailed) { return TryMakePreToilReservations(this, errorOnFailed); } protected override IEnumerable MakeNewToils() { return Toils(this); } } ```