public void MappingFinished(Entity target, bool wasInterrupted) { previousPlans = currentPlans; previousPlanIndex = CurrentPlanIndex; if (wasInterrupted) { Debug.Log(agent.name + ":" + CurrentMapping.ToString() + " was interrupted and not completed"); currentPlans.statuses[CurrentPlanIndex] = Plans.Status.Interrupted; PreviousMapping = CurrentMapping; CurrentMapping = null; currentPlans = null; isActing = false; if (PreviousMapping.mappingType.actionType.noWaitOnInterrupt) { agent.RunEarly(); } } else if (CurrentMapping != null && CurrentPlanIndex != -1 && currentPlans.rootMappings.Count > CurrentPlanIndex) { Debug.Log(agent.name + ": " + CurrentMapping.ToString() + " on root mapping " + currentPlans.rootMappings[CurrentPlanIndex] + " has completed."); deciderType.MappingFinished(agent, CurrentMapping); // Move to the next mapping in the mapping tree PreviousMapping = CurrentMapping; CurrentMapping = CurrentMapping.NextMapping(); if (CurrentMapping == null) { Debug.Log(agent.name + ": Plan (" + currentPlans.rootMappings[CurrentPlanIndex] + ") Finished - Took " + (Time.time - PlanStartTime) + " seconds."); // Plan has completed currentPlans.statuses[CurrentPlanIndex] = Plans.Status.Finished; currentPlans = null; isActing = false; if (PreviousMapping.mappingType.actionType.noWaitOnFinishNoNextMapping) { agent.RunEarly(); } } else if (PreviousMapping.mappingType.actionType.noWaitOnFinishHasNextMapping) { Debug.Log("*********** RunEarly **************"); isActing = false; agent.RunEarly(); } else { isActing = false; } } else { isActing = false; } }
// What should agent do when they have no valid plans? public virtual Dictionary <DriveType, Plans> DefaultPlans(Agent agent, out DriveType currentDriveType, out Mapping newMapping) { if (agent.noneDriveType != null && agent.noPlansMappingType != null) { currentDriveType = agent.noneDriveType; newMapping = new Mapping(agent.noPlansMappingType) { isComplete = true }; Plans plans = new Plans(currentDriveType, newMapping) { statuses = new List <Plans.Status>() { Plans.Status.Complete } }; return(new Dictionary <DriveType, Plans>() { { currentDriveType, plans } }); } currentDriveType = null; newMapping = null; return(null); }
// Returns the rootMapping that has the highest utility out of all rootMappings that are complete (all leaves have all inputs) // Use force to allow plans with negative or zero drive rate changes protected virtual Mapping GetBestPlan(Agent agent, Plans plans, out float bestUtility, bool force = true) { // TODO: Move this to top of DeciderType - be nice to be able to set this in the TAI Settings bool verboseLogging = false; Mapping best = null; bestUtility = -1000; foreach (Mapping rootMapping in plans.GetCompletePlans()) { if (verboseLogging) { Debug.Log(agent.name + ": *** GetBestPlan checking " + rootMapping.mappingType.name + " ***"); } // Returns driveAmount, timeEst, sideEffectsUtility in the float array (only go through tree once) float[] planInfo = new float[3]; rootMapping.CalcUtilityInfoForTree(agent, plans.driveType, planInfo); float driveAmount = planInfo[0]; float timeEst = planInfo[1]; float sideEffectsUtility = planInfo[2]; //float driveAmount = rootMapping.CalcDriveChangeForTree(agent, plans.driveType); //float timeEst = rootMapping.CalcTimeToCompleteForTree(agent); //float sideEffectsUtility = rootMapping.CalcSideEffectsUtilityForTree(agent, plans.driveType); float utility = agent.utilityFunction.Evaluate(agent, rootMapping, plans.driveType, driveAmount, timeEst, sideEffectsUtility); // TODO: For logging - Maybe move this into UFT? Should this even be in Plans? int rootMappingIndex = plans.rootMappings.IndexOf(rootMapping); plans.driveAmountEstimates[rootMappingIndex] = driveAmount; plans.timeEstimates[rootMappingIndex] = timeEst; plans.sideEffectsUtility[rootMappingIndex] = sideEffectsUtility; plans.utility[rootMappingIndex] = utility; if (!force && driveAmount >= 0) { Debug.Log("DriveType change is greater than or equal to zero (" + driveAmount + ") - skipping it."); } else { if (utility > bestUtility) { best = rootMapping; bestUtility = utility; } } if (verboseLogging) { Debug.Log("Utility Score = " + utility); Debug.Log("Side Effects Utility = " + plans.sideEffectsUtility[rootMappingIndex]); Debug.Log("Time To Complete = " + plans.timeEstimates[rootMappingIndex]); Debug.Log("DriveType Reduction = " + plans.driveAmountEstimates[rootMappingIndex]); Debug.Log(agent.name + ": *** GetBestPlan done checking " + rootMapping.mappingType.name + " ***"); } } return(best); }
public virtual PlansLog FindPlansLogFromPlans(Agent agent, Plans plans) { int num = agentsPlansLogs[agent].Count; if (num == 0) { return(null); } return(agentsPlansLogs[agent].Find(x => x.allPlans.Values.Contains(plans))); }
private void StartPlan(DriveType selectedDriveType, int newPlanIndex, float newPlanUtility, Mapping newMapping) { // Starting new plan - either because there was no plan or it decided to change plans between actions CurrentDriveType = selectedDriveType; currentPlans = AllCurrentPlans[selectedDriveType]; PreviousMapping = CurrentMapping; CurrentMapping = newMapping; CurrentPlanIndex = newPlanIndex; currentPlanUtility = newPlanUtility; PlanStartTime = Time.time; currentPlans.statuses[CurrentPlanIndex] = Plans.Status.Running; // This is for the drive modifyBonus for continuing to reduce the same drive PreviousDriveType = CurrentDriveType; }
public virtual bool GetPlans(Agent agent, Plans previousPlans, int previousPlansIndex, bool previouslyInterrupted, out DriveType currentDriveType, out Dictionary <DriveType, float> currentDriveTypesRanked, out Dictionary <DriveType, Plans> allPlans) { currentDriveType = null; Plans currentPlans = null; // Find mapping for highest priority drive currentDriveTypesRanked = RankDrives(agent.ActiveDrives()); allPlans = new Dictionary <DriveType, Plans>(); foreach (DriveType driveType in currentDriveTypesRanked.Keys) { currentPlans = plannerTypes[0].CreatePlansForDriveType(agent, driveType, false); if (currentPlans == null) { return(false); } allPlans.Add(driveType, currentPlans); //Debug.Log(agent.name + ": GetPlans for " + driveType.name + " found " + currentPlans.rootMappings.Count + " plans."); // If there is at least one complete plan we quit early // TODO: Improve this - planner should mark the Plans statuses // TODO: Add a minimum utility threshold so it doesn't quit and go with a bad plan List <Mapping> excludeRootMappings = null; if (previouslyInterrupted && previousPlans != null) { excludeRootMappings = new List <Mapping>() { previousPlans.rootMappings[previousPlansIndex] } } ; if (currentPlans.GetCompletePlans(excludeRootMappings).Count > 0) { //Debug.Log(agent.name + ": GetPlans for " + driveType.name + " found a completed plan."); currentDriveType = driveType; return(true); } } return(false); }
public override bool GetPlans(Agent agent, Plans previousPlans, int previousPlansIndex, bool previouslyInterrupted, out DriveType currentDriveType, out Dictionary <DriveType, float> currentDriveTypesRanked, out Dictionary <DriveType, Plans> allPlans) { currentDriveType = defaultDriveType; currentDriveTypesRanked = new Dictionary <DriveType, float>() { { defaultDriveType, 1f } }; allPlans = new Dictionary <DriveType, Plans>(); Plans currentPlans = null; currentPlans = plannerTypes[0].CreatePlansForDriveType(agent, defaultDriveType, false); if (currentPlans == null) { return(false); } allPlans.Add(defaultDriveType, currentPlans); //Debug.Log(agent.name + ": GetPlans for " + driveType.name + " found " + currentPlans.rootMappings.Count + " plans."); List <Mapping> excludeRootMappings = null; if (previouslyInterrupted && previousPlans != null) { excludeRootMappings = new List <Mapping>() { previousPlans.rootMappings[previousPlansIndex] } } ; // TODO: Figure out the statuses mess - when should they be set? if (currentPlans.GetCompletePlans(excludeRootMappings).Count > 0) { return(true); } return(false); }
public Decider(Agent agent, DeciderType deciderType) { currentPlans = null; previousPlans = null; CurrentPlanIndex = -1; CurrentMapping = null; PreviousMapping = null; CurrentDriveType = null; isActing = false; previouslyInterrupted = false; lastReplanTime = 0; currentPlanUtility = -1000; animationEventCount = 0; this.agent = agent; this.deciderType = deciderType; if (deciderType != null) { deciderType.Setup(agent); } }
// Returns the rootMapping that has the highest utility out of all rootMappings that are complete (all leaves have all inputs) // Use force to allow plans with negative or zero drive rate changes protected override Mapping GetBestPlan(Agent agent, Plans plans, out float bestUtility, bool force = true) { // TODO: Move this to top of DeciderType - be nice to be able to set this in the TAI Settings bool verboseLogging = true; Mapping best = null; bestUtility = -1000; foreach (Mapping rootMapping in plans.rootMappings) { float utility = agent.utilityFunction.Evaluate(agent, rootMapping, plans.driveType, 0f, 0f, 0f); // TODO: For logging - Maybe move this into UFT? Should this even be in Plans? int rootMappingIndex = plans.rootMappings.IndexOf(rootMapping); plans.driveAmountEstimates[rootMappingIndex] = 0f; plans.timeEstimates[rootMappingIndex] = 0f; plans.sideEffectsUtility[rootMappingIndex] = 0f; plans.utility[rootMappingIndex] = utility; if (!force && utility <= 0) { Debug.Log("UtilityAIPT.GetBestPlan for " + rootMapping.mappingType.name + " - Utility is <= 0 (" + utility + ") - skipping it."); } else { if (utility > bestUtility) { best = rootMapping; bestUtility = utility; } if (verboseLogging) { Debug.Log("UtilityAIPT.GetBestPlan for " + rootMapping.mappingType.name + " - Utility Score = " + utility); } } } return(best); }
// TODO: Are agent.isAlive checks needed? public void Run() { // Everytime decider runs it can do nothing, check to see if it should switch plans, or if doing nothing start a plan float lastPlannedAt = lastReplanTime; if (isActing && !previouslyInterrupted && deciderType.ShouldInterrupt(agent, CurrentMapping, CurrentDriveType, currentPlanUtility, lastReplanTime, out lastPlannedAt)) { // End Action and then plan next time - this allows action to end before starting new plan InterruptMapping(false); // This will allow decider to not choose the same Mapping next time around previouslyInterrupted = true; return; } else if (!isActing && deciderType.ShouldPlan(CurrentMapping)) { lastPlannedAt = Time.time; System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew(); bool foundCompletedPlan = deciderType.GetPlans(agent, previousPlans, previousPlanIndex, previouslyInterrupted, out DriveType selectedDriveType, out currentDriveTypesRanked, out Dictionary <DriveType, Plans> plans); AllCurrentPlans = plans; watch.Stop(); long timeToPlan = watch.ElapsedMilliseconds; // If no current plan see if there is a default (idle) plan if (selectedDriveType == null && currentPlans == null) { PreviousDriveType = null; // TODO: Put this in to prevent AllCurrentPlans from getting wiped for the Tree Plan Editor if (agent.noPlansMappingType != null) { AllCurrentPlans = deciderType.DefaultPlans(agent, out selectedDriveType, out Mapping newMapping); if (selectedDriveType != null && newMapping != null) { StartPlan(selectedDriveType, 0, 0, newMapping); } } } else if (selectedDriveType != null) { int newPlanIndex = -1; float newPlanUtility; Mapping newMapping = null; if (currentPlans != null) { // TODO: Change plans when between Mappings of a plan - this is NOT TESTED - deciderType.ShouldPlan never does this newPlanIndex = deciderType.MaybeChangePlan(agent, CurrentMapping, selectedDriveType, AllCurrentPlans, timeToPlan, out selectedDriveType, out newMapping, out newPlanUtility); } else { newPlanIndex = deciderType.ChooseNewPlan(agent, CurrentMapping, selectedDriveType, AllCurrentPlans, timeToPlan, out selectedDriveType, out newMapping, out newPlanUtility); } if (newPlanIndex != -1) { StartPlan(selectedDriveType, newPlanIndex, newPlanUtility, newMapping); } else { // Unable to find anything to do - do default MappingType PreviousDriveType = null; // TODO: Put this in to prevent AllCurrentPlans from getting wiped for the Tree Plan Editor if (agent.noPlansMappingType != null) { AllCurrentPlans = deciderType.DefaultPlans(agent, out selectedDriveType, out Mapping defaultMapping); if (selectedDriveType != null && defaultMapping != null) { StartPlan(selectedDriveType, 0, 0, defaultMapping); } } } } previouslyInterrupted = false; } lastReplanTime = lastPlannedAt; if (CurrentMapping != null && !isActing) { // Don't need to recheck conditions if we just started plan if (PlanStartTime == Time.time || deciderType.RecheckInputConditions(agent, CurrentMapping)) { // See if we want to revaluate the current targets before maybe adding a GoTo and starting the Mapping deciderType.ReevaluateTargets(agent, CurrentMapping); // Adds a GoTo Mapping child if needed CurrentMapping = deciderType.MaybeAddGoToMapping(agent, CurrentMapping); // TODO: This currently always returns true - can it ever return false? isActing = deciderType.StartMapping(agent, CurrentMapping); if (isActing) { mappingStartTime = Time.time; // Will return an empty Dictionary if there are no Repeating and no AfterGameMinutesOCs lastUpdateTimes = CurrentMapping.mappingType.InitLastUpdateTimes(); animationEventCount = 0; } else { Debug.Log(agent.name + ": deciderType.StartAction - Failed: " + CurrentMapping); } } else { // Recheck IC failed currentPlans.SetSelectedPlanStatus(Plans.Status.Interrupted, CurrentPlanIndex); currentPlans = null; PreviousMapping = CurrentMapping; CurrentMapping = null; } } }
public override PlansLog FindPlansLogFromPlans(Agent agent, Plans plans) { return(null); }
// This allows plannerTypes to save chosen Mapping when Decider Interrupts public abstract void NotifyOfInterrupt(Agent agent, Plans plans, Mapping rootMapping);