when the game disconnected,is it possible to read that state from memory?
when the game disconnected,is it possible to read that state from memory?
Good question, would also like to know the answer.
Why read from memory? Just check if you're sending/recieving info to/from their servers... Wouldn't that be easier?
I'm only reading memory (don't want a conflict with Blizzard), and I have a problem with states too.
For example when you are using the waypoint from town to anywhere, then the "state" looks like this:
- you have "intown" buff, your coordinate is in town, your area is the town, NOW you click on the waypoint, and
- you still have "intown" buff, your coordinate is in the new area, your area is the town, and your "loading" buff is active. a second later (on a fast computer):
- you do not have intown buff, your coordinate is in the new area, your area is the town, there is no loading buff, and an other split second later:
- you are done, you are in the new area, new coordinate, no loading or town buffs
this is NOT a 100% state handling, because there is a point where you ARE in the old area, but your actor's coordinate is already set to the new coordinate which cause for example TurboHUD's interface to show complete mess for 1..5 seconds (depends on your computer speed).
So, if anybody knows a better state-reading right from the memory instead of actor and attribute information, I would be very happy to see it
Do not send me private messages unless it is absolutely necessary or the content is sensitive or when I ask you to do that...
This is what I've found with some experimentation. There are 2 interesting counters to keep track of:
int CurrentAnimationFrame (ObjectManager+0x038)
int CurrentGameFrame (ObjectManager+0x828)
(offsets valid for 1.0.7.14633)
@KillerJohn: If the CurrentAnimationFrame does not change, do not update as it might be in a transition state. Hopefully it can be as easy as that. For your purpose this property should be better than CurrentGameFrame as i suspect it cannot animate without a level loaded.
CurrentGameFrame is kept updated server-side I believe and is where it expects you to be. If you start a new single player game it will start counting from 1, but if you join an existing multiplayer game it will start from a higher number meaning it is related to game lifetime. When network connection is lost (I unplugged cable), it will stop increasing and when it's back it will sync with server again, "catching up" if multiplayer or continue from where it stopped if single player. I believe you've asked for this property before KillerJohn. I suppose it could be used to show accurate cooldowns.
To answer OP: My best suggestion is to check for CurrentGameFrame changes, and when it halts, check if an UI element from the "Disconnected" dialog is visible. There's probably a better way to check it, and looking at the data around CurrentGameFrame might be a good place to start. There's at least a string containing server address, so if you're lucky you might be able to find a socket connection status variable :)
I do chek the game connection to server,it works most of time,but there is some cases the toon has been disconncted from server,but the connections(2 connections) still alive,so it can't be 100% detected.
Yes, I know about those counters. CurrentGameFrame is maintained on server-side, and it is the base counter for all cooldowns, timers, counters, etc. I'm currently using this in TurboHUD.
But sadly none of them allows me to handle the very-precise game state, loadings. I can detect disconnects through the corresponding modal window UI component, so it is not the problem.
I want to detect the transition states in memory, when the player's actor coordinate is already changed to the new value (after a waypoint or town portal) but the current area is still the old.
Do not send me private messages unless it is absolutely necessary or the content is sensitive or when I ask you to do that...
i guess he means the Network Disconnect window that pops up. I´m checking for this one:
PHP Code:
auto* elem = D3::Ui::getElement("Root.TopLayer.BattleNetModalNotifications_main.ModalNotification.Content.List.Title");
if(elem && elem->isVisible() && elem->getText() == "NETWORK DISCONNECT" )
...
Since I like a challenge and since I like what you do with TurboHUD I decided to throw together some code that solves the issue. For me this works perfectly. The only issue I can image is if a teleporting cutscene causes a large enough displacement of coordinate without changing the zone, but that doesn't seem logical.
Enjoy
Code:using System; using System.Collections.Generic; using System.Linq; using System.Text; using Enigma.D3; namespace WarpDetectionDemo { class Program { static void Main(string[] args) { var engine = Engine.Create(); if (engine == null) { Console.WriteLine("Could not create engine. Make sure the process is running."); return; } var state = new WorldState(engine); while (true) { state.Refresh(); Console.Clear(); Console.WriteLine("IsWarping: " + state.IsWarping); Console.WriteLine(); Console.WriteLine("WorldCoordinate: " + state.Coordinate); Console.WriteLine("WorldId: 0x" + state.World.ToString("X8")); Console.WriteLine("ZoneId: 0x" + state.Zone.ToString("X8")); System.Threading.Thread.Sleep(10); } } static void WriteLine(string value) { Console.WriteLine(value); } } internal class WorldState { private Engine _engine; private int _previousFrame = 0; public WorldState(Engine engine) { _engine = engine; } public bool IsWarping { get; private set; } public int Zone { get; private set; } public int World { get; private set; } public Point3D Coordinate { get; private set; } public void Refresh() { // Start by updating the current frame. If there has been no // modification, return without updating anything. int currentFrame = _engine.ObjectManager.CurrentFrame; if (currentFrame == _previousFrame) { return; } _previousFrame = currentFrame; var player = _engine.GetLocalActor(); // Check world id. If there is a change then we are warping to a // new area. int currentWorld = player.WorldId; if (currentWorld != World) { IsWarping = true; } else { // Only update the value if we aren't warping, since it doesn't // match the zone otherwise. World = currentWorld; } // Check world coordinate. If there has been a major change, we are // warping. We need to check this since some waypoints in the open // world share the same world id. var currentCoordinate = player.WorldCoordinate; if ((Coordinate - currentCoordinate).Length > 100) { IsWarping = true; } else { // Only update the value if we aren't warping, since it doesn't // match the zone otherwise. Coordinate = currentCoordinate; } int currentZone = _engine.GetCurrentLevelArea(); if (currentZone != Zone) { // The zone has caught up with the world and coordinate we were // warping to. Update the values with what we read this refresh // since they are now valid and matches the zone. Zone = currentZone; IsWarping = false; World = currentWorld; Coordinate = currentCoordinate; } } } }
i'm digging around for you guys i'll let you know if theres a better solution
Last edited by iamclint; 03-07-2013 at 12:08 AM.
connection status seems to be at 0x1855470 + 0x28.
1 = connected. 0 = disconnected
found in sub_D238E0
Yes, sir!
Thanks, I'll try this way! Basically the core of your solution is to detect a huge coordinate (or world ID) change, store it as "warping = true", and when the area changes too, set it to false. Am I right?
Cool! Do you have any idea to connect this address to objectmanager or it is not related?
Last edited by KillerJohn; 03-07-2013 at 02:39 PM.
Do not send me private messages unless it is absolutely necessary or the content is sensitive or when I ask you to do that...
It doesn´t seem to be connected to the ObjMgr. But maybe i just overlooked something. it should be easy to keep track of this address. It is referenced quite often in the client.
And it´s acutally:
*(DWORD*)0x1855470 + offset
but i guess you already figured that out.