///<summary> ///Checks if the position is total blocked from adjacent movements either by objects or non navigation ///</summary> private bool IsVectorBlocked(Vector3 location) { //Reset Navigationally Blocked GPs LastNavigationBlockedPoints = new List <GridPoint>(); //Create Local GPRect! if (LastUsedBlockCheckGPRect == null || LastUsedBlockCheckGPRect.centerpoint != (GridPoint)location) { //Clear lists LastObjectblockCounter.Clear(); LastObjectOccupiedGridPoints.Clear(); LastUsedBlockCheckGPRect = new GPRectangle(location); } if (LastUsedBlockCheckGPRect.Count == 0) { //Logger.DBLog.DebugFormat("Current Location GP Rect has no valid Grid Points!"); return(false); } GridPoint[] CurrentLocationGridPoints = LastUsedBlockCheckGPRect.Keys.ToArray(); List <GridPoint> SurroundingPoints = new List <GridPoint>(); int SurroundingMaxCount = LastUsedBlockCheckGPRect.Count >= 8 ? 8 : LastUsedBlockCheckGPRect.Count; for (int i = 0; i < SurroundingMaxCount; i++) { GridPoint gp = CurrentLocationGridPoints[i]; if (!gp.Ignored) { SurroundingPoints.Add(gp); } else { LastNavigationBlockedPoints.Add(gp); } } List <int> NearbyObjectRAGUIDs = new List <int>(); List <CacheServerObject> NearbyObjects = FunkyGame.Targeting.Cache.Environment.NearbyObstacleObjects.Where(obj => obj.RadiusDistance <= 6f).ToList(); //ObjectCache.Obstacles.Navigations.Where(obj => obj.RadiusDistance<=5f).ToList(); //no nearby objects passed distance check.. if (NearbyObjects.Count == 0) { //Clear list, and return pure navigational check (Zero means we are completely stuck in a non-navigable location?) LastObjectblockCounter.Clear(); LastObjectOccupiedGridPoints.Clear(); //Logger.DBLog.InfoFormat("Current Location Point has {0} usable points (NoNewObjs)", SurroundingPoints.Count); return(SurroundingPoints.Count == 0); } //Update ObjectBlockCounter Collection if (LastObjectblockCounter.Count > 0) { //Add current nearby object RAGUIDs to collection NearbyObjectRAGUIDs.AddRange((from objs in NearbyObjects select objs.RAGUID).ToArray()); //Generate Removal List for ObjectBlockCounter Collections List <int> RemovalRAGUIDList = (from raguids in LastObjectblockCounter.Keys where !NearbyObjectRAGUIDs.Contains(raguids) select raguids).ToList(); //Removal foreach (var item in RemovalRAGUIDList) { LastObjectblockCounter.Remove(item); LastObjectOccupiedGridPoints.Remove(item); } } //Check any exisiting block entries if (LastObjectblockCounter.Count > 0) { foreach (var item in LastObjectOccupiedGridPoints.Values) { LastNavigationBlockedPoints.AddRange(item); } //Update Surrounding Points SurroundingPoints = SurroundingPoints.Except(LastNavigationBlockedPoints).ToList(); if (SurroundingPoints.Count == 0) { //Logger.DBLog.InfoFormat("NavBlocked -- No available surrounding points."); return(true); } } //Generate new object list that contains objects that are not already accounted for List <CacheServerObject> NewObjects = NearbyObjects.Where(obj => !LastObjectblockCounter.ContainsKey(obj.RAGUID) || LastObjectblockCounter[obj.RAGUID] < 4).ToList(); //No new objects to test.. if (NewObjects.Count == 0) { //Logger.DBLog.InfoFormat("No new Objects Unaccounted"); return(SurroundingPoints.Count == 0); } foreach (GridPoint item in SurroundingPoints) { //Find any objects that contain this GP CacheServerObject[] ContainedObjs = NewObjects.Where(Obj => Obj.PointInside(item) && //only objects that have hit there maximum block count. (!LastObjectblockCounter.ContainsKey(Obj.RAGUID) || Math.Round(Obj.PointRadius) < LastObjectblockCounter[Obj.RAGUID])).ToArray(); if (ContainedObjs.Length > 0) { //if (ContainedObjs.Length > 1 && FunkyBaseExtension.Settings.Debugging.FunkyLogFlags.HasFlag(LogLevel.Movement)) //Logger.DBLog.InfoFormat("Multiple Objects Found Occuping Grid Point!"); CacheServerObject ThisObjBlocking = ContainedObjs[0]; int ObjRAGUID = ThisObjBlocking.RAGUID; if (LastObjectblockCounter.ContainsKey(ObjRAGUID)) { int GPCount = LastObjectOccupiedGridPoints[ObjRAGUID].Length; LastObjectblockCounter[ObjRAGUID]++; GridPoint[] newArrayGPs = new GridPoint[GPCount]; LastObjectOccupiedGridPoints[ObjRAGUID].CopyTo(newArrayGPs, 0); newArrayGPs[GPCount - 1] = item.Clone(); LastObjectOccupiedGridPoints[ObjRAGUID] = newArrayGPs; } else { LastObjectblockCounter.Add(ObjRAGUID, 1); GridPoint[] NewArrayGP = new GridPoint[1] { item.Clone() }; LastObjectOccupiedGridPoints.Add(ObjRAGUID, NewArrayGP); } LastNavigationBlockedPoints.Add(item); } } //Update Surrounding Points SurroundingPoints = SurroundingPoints.Except(LastNavigationBlockedPoints).ToList(); //Logger.DBLog.InfoFormat("Current Location Point has {0} usable points", SurroundingPoints.Count); return(SurroundingPoints.Count == 0); }
// ///<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() { //Update Character (just incase it wasnt called before..) FunkyGame.Hero.Update(false, true); Obstacles.AttemptToClearEntries(); 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)) { ActorType Actortype; Vector3 tmp_position; int tmp_acdguid; int tmp_SNOID; #region SNO //Lookup SNO try { tmp_SNOID = thisObj.ActorSNO; } catch (Exception ex) { Logger.Write(LogLevel.Cache, "Safely handled getting SNO for {0}", tmp_raGUID); //Logger.DBLog.InfoFormat("Failure to get SNO from object! RaGUID: {0}", tmp_raGUID); continue; } #endregion //check our SNO blacklist (exclude pets?) if (BlacklistCache.IsSNOIDBlacklisted(tmp_SNOID)) { continue; } #region Position try { tmp_position = thisObj.Position; } catch (Exception ex) { Logger.Write(LogLevel.Cache, "Safely handled getting Position for {0}", tmp_SNOID); continue; } #endregion #region AcdGUID try { tmp_acdguid = thisObj.ACDGuid; } catch (Exception ex) { Logger.Write(LogLevel.Cache, "Safely handled getting ACDGuid for {0}", tmp_SNOID); continue; } #endregion tmp_CachedObj = new CacheObject(tmp_SNOID, tmp_raGUID, tmp_acdguid, tmp_position); } else { //Reset unseen var tmp_CachedObj.LoopsUnseen = 0; } ////Validate (ignore special object SNO Ids) //if (!CacheIDLookup.hashSNOSkipCommonDataCheck.Contains(tmp_CachedObj.SNOID)) //{ // try // { // if (thisObj.CommonData == null) // { // Logger.Write(LogLevel.Cache, "CommonData is no longer valid! {0}", tmp_CachedObj.DebugStringSimple); // //BlacklistCache.AddObjectToBlacklist(tmp_CachedObj.RAGUID, BlacklistType.Temporary); // continue; // } // if (thisObj.CommonData.ACDGuid != thisObj.ACDGuid) // { // Logger.Write(LogLevel.Cache, "ACDGuid Mismatched! {0}", tmp_CachedObj.DebugStringSimple); // //BlacklistCache.AddObjectToBlacklist(tmp_CachedObj.RAGUID, BlacklistType.Temporary); // continue; // } // } // catch (Exception ex) // { // //Logger.Write(LogLevel.Cache, "Object is no longer valid! (Exception) SNOID {0}", tmp_CachedObj.DebugStringSimple); // //BlacklistCache.AddObjectToBlacklist(tmp_CachedObj.RAGUID, BlacklistType.Temporary); // continue; // } //} //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 //Check if this object is a summoned unit by a player... #region SummonedUnits if (tmp_CachedObj.IsSummonedPet && CacheIDLookup.hashSNOSkipCommonDataCheck.Contains(tmp_CachedObj.SNOID)) { PetTypes PetType = (PetTypes)TheCache.ObjectIDCache.UnitPetEntries[tmp_CachedObj.SNOID].ObjectType; if (PetType == PetTypes.WIZARD_ArcaneOrbs) { FunkyGame.Targeting.Cache.Environment.HeroPets.WizardArcaneOrbs++; tmp_CachedObj.NeedsRemoved = true; continue; } } #endregion //Special Cache for Interactable Server Objects if (CheckFlag(tmp_CachedObj.targetType.Value, TargetType.ServerInteractable)) { if (!InteractableObjectCache.ContainsKey(tmp_CachedObj.RAGUID)) { InteractableObjectCache.Add(tmp_CachedObj.RAGUID, tmp_CachedObj); //Adventure Mode -- Rifting we add Exit to LOS movement! //if (FunkyGame.AdventureMode && FunkyGame.Bounty.IsInRiftWorld && FunkyBaseExtension.Settings.AdventureMode.EnableAdventuringMode) //{ // if (tmp_CachedObj.InternalName.Contains("Exit")) // { // int index = FunkyGame.Bounty.CurrentBountyMapMarkers.Count; // FunkyGame.Bounty.CurrentBountyMapMarkers.Add(index, new BountyCache.BountyMapMarker(tmp_CachedObj.Position, FunkyGame.Hero.CurrentWorldDynamicID, index)); // } //} } //Whymsdal Portal! if (tmp_CachedObj.SNOID == 405590) { GoblinBehavior.Portal = tmp_CachedObj; } else if (tmp_CachedObj.SNOID == 393030) { GoblinBehavior.Portal = 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 (CheckFlag(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}", tmp_CachedObj.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) { //This is where we create the real object after its done with SNO Update. //Specific updates if (tmp_CachedObj.Actortype.Value == ActorType.Item) { tmp_CachedObj = new CacheItem(tmp_CachedObj); } else if (tmp_CachedObj.Actortype.Value == ActorType.Monster) { if (!tmp_CachedObj.IsSummonedPet) { tmp_CachedObj = new CacheUnit(tmp_CachedObj); } else { PetTypes PetType = (PetTypes)TheCache.ObjectIDCache.UnitPetEntries[tmp_CachedObj.SNOID].ObjectType; #region Summoner ID Check // 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; } } if (FunkyGame.Hero.iMyDynamicID != tmp_CachedObj.SummonerID.Value) { BlacklistCache.IgnoreThisObject(tmp_CachedObj, false, false); tmp_CachedObj.NeedsRemoved = true; continue; } #endregion tmp_CachedObj = new CachePet(tmp_CachedObj, PetType); } } else if (tmp_CachedObj.Actortype.Value == ActorType.Gizmo) { if (CheckFlag(tmp_CachedObj.targetType.Value, TargetType.Interactables)) { tmp_CachedObj = new CacheInteractable(tmp_CachedObj); } else { tmp_CachedObj = new CacheDestructable(tmp_CachedObj); } } //Update Properties (currently only for units) try { tmp_CachedObj.UpdateProperties(); } catch { Logger.Write(LogLevel.Cache, "Failed to update properties for {0}", tmp_CachedObj.DebugStringSimple); } } if (!tmp_CachedObj.UpdateData()) { //Logger.Write(LogLevel.Cache, "Update Failed for {0}", tmp_CachedObj.DebugStringSimple); if (!tmp_CachedObj.IsStillValid()) { tmp_CachedObj.NeedsRemoved = true; } continue; } //Obstacle cache if (tmp_CachedObj.Obstacletype.Value != ObstacleType.None && (CheckFlag(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.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 && (CheckFlag(CO.targetType.Value, TargetType.Gold | TargetType.Globe)) && CO.LoopsUnseen > 0)))) //gold/globe only 1 loop! { item.NeedsRemoved = true; } } CheckForCacheRemoval(); _lastUpdatedCacheCollection = DateTime.Now; return(true); }
///<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); }