public UnitCluster(double p_Dist, CacheUnit unit) : base(p_Dist, unit) { ListUnits = new List<CacheUnit>(); ListUnits.Add(unit); NearestMonsterDistance = unit.CentreDistance; Info = new ClusterInfo(); Info.Update(ref unit); }
public void Update(ref CacheUnit unit, bool refreshproperties = false) { UnitCounter++; if (unit.UnitMaxHitPointAverageWeight < 0) WeakCounter++; else if (unit.UnitMaxHitPointAverageWeight > 0) StrongCounter++; if (unit.IsEliteRareUnique) ElitesCounter++; else if (unit.IsBoss) BossCounter++; if (unit.IsFast) FastCounter++; if (unit.IsRanged) RangedCounter++; if (Bot.Targeting.Cache.Environment.UsesDOTDPSAbility && unit.HasDOTdps.HasValue && unit.HasDOTdps.Value) DOTDPSCounter++; if (refreshproperties) UpdateProperties(); }
///<summary> ///Resets/Updates cache and misc vars ///</summary> private void InitObjectRefresh() { //Cache last target only if current target is not avoidance (Movement). LastCachedTarget = CurrentTarget != null ? CurrentTarget : ObjectCache.FakeCacheObject; if (CurrentTarget != null && CurrentTarget.targetType.HasValue && ObjectCache.CheckTargetTypeFlag(CurrentTarget.targetType.Value, TargetType.AvoidanceMovements)) { if (CurrentTarget.targetType.Value == TargetType.Fleeing) { LastFleeAction = DateTime.Now; FleeingLastTarget = true; } else { LastAvoidanceMovement = DateTime.Now; AvoidanceLastTarget = true; } } else { FleeingLastTarget = false; AvoidanceLastTarget = false; } //Traveling Flag Reset TravellingAvoidance = false; //Reset target CurrentTarget = null; CurrentUnitTarget = null; //Kill Loot Radius Update UpdateKillLootRadiusValues(); // Refresh buffs (so we can check for wrath being up to ignore ice balls and anything else like that) Bot.Character.Class.HotBar.RefreshHotbarBuffs(); // Bunch of variables used throughout Bot.Character.Data.PetData.Reset(); // Reset the counters for monsters at various ranges Environment.Reset(); //Check if we should trim our SNO cache.. if (DateTime.Now.Subtract(ObjectCache.cacheSnoCollection.lastTrimming).TotalMilliseconds > Bot.Settings.Plugin.UnusedSNORemovalRate) ObjectCache.cacheSnoCollection.TrimOldUnusedEntries(); //Check Cached Object Removal flag if (RemovalCheck) { //Remove flagged objects var RemovalObjs = (from objs in ObjectCache.Objects.Values where objs.NeedsRemoved select objs.RAGUID).ToList(); foreach (var item in RemovalObjs) { CacheObject thisObj = ObjectCache.Objects[item]; //remove prioritized raguid if (Bot.NavigationCache.PrioritizedRAGUIDs.Contains(item)) Bot.NavigationCache.PrioritizedRAGUIDs.Remove(item); //Blacklist flag check if (thisObj.BlacklistFlag != BlacklistType.None) BlacklistCache.AddObjectToBlacklist(thisObj.RAGUID, thisObj.BlacklistFlag); ObjectCache.Objects.Remove(thisObj.RAGUID); } RemovalCheck = false; } //Increase counter, clear entries if overdue. ObjectCache.Obstacles.AttemptToClearEntries(); //Non-Combat behavior we reset temp blacklist so we don't get killed by "ignored" units.. if (Bot.IsInNonCombatBehavior) BlacklistCache.CheckRefreshBlacklists(10); //Check Gold Inactivity Bot.Game.GoldTimeoutChecker.CheckTimeoutTripped(); }
internal void OnTargetChanged(TargetChangedArgs e) { Logger.Write(LogLevel.Target, "Changed Object: {0}", MakeStringSingleLine(e.newObject.DebugString)); LastChangeOfTarget = DateTime.Now; if (Bot.Settings.EnableWaitAfterContainers && CurrentTarget.targetType == TargetType.Container) { //Herbfunks delay for container loot. lastHadContainerAsTarget = DateTime.Now; if (CurrentTarget.IsResplendantChest) lastHadRareChestAsTarget = DateTime.Now; } // We're sticking to the same target, so update the target's health cache to check for stucks if (CurrentTarget.targetType == TargetType.Unit) { CurrentUnitTarget = (CacheUnit)CurrentTarget; //Used to pause after no targets found. lastHadUnitInSights = DateTime.Now; // And record when we last saw any form of elite if (CurrentUnitTarget.IsBoss || CurrentUnitTarget.IsEliteRareUnique || CurrentUnitTarget.IsTreasureGoblin) lastHadEliteUnitInSights = DateTime.Now; } bWholeNewTarget = true; bPickNewAbilities = true; TargetChangeHandler handler = TargetChanged; if (handler != null) { handler(this, e); } }
internal static TargetProperties EvaluateUnitProperties(CacheUnit unit) { TargetProperties properties=TargetProperties.None; if (unit.IsBoss) properties|=TargetProperties.Boss; if (unit.IsBurrowableUnit) properties|=TargetProperties.Burrowing; if (unit.MonsterMissileDampening) properties|=TargetProperties.MissileDampening; if (unit.IsMissileReflecting) properties|=TargetProperties.MissileReflecting; if (unit.MonsterShielding) properties|=TargetProperties.Shielding; if (unit.IsStealthableUnit) properties|=TargetProperties.Stealthable; if (unit.IsSucideBomber) properties|=TargetProperties.SucideBomber; if (unit.IsTreasureGoblin) properties|=TargetProperties.TreasureGoblin; if (unit.IsFast) properties|=TargetProperties.Fast; if (unit.IsEliteRareUnique) properties|=TargetProperties.RareElite; if (unit.MonsterUnique) properties|=TargetProperties.Unique; if (unit.ObjectIsSpecial) properties|=TargetProperties.IsSpecial; if (unit.CurrentHealthPct.HasValue&&unit.CurrentHealthPct.Value==1d) properties|=TargetProperties.FullHealth; if (unit.UnitMaxHitPointAverageWeight<0) properties|=TargetProperties.Weak; if (unit.IsRanged) properties|=TargetProperties.Ranged; if (unit.IsTargetableAndAttackable) properties|=TargetProperties.TargetableAndAttackable; if (unit.HasDOTdps.HasValue&&unit.HasDOTdps.Value) properties|=TargetProperties.DOTDPS; if (unit.RadiusDistance<10f) properties|=TargetProperties.CloseDistance; if (unit.MonsterReflectDamage) properties|=TargetProperties.ReflectsDamage; if (unit.MonsterElectrified) properties |= TargetProperties.Electrified; if (unit.MonsterNormal) properties |= TargetProperties.Normal; return properties; }
///<summary> ///Adds/Updates CacheObjects inside collection by Iteration of RactorList ///This is the method that caches all live data about an object! ///</summary> internal static bool UpdateCacheObjectCollection() { HashSet<int> hashDoneThisRactor = new HashSet<int>(); using (ZetaDia.Memory.AcquireFrame(true)) { if (!ZetaDia.IsInGame || ZetaDia.IsLoadingWorld || !ZetaDia.Me.IsValid) return false; foreach (Actor thisActor in ZetaDia.Actors.RActorList) { int tmp_raGUID; DiaObject thisObj; if (!thisActor.IsValid) continue; //Convert to DiaObject thisObj = (DiaObject)thisActor; tmp_raGUID = thisObj.RActorGuid; // See if we've already checked this ractor, this loop if (hashDoneThisRactor.Contains(tmp_raGUID)) continue; hashDoneThisRactor.Add(tmp_raGUID); //Update RactorGUID and check blacklisting.. if (BlacklistCache.IsRAGUIDBlacklisted(tmp_raGUID)) continue; CacheObject tmp_CachedObj; if (!Objects.TryGetValue(tmp_raGUID, out tmp_CachedObj)) { Vector3 tmp_position; int tmp_acdguid; int tmp_SNOID; #region SNO //Lookup SNO try { tmp_SNOID = thisObj.ActorSNO; } catch (NullReferenceException) { //Logger.DBLog.InfoFormat("Failure to get SNO from object! RaGUID: {0}", tmp_raGUID); continue; } #endregion //check our SNO blacklist if (BlacklistCache.IsSNOIDBlacklisted(tmp_SNOID) && !CacheIDLookup.hashSummonedPets.Contains(tmp_SNOID)) continue; #region Position try { tmp_position = thisObj.Position; } catch (NullReferenceException) { //Logger.DBLog.InfoFormat("Failure to get position vector for RAGUID {0}", tmp_raGUID); continue; } #endregion #region AcdGUID try { tmp_acdguid = thisObj.ACDGuid; } catch (NullReferenceException) { //Logger.DBLog.InfoFormat("Failure to get ACDGUID for RAGUID {0}", tmp_raGUID); continue; } #endregion tmp_CachedObj = new CacheObject(tmp_SNOID, tmp_raGUID, tmp_acdguid, tmp_position); } else //Reset unseen var tmp_CachedObj.LoopsUnseen = 0; //Validate try { if (thisObj.CommonData == null || thisObj.CommonData.ACDGuid != thisObj.ACDGuid) continue; } catch (NullReferenceException) { continue; } //Check if this object is a summoned unit by a player... #region SummonedUnits if (tmp_CachedObj.IsSummonedPet) { // Get the summoned-by info, cached if possible if (!tmp_CachedObj.SummonerID.HasValue) { try { tmp_CachedObj.SummonerID = thisObj.CommonData.GetAttribute<int>(ActorAttributeType.SummonedByACDID); } catch (Exception ex) { //Logger.DBLog.InfoFormat("[Funky] Safely handled exception getting summoned-by info [" + tmp_CachedObj.SNOID.ToString(CultureInfo.InvariantCulture) + "]"); //Logger.DBLog.DebugFormat(ex.ToString()); continue; } } //See if this summoned unit was summoned by the bot. if (Bot.Character.Data.iMyDynamicID == tmp_CachedObj.SummonerID.Value) { //Now modify the player data pets count.. if (Bot.Character.Class.AC == ActorClass.Monk) Bot.Character.Data.PetData.MysticAlly++; else if (Bot.Character.Class.AC == ActorClass.DemonHunter) { if (CacheIDLookup.hashDHPets.Contains(tmp_CachedObj.SNOID)) Bot.Character.Data.PetData.DemonHunterPet++; else if (CacheIDLookup.hashDHSpikeTraps.Contains(tmp_CachedObj.SNOID) && tmp_CachedObj.CentreDistance <= 50f) Bot.Character.Data.PetData.DemonHunterSpikeTraps++; } else if (Bot.Character.Class.AC == ActorClass.Witchdoctor) { if (CacheIDLookup.hashZombie.Contains(tmp_CachedObj.SNOID)) Bot.Character.Data.PetData.ZombieDogs++; else if (CacheIDLookup.hashGargantuan.Contains(tmp_CachedObj.SNOID)) Bot.Character.Data.PetData.Gargantuan++; } else if (Bot.Character.Class.AC == ActorClass.Wizard) { //only count when range is within 45f (so we can summon a new one) if (CacheIDLookup.hashWizHydras.Contains(tmp_CachedObj.SNOID) && tmp_CachedObj.CentreDistance <= 45f) Bot.Character.Data.PetData.WizardHydra++; } } //We return regardless if it was summoned by us or not since this object is not anything we want to deal with.. tmp_CachedObj.NeedsRemoved = true; continue; } #endregion //Update any SNO Data. #region SNO_Cache_Update if (tmp_CachedObj.ref_DiaObject == null || tmp_CachedObj.ContainsNullValues()) { if (!tmp_CachedObj.UpdateData(thisObj, tmp_CachedObj.RAGUID)) continue; } else if (!tmp_CachedObj.IsFinalized) {//Finalize this data by recreating it and updating the Sno cache with a new finalized entry, this also clears our all Sno cache dictionaries since we no longer need them! cacheSnoCollection.FinalizeEntry(tmp_CachedObj.SNOID); } #endregion //Special Cache for Interactable Server Objects if (CheckTargetTypeFlag(tmp_CachedObj.targetType.Value, TargetType.ServerInteractable)) { if (!Bot.Game.Profile.InteractableObjectCache.ContainsKey(tmp_CachedObj.RAGUID)) { Bot.Game.Profile.InteractableObjectCache.Add(tmp_CachedObj.RAGUID, tmp_CachedObj); } //Do not add to main cache! continue; } //Objects with static positions already cached don't need to be updated here. if (!tmp_CachedObj.NeedsUpdate) continue; //Obstacles -- (Not an actual object we add to targeting.) if (CheckTargetTypeFlag(tmp_CachedObj.targetType.Value, TargetType.Avoidance) || tmp_CachedObj.IsObstacle || tmp_CachedObj.HandleAsAvoidanceObject) { #region Obstacles CacheObstacle thisObstacle; //Do we have this cached? if (!Obstacles.TryGetValue(tmp_CachedObj.RAGUID, out thisObstacle)) { AvoidanceType AvoidanceType = AvoidanceType.None; if (tmp_CachedObj.IsAvoidance) { AvoidanceType = AvoidanceCache.FindAvoidanceUsingSNOID(tmp_CachedObj.SNOID); if (AvoidanceType == AvoidanceType.None) { AvoidanceType = AvoidanceCache.FindAvoidanceUsingName(tmp_CachedObj.InternalName); if (AvoidanceType == AvoidanceType.None) continue; } } if (tmp_CachedObj.IsAvoidance && tmp_CachedObj.IsProjectileAvoidance) {//Ranged Projectiles require more than simple bounding points.. so we create it as avoidance zone to cache it with properties. //Check for intersection.. try { ActorMovement thisMovement = thisObj.Movement; Vector2 Direction = thisMovement.DirectionVector; Ray R = new Ray(tmp_CachedObj.Position, Direction.ToVector3()); double Speed; //Lookup Cached Speed, or add new entry. if (!dictProjectileSpeed.TryGetValue(tmp_CachedObj.SNOID, out Speed)) { Speed = thisMovement.DesiredSpeed; dictProjectileSpeed.Add(tmp_CachedObj.SNOID, Speed); } thisObstacle = new CacheAvoidance(tmp_CachedObj, AvoidanceType, R, Speed); Obstacles.Add(thisObstacle); } catch { Logger.Write(LogLevel.Cache, "Failed to create projectile avoidance with rotation and speed. {0}", tmp_CachedObj.InternalName); } } else if (tmp_CachedObj.IsAvoidance) { //Poison Gas Can Be Friendly... if (AvoidanceType == AvoidanceType.PoisonGas) { int TeamID = 0; try { TeamID = thisObj.CommonData.GetAttribute<int>(ActorAttributeType.TeamID); } catch { Logger.Write(LogLevel.Cache, "Failed to retrieve TeamID attribute for object {0}", thisObstacle.InternalName); } //ID of 1 means its non-hostile! (-1?) 2?? //if (TeamID==1||TeamID==-1) if (TeamID != 10) { //Logger.Write(LogLevel.None, "Ignoring Avoidance {0} due to Friendly TeamID match!", tmp_CachedObj.InternalName); BlacklistCache.AddObjectToBlacklist(tmp_CachedObj.RAGUID, BlacklistType.Permanent); continue; } } thisObstacle = new CacheAvoidance(tmp_CachedObj, AvoidanceType); Obstacles.Add(thisObstacle); } else { //Obstacles. thisObstacle = new CacheServerObject(tmp_CachedObj); Obstacles.Add(thisObstacle); } } continue; #endregion } if (tmp_CachedObj.ObjectShouldBeRecreated) { //Specific updates if (tmp_CachedObj.Actortype.Value == ActorType.Item) { tmp_CachedObj = new CacheItem(tmp_CachedObj); } else if (tmp_CachedObj.Actortype.Value == ActorType.Monster) { tmp_CachedObj = new CacheUnit(tmp_CachedObj); } else if (tmp_CachedObj.Actortype.Value == ActorType.Gizmo) { if (CheckTargetTypeFlag(tmp_CachedObj.targetType.Value, TargetType.Interactables)) tmp_CachedObj = new CacheInteractable(tmp_CachedObj); else tmp_CachedObj = new CacheDestructable(tmp_CachedObj); } //Update Properties tmp_CachedObj.UpdateProperties(); } if (!tmp_CachedObj.UpdateData()) { if (!tmp_CachedObj.IsStillValid()) tmp_CachedObj.NeedsRemoved = true; continue; } //Obstacle cache if (tmp_CachedObj.Obstacletype.Value != ObstacleType.None && (CheckTargetTypeFlag(tmp_CachedObj.targetType.Value, TargetType.ServerObjects))) { CacheObstacle thisObstacleObj; if (!Obstacles.TryGetValue(tmp_CachedObj.RAGUID, out thisObstacleObj)) { CacheServerObject newobj = new CacheServerObject(tmp_CachedObj); Obstacles.Add(tmp_CachedObj.RAGUID, newobj); //Add nearby objects to our collection (used in navblock/obstaclecheck methods to reduce queries) if (CacheIDLookup.hashSNONavigationObstacles.Contains(newobj.SNOID)) Navigation.MGP.AddCellWeightingObstacle(newobj.SNOID, newobj.Radius); } else { if (thisObstacleObj.targetType.Value == TargetType.Unit) { //Since units position requires updating, we update using the CacheObject thisObstacleObj.Position = tmp_CachedObj.Position; Obstacles[tmp_CachedObj.RAGUID] = thisObstacleObj; } } } //cache it if (Objects.ContainsKey(tmp_CachedObj.RAGUID)) Objects[tmp_CachedObj.RAGUID] = tmp_CachedObj; else Objects.Add(tmp_CachedObj.RAGUID, tmp_CachedObj); } //End of Loop }// End of Framelock //Tally up unseen objects. var UnseenObjects = Objects.Keys.Where(O => !hashDoneThisRactor.Contains(O)).ToList(); if (UnseenObjects.Any()) { for (int i = 0; i < UnseenObjects.Count(); i++) { Objects[UnseenObjects[i]].LoopsUnseen++; } } //Trim our collection every 5th refresh. UpdateLoopCounter++; if (UpdateLoopCounter > 4) { UpdateLoopCounter = 0; //Now flag any objects not seen for 5 loops. Gold/Globe only 1 loop. foreach (var item in Objects.Values.Where(CO => (CO.LoopsUnseen >= 5 || //5 loops max.. (CO.targetType.HasValue && (CheckTargetTypeFlag(CO.targetType.Value, TargetType.Gold | TargetType.Globe)) && CO.LoopsUnseen > 0)))) //gold/globe only 1 loop! { item.NeedsRemoved = true; } } return true; }
internal List<Skill> ReturnAllUsableAbilities(CacheUnit obj, bool IgnoreOutOfRange = false) { //Reset default attack can use CanUseDefaultAttack = !Abilities.ContainsKey(DefaultAttack.Power) ? false : true; ConditionCriteraTypes criterias = ConditionCriteraTypes.All; //Although the unit is a cluster exception.. we should verify it is not a clustered object. if (obj.IsClusterException && obj.BeingIgnoredDueToClusterLogic) { criterias = ConditionCriteraTypes.SingleTarget; } List<Skill> UsableAbilities = new List<Skill>(); foreach (var item in SortedAbilities) { //Check precast conditions if (!item.CheckPreCastConditionMethod()) continue; //Check Combat Conditions! if (!item.CheckCombatConditionMethod(criterias)) { continue; } //Check if we can execute or if it requires movement if (IgnoreOutOfRange) { if (item.DestinationVector != Bot.Character.Data.Position) continue; } Skill ability = item; Skill.SetupAbilityForUse(ref ability); UsableAbilities.Add(ability); } return UsableAbilities; }
///<summary> ///Sets criteria based on object given. ///</summary> internal virtual Skill AbilitySelector(CacheUnit obj, bool IgnoreOutOfRange = false) { //Reset default attack can use CanUseDefaultAttack = !HotBar.HotbarPowers.Contains(DefaultAttack.Power) ? false : true; //Reset waiting for special! bWaitingForSpecial = false; ConditionCriteraTypes criterias = ConditionCriteraTypes.All; //Although the unit is a cluster exception.. we should verify it is not a clustered object. if (obj.IsClusterException && obj.BeingIgnoredDueToClusterLogic) { criterias = ConditionCriteraTypes.SingleTarget; } return AbilitySelector(criterias, IgnoreOutOfRange); }
private void UpdateProperties(CacheUnit unit) { float distance = unit.CentreDistance; if (distance < this.NearestMonsterDistance) this.NearestMonsterDistance = distance; Info.Update(ref unit, true); }
private bool ContainsUnit(CacheUnit unit) { bool u_Exists = false; if (base.RAGUIDS.Contains(unit.RAGUID)) u_Exists = true; return u_Exists; }