1. Hey Guest, is it this your first time on the forums?

    Visit the Beginner's Box

    Introduce yourself, read some of the ins and outs of the community, access to useful links and information.

    Dismiss Notice

How to track stats.

Discussion in 'Modding Help' started by kodysch, Feb 15, 2015.

  1. kodysch

    kodysch Bison Rider Staff Alumni
    1. Archers [Arch] (Recruiting)

    Messages:
    454
    It's been suggested before to have an end of match statistics dialogue box. It would be similar to the end of game statistics of worms. I was just posting to see how this could be done, as a thought coding. Starting somewhere basic like how many times you killed/ where killed and by what. Would this be too tasking on the engine, where would it store the info, would it cause more lag?
     
    SirDangalang likes this.
  2. SirDangalang

    SirDangalang Lvl. 128 MissingNo. Donator

    Messages:
    235
    Oh god and if there were like little trophies awarded to players like most damage dealt, or the Darwinism award for most suicides my life would be complete haha :D
     
  3. Geti

    Geti Please avoid PMing me (poke a mod instead) THD Team Administrator Global Moderator

    Messages:
    3,730
    This is actually a really simple piece of programming, the hard part is the sheer coverage you need for it to really be useful.

    You can store it a rules-side class - which is easier to work with from within AS than a set of rules properties (get_s32, set_s32 and the like) and lets you implement more complex functionality without requiring a heap of (manual, slow) getting and setting. The overhead (ie how much lag is added) is really up to you in how you collect these stats. Using hooks for specific events (eg a blob dying) is much faster than looping over all blobs every frame to check if they're dying and tracking which blobs have been counted as dead, for example.

    If someone feels like making a fully fledged stats system and people want it included in vanilla I'm happy to oblige - however the fact that this question has somehow only just been raised is rather damning.

    you'll need to attach this to a gamemode:

    Code:
    //Example stats implementation for KAG
    //  needs testing and extension but should
    //  illustrate the point quite nicely.
    
    //file here will end up inside cache
    string config_filename = "example_stats_data.cfg";
    
    //the stats storage class - I've tried to keep this
    //as simple as possible. As such, it's not actually
    //the most flexible system, as adding new variables
    //involves a bit of typing - however it's very easy
    //to use, just modify the internal stats and they're
    //saved every map change.
    class ExampleStats
    {
      s32 kills;
      s32 deaths;
    
      //load on construction
      ExampleStats() {
      load();
      }
    
      //saving and loading the data
      // - we need to go through each
      //  variable here because it
      //  needs to be given a name
      //  in the config file as well
      void load()
      {
      ConfigFile cfg = ConfigFile();
      //this can fail, but the cfg will just read default values
      //note that we load from cache, not just the filename
      cfg.loadFile("../Cache/"+config_filename);
       
      kills = cfg.read_s32("kills", 0);
      deaths = cfg.read_s32("deaths", 0);
      }
    
      void save()
      {
      ConfigFile cfg = ConfigFile();
    
      cfg.add_s32("kills", kills);
      cfg.add_s32("deaths", deaths);
    
      cfg.saveFile(config_filename);
      }
    
      //get the formatted stats as a multi-line string
      string[] getFormattedStats() {
      string[] ret;
      ret.push_back("STATS:");
      ret.push_back("  "+kills+" kills");
      ret.push_back("  "+deaths+" deaths");
      ret.push_back("  "+int((1.0f-float(kills)/deaths)*100)+"% stupid deaths"); //an example of higher level, calculated stats - how many deaths weren't caused by the enemy?
      return ret;
      }
    };
    
    //helpers to get or set up the stats structure
    ExampleStats@ getStats() {
      ExampleStats@ s = null;
      getRules().get("example stats", @s);
      return s;
    }
    
    void initStats() {
      //save old stats if they exist
      ExampleStats@ oldstats = getStats();
      if(oldstats !is null) {
      oldstats.save();
      }
      //load new stats
      ExampleStats s;
      getRules().set("example stats", @s);
    }
    
    //hooks: generally where you'll do your actual stat collection
    
    //engine-side hooks to set up the rules each time
    void onRestart(CRules@ this) { initStats(); }
    void onInit(CRules@ this) { onRestart(this); }
    
    // set kills and deaths
    void onBlobDie( CRules@ this, CBlob@ blob )
    {
      if (blob !is null)
      {
      CPlayer@ killer = blob.getPlayerOfRecentDamage();
      CPlayer@ victim = blob.getPlayer();
    
      if (victim !is null)
      {
      ExampleStats@ s = getStats();
      s.deaths++;
       
      if (killer !is null && killer.getTeamNum() != blob.getTeamNum())
      {
      s.kills++;
      }
       
      }
      }
    }
    
    bool onServerProcessChat( CRules@ this, const string& in text_in, string& out text_out, CPlayer@ player )
    {
      if (player is null)
      return true;
    
      //probably want to limit spamming this tbh
      if(text_in == "!stats")
      {
      ExampleStats@ s = getStats();
      //ensure stats exist
      if(s is null) return false;
    
      //send the stats messages
      string[] str = s.getFormattedStats();
      for(uint i = 0; i < str.length; i++)
      {
      getNet().server_SendMsg(str[i]);
      }
    
      //dont print the !stats from them
      return false;
      }
    
      return true;
    }
    
    //you could also use oncommand in conjunction with gameplay event
    //commands, like the ones sent by flag capture, and vehicle
    //destruction to log all sorts of things. Sky's the limit.
    
    
    stats example in game with some simple bot kills
    http://grab.by/ENYS

    If you want per-player stats you'll have to implement some sort of look up by username and store an array of stats objects for players.

    Don't ever say I don't support the modding scene :)

    Have fun.
     
    kodysch and zerd like this.
  4. kittycity

    kittycity Haxor

    Messages:
    256
    Couldnt you just nick the system from BD and intergrate that with all servers?
     
  5. Geti

    Geti Please avoid PMing me (poke a mod instead) THD Team Administrator Global Moderator

    Messages:
    3,730
    Not really, as it's based on separate external programs afaik if it's anything like the older stats systems and Leo treats most things like that as trade secrets (which is fine, it's his server and he's providing it as a service to the community).
     
  6. makmoud98

    makmoud98 You are already DEAD Forum Moderator Staff Alumni Tester

    Messages:
    586
    This sounds like something I might work on. Ill think about it