Movement packets

06/11/2019 21:30 sandsnip3r#1
Hello all!

I'm starting to try to do some packet-based movement as well as character & monster tracking. I have some questions about the movement system in general as well as packet-specific details.

First, I'd like to ask about general movement things.
  1. What is the translation between the X,Y shown on the minimap and the regionIds/offsets? [Only registered and activated users can see links. Click Here To Register...] for the translation, but what is the "sector" and how is that found? [Only registered and activated users can see links. Click Here To Register...]
  2. In regards to sending a packet to move your character, I noticed that there seems to be no response from the server. How do you know when you've reached your destination?

Second, some specific packet questions. As monsters are moving around, the server sends 0xb021 packets to the client. I cant find the documentation on the structure of this packet right now, so these are based on my memory.
  1. The x and y offset are supposedly 2 byte float values, is this true?
  2. The packet has what seems to be an optional destination, but also an optional source. I cant figure out what the last 2 bytes are of this source section.

Any further information on player & monster movement in general would be greatly appreciated.
06/12/2019 00:54 konserwa#2
Quote:
In regards to sending a packet to move your character, I noticed that there seems to be no response from the server. How do you know when you've reached your destination?
Read memory ? There is in memory byte value, with one inform you if character is play move animation(After character reach point its turn from 1 to 0). If you want more info i can at least give you advice form private servers. I will give you good start point "PUSH <OPCODE OF MOVE>"


Quote:
The x and y offset are supposedly 2 byte float values, is this true?
I TALK ABOUT CLICK.
Inside client its take about 4 bytes each x,y,z(At least mouse click) .Check old VB Phbot?
06/12/2019 01:06 DaxterSoul#3
Quote:
Originally Posted by sandsnip3r View Post
What is the translation between the X,Y shown on the minimap and the regionIds/offsets?
The region id consists of a dungeon flag, x and y in the map grid.

The coordinates shown above the minimap show your distance in each axis from the "world origin" in meters. Joymax declared this to be at region 135x92. This does not reflect the center of the map grid which has a size of 256x128 regions. A region has a size of 1920x1920 units or 192x192 meter, so 1 meter = 10 units. You may recognize all these numbers from the posted formulas. Understanding what they mean doesn't hurt.
Note that they do not apply for dungeons, as they're not directly part of the world map grid.

Offsets show the distance in each axis from the regions or dungeons origin (0.0; 0.0)
Regions offsets will be around 0~1920 but may go negative or above and translate into neighboring regions.
Dungeon offsets are infinite, unless you count the dungeon bounding box.

Quote:
Originally Posted by sandsnip3r View Post
In regards to sending a packet to move your character, I noticed that there seems to be no response from the server. How do you know when you've reached your destination?
time = distance / speed

Quote:
Originally Posted by sandsnip3r View Post
I cant find the documentation on the structure of this packet right now, so these are based on my memory.
I posted a complete documentation of the 0x7021 opcode [Only registered and activated users can see links. Click Here To Register...]. 0xB021 very similar.

Quote:
Originally Posted by sandsnip3r View Post
The x and y offset are supposedly 2 byte float values, is this true?
There are no half precision floating point values used in packets or file formats afaik.

Quote:
Originally Posted by sandsnip3r View Post
The packet has what seems to be an optional destination, but also an optional source. I cant figure out what the last 2 bytes are of this source section.
1. There is no destination when using arrow keys/clicking into the sky (directional walking).
2. There is no source when walking north-east.
3. There must be a source provided when there is no destination (directional walking).

The source part is identical to the destination part, the only difference being y is always a float.

A general advice: Try to get all local coordinates to output the same values as /getcurpos or /frame.

I didn't go into too much details about dungeons, as they're really a complete edge case in every which led to a lot of misconceptions about their coordinates. You may want to ask more specific questions about them when you got the gist of regular region stuff.
06/12/2019 04:38 sandsnip3r#4
Quote:
Originally Posted by DaxterSoul View Post
time = distance / speed
The client and the server both do the math to keep track of a character's location? Then that means for any actor, I need to know his speed to calculate where he's at?


Quote:
Originally Posted by DaxterSoul View Post
I posted a complete documentation of the 0x7021 opcode [Only registered and activated users can see links. Click Here To Register...]. 0xB021 very similar.
Ah yeah, I've seen this. I'm still confused about the final 2 bytes in the case where there's an origin. After the 0/1 origin byte, there are 10 bytes, but I only understand 8:
Code:
uint8_t xSector
uint8_t ySector
uint16_t xOffset
uint16_t yOffset
uint16_t zOffset
uint16_t unknown
Quote:
Originally Posted by DaxterSoul View Post
2. There is no source when walking north-east.
Lol what? What's the reason behind this?

Quote:
Originally Posted by DaxterSoul View Post
The source part is identical to the destination part, the only difference being y is always a float.
That still doesnt quite line up with the data I've observed. Are you saying that in the structure I gave above, the `uint16_t yOffset` is replaced with a `float yOffset` and the 2 unknown bytes are no longer there?
I did a test where I walked east in the same direction for the same distance. The source of movement doesnt match the destination of the previous movement. The destination y is always 0. I can post the data I'm seeing if that would be helpful.

Quote:
Originally Posted by DaxterSoul View Post
A general advice: Try to get all local coordinates to output the same values as /getcurpos or /frame.
Are these pserver console/gm commands? I'm not familiar with these currently.

Quote:
Originally Posted by DaxterSoul View Post
I didn't go into too much details about dungeons, as they're really a complete edge case in every which led to a lot of misconceptions about their coordinates. You may want to ask more specific questions about them when you got the gist of regular region stuff.
Yeah, that's fine. I'd be overwhelmed anyways. Thanks for the help.
06/12/2019 13:53 DaxterSoul#5
Quote:
Originally Posted by sandsnip3r View Post
The client and the server both do the math to keep track of a character's location? Then that means for any actor, I need to know his speed to calculate where he's at?
Yes, the speed is in the spawn data and updates are also sent if something changes.

Quote:
Originally Posted by sandsnip3r View Post
Are you saying that in the structure I gave above, the `uint16_t yOffset` is replaced with a `float yOffset` and the 2 unknown bytes are no longer there?
If you replace the uint16 (2 bytes) with a float (4 bytes) you need to push zOffset back into what used to be unknown.

Quote:
Originally Posted by sandsnip3r View Post
I did a test where I walked east in the same direction for the same distance. The source of movement doesnt match the destination of the previous movement. The destination y is always 0.
You don't need to think that much about y because the navigation is mostly 2D. But I can assure you that the math works out if you convert to the correct units.
[Only registered and activated users can see links. Click Here To Register...]

Quote:
Originally Posted by sandsnip3r View Post
I can post the data I'm seeing if that would be helpful.
It's always a good idea to present your view on problems, in order to make out mistakes faster. Maybe you're still having structural mistakes or just misinterpreting values. Make sure you read the values signed. I know my documentation says unsigned int, but they're old :p

Quote:
Originally Posted by sandsnip3r View Post
Are these pserver console/gm commands? I'm not familiar with these currently.
Yes, but you can access the console in different ways.
1. [Only registered and activated users can see links. Click Here To Register...]
2. [Only registered and activated users can see links. Click Here To Register...]

Quote:
Originally Posted by sandsnip3r View Post
Quote:
Originally Posted by daxtersoul View Post
2. There is no source when walking north-east.
Lol what? What's the reason behind this?
Not sure, so I won't speculate on this.
06/12/2019 17:57 JellyBitz#6
I'm using this packet structure SERVER_ENTITY_MOVEMENT = 0xB021 :
PHP Code:
SRObject entity = new SRObject();
entity[SRAttribute.UniqueID] = packet.ReadUInt();
entity[SRAttribute.hasMovement] = packet.ReadByte() == 1;
if ((bool)
entity[SRAttribute.hasMovement])
{
    
entity[SRAttribute.MovementRegion] = packet.ReadUShort();
    if (
entity.inDungeon((ushort)entity[SRAttribute.MovementRegion]))
    {
        
entity[SRAttribute.MovementOffsetX] = packet.ReadInt32();
        
entity[SRAttribute.MovementOffsetZ] = packet.ReadInt32();
        
entity[SRAttribute.MovementOffsetY] = packet.ReadInt32();
    }
    else
    {
        
entity[SRAttribute.MovementOffsetX] = packet.ReadInt16();
        
entity[SRAttribute.MovementOffsetZ] = packet.ReadInt16();
        
entity[SRAttribute.MovementOffsetY] = packet.ReadInt16();
    }
}
bool flag packet.ReadByte() == 1;
if (
flag)
{
    
packet.ReadUShort(); // Region
    
packet.ReadUShort(); // ???
    
packet.ReadUShort(); // ???
    
packet.ReadUShort(); // ???
    
packet.ReadUShort(); // ???
}
// End of Packet 
And works well as you can see:
[Only registered and activated users can see links. Click Here To Register...]
Getting ingame coords :
PHP Code:
if (!this.inDungeon())
{
    
// Map: {yTile}x{xTile}.jpg
    
byte yTile = (byte)((ushort)this[SRAttribute.Region] >> 8);
    
byte xTile = (byte)((ushort)this[SRAttribute.Region] & 255);
    
// World tiles offsets. Y: 135; X: 92;
    // 192x192 map units / 10:1 scale 
    
Point p = new Point();
    
p.= (int)((xTile 135) * 192 + ((float)this[SRAttribute.X]) / 10);
    
p.= (int)((yTile 92) * 192 + ((float)this[SRAttribute.Y]) / 10);
    return 
p;