public void Cleanup(int myIndex, JobDriver jobDriver) { if (this.finishActions != null) { for (int i = 0; i < this.finishActions.Count; i++) { try { this.finishActions[i](); } catch (Exception ex) { Log.Error(string.Concat(new object[] { "Pawn ", this.actor.ToStringSafe <Pawn>(), " threw exception while executing toil's finish action (", i, "), jobDriver=", jobDriver.ToStringSafe <JobDriver>(), ", job=", jobDriver.job.ToStringSafe <Job>(), ", toilIndex=", myIndex, ": ", ex }), false); } } } }
private static void AppendVarsInfoToDebugMessage(Pawn pawn, ref string msg, JobDriver concreteDriver) { if (concreteDriver != null) { string text = msg; msg = text + " driver=" + concreteDriver.GetType().Name + " (toilIndex=" + concreteDriver.CurToilIndex + ")"; if (concreteDriver.job != null) { msg = msg + " driver.job=(" + concreteDriver.job.ToStringSafe() + ")"; } } else if (pawn.jobs != null) { if (pawn.jobs.curDriver != null) { string text = msg; msg = text + " curDriver=" + pawn.jobs.curDriver.GetType().Name + " (toilIndex=" + pawn.jobs.curDriver.CurToilIndex + ")"; } if (pawn.jobs.curJob != null) { msg = msg + " curJob=(" + pawn.jobs.curJob.ToStringSafe() + ")"; } } if (pawn.mindState != null) { msg = msg + " lastJobGiver=" + pawn.mindState.lastJobGiver.ToStringSafe(); } }
private void CleanupCurrentJob(JobCondition condition, bool releaseReservations, bool cancelBusyStancesSoft = true, bool canReturnToPool = false) { if (debugLog) { DebugLogEvent("CleanupCurrentJob " + ((curJob != null) ? curJob.def.ToString() : "null") + " condition " + condition); } if (curJob != null) { if (releaseReservations) { pawn.ClearReservationsForJob(curJob); } if (curDriver != null) { curDriver.ended = true; curDriver.Cleanup(condition); } curDriver = null; Job job = curJob; curJob = null; pawn.VerifyReservations(); if (cancelBusyStancesSoft) { pawn.stances.CancelBusyStanceSoft(); } if (!pawn.Destroyed && pawn.carryTracker != null && pawn.carryTracker.CarriedThing != null) { pawn.carryTracker.TryDropCarriedThing(pawn.Position, ThingPlaceMode.Near, out var _); } if (releaseReservations && canReturnToPool) { JobMaker.ReturnToPool(job); } } }
private void CleanupCurrentJob(JobCondition condition, bool releaseReservations, bool cancelBusyStancesSoft = true) { if (this.debugLog) { this.DebugLogEvent(string.Concat(new object[] { "CleanupCurrentJob ", (this.curJob == null) ? "null" : this.curJob.def.ToString(), " condition ", condition })); } if (this.curJob == null) { return; } if (releaseReservations) { this.pawn.ClearReservationsForJob(this.curJob); } this.curDriver.ended = true; this.curDriver.Cleanup(condition); this.curDriver = null; this.curJob = null; this.pawn.VerifyReservations(); if (cancelBusyStancesSoft) { this.pawn.stances.CancelBusyStanceSoft(); } if (!this.pawn.Destroyed && this.pawn.carryTracker != null && this.pawn.carryTracker.CarriedThing != null) { Thing thing; this.pawn.carryTracker.TryDropCarriedThing(this.pawn.Position, ThingPlaceMode.Near, out thing, null); } }
public void Clear() { def = null; targetA = LocalTargetInfo.Invalid; targetB = LocalTargetInfo.Invalid; targetC = LocalTargetInfo.Invalid; targetQueueA = null; targetQueueB = null; count = -1; countQueue = null; loadID = -1; startTick = -1; expiryInterval = -1; checkOverrideOnExpire = false; playerForced = false; placedThings = null; maxNumMeleeAttacks = int.MaxValue; maxNumStaticAttacks = int.MaxValue; locomotionUrgency = LocomotionUrgency.Jog; haulMode = HaulMode.Undefined; bill = null; commTarget = null; plantDefToSow = null; verbToUse = null; haulOpportunisticDuplicates = false; exitMapOnArrival = false; failIfCantJoinOrCreateCaravan = false; killIncappedTarget = false; ignoreForbidden = false; ignoreDesignations = false; canBash = false; canUseRangedWeapon = true; haulDroppedApparel = false; restUntilHealed = false; ignoreJoyTimeAssignment = false; doUntilGatheringEnded = false; overeat = false; attackDoorIfTargetLost = false; takeExtraIngestibles = 0; expireRequiresEnemiesNearby = false; lord = null; collideWithPawns = false; forceSleep = false; interaction = null; endIfCantShootTargetFromCurPos = false; endIfCantShootInMelee = false; checkEncumbrance = false; followRadius = 0f; endAfterTendedOnce = false; quest = null; mote = null; jobGiverThinkTree = null; jobGiver = null; workGiverDef = null; if (cachedDriver != null) { cachedDriver.job = null; } cachedDriver = null; }
private void CleanupCurrentJob(JobCondition condition, bool releaseReservations, bool cancelBusyStancesSoft = true) { if (this.debugLog) { this.DebugLogEvent("CleanupCurrentJob " + ((this.curJob == null) ? "null" : this.curJob.def.ToString()) + " condition " + condition); } if (this.curJob != null) { if (releaseReservations) { this.pawn.ClearReservationsForJob(this.curJob); } this.curDriver.ended = true; this.curDriver.Cleanup(condition); this.curDriver = null; this.curJob = null; this.pawn.VerifyReservations(); if (cancelBusyStancesSoft) { this.pawn.stances.CancelBusyStanceSoft(); } if (!this.pawn.Destroyed && this.pawn.carryTracker != null && this.pawn.carryTracker.CarriedThing != null) { Thing thing = default(Thing); this.pawn.carryTracker.TryDropCarriedThing(this.pawn.Position, ThingPlaceMode.Near, out thing, (Action <Thing, int>)null); } } }
public static Toil FollowAndMeleeAttack(TargetIndex targetInd, Action hitAction) { Toil followAndAttack = new Toil(); followAndAttack.tickAction = delegate() { Pawn actor = followAndAttack.actor; Job curJob = actor.jobs.curJob; JobDriver curDriver = actor.jobs.curDriver; Thing thing = curJob.GetTarget(targetInd).Thing; Pawn pawn = thing as Pawn; if (!thing.Spawned) { curDriver.ReadyForNextToil(); return; } if (thing != actor.pather.Destination.Thing || (!actor.pather.Moving && !actor.CanReachImmediate(thing, PathEndMode.Touch))) { actor.pather.StartPath(thing, PathEndMode.Touch); } else if (actor.CanReachImmediate(thing, PathEndMode.Touch)) { if (pawn != null && pawn.Downed && !curJob.killIncappedTarget) { curDriver.ReadyForNextToil(); return; } hitAction(); } }; followAndAttack.defaultCompleteMode = ToilCompleteMode.Never; return(followAndAttack); }
public JobDriver MakeDriver(Pawn driverPawn) { JobDriver obj = (JobDriver)Activator.CreateInstance(def.driverClass); obj.pawn = driverPawn; obj.job = this; return(obj); }
public JobDriver MakeDriver(Pawn driverPawn) { JobDriver jobDriver = (JobDriver)Activator.CreateInstance(this.def.driverClass); jobDriver.pawn = driverPawn; jobDriver.job = this; return(jobDriver); }
private JobDriver GetCachedDriver(Pawn driverPawn) { if (this.cachedDriver == null) { this.cachedDriver = this.MakeDriver(driverPawn); } if (this.cachedDriver.pawn != driverPawn) { Log.Error("Tried to use the same driver for 2 pawns: " + this.cachedDriver.ToStringSafe() + ", first pawn= " + this.cachedDriver.pawn.ToStringSafe() + ", second pawn=" + driverPawn.ToStringSafe()); } return(this.cachedDriver); }
public void Cleanup(int myIndex, JobDriver jobDriver) { if (finishActions != null) { for (int i = 0; i < finishActions.Count; i++) { try { finishActions[i](); } catch (Exception ex) { Log.Error("Pawn " + actor.ToStringSafe() + " threw exception while executing toil's finish action (" + i + "), jobDriver=" + jobDriver.ToStringSafe() + ", job=" + jobDriver.job.ToStringSafe() + ", toilIndex=" + myIndex + ": " + ex); } } } }
private static void AppendVarsInfoToDebugMessage(Pawn pawn, ref string msg, JobDriver concreteDriver) { if (concreteDriver != null) { string text = msg; msg = string.Concat(new object[] { text, " driver=", concreteDriver.GetType().Name, " (toilIndex=", concreteDriver.CurToilIndex, ")" }); if (concreteDriver.job != null) { msg = msg + " driver.job=(" + concreteDriver.job.ToStringSafe <Job>() + ")"; } } else if (pawn.jobs != null) { if (pawn.jobs.curDriver != null) { string text = msg; msg = string.Concat(new object[] { text, " curDriver=", pawn.jobs.curDriver.GetType().Name, " (toilIndex=", pawn.jobs.curDriver.CurToilIndex, ")" }); } if (pawn.jobs.curJob != null) { msg = msg + " curJob=(" + pawn.jobs.curJob.ToStringSafe <Job>() + ")"; } } if (pawn.mindState != null) { msg = msg + " lastJobGiver=" + pawn.mindState.lastJobGiver.ToStringSafe <ThinkNode>(); } }
public static Toil FollowAndMeleeAttack(TargetIndex targetInd, Action hitAction) { //Follow and attack victim Toil followAndAttack = new Toil(); followAndAttack.tickAction = () => { Pawn actor = followAndAttack.actor; Job curJob = actor.jobs.curJob; JobDriver driver = actor.jobs.curDriver; Thing victim = curJob.GetTarget(targetInd).Thing; Pawn victimPawn = victim as Pawn; if (!victim.Spawned) { driver.ReadyForNextToil(); return; } if (victim != actor.pather.Destination.Thing || (!actor.pather.Moving && !actor.CanReachImmediate(victim, PathEndMode.Touch))) { actor.pather.StartPath(victim, PathEndMode.Touch); } else { if (actor.CanReachImmediate(victim, PathEndMode.Touch)) { //Do not attack downed people unless the job specifies to do so if (victimPawn != null && victimPawn.Downed && !curJob.killIncappedTarget) { driver.ReadyForNextToil(); return; } //Try to hit them hitAction(); } } }; followAndAttack.defaultCompleteMode = ToilCompleteMode.Never; return(followAndAttack); }
private JobDriver GetCachedDriver(Pawn driverPawn) { if (this.cachedDriver == null) { this.cachedDriver = this.MakeDriver(driverPawn); } if (this.cachedDriver.pawn != driverPawn) { Log.Error(string.Concat(new string[] { "Tried to use the same driver for 2 pawns: ", this.cachedDriver.ToStringSafe <JobDriver>(), ", first pawn= ", this.cachedDriver.pawn.ToStringSafe <Pawn>(), ", second pawn=", driverPawn.ToStringSafe <Pawn>() })); } return(this.cachedDriver); }
public void StartJob(Job newJob, JobCondition lastJobEndCondition = JobCondition.None, ThinkNode jobGiver = null, bool resumeCurJobAfterwards = false, bool cancelBusyStances = true, ThinkTreeDef thinkTree = null, JobTag?tag = null, bool fromQueue = false, bool canReturnCurJobToPool = false) { startingNewJob = true; try { if (!fromQueue && (!Find.TickManager.Paused || lastJobGivenAtFrame == RealTime.frameCount)) { jobsGivenThisTick++; if (Prefs.DevMode) { jobsGivenThisTickTextual = jobsGivenThisTickTextual + "(" + newJob.ToString() + ") "; } } lastJobGivenAtFrame = RealTime.frameCount; if (jobsGivenThisTick > 10) { string text = jobsGivenThisTickTextual; jobsGivenThisTick = 0; jobsGivenThisTickTextual = ""; startingNewJob = false; pawn.ClearReservationsForJob(newJob); JobUtility.TryStartErrorRecoverJob(pawn, pawn.ToStringSafe() + " started 10 jobs in one tick. newJob=" + newJob.ToStringSafe() + " jobGiver=" + jobGiver.ToStringSafe() + " jobList=" + text); return; } if (debugLog) { DebugLogEvent(string.Concat("StartJob [", newJob, "] lastJobEndCondition=", lastJobEndCondition, ", jobGiver=", jobGiver, ", cancelBusyStances=", cancelBusyStances.ToString())); } if (cancelBusyStances && pawn.stances.FullBodyBusy) { pawn.stances.CancelBusyStanceHard(); } if (curJob != null) { if (lastJobEndCondition == JobCondition.None) { Log.Warning(string.Concat(pawn, " starting job ", newJob, " from JobGiver ", newJob.jobGiver, " while already having job ", curJob, " without a specific job end condition.")); lastJobEndCondition = JobCondition.InterruptForced; } if (resumeCurJobAfterwards && curJob.def.suspendable) { jobQueue.EnqueueFirst(curJob); if (debugLog) { DebugLogEvent(" JobQueue EnqueueFirst curJob: " + curJob); } CleanupCurrentJob(lastJobEndCondition, releaseReservations: false, cancelBusyStances); } else { CleanupCurrentJob(lastJobEndCondition, releaseReservations: true, cancelBusyStances, canReturnCurJobToPool); } } if (newJob == null) { Log.Warning(string.Concat(pawn, " tried to start doing a null job.")); return; } newJob.startTick = Find.TickManager.TicksGame; if (pawn.Drafted || newJob.playerForced) { newJob.ignoreForbidden = true; newJob.ignoreDesignations = true; } curJob = newJob; curJob.jobGiverThinkTree = thinkTree; curJob.jobGiver = jobGiver; curDriver = curJob.MakeDriver(pawn); bool flag = fromQueue; if (curDriver.TryMakePreToilReservations(!flag)) { Job job = TryOpportunisticJob(newJob); if (job != null) { jobQueue.EnqueueFirst(newJob); curJob = null; curDriver = null; StartJob(job); return; } if (tag.HasValue) { pawn.mindState.lastJobTag = tag.Value; } curDriver.SetInitialPosture(); curDriver.Notify_Starting(); curDriver.SetupToils(); curDriver.ReadyForNextToil(); } else if (flag) { EndCurrentJob(JobCondition.QueuedNoLongerValid); } else { Log.Warning("TryMakePreToilReservations() returned false for a non-queued job right after StartJob(). This should have been checked before. curJob=" + curJob.ToStringSafe()); EndCurrentJob(JobCondition.Errored); } } finally { startingNewJob = false; } }
public void StartJob(Job newJob, JobCondition lastJobEndCondition = JobCondition.None, ThinkNode jobGiver = null, bool resumeCurJobAfterwards = false, bool cancelBusyStances = true, ThinkTreeDef thinkTree = null, JobTag?tag = null, bool fromQueue = false) { this.startingNewJob = true; try { if (!fromQueue && (!Find.TickManager.Paused || this.lastJobGivenAtFrame == RealTime.frameCount)) { this.jobsGivenThisTick++; this.jobsGivenThisTickTextual = this.jobsGivenThisTickTextual + "(" + newJob.ToString() + ") "; } this.lastJobGivenAtFrame = RealTime.frameCount; if (this.jobsGivenThisTick > 10) { string text = this.jobsGivenThisTickTextual; this.jobsGivenThisTick = 0; this.jobsGivenThisTickTextual = ""; this.startingNewJob = false; this.pawn.ClearReservationsForJob(newJob); JobUtility.TryStartErrorRecoverJob(this.pawn, string.Concat(new string[] { this.pawn.ToStringSafe <Pawn>(), " started 10 jobs in one tick. newJob=", newJob.ToStringSafe <Job>(), " jobGiver=", jobGiver.ToStringSafe <ThinkNode>(), " jobList=", text }), null, null); } else { if (this.debugLog) { this.DebugLogEvent(string.Concat(new object[] { "StartJob [", newJob, "] lastJobEndCondition=", lastJobEndCondition, ", jobGiver=", jobGiver, ", cancelBusyStances=", cancelBusyStances })); } if (cancelBusyStances && this.pawn.stances.FullBodyBusy) { this.pawn.stances.CancelBusyStanceHard(); } if (this.curJob != null) { if (lastJobEndCondition == JobCondition.None) { Log.Warning(string.Concat(new object[] { this.pawn, " starting job ", newJob, " from JobGiver ", this.pawn.mindState.lastJobGiver, " while already having job ", this.curJob, " without a specific job end condition." }), false); lastJobEndCondition = JobCondition.InterruptForced; } if (resumeCurJobAfterwards && this.curJob.def.suspendable) { this.jobQueue.EnqueueFirst(this.curJob, null); if (this.debugLog) { this.DebugLogEvent(" JobQueue EnqueueFirst curJob: " + this.curJob); } this.CleanupCurrentJob(lastJobEndCondition, false, cancelBusyStances); } else { this.CleanupCurrentJob(lastJobEndCondition, true, cancelBusyStances); } } if (newJob == null) { Log.Warning(this.pawn + " tried to start doing a null job.", false); } else { newJob.startTick = Find.TickManager.TicksGame; if (this.pawn.Drafted || newJob.playerForced) { newJob.ignoreForbidden = true; newJob.ignoreDesignations = true; } this.curJob = newJob; this.pawn.mindState.lastJobGiver = jobGiver; this.pawn.mindState.lastJobGiverThinkTree = thinkTree; this.curDriver = this.curJob.MakeDriver(this.pawn); if (this.curDriver.TryMakePreToilReservations()) { Job job = this.TryOpportunisticJob(newJob); if (job != null) { this.jobQueue.EnqueueFirst(newJob, null); this.curJob = null; this.curDriver = null; this.StartJob(job, JobCondition.None, null, false, true, null, null, false); } else { if (tag != null) { this.pawn.mindState.lastJobTag = tag.Value; } this.curDriver.SetInitialPosture(); this.curDriver.Notify_Starting(); this.curDriver.SetupToils(); this.curDriver.ReadyForNextToil(); } } else if (fromQueue) { this.EndCurrentJob(JobCondition.QueuedNoLongerValid, true); } else { Log.Warning("TryMakePreToilReservations() returned false for a non-queued job right after StartJob(). This should have been checked before. curJob=" + this.curJob.ToStringSafe <Job>(), false); this.EndCurrentJob(JobCondition.Errored, true); } } } } finally { this.startingNewJob = false; } }
public static void TryStartErrorRecoverJob(Pawn pawn, string message, Exception exception = null, JobDriver concreteDriver = null) { string msg = message; AppendVarsInfoToDebugMessage(pawn, ref msg, concreteDriver); if (exception != null) { msg = msg + "\n" + exception; } Log.Error(msg); if (pawn.jobs == null) { return; } if (pawn.jobs.curJob != null) { pawn.jobs.EndCurrentJob(JobCondition.Errored, startNewJob: false); } if (startingErrorRecoverJob) { Log.Error("An error occurred while starting an error recover job. We have to stop now to avoid infinite loops. This means that the pawn is now jobless which can cause further bugs. pawn=" + pawn.ToStringSafe()); return; } startingErrorRecoverJob = true; try { pawn.jobs.StartJob(JobMaker.MakeJob(JobDefOf.Wait, 150)); } finally { startingErrorRecoverJob = false; } }
public static void TryStartErrorRecoverJob(Pawn pawn, string message, Exception exception = null, JobDriver concreteDriver = null) { string text = message; JobUtility.AppendVarsInfoToDebugMessage(pawn, ref text, concreteDriver); if (exception != null) { text = text + "\n" + exception; } Log.Error(text, false); if (pawn.jobs != null) { if (pawn.jobs.curJob != null) { pawn.jobs.EndCurrentJob(JobCondition.Errored, false); } if (JobUtility.startingErrorRecoverJob) { Log.Error("An error occurred while starting an error recover job. We have to stop now to avoid infinite loops. This means that the pawn is now jobless which can cause further bugs. pawn=" + pawn.ToStringSafe <Pawn>(), false); } else { JobUtility.startingErrorRecoverJob = true; try { pawn.jobs.StartJob(new Job(JobDefOf.Wait, 150, false), JobCondition.None, null, false, true, null, null, false); } finally { JobUtility.startingErrorRecoverJob = false; } } } }
public void StartJob(Job newJob, JobCondition lastJobEndCondition = JobCondition.None, ThinkNode jobGiver = null, bool resumeCurJobAfterwards = false, bool cancelBusyStances = true, ThinkTreeDef thinkTree = null, JobTag?tag = default(JobTag?), bool fromQueue = false) { this.startingNewJob = true; try { if (!fromQueue && (!Find.TickManager.Paused || this.lastJobGivenAtFrame == RealTime.frameCount)) { this.jobsGivenThisTick++; this.jobsGivenThisTickTextual = this.jobsGivenThisTickTextual + "(" + newJob.ToString() + ") "; } this.lastJobGivenAtFrame = RealTime.frameCount; if (this.jobsGivenThisTick > 10) { string text = this.jobsGivenThisTickTextual; this.jobsGivenThisTick = 0; this.jobsGivenThisTickTextual = string.Empty; this.startingNewJob = false; this.pawn.ClearReservationsForJob(newJob); this.StartErrorRecoverJob(this.pawn + " started 10 jobs in one tick. newJob=" + newJob + " jobGiver=" + jobGiver + " jobList=" + text); } else { PawnPosture posture = this.pawn.GetPosture(); LayingDownState layingDown = (this.pawn.jobs != null && this.pawn.jobs.curDriver != null) ? this.pawn.jobs.curDriver.layingDown : LayingDownState.NotLaying; if (this.debugLog) { this.DebugLogEvent("StartJob [" + newJob + "] lastJobEndCondition=" + lastJobEndCondition + ", jobGiver=" + jobGiver + ", cancelBusyStances=" + cancelBusyStances); } if (cancelBusyStances && this.pawn.stances.FullBodyBusy) { this.pawn.stances.CancelBusyStanceHard(); } if (this.curJob != null) { if (lastJobEndCondition == JobCondition.None) { Log.Warning(this.pawn + " starting job " + newJob + " from JobGiver " + this.pawn.mindState.lastJobGiver + " while already having job " + this.curJob + " without a specific job end condition."); lastJobEndCondition = JobCondition.InterruptForced; } if (resumeCurJobAfterwards && this.curJob.def.suspendable) { this.jobQueue.EnqueueFirst(this.curJob, null); if (this.debugLog) { this.DebugLogEvent(" JobQueue EnqueueFirst curJob: " + this.curJob); } this.CleanupCurrentJob(lastJobEndCondition, false, cancelBusyStances); } else { this.CleanupCurrentJob(lastJobEndCondition, true, cancelBusyStances); } } if (newJob == null) { Log.Warning(this.pawn + " tried to start doing a null job."); } else { newJob.startTick = Find.TickManager.TicksGame; if (this.pawn.Drafted || newJob.playerForced) { newJob.ignoreForbidden = true; newJob.ignoreDesignations = true; } this.curJob = newJob; this.pawn.mindState.lastJobGiver = jobGiver; this.pawn.mindState.lastJobGiverThinkTree = thinkTree; this.curDriver = this.curJob.MakeDriver(this.pawn); if (this.curDriver.TryMakePreToilReservations()) { if (tag.HasValue) { this.pawn.mindState.lastJobTag = tag.Value; } this.curDriver.Notify_Starting(); this.curDriver.Notify_LastPosture(posture, layingDown); this.curDriver.SetupToils(); this.curDriver.ReadyForNextToil(); } else if (fromQueue) { this.EndCurrentJob(JobCondition.QueuedNoLongerValid, true); } else { Log.Warning("TryMakePreToilReservations() returned false for a non-queued job right after StartJob(). This should have been checked before. curJob=" + this.curJob.ToStringSafe()); this.EndCurrentJob(JobCondition.Errored, true); } } } } finally { this.startingNewJob = false; } }