English How to decode UserStats since steam update

3 replies
Goto Page
To the start Previous 1 Next To the start
Up
Nekomata
User
Offline Off
Since the steam update, the userstats decoders have broken.

For example the ReadInt() here no longer works which points that the reading format has changed.

I'm working on a project that parses this data. What's a solution for this?


Edit: I believe previous versions were following this format
user DC has written:
It only seems to affect the first two players and their score value. All other values seem to be legit (the third guy played over 30 days on your server. omg!). You may consider to edit sys/stats/userstats.dat with a hexeditor or with a tool for stats editing (I think there was one somewhere but I can't find it). Just set the wrong scores to the same values as the kill values. Those two values are quite equal in most cases because only special actions like defusing a bomb gives you additional score points besides killing.

!!!Make a backup before editing!!!

The userstats.dat format is very simple:
Code:
1
2
3
4
5
6
username (string, linebreak afterwards)
usgn id (32 bit signed integer)
score (32 bit signed integer)
frags (32 bit signed integer)
deaths (32 bit signed integer)
time on server in seconds (32 bit signed integer)

this data set for each saved user

So when using a hex editor you have to
• find the username which has a wrong score
• skip 4 bytes (characters) in the line right after that username
• and copy&paste the 4 bytes right after that back to the first 4 bytes in that line

you could also simply remove the "damaged" users from the file.

Has this format changed? I don't really know how to work with bytes or hex.
08.04.18 09:36:02 pm
Up
DC
Admin
Offline Off
It's now (new/changed fields marked with *):
Code:
1
2
3
4
5
6
7
8
9
username (string, linebreak afterwards)
*user type (byte, 8 bit, either 0 for U.S.G.N. user or 1 for Steam user)
*U.S.G.N. or Steam ID (64 bit signed long)
score (32 bit signed integer)
frags (32 bit signed integer)
deaths (32 bit signed integer)
*assists (32 bit signed integer)
*mvps (32 bit signed integer)
time on server in seconds (32 bit signed integer)


The new second value basically says if the third value is a U.S.G.N. ID or a Steam ID. The ID is now a long (64 bit) because Steam IDs can be quite long. Also the count of assists was added and also how often the player was the MVP.

Also don't forget that there is a header string (first line in file) describing the format:
userstats alpha

for the old format you just quoted
userstats beta

for a temporary format which just added assists and mvp
userstats steam

for the new format I just explained

CS2D is still able to read all these formats but it will save stats always in the new Steam format.
www.UnrealSoftware.de | www.CS2D.com | www.CarnageContest.com | Use the forum & avoid PMs!
09.04.18 03:28:40 am
Up
Nekomata
User
Offline Off
@user DC Thank you! I have one more favour; I've been trying to go at this for a while and it's leading me nowhere. Could you help me out one step further? I don't really understand how to put it to practical use.

For example, MikuAuahDark's PHP code was written like this
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
function GetUserStatsRank($usgn) {
     $Int=function($f) {
          return ord(fread($f,1))+ord(fread($f,1))*256+ord(fread($f,1))*65536+ord(fread($f,1))*16777216;
     };
     $f=fopen("sys/stats/userstats.dat","rb");
     fseek($f,0,SEEK_END);
     $size=ftell($f);
     fseek($f,17,SEEK_SET);
     $temp=[
          "isexists"=>FALSE,
          "score"=>0,
          "frags"=>0,
          "deaths"=>0,
          "time"=>0,
     ];
     while(ftell($f)!=$size) {
          fgets($f);          // skip player name
          $temp_usgn=$Int($f);
          if($usgn==$temp_usgn) {
               $temp["isexists"]=TRUE;
               $temp["score"]=$Int($f);
               $temp["frags"]=$Int($f);
               $temp["deaths"]=$Int($f);
               $temp["time"]=$Int($f);
               break;
          } else fseek($f,16,SEEK_CUR);
     }
     fclose($f);
     return $temp;
}
?>


I've been trying to go at the changes needed in this part
Code:
1
2
3
$Int=function($f) {
          return ord(fread($f,1))+ord(fread($f,1))*256+ord(fread($f,1))*65536+ord(fread($f,1))*16777216;
     };

but to no avail.



What changes are needed to reflect the updated version for correct read-offs?
09.04.18 07:11:26 pm
Up
DC
Admin
Offline Off
The function you want to change does not need to be changed (if it works / worked before - I'm not sure about that). It's used to read an integer and of course you still need to do that.

You also need a new function which can read a byte and a function which can read a long and then you just have to call them in the right order as I explained.

I previously used http://php.net/manual/en/function.ord.php (for single byte) and http://php.net/manual/en/function.unpack.php (for other types) to convert the values. That should still work.

Reading a byte:
$byte = ord(fread($handle, 1));


Reading an integer:
$int = unpack('l', fread($handle, 4));

Attention: 'l' is a small L here! Don't mix that up!

Reading a long (untested):
$long = unpack('q', fread($handle, 8));


Reading the name (untested):
$name = fgets($handle);
edited 1×, last 09.04.18 07:23:08 pm
www.UnrealSoftware.de | www.CS2D.com | www.CarnageContest.com | Use the forum & avoid PMs!
To the start Previous 1 Next To the start