public static async Task <ActorResult> GetActors() { var result = new ActorResult(); if (!CanGetActors() || !MemoryHandler.Instance.IsAttached) { return(result); } try { IntPtr targetAddress = IntPtr.Zero; var endianSize = MemoryHandler.Instance.ProcessModel.IsWin64 ? 8 : 4; var sourceSize = MemoryHandler.Instance.Structures.ActorItem.SourceSize; var limit = MemoryHandler.Instance.Structures.ActorItem.EntityCount; byte[] characterAddressMap = MemoryHandler.Instance.GetByteArray(Scanner.Instance.Locations[Signatures.CharacterMapKey], endianSize * limit); Dictionary <IntPtr, IntPtr> uniqueAddresses = new Dictionary <IntPtr, IntPtr>(); IntPtr firstAddress = IntPtr.Zero; DateTime now = DateTime.Now; TimeSpan staleActorRemovalTime = TimeSpan.FromSeconds(0.25); var firstTime = true; for (var i = 0; i < limit; i++) { IntPtr characterAddress; if (MemoryHandler.Instance.ProcessModel.IsWin64) { characterAddress = new IntPtr(BitConverter.TryToInt64(characterAddressMap, i * endianSize)); } else { characterAddress = new IntPtr(BitConverter.TryToInt32(characterAddressMap, i * endianSize)); } if (characterAddress == IntPtr.Zero) { continue; } if (firstTime) { firstAddress = characterAddress; firstTime = false; } uniqueAddresses[characterAddress] = characterAddress; } foreach (KeyValuePair <uint, ActorItem> kvp in MonsterWorkerDelegate.ActorItems) { result.RemovedMonsters.TryAdd(kvp.Key, kvp.Value.Clone()); } foreach (KeyValuePair <uint, ActorItem> kvp in NPCWorkerDelegate.ActorItems) { result.RemovedNPCs.TryAdd(kvp.Key, kvp.Value.Clone()); } foreach (KeyValuePair <uint, ActorItem> kvp in PCWorkerDelegate.ActorItems) { result.RemovedPCs.TryAdd(kvp.Key, kvp.Value.Clone()); } foreach (KeyValuePair <IntPtr, IntPtr> kvp in uniqueAddresses) { try { var characterAddress = new IntPtr(kvp.Value.ToInt64()); byte[] source = MemoryHandler.Instance.GetByteArray(characterAddress, sourceSize); // var source = MemoryHandler.Instance.GetByteArray(characterAddress, 0x3F40); var ID = BitConverter.TryToUInt32(source, MemoryHandler.Instance.Structures.ActorItem.ID); var NPCID2 = BitConverter.TryToUInt32(source, MemoryHandler.Instance.Structures.ActorItem.NPCID2); var Type = (Actor.Type)source[MemoryHandler.Instance.Structures.ActorItem.Type]; ActorItem existing = null; var newEntry = false; switch (Type) { case Actor.Type.Monster: if (result.RemovedMonsters.ContainsKey(ID)) { result.RemovedMonsters.TryRemove(ID, out ActorItem removedMonster); existing = MonsterWorkerDelegate.GetActorItem(ID); } else { newEntry = true; } break; case Actor.Type.PC: if (result.RemovedPCs.ContainsKey(ID)) { result.RemovedPCs.TryRemove(ID, out ActorItem removedPC); existing = PCWorkerDelegate.GetActorItem(ID); } else { newEntry = true; } break; case Actor.Type.NPC: case Actor.Type.Aetheryte: case Actor.Type.EventObject: if (result.RemovedNPCs.ContainsKey(NPCID2)) { result.RemovedNPCs.TryRemove(NPCID2, out ActorItem removedNPC); existing = NPCWorkerDelegate.GetActorItem(NPCID2); } else { newEntry = true; } break; default: if (result.RemovedNPCs.ContainsKey(ID)) { result.RemovedNPCs.TryRemove(ID, out ActorItem removedNPC); existing = NPCWorkerDelegate.GetActorItem(ID); } else { newEntry = true; } break; } var isFirstEntry = kvp.Value.ToInt64() == firstAddress.ToInt64(); ActorItem entry = await ActorItemResolver.ResolveActorFromBytes(source, isFirstEntry, existing); if (entry != null && entry.IsValid) { if (expiringActors.ContainsKey(ID)) { expiringActors.Remove(ID); } } if (entry.Type == Actor.Type.EventObject) { var(EventObjectTypeID, EventObjectType) = GetEventObjectType(targetAddress); entry.EventObjectTypeID = EventObjectTypeID; entry.EventObjectType = EventObjectType; } EnsureMapAndZone(entry); if (isFirstEntry) { if (targetAddress.ToInt64() > 0) { byte[] targetInfoSource = MemoryHandler.Instance.GetByteArray(targetAddress, 128); entry.TargetID = (int)BitConverter.TryToUInt32(targetInfoSource, MemoryHandler.Instance.Structures.ActorItem.ID); } } // it doesn't matter what this is set to; it won't be used in code below ActorItem removed; if (!entry.IsValid) { result.NewMonsters.TryRemove(entry.ID, out removed); result.NewMonsters.TryRemove(entry.NPCID2, out removed); result.NewNPCs.TryRemove(entry.ID, out removed); result.NewNPCs.TryRemove(entry.NPCID2, out removed); result.NewPCs.TryRemove(entry.ID, out removed); result.NewPCs.TryRemove(entry.NPCID2, out removed); continue; } if (existing != null) { continue; } if (newEntry) { switch (entry.Type) { case Actor.Type.Monster: MonsterWorkerDelegate.EnsureActorItem(entry.ID, entry); result.NewMonsters.TryAdd(entry.ID, entry.Clone()); break; case Actor.Type.PC: PCWorkerDelegate.EnsureActorItem(entry.ID, entry); result.NewPCs.TryAdd(entry.ID, entry.Clone()); break; case Actor.Type.Aetheryte: case Actor.Type.EventObject: case Actor.Type.NPC: NPCWorkerDelegate.EnsureActorItem(entry.NPCID2, entry); result.NewNPCs.TryAdd(entry.NPCID2, entry.Clone()); break; default: NPCWorkerDelegate.EnsureActorItem(entry.ID, entry); result.NewNPCs.TryAdd(entry.ID, entry.Clone()); break; } } } catch (Exception ex) { MemoryHandler.Instance.RaiseException(Logger, ex, true); } } try { // add the "removed" actors to the expiring list foreach (KeyValuePair <uint, ActorItem> kvp in result.RemovedMonsters) { if (!expiringActors.ContainsKey(kvp.Key)) { expiringActors[kvp.Key] = now + staleActorRemovalTime; } } foreach (KeyValuePair <uint, ActorItem> kvp in result.RemovedNPCs) { if (!expiringActors.ContainsKey(kvp.Key)) { expiringActors[kvp.Key] = now + staleActorRemovalTime; } } foreach (KeyValuePair <uint, ActorItem> kvp in result.RemovedPCs) { if (!expiringActors.ContainsKey(kvp.Key)) { expiringActors[kvp.Key] = now + staleActorRemovalTime; } } // check expiring list for stale actors foreach (var kvp in expiringActors.ToList()) { if (now > kvp.Value) { // Stale actor. Remove it. MonsterWorkerDelegate.RemoveActorItem(kvp.Key); NPCWorkerDelegate.RemoveActorItem(kvp.Key); PCWorkerDelegate.RemoveActorItem(kvp.Key); expiringActors.Remove(kvp.Key); } else { // Not stale enough yet. We're not actually removing it. result.RemovedMonsters.TryRemove(kvp.Key, out ActorItem _); result.RemovedNPCs.TryRemove(kvp.Key, out ActorItem _); result.RemovedPCs.TryRemove(kvp.Key, out ActorItem _); } } } catch (Exception ex) { MemoryHandler.Instance.RaiseException(Logger, ex, true); } MemoryHandler.Instance.ScanCount++; } catch (Exception ex) { MemoryHandler.Instance.RaiseException(Logger, ex, true); } return(result); }
public ActorResult GetActors() { ActorResult result = new ActorResult(); if (!this.CanGetActors() || !this._memoryHandler.IsAttached) { return(result); } IntPtr targetAddress = IntPtr.Zero; int limit = this._memoryHandler.Structures.ActorItem.EntityCount; int sourceSize = this._memoryHandler.Structures.ActorItem.SourceSize; byte[] characterAddressMap = this._memoryHandler.BufferPool.Rent(8 * limit); byte[] sourceMap = this._memoryHandler.BufferPool.Rent(sourceSize); byte[] targetInfoMap = this._memoryHandler.BufferPool.Rent(128); try { this._memoryHandler.GetByteArray(this._memoryHandler.Scanner.Locations[Signatures.CHARMAP_KEY], characterAddressMap); IntPtr firstAddress = IntPtr.Zero; DateTime now = DateTime.Now; TimeSpan staleActorRemovalTime = TimeSpan.FromSeconds(0.25); bool firstTime = true; for (int i = 0; i < limit; i++) { IntPtr characterAddress = new IntPtr(SharlayanBitConverter.TryToInt64(characterAddressMap, i * 8)); if (characterAddress == IntPtr.Zero) { continue; } if (firstTime) { firstAddress = characterAddress; firstTime = false; } this._uniqueCharacterAddresses[characterAddress] = characterAddress; } foreach (KeyValuePair <uint, ActorItem> kvp in this._monsterWorkerDelegate.ActorItems) { result.RemovedMonsters.TryAdd(kvp.Key, kvp.Value.Clone()); } foreach (KeyValuePair <uint, ActorItem> kvp in this._npcWorkerDelegate.ActorItems) { result.RemovedNPCs.TryAdd(kvp.Key, kvp.Value.Clone()); } foreach (KeyValuePair <uint, ActorItem> kvp in this._pcWorkerDelegate.ActorItems) { result.RemovedPCs.TryAdd(kvp.Key, kvp.Value.Clone()); } (uint mapID, uint mapIndex, uint mapTerritory) = this.GetMapInfo(); foreach (KeyValuePair <IntPtr, IntPtr> kvp in this._uniqueCharacterAddresses) { try { IntPtr characterAddress = new IntPtr(kvp.Value.ToInt64()); this._memoryHandler.GetByteArray(characterAddress, sourceMap); uint ID = SharlayanBitConverter.TryToUInt32(sourceMap, this._memoryHandler.Structures.ActorItem.ID); uint NPCID2 = SharlayanBitConverter.TryToUInt32(sourceMap, this._memoryHandler.Structures.ActorItem.NPCID2); Actor.Type Type = (Actor.Type)sourceMap[this._memoryHandler.Structures.ActorItem.Type]; ActorItem existing = null; bool newEntry = false; switch (Type) { case Actor.Type.Monster: if (result.RemovedMonsters.ContainsKey(ID)) { result.RemovedMonsters.TryRemove(ID, out ActorItem removedMonster); existing = this._monsterWorkerDelegate.GetActorItem(ID); } else { newEntry = true; } break; case Actor.Type.PC: if (result.RemovedPCs.ContainsKey(ID)) { result.RemovedPCs.TryRemove(ID, out ActorItem removedPC); existing = this._pcWorkerDelegate.GetActorItem(ID); } else { newEntry = true; } break; case Actor.Type.NPC: case Actor.Type.Aetheryte: case Actor.Type.EventObject: if (result.RemovedNPCs.ContainsKey(NPCID2)) { result.RemovedNPCs.TryRemove(NPCID2, out ActorItem removedNPC); existing = this._npcWorkerDelegate.GetActorItem(NPCID2); } else { newEntry = true; } break; default: if (result.RemovedNPCs.ContainsKey(ID)) { result.RemovedNPCs.TryRemove(ID, out ActorItem removedNPC); existing = this._npcWorkerDelegate.GetActorItem(ID); } else { newEntry = true; } break; } bool isFirstEntry = kvp.Value.ToInt64() == firstAddress.ToInt64(); ActorItem entry = this._actorItemResolver.ResolveActorFromBytes(sourceMap, isFirstEntry, existing); if (entry != null && entry.IsValid) { if (this._expiringActors.ContainsKey(ID)) { this._expiringActors.TryRemove(ID, out DateTime removedDateTime); } } if (entry.Type == Actor.Type.EventObject) { (ushort EventObjectTypeID, Actor.EventObjectType EventObjectType) = this.GetEventObjectType(targetAddress); entry.EventObjectTypeID = EventObjectTypeID; entry.EventObjectType = EventObjectType; } entry.MapID = mapID; entry.MapIndex = mapIndex; entry.MapTerritory = mapTerritory; if (isFirstEntry) { if (targetAddress.ToInt64() > 0) { this._memoryHandler.GetByteArray(targetAddress, targetInfoMap); entry.TargetID = (int)SharlayanBitConverter.TryToUInt32(targetInfoMap, this._memoryHandler.Structures.ActorItem.ID); } } if (!entry.IsValid) { result.NewMonsters.TryRemove(entry.ID, out ActorItem _); result.NewMonsters.TryRemove(entry.NPCID2, out ActorItem _); result.NewNPCs.TryRemove(entry.ID, out ActorItem _); result.NewNPCs.TryRemove(entry.NPCID2, out ActorItem _); result.NewPCs.TryRemove(entry.ID, out ActorItem _); result.NewPCs.TryRemove(entry.NPCID2, out ActorItem _); continue; } if (existing != null) { continue; } if (newEntry) { switch (entry.Type) { case Actor.Type.Monster: this._monsterWorkerDelegate.EnsureActorItem(entry.ID, entry); result.NewMonsters.TryAdd(entry.ID, entry.Clone()); break; case Actor.Type.PC: this._pcWorkerDelegate.EnsureActorItem(entry.ID, entry); result.NewPCs.TryAdd(entry.ID, entry.Clone()); break; case Actor.Type.Aetheryte: case Actor.Type.EventObject: case Actor.Type.NPC: this._npcWorkerDelegate.EnsureActorItem(entry.NPCID2, entry); result.NewNPCs.TryAdd(entry.NPCID2, entry.Clone()); break; default: this._npcWorkerDelegate.EnsureActorItem(entry.ID, entry); result.NewNPCs.TryAdd(entry.ID, entry.Clone()); break; } } } catch (Exception ex) { this._memoryHandler.RaiseException(Logger, ex); } } try { // add the "removed" actors to the expiring list foreach (KeyValuePair <uint, ActorItem> kvp in result.RemovedMonsters) { if (!this._expiringActors.ContainsKey(kvp.Key)) { this._expiringActors[kvp.Key] = now + staleActorRemovalTime; } } foreach (KeyValuePair <uint, ActorItem> kvp in result.RemovedNPCs) { if (!this._expiringActors.ContainsKey(kvp.Key)) { this._expiringActors[kvp.Key] = now + staleActorRemovalTime; } } foreach (KeyValuePair <uint, ActorItem> kvp in result.RemovedPCs) { if (!this._expiringActors.ContainsKey(kvp.Key)) { this._expiringActors[kvp.Key] = now + staleActorRemovalTime; } } // check expiring list for stale actors foreach (KeyValuePair <uint, DateTime> kvp in this._expiringActors) { if (now > kvp.Value) { // Stale actor. Remove it. this._monsterWorkerDelegate.RemoveActorItem(kvp.Key); this._npcWorkerDelegate.RemoveActorItem(kvp.Key); this._pcWorkerDelegate.RemoveActorItem(kvp.Key); this._expiringActors.TryRemove(kvp.Key, out DateTime removedDateTime); } else { // Not stale enough yet. We're not actually removing it. result.RemovedMonsters.TryRemove(kvp.Key, out ActorItem _); result.RemovedNPCs.TryRemove(kvp.Key, out ActorItem _); result.RemovedPCs.TryRemove(kvp.Key, out ActorItem _); } } } catch (Exception ex) { this._memoryHandler.RaiseException(Logger, ex); } this._memoryHandler.ScanCount++; } catch (Exception ex) { this._memoryHandler.RaiseException(Logger, ex); } finally { this._memoryHandler.BufferPool.Return(characterAddressMap); this._memoryHandler.BufferPool.Return(sourceMap); this._memoryHandler.BufferPool.Return(targetInfoMap); } result.CurrentMonsters = this._monsterWorkerDelegate.ActorItems; result.CurrentNPCs = this._npcWorkerDelegate.ActorItems; result.CurrentPCs = this._pcWorkerDelegate.ActorItems; this._uniqueCharacterAddresses.Clear(); return(result); }