Monstrofil / replays_unpack

51 stars 19 forks source link

Position of allied/enemy? ships outside the player's render distance #4

Closed imkindaprogrammermyself closed 4 years ago

imkindaprogrammermyself commented 4 years ago

I was able to parse the position from packets Position and 0x2b and created a video of the minimap with it.

If an ally ship goes outside the player's render distance, the ship disappears from the video and comes back when it re-enters again. Is there a separate packet for that since ships outside render distance updates infrequently.

Monstrofil commented 4 years ago
Entity.subscribe_method_call('Avatar', 'updateMinimapVisionInfo', self.updateMinimapVisionInfo)

def updateMinimapVisionInfo(self, avatar, shipsMinimapDiff, buildingsMinimapDiff):
  pass

The method above receives packed information about player's position on minimap, but I don't know how to unpack it.

[{'vehicleID': 1039019, 'packedData': 370658389}, {'vehicleID': 1039027, 'packedData': 1239110659}, {'vehicleID': 1039029, 'packedData': 681372441}, {'vehicleID': 1039031, 'packedData': 1088627968}, {'vehicleID': 1039047, 'packedData': 946085110}, {'vehicleID': 1039053, 'packedData': 618468173}, {'vehicleID': 1039055, 'packedData': 1893924126}, {'vehicleID': 1039057, 'packedData': 743918505}, {'vehicleID': 1039059, 'packedData': 207375345}, {'vehicleID': 1039061, 'packedData': 1231133953}]

Here is what game unpacks:

>>> Avatar.PlayersInfo.MinimapInfoPacker.unpackData(1231133953)
((628.969, 0, 125.794), 0.461094826847817, True)
>>> Avatar.PlayersInfo.MinimapInfoPacker.unpackData(946085110)
((602.101, 0, 321.202), -0.3750237925028914, True)
>>> Avatar.PlayersInfo.MinimapInfoPacker.unpackData(370658389)
((208.842, 0, -641.182), -2.059556893253583, True)

Probably these magic contants may help somehow:

{'__module__': 'm2a392713', 'packData': <staticmethod object at 0x000001AD1D806B28>, 'piExt': 3.141592753589793, '__doc__': None, 'unpackData': <staticmethod object at 0x000001AD1D806B58>, 'packPattern': ((-2500.0, 2500.0, 11), (-2500.0, 2500.0, 11), (-3.141592753589793, 3.141592753589793, 9)), 'mapHalfSize': 2500.0, 'hiddenData': 2147483648L}
Monstrofil commented 4 years ago

I can give you mod that provides remote python console for wows, probably you will be able to find out how DataPacker works, but I don't want to make that mod public, so email me pls: shalal545@gmail.com

imkindaprogrammermyself commented 4 years ago

Email sent

imkindaprogrammermyself commented 4 years ago

This is what I have discovered so far. It's performing XOR operation with the input with hiddenData 2147483648L 2147483648 ^ 2147483648 = 0 unpackData(2147483648) = ((0, 0, 0), 0.0, False)

Monstrofil commented 4 years ago

I've just sent this link on email, but I also publish it here, probably someone else it going to do the same stuff: https://github.com/Monstrofil/replays_unpack/commit/010508e232a055f9ac54c626e66a050380486754

The thing is that WG tried to compress data and did this hardcoded pattern:

pack_pattern = (
            (-2500.0, 2500.0, 11),
            (-2500.0, 2500.0, 11),
            (-3.141592753589793, 3.141592753589793, 9)
        ) 

It seems that it means that packedData contains of 3 values: 11, 11 and 9 bits each. We must get those values and then transform them into float value in range of [min_value, max_value), that's what I do in patch above.

First two is x and z, third is yaw obviously, y seems to be always zero. The only thing I can't understand where the last boolean value is stored (or probably it is calculated somehow?):

>>> Avatar.PlayersInfo.MinimapInfoPacker.unpackData(370658389)
((208.842, 0, -641.182), -2.059556893253583, True)
imkindaprogrammermyself commented 4 years ago

Maybe hiddenData 2147483648L is used in the process somehow, in the obfuscated code at least since calling unpackData(2147483648) returns everything to 0 and setting the bool to false

Monstrofil commented 4 years ago

Yea, probably like you are right, cause

>>> 2**(11 + 11 + 9)
2147483648L

So last boolean can be something like packedValue & 2147483648

DeckerCHAN commented 4 years ago

Hi guys! Have you figured out what is that last boolean for? Ship is dead or it is inactive? And I have tried to unpack it since it is leftest bit of a 32bit UInt binary, it seems always 0(false) to me.

Update: I have found that in case that boolean is set to true, other values are always max:

                pack_pattern = (
                    (-2500.0, 2500.0, 11),
                    (-2500.0, 2500.0, 11),
                    (-3.141592753589793, 3.141592753589793, 9),
                    (0, 1, 1),
                )
                value = unpack_values(packed_data, pack_pattern)

image

nickntg commented 2 years ago

@Monstrofil How come some version of this didn't find its way into master?

Monstrofil commented 2 years ago

@nickntg no one ever asked for that.

nickntg commented 2 years ago

@Monstrofil I found it useful to be honest and embedded it into my own copy. My Python skills are rudimentary at the moment. When I get better, I'd like to send a PR for this.