-
Member
Originally Posted by
d2k2
var cooldown_time = AttributeReader.Instance.GetAttributeValue(localacd.FastAttribGroupID, Enigma.D3.Enums.AttributeId.PowerCooldown, powersnoid);
-1 if not on cooldown
Awesome, that's what I was looking for, thanks!
Btw. I've found that AttributeId.ResourceCur and AttributeId.ResourceMax are always 0 for necromancer class. If that's intended where should I find current and maximum essence values?
-
Member
Enigma, everything is so clean! Hopefully I can be as productive as you one day. Thank you so much for sharing all of your hard work.
I have a question about the cause of some elusive Win32 mem read exceptions ("Read/Write could not complete"), if anyone knows. Dolphe/d2k2 please feel free to chime in as you're both probably familiar with this. I get them from attempting to read certain x00_snoID from Enigma.D3.Assets.Scenes SNOHeaders. I currently work around the issue with a try/catch for that section, but I can't seem to identify the issue to prevent the exceptions in the first place. I've tried to see if the SNOHeader is null (never is).
What I'm doing: Reading Navcell data from nearby Scenes in memory.
Code:
var sceneData = ctx.DataSegment.SNOGroupStorage[(int)SNOType.Scene].Cast<SNOGroupStorage<Enigma.D3.Assets.Scene>>().Dereference().Container.Where(elem => elem.SNOType == SNOType.Scene).Select(a => a.PtrValue.Dereference()); //sorry for the ugly query, new to c# and linq
//example
foreach(var scene in sceneData)
scene.x000_Header.x00_snoID;
Reading the snoID off the SNOHeader causes the exception, but only on a few out the couple/several hundred SceneSNOs enumerated. (The exception is thrown off the Read when calling the snoID property field)
Last edited by Comment; 08-10-2017 at 08:16 AM.
Reason: Code Wrap
-
Contributor
The SnoHeader will never be null since every call "get" a new instance will be created (unless you get exception first) and SNO is a struct ( value type ) and cannot be null either.
If you get "out of memory", it could be because ( the memory address range has shrinked ( no longer a value in that memory address )).
I don't know how the new "MemoryModel" works, but you should "snapshot" your sceneData instead of reading it live ( as it will constantly change ).
Most In memory "Assets" have Lazy load, so it will only load the entity when its needed. The only exception I have found is "Gamebalance" which is eager load.
If you need all data / scenes, you need to open the CASC files directly and parse out the data.
@kjata, you need to add a second parameter "identifer" and add in your case the class "Resource", 8 is for necro essence.
-
Legendary
That error message sounds a bit generic to be Win32. You've got an error code perhaps? [MS-ERREF]: Win32 Error Codes
-
Member
The SnoHeader will never be null since every call "get" a new instance will be created (unless you get exception first) and SNO is a struct ( value type ) and cannot be null either.
Good points. Embarassed. Rookie mistakes.
If you get "out of memory", it could be because ( the memory address range has shrinked ( no longer a value in that memory address )).
I don't know how the new "MemoryModel" works, but you should "snapshot" your sceneData instead of reading it live ( as it will constantly change ).
I don't believe I'm getting an out of memory message. e.what()-> "Only part of a ReadProcessMemory or WriteProcessMemory request was completed". I also wondered if it was a process bounds issue.
It's not "out of memory" exception, it would say "ReadProcessMemory or WriteProcessMemory could not be completed".
MemoryObject.TakeSnapShot(), you are probably right. Although I am using the object immediately, I had originally assumed each MemoryObject created a snapshot upon creation. I completely overlooked it. The datamay have shifted around when calling SNOHeader.x00_SnoID(that calls Read, obviously doesn't see a snapshot, so it tries to read the live memory using the old offset). Yet, if that were the case, it wouldn't be the same address that I'm missing repeatedly, over several thousand reads. That's statistically improbable. Again, these exceptions are few and far between...but I hate knowledge gaps, so I am trying to be comprehensive. It doesn't seem to effect performance, so maybe I'll have to leave that in the wish-list pile.
Most In memory "Assets" have Lazy load, so it will only load the entity when its needed. The only exception I have found is "Gamebalance" which is eager load.
If you need all data / scenes, you need to open the CASC files directly and parse out the data.
I originally followed Creez's Nav.D3 approach of cached data (and archiving it to file) and only pulling it out of memory as as needed. You also seem to pull it out of memory and cache it into SceneHelper/NavContainer for yours.
I will look into doing an offline approach similar to KJ's post about .scn in MPQ's (2013 pre-CASC/CascLib). Then I can simply read the MemModel.Scene data and lookup the corresponding navcells for that sceneSNO.
-
Member
Originally Posted by
enigma32
I've never called Win32 functions outside of c/c++. In C# I was lazy and logged the e.Message (Bold). Catching only for the error from calling x00_snoID
The hex is from SNOHeader.Address
Code:
snoDataHeader/IDExc: 0x4DAD5D68- Only part of a ReadProcessMemory or WriteProcessMemory request was completed 8/10/2017 1:23:44 PM
snoDataHeader/IDExc: 0x4DAD5D68- Only part of a ReadProcessMemory or WriteProcessMemory request was completed 8/10/2017 1:23:45 PM
snoDataHeader/IDExc: 0x4DAD5D68- Only part of a ReadProcessMemory or WriteProcessMemory request was completed 8/10/2017 1:24:36 PM
snoDataHeader/IDExc: 0x4DAD5D68- Only part of a ReadProcessMemory or WriteProcessMemory request was completed 8/10/2017 1:24:46 PM
Popped it into the debugger and the memory exceptions come from Enigma.Memory.dll as a Win32 Exception from the UnsafeReadByteCore (that wraps RPM).
I only pull in the SceneSNO data whenever new Scenes appear, therefore these exceptions are probably happening everytime I'm enumerating all the scenes. But it only happens occasionally, as you can see it's that 1 Sno out of a few hundred in that Container.While I was writing the other post, I was running into different levelAreas to see if I would have any problems and didn't get any exceptions.
Thank you for the feedback. Don't spend any extra energy on this(I've blown 14 hours on this one tidbit). I wanted to ask in case I missed something obvious or was using the framework improperly.
Last edited by Comment; 08-10-2017 at 03:58 PM.
Reason: Clarify exception message
-
Legendary
OK, that message I do recognize It happens when the read starts at a good address, but then tries to read beyond the memory page with no page to continue on. So either having a bad address or trying to read too much data.
Like Dolphe hinted at, if the container is modified (items removed) while you're doing a read, you may end up with bad addresses. That's the tricky part with memory reading. Can't freeze the process each time we want to spy on it So at some point we're bound to run into a race condition that messes things up.
You might be able to reduce the frequency of those errors by checking ID on the SNODefintion. If it's -1, then don't attempt to Dereference the pointer it has. If you're lucky it's 0 and you get NULL back. If unlucky, it just got de-allocated, but pointer not set to 0 yet, so it points to who knows what.
If you include reference to Enigma.D3.MemoryModel.Caching you can call GetCachedItems on the container. It does a full container read using as few ReadProcessMemory operations as possible, and snapshots each element
Code:
ctx.DataSegment.SNOGroupStorage[(int)SNOType.Scene]
.Cast<SNOGroupStorage<Scene>>()
.Dereference()
.Container.GetCachedItems()
.Where(x => x.SNOType == SNOType.Scene)
.Where(x => x.ID != -1)
.Select(x => x.PtrValue.Dereference())
.Where(x => x != null);
(TODO: might be wise to snapshot each dereferenced value if you read multiple properties on each one)
(EDIT: Nevermind, snapshot will not play nice with asset types, as they contain dynamic data. I have a solution somewhere, but can't find right now)
Last edited by enigma32; 08-10-2017 at 05:48 PM.
-
Member
Offsets for 2.6.1
Hello,
so i've been looking around to update my offsets through the PTR. I finished everything and I found it, except for two -_- and i've been at it all day.
containmanager:
messagedescriptor:
I have been trying to find these two and their corresponding offset for 2.6.1 and I cannot find it anywhere while disassembling. anyone have any tips?
-
Member
Hello,
I'm trying to figure out how to tell if a chest has already been clicked on using the memory model. I saw in an earlier post on this thread that after you click on a chest its hitpoints will turn to 0 from 0.001, but it seems that is no longer the case. I have also tried comparing all the ACD attributes before and after I clicked on a chest but nothing seemed to change. If anyone could give me any tips or pointers I would very much appreciate it.
Thank you
-
Legendary
Originally Posted by
perp|ex
Hello,
I'm trying to figure out how to tell if a chest has already been clicked on using the memory model. I saw in an earlier post on this thread that after you click on a chest its hitpoints will turn to 0 from 0.001, but it seems that is no longer the case. I have also tried comparing all the ACD attributes before and after I clicked on a chest but nothing seemed to change. If anyone could give me any tips or pointers I would very much appreciate it.
Thank you
I've been using this
Enigma.D3/MapMarkerFactory.cs at da7409b3e56721396b3cb72f60ac0c73a45cb98f * Enigma32/Enigma.D3 * GitHub
I think it still works..
-
Post Thanks / Like - 1 Thanks
perp|ex (1 members gave Thanks to enigma32 for this useful post)
-
Member
Originally Posted by
enigma32
Yup this still works thank you very much.
-
Member
I have had some success using the new 64bit version and MemoryModel, but I have a couple of questions.
How can I find counts for cast skills. IE If I cast Skeletal Mages, how many are cast? Or Soul Harvest, how many stacks do I have?
How can I tell what key is bound to a specific skill? I can find all the skills, but they seem to be in random order and I cannot determine the bound key.
Also it looks like the ResourceType enum for Essence is missing in Enigma.D3\Enigma.D3.Core\Enums\ResourceType.cs.
Code:
namespace Enigma.D3.Enums
{
public enum ResourceType
{
Mana = 0,
Arcanum = 1,
Fury = 2,
Spirit = 3,
Power = 4,
Hatred = 5,
Discipline = 6,
Faith = 7,
Essence = 8 // <-- Please add
}
}
Thank you!
-
Active Member
Originally Posted by
WindForcer
How can I find counts for cast skills. IE If I cast Skeletal Mages, how many are cast?
I dont know if there is a direct way to read the number of pets. but you can count them. Each pet is an ACD which has a speficic ActorSNO id depending on the skill rune.
For example: acd.ActorSNO = 472606 for Skeleton Mage - Singularity
you can also detect pets by the acd.Name. For example:
int petCount = allACDs.Count(x => x.acd.Name.ToLower().Contains("skeletonmage"))
in a multiplayer game its important that you only count your own pets:
acd.GetAttributeValue(AttributeId.PetOwner) == PlayerData.Index //(MemoryContext.Current.DataSegment.ObjectManager.Player.LocalPlayerIndex)
this is how d3helper counts pets:
Code:
public class B_Necromancer
{
private static HashSet<int> skeletonMageActorSNOs = new HashSet<int>
{
472275, // Skeleton Mage - No Rune
472588, // Skeleton Mage - Gift of Death
472769, // Skeleton Mage - Contamination
472801, // Skeleton Mage - Archer
472606, // Skeleton Mage - Singularity
472715 // Skeleton Mage - Life Support
};
public static int get_SkeletalMageCount()
{
try
{
List<A_Collector.ACDWrapper> acdcontainer;
lock (A_Collection.Environment.Actors.AllActors) acdcontainer = A_Collection.Environment.Actors.AllActors.ToList();
PlayerData local;
lock (A_Collection.Me.HeroGlobals.LocalPlayerData) local = A_Collection.Me.HeroGlobals.LocalPlayerData;
var allmages = acdcontainer.Where(x => x.acd.ID != -1 && x.acd.GetAttributeValue(AttributeId.PetOwner) == local.Index && skeletonMageActorSNOs.Contains(x.acd.ActorSNO));
int petCount = allmages.Count(x => x.acd.Name.ToLower().Contains("skeletonmage")); //SNO check should be already eenough. dont need check by name
Debug.WriteLine("magecount : " + petCount);
return petCount;
}
catch { return 0; }
}
}
Last edited by d2k2; 09-11-2017 at 04:17 AM.
-
Active Member
Originally Posted by
WindForcer
How can I tell what key is bound to a specific skill? I can find all the skills, but they seem to be in random order and I cannot determine the bound key.
ActiveSkillSavedData stores the active Skills in the correct order like on the ingame hotbar
Code:
PlayerData localPlayerData = MemoryContext.Current.DataSegment.ObjectManager.PlayerDataManager[MemoryContext.Current.DataSegment.ObjectManager.Player.LocalPlayerIndex]
int HotBarLeftClick_powerSnoId = localPlayerData.PlayerSavedData.ActiveSkillSavedData[0].PowerSNO;
int HotBarRightClick_powerSnoId = localPlayerData.PlayerSavedData.ActiveSkillSavedData[1].PowerSNO;
int HotBar1_powerSnoId = localPlayerData.PlayerSavedData.ActiveSkillSavedData[2].PowerSNO;
int HotBar2_powerSnoId = localPlayerData.PlayerSavedData.ActiveSkillSavedData[3].PowerSNO;
int HotBar3_powerSnoId = localPlayerData.PlayerSavedData.ActiveSkillSavedData[4].PowerSNO;
int HotBar4_powerSnoId = localPlayerData.PlayerSavedData.ActiveSkillSavedData[5].PowerSNO;
Bound Hotkey you can find like this;
Code:
Enigma.D3.Enums.HotkeyIndex index = Enigma.D3.Enums.HotkeyIndex.ActionBarSkill1;
Enigma.D3.MemoryModel.Preferences.Hotkey hotkey = MemoryContext.Current.DataSegment.HotkeyPreferences.Hotkeys[(int)index]
Last edited by d2k2; 09-11-2017 at 07:32 AM.
-
Active Member
Originally Posted by
WindForcer
I have had some success using the new 64bit version and MemoryModel, but I have a couple of questions.
How can I find counts for cast skills. Or Soul Harvest, how many stacks do I have?
i think for Soul Harvest you have the read the active buffs of the ACD (LocalACD) by enumerating all Attributes with the AttributeReader. I dont know if there is better way doing it with the framework
Here is an example. i did not test it:
Code:
void bool testForBuff(ACD acd, int _powerSno, int _attribId, int _value)
{
Dictionary<AttributeKey, double> attributes = AttributeReader.Instance.GetAttributes(acd.FastAttribGroupID); //acd = can be localACD of player
foreach (var attrib in attributes)
{
uint powerSNO = (uint)(attrib.Key.Value >> 12); //PowerSNO id of soul harvest ?
uint attribId = (uint)(attrib.Key.Value & 0xFFF); //AttribId depending many time on skill rune and can be different each patch
int value = (int)attrib.Value; //can be number of stacks
if(powerSNO == _powerSno && attribId == _attribId && _value == value)
{
return true;
}
}
return false;
}