Welcome to The Forum

Register now to gain access to all of our features. Once registered and logged in, you will be able to create topics, post replies to existing threads

Automatic Mdx_Stats Utility


Hydranix_
 Share

Recommended Posts

I wrote a small program which automatically queries macrodox and processes the results. If someone is found to be Hyperscrolling, it announces it in game chat. If someone is found to have a very high perf, with a very high or default fps_max, it announces it in chat.

 

Update: 4/9/2016

Big thanks to tfreeman451 for informing me that the 'mdx_stats @all' command is unreliable when there are more than 19 players on the server.

When there are more than 19 players, 'mdx_stats @all' will still only return 19 results, the remaining players results are truncated and never displayed.

 

File updated. This tool now reliably processes every single players mdx_stats.

 

 

It allows you to pay attention to other things, or play the game and not need to worry about checking macrodox.

 

 

A few things to note:

  • It runs on Windows x86_64
  • This is for CSS
  • It only works when the game is focused.
  • It runs independently of the server and it's plugins.
  • It requires a single keybind. Currently the F8 key and is not yet configurable.
  • It also requires a couple convars to be set, and sets them automatically.

If you have any suggestions or any issues/bugs let me know via PM or in this thread.

 

 

How to setup:

  • Download and unzip exe file and save it somewhere.
     
  • Run the exe, and press yes on the UAC dialog.
     
  • It should instruct you to add "+exec HNx" to CSS's launch options
     
  • Open steam to the Libraries page.
     
  • Right click Counter-Strike Source and click properties
     
  • Click Set Launch Options...
     
  • Add '+exec HNx' to the end of the Launch Options and click ok.
     
  • Restart CSS and run the exe again, it should now say it's waiting for the game to take focus.
     
  • Enter an [HG] server which has macrodox enabled and you should be set.

To check if it's working, wait about a minute and alt tab to the console window of the exe. You should see Macrodox output in the console. If you do, it's working.

 

 

Here an example of it in action:

0 do work son<68><[u:1:3707848]><> Avg: 9.382871/178.964874 Perf: 0.043983 cs_crackhouse_hg_a2 10263.503906 -46.968750 372.031250 Last: 5 15 19 18 15 14 5 5 2 4 3 17 10 9 19 1 1 1 1 1 1 1 1 1 1 1 2 13 16 14

rJIXqzz.png

CSS_MDX_Stats.zip

Edited by Hydranix_
  • Like 4
Link to comment
Share on other sites

How does this work, are you hooking the game in some way?

 

No game hooking, manipulation of the game process or any modules being loaded. This simply reads the console.log file which I'll explain below.

 

First, a summary of how this tool works.

  1. It tries to find where steam is installed by first checking the default install path, if that fails, it reads steams registry entry for InstallPath, and if that fails it asks the user to locate the cstrike folder (not yet implemented).
     
  2. Once it gets the directory, it remembers the location by saving its own entry in the registry, so it doesn't have to ever search again. (unless steam is reinstalled somewhere different at some point in the future)
     
  3. Then it creates a couple .cfg files in ".\cstrike\cfg". The first, HNx.cfg:
    unbind F8
    bind F8 "exec dyncmd"
    con_logfile Conlog\console.log
    


     

  4. The other .cfg file is empty (for now) and is called dyncmd.cfg (short for dynamic command). It uses this file to execute console commands in the game without having to have a bunch of different keybindings.
     
  5. It also sets the ConVar "con_logfile 'ConLog\console.log'" which causes Counter-strike to write the contents of the in game console to a file in real time.
     
  6. Using DynCmd, it executes "mdx_stats @all" once about every minute so long as CSS is the focused window, otherwise is goes idle.
     
  7. If a player has high perf percentage, it executes "get_fps_max <name>" and looks for values which make certain perf percentages impossible physically to obtain without scripted help.
     
  8. If the numbers indicate a clear cheater, it announces in all_chat the name of the scripter and how severe their cheating is.

So far I've detected about 5-6 different people using scripts, and each time it was a valid detection. More often than not the detection is so quick that the player immediately stops using their scripts, and a few have even apologized.

 

 

If this tool proves useful I plan to update the program to work with CS:GO and other games that support macrodox as well.

 

Hi there. We all love the coding world and I would please like to ask you to post your sourcecode here as well, or you can PM me it. We do not want any malicious programs going out :)

 

Nothing malicious here. The source is a bit of a mess though and I'm currently cleaning it up.

 

I'll pm you the current state of the source if you're worried of my evil intentions.

 

Here some of the cleaner code:

 

// MDX_Output.hpp

#pragma once
#include <string>

// Upon construction, this class extracts the relevant macrodox information from
// the mdx_stats console output

// note that this uses very unsophisticated string manipulation

class MDX_Stats
{
public:
MDX_Stats(const std::string &line);
~MDX_Stats();
/* MDX_Stats(const MDX_Stats &from); */

// player identification
std::string name();
std::string steamId();

// the main variable worth watching
float perf();

// 2 more variables worth including
float avgJumps();
float avgSpeed();

// highest jumps per hop of last thirty hops (hyperscrollers)
int lastHighest();

private:
std::string _PlayerName;
std::string _SteamId;
float _perf;
float _avgJumps;
float _avgSpeed;
int _Last[30];
};

// MDX_Output.cpp

#include "MDX_Output.hpp"
#include "Util.hpp"

// example of one line of the MDX output
// 0 [HG] Hydranix<764><[u:1:201393689]><> Avg: 1.004638/176.456207 Perf: 0.073529 cs_crackhouse_hg_a2 10017.465820 -784.924560 372.031250 Last: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

MDX_Stats::MDX_Stats(const std::string &line)
{
auto vLine = split(line, ' ');
int PlayerIndex;
for (int i = 1; i < vLine.size(); i++)
{
if (vLine[i].compare("Avg:") == 0)
{
 PlayerIndex = i - 1;
 break;
}
}

// Extract SteamID first
size_t pos = vLine[PlayerIndex].find_last_of('[') + 1;
size_t len = vLine[PlayerIndex].find_last_of(']') - pos;
_SteamId = vLine[PlayerIndex].substr(pos, len);

// Now get the name
_PlayerName = vLine[1];
if (PlayerIndex > 1)
{
int i = 1;
while(true)
{
 i++;
 if (vLine[i].compare("Avg:") == 0)
 {
 break;
 }
 _PlayerName.push_back(' ');
 _PlayerName += vLine[i];
}
}

// remove extra crap from name
for (int i = 0; i < 3; i++)
_PlayerName.erase(_PlayerName.find_last_of('<'));

// get average values
auto avg = split(vLine[PlayerIndex + 2], '/');
_avgJumps = std::stof(avg[0], nullptr);
_avgSpeed = std::stof(avg[1], nullptr);

// now find perf
size_t PerfIndex;
for (size_t i = 0; i < vLine.size(); i++)
{
if (vLine[i].compare("Perf:") == 0)
{
 PerfIndex = i + 1;
 break;
}
}
_perf = std::stof(vLine[PerfIndex], nullptr);

// finally get last thirty jumps-per-hop
auto vri = vLine.rbegin();
for (int i = 0; i < 30; ++vri, i++)
{
_Last[29-i] = std::stoi(*vri, nullptr, 10);
}
}

MDX_Stats::~MDX_Stats()
{
}
/*
MDX_Stats::MDX_Stats(const MDX_Stats &from)
{
_PlayerName = new std::string(from.name());
_SteamId = new std::string(from.steamId());
}
*/
std::string MDX_Stats::name()
{
return _PlayerName;
}

std::string MDX_Stats::steamId()
{
return _SteamId;
}

float MDX_Stats::perf()
{
return _perf;
}

float MDX_Stats::avgJumps()
{
return _avgJumps;
}

float MDX_Stats::avgSpeed()
{
return _avgSpeed;
}

int MDX_Stats::lastHighest()
{
int highest = 0;
for (int i = 1; i < 29; i++)
{
if (_Last[highest] < _Last[i])
 highest = i;
}
return _Last[highest];
}

 

Edit: Cleaned up this post, was in a rush earlier when I first posted it.

Edited by Hydranix_
  • Like 1
Link to comment
Share on other sites

0 do work son<68><[U:1:3707848]><> Avg: 9.382871/178.964874 Perf: 0.043983 cs_crackhouse_hg_a2 10263.503906 -46.968750 372.031250 Last: 5 15 19 18 15 14 5 5 2 4 3 17 10 9 19 1 1 1 1 1 1 1 1 1 1 1 2 13 16 14

His AVG doesn't match his Last and his perf is 0.04.

Link to comment
Share on other sites

Ok looks fine for me. Although I would like to talk to you with some integration with something I had in mind.

 

Sure, that's only a part of the code, it's nearly halfway finished cleaning up.

 

Great idea and concept but rather than something that needs to be installed on a client PC, could you look in to making it a SM plugin?

 

An sm plugin or even an extension of macrodox itself sounds interesting. Being able to have direct access to the macrodox variables would make it much easier and a lot more powerful.

 

 

0 do work son<68><[U:1:3707848]><> Avg: 9.382871/178.964874 Perf: 0.043983 cs_crackhouse_hg_a2 10263.503906 -46.968750 372.031250 Last: 5 15 19 18 15 14 5 5 2 4 3 17 10 9 19 1 1 1 1 1 1 1 1 1 1 1 2 13 16 14

His AVG doesn't match his Last and his perf is 0.04.

 

But he was hyperscrolling, but only just started using it, so didn't get a good perf built up. The Avg is based on the entire session, rather than the last 30 IIRC.

 

It's not possible without an unlocked mousewheel or script to get over 11-12 scrolls per hop several times in a row.

Edited by Hydranix_
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share