Page 4 of 8 FirstFirst 12345678 LastLast
Results 31 to 40 of 79

Thread: Stats

  1. Registered TeamPlayer
    Join Date
    10-29-07
    Posts
    4,953
    Post Thanks / Like
    Stat Links

    Stats
    #31

    Re: Stats

    Bunni, another reason is that between those two log sets DoD was migrated from the old Source engine (the one CSS uses) to the Orange Box Source engine (the one TF2) uses. Because of the game engine upgrade, the log entries might be different/updated to use different terms.

  2. Administrator Bunni's Avatar
    Join Date
    08-29-07
    Posts
    14,279
    Post Thanks / Like
    Blog Entries
    7
    Stat Links

    Stats Stats Stats Stats Stats
    Gamer IDs

    Steam ID: bunni Bunni's Originid: Dr_Bunni
    #32

    Re: Stats

    Quote Originally Posted by Ewok
    Bunni, another reason is that between those two log sets DoD was migrated from the old Source engine (the one CSS uses) to the Orange Box Source engine (the one TF2) uses. Because of the game engine upgrade, the log entries might be different/updated to use different terms.
    Q_Q wow, can i just get a copy of ttps pstat parser for dod? Would save me a ton of time from crosschecking logs and trying to hypothesize on what the parser is looking for...


    As for hs tracking... the problem is that the player_death event for dod does not return a bool for a headshot... Thus the only way i could think of to track headshots should have to be for every headshot hitgroup on player_hurt check to see if a player_death event follows with the same victim and attacker... But even then that's a little resource heavy...

    Edit and as im looking through these 5000+ lined logs, it appears that mani was not able to track headshots eaither, seeing as i have yet to come across a weaponstat with a headshot hit group logged to it...

  3. Registered TeamPlayer
    Join Date
    10-29-07
    Posts
    4,953
    Post Thanks / Like
    Stat Links

    Stats
    #33

    Re: Stats

    It's just pstats 3.1, so you should be able to just download it normally.

    Since DoD doesn't properly support headshot tracking, I'm thinking we should go after more lower-hanging fruit.

  4. Administrator ...bigdog...'s Avatar
    Join Date
    06-10-05
    Posts
    51,240
    Post Thanks / Like
    Stat Links

    Stats Stats Stats
    Gamer IDs

    Steam ID: bigdogttp
    #34

    Re: Stats

    Quote Originally Posted by Ewok
    It's just pstats 3.1, so you should be able to just download it normally.

    Since DoD doesn't properly support headshot tracking, I'm thinking we should go after more lower-hanging fruit.
    correct. never has done it properly (for headshot kills, I believe). but it does do headshot hits for accuracy stats.

    antoher notable issue with DoD is that it doesn't distinguish between the chest and stomach like CSS does. It's just the torso.
    Quote Originally Posted by ...bigdog... View Post
    If turd fergusons want to troll their lives away, that's the world's problem. Go read the CNN.com comments section, or any comments section, anywhere. All of the big threads are going to be the crazy people saying stupid shit.

  5. Administrator Bunni's Avatar
    Join Date
    08-29-07
    Posts
    14,279
    Post Thanks / Like
    Blog Entries
    7
    Stat Links

    Stats Stats Stats Stats Stats
    Gamer IDs

    Steam ID: bunni Bunni's Originid: Dr_Bunni
    #35

    Re: Stats

    Quote Originally Posted by ...bigdog...
    Quote Originally Posted by Ewok
    It's just pstats 3.1, so you should be able to just download it normally.
    :3 :3
    Since DoD doesn't properly support headshot tracking, I'm thinking we should go after more lower-hanging fruit.
    correct. never has done it properly (for headshot kills, I believe). but it does do headshot hits for accuracy stats.

    antoher notable issue with DoD is that it doesn't distinguish between the chest and stomach like CSS does. It's just the torso.
    fantastic, not entirely different, just enough in which there needs to be a separate (and rewritten) function for everything :3


    Pseudo for DOD:
    Noted Differences:
    CounterStrike SourceDay Of Defeat Source
    Quote Originally Posted by CSS
    player_death

    Note: When a client dies
    Name: player_death
    Structure:
    short userid
    short attacker
    string weapon
    bool headshot
    Quote Originally Posted by DOD
    player_death

    Note: When a player dies
    Name: player_death
    Structure:
    short userid
    short attacker
    string weapon
    bool dominated
    bool revenge
    Quote Originally Posted by WeaponFire
    weapon_fire

    Note: Every time a client fires their weapon
    Name: weapon_fire
    Structure:
    short userid
    string weapon
    dod_stats_weapon_attack

    Note: When a player attacks with a weapon
    Name: dod_stats_weapon_attack
    Structure:
    short attacker
    byte weapon
    player_hurt

    Note: When a client is damaged
    Name: player_hurt
    Structure:
    short userid
    short attacker
    byte health
    byte armor
    string weapon
    byte dmg_health
    byte dmg_armor
    byte hitgroup
    dod_stats_player_damage

    Note: When a player damages another
    Name: dod_stats_player_damage
    Structure:
    short attacker
    short victim
    byte weapon
    short damage
    byte damage_given
    float distance
    byte hitgroup
    round_end

    Note: The round ended
    Name: round_end
    Structure:
    byte winner
    byte reason
    string message
    dod_round_win

    Note: When a round is won
    Name: dod_round_win
    Structure:
    byte team




    Either, will need to make a new function for each dod event or will need to check modinfo for every event save player_death
    Im in favor of creating a new event entirely to save the server the hastle of the extra if loop, though the codes length will significantly increase. :3

    Thoughts?
    _________________________________________________
    Code:
    Check mod info:
    watch for event weapon_fire if triggered go to weaponfired:
    watch for event dod_stats_weapon_attack if triggered to go weaponfired:
    
    weaponfired:
       if modinfo == dod:
         get eventstring attacker (inplace of userid for css)
       if modinfo == css
         get eventstring userid
    _________________________________________________
    New Function for each:
    Code:
    watch for event weapon_fire if triggered go to cssweaponfired:
    watch for event dod_stats_weapon_attack if triggered to go dodweaponfired:
    
    cssweaponfired:
         get eventstring userid
         ....
    
    dodweaponfired:
         get eventstring attacker
    and so on for each...


    _________________________________________________

    As i said before, Im in favor of the latter of the two, saves resources at the cost of length...




    Bun-

  6. Administrator Bunni's Avatar
    Join Date
    08-29-07
    Posts
    14,279
    Post Thanks / Like
    Blog Entries
    7
    Stat Links

    Stats Stats Stats Stats Stats
    Gamer IDs

    Steam ID: bunni Bunni's Originid: Dr_Bunni
    #36

    Re: Stats

    dod_stats_player_damage

    Note: When a player damages another
    Name: dod_stats_player_damage
    Structure:
    short attacker
    short victim
    byte weapon
    short damage
    byte damage_given
    float distance
    byte hitgroup


    makes me worry, might need to have a hook which prints the byte below the player_death default log output, for a few days inorder to get all the numbers matched with weapon names... :3
    edit:
    fucking hell ima need to buy this game, unless i can get bots to fight and print test lines on a dedicated server.... :3


    edit2

    Ewok, im going to need to add vars in the cfg files for stats now, since dod will need to print weaponstats at a set time, which cfg do you want them in?

  7. Administrator Bunni's Avatar
    Join Date
    08-29-07
    Posts
    14,279
    Post Thanks / Like
    Blog Entries
    7
    Stat Links

    Stats Stats Stats Stats Stats
    Gamer IDs

    Steam ID: bunni Bunni's Originid: Dr_Bunni
    #37

    Re: Stats

    support for dod added, all thats left is to add in the method to check the cfgs for a specified time to run print stats...
    Code:
    import hl2sdk as sdk
    from lonestar import events
    from lonestar.logging import logger
    from lonestar.client import playerManager
    from lonestar.client import Player
    from lonestar import client
    from lonestar import modinfo
    from lonestar.modinfo import teamManager
    from lonestar.modinfo import discoverModInfo
    from lonestar import hud
    import time
    import threading
    
    class TimerDOD(threading.Thread):
      def __init__(self, seconds):
        self.runTime = seconds
        threading.Thread.__init__(self)
      def run(self, funcToExecute):
        time.sleep(self.runTime)
        StatisticsDaemon._forceprintWeaponStatsDOD()
    
    
    class PlayerStats(object):
      def __init__(self):
        self.allWeaponStats = {} 
      
      def getStatsForWeapon(self, weaponName):
        try:
          weaponStats = self.allWeaponStats[weaponName]
        except KeyError:
          weaponStats = WeaponStats(weaponName)
          self.allWeaponStats[weaponName] = weaponStats
        return weaponStats
        
    class WeaponStats(object):
      def __init__(self, weaponName):
        self.weaponName = weaponName
        self.S_shotsFired = 0
        self.S_hits = 0
        self.S_kills = 0
        self.S_headshots = 0
        self.S_tks = 0
        self.S_damage = 0
        self.S_deaths = 0
        self.S_head = 0
        self.S_chest = 0
        self.S_stomach = 0
        self.S_leftarm = 0
        self.S_rightarm = 0
        self.S_leftleg = 0
        self.S_rightleg = 0
      
    class TeamStats(object):
      def __init__(self):
        self.roundsWon = 0
        
    class GameStats(object):
      def __init__(self):
        self.someGameStat = 0
    
    _PDATA_KEY_STATS = "stats"
    class StatisticsDaemon(object):
      def __init__(self):
        self.gameStats = GameStats()
        for team in teamManager.getTeams():
          team.data[_PDATA_KEY_STATS] = TeamStats()
        self.offlinePlayers = {}
        events.addListener(events.EVENT_PLAYER_CONNECTED, self._playerConnected)
        events.addListener(events.EVENT_PLAYER_DISCONNECTED, self._playerDisconnected)
        if modinfo.modName == "cstrike":
          sdk.addGameEventListener("player_death", self._determineSourceOfDeathCSS)
          sdk.addGameEventListener("player_hurt", self._playerHurtCSS)
          sdk.addGameEventListener("weapon_fire", self._weaponFireCSS)
          sdk.addGameEventListener("round_end", self._roundendCSS)
        if modinfo.modName == "dod":
          sdk.addGameEventListener("player_death", self._determineSourceOfDeathDOD)
          sdk.addGameEventListener("dod_stats_player_damage", self._playerHurtDOD)
          sdk.addGameEventListener("dod_stats_weapon_attack", self._weaponFireDOD)
          sdk.addGameEventListener("dod_round_win", self._roundendDOD)
        #... add other event listeners...
        
      def getPlayerStats(self, player):
        return player.data[_PDATA_KEY_STATS]
      
      def getPlayerWeaponStats(self, player, weaponName):
        return player.data[_PDATA_KEY_STATS].getStatsForWeapon(weaponName)
      
      def _playerConnected(self, data, player):
        # Check if the player has existing stats, and use them if he does, otherwise make new stats
        player.data[_PDATA_KEY_STATS] = PlayerStats()    
      
      def _playerDisconnected(self, data, player):
        # Store the stats in the offline database
        self._printWeaponStats(player)    
        del player.data[_PDATA_KEY_STATS]
        
      def _determineSourceOfDeathCSS(self, event):
        if event.getInt("userid") == event.getInt("attacker"):
          self._playerSuicideCSS(event)
          
        if event.getInt("userid") != event.getInt("attacker"):
          self._playerKilledCSS(event)
          
      def _determineSourceOfDeathDOD(self, event):
        if event.getInt("userid") == event.getInt("attacker"):
          self._playerSuicideDOD(event)
          
        if event.getInt("userid") != event.getInt("attacker"):
          self._playerKilledDOD(event)
    
      def _playerKilledCSS(self, event):
        weapon = event.getString("weapon")
        victim = playerManager.findPlayers(event.getInt("userid"))[0]
        victimStats = self.getPlayerStats(victim).getStatsForWeapon(weapon)    
        attacker = playerManager.findPlayers(event.getInt("attacker"))[0]
        attackerStats = self.getPlayerStats(attacker).getStatsForWeapon(weapon)
        if (victim.getTeamId() == attacker.getTeamId()):
          attackerStats.S_tks += 1
        elif (victim.getTeamId() != attacker.getTeamId()):
          victimStats.S_deaths += 1
          attackerStats.S_kills += 1
          if (event.getBool("headshot") == True):
              attackerStats.S_headshots += 1
              
      def _playerKilledDOD(self, event):
        weapon = event.getString("weapon")
        victim = playerManager.findPlayers(event.getInt("userid"))[0]
        victimStats = self.getPlayerStats(victim).getStatsForWeapon(weapon)    
        attacker = playerManager.findPlayers(event.getInt("attacker"))[0]
        attackerStats = self.getPlayerStats(attacker).getStatsForWeapon(weapon)
        if (victim.getTeamId() == attacker.getTeamId()):
          attackerStats.S_tks += 1
        elif (victim.getTeamId() != attacker.getTeamId()):
          victimStats.S_deaths += 1
          attackerStats.S_kills += 1
          if (event.getBool("headshot") == True):
              attackerStats.S_headshots += 1
              
      def _playerSuicideCSS(self, event):
        weapon = event.getString("weapon")
        victim = playerManager.findPlayers(event.getInt("userid"))[0]
        victimStats = self.getPlayerStats(victim).getStatsForWeapon(weapon)
        victimStats.S_deaths += 1
        
      def _playerSuicideDOD(self, event):
        weapon = event.getString("weapon")
        victim = playerManager.findPlayers(event.getInt("userid"))[0]
        victimStats = self.getPlayerStats(victim).getStatsForWeapon(weapon)
        victimStats.S_deaths += 1
        
      def _playerHurtCSS(self, event):
        weapon = event.getString("weapon")      
        attacker = playerManager.findPlayers(event.getInt("attacker"))[0]
        attackerStats = self.getPlayerStats(attacker).getStatsForWeapon(weapon)
        attackerStats.S_damage += (event.getInt("dmg_health") + event.getInt("dmg_armor"))
        attackerStats.S_hits += 1    
        hitgroup = event.getInt("hitgroup")
        if (hitgroup == 1):
          attackerStats.S_head += 1
        elif (hitgroup == 2):
          attackerStats.S_chest += 1
        elif (hitgroup == 3):
          attackerStats.S_stomach += 1
        elif (hitgroup == 4):
          attackerStats.S_leftarm += 1
        elif (hitgroup == 5):
          attackerStats.S_rightarm += 1        
        elif (hitgroup == 6):
          attackerStats.S_leftleg += 1
        elif (hitgroup == 7):
          attackerStats.S_rightleg += 1
        else:
          logger.error("Stats returned invalid hitgroup: %d" % (event.getInt("hitgroup")))
          
      def _playerHurtDOD(self, event):
        weapon = event.getString("weapon")      
        attacker = playerManager.findPlayers(event.getInt("attacker"))[0]
        attackerStats = self.getPlayerStats(attacker).getStatsForWeapon(weapon)
        attackerStats.S_damage += (event.getInt("damage_given"))
        attackerStats.S_hits += 1    
        hitgroup = event.getInt("hitgroup")
        if (hitgroup == 1):
          attackerStats.S_head += 1
        elif (hitgroup == 2):
          attackerStats.S_chest += 1
        elif (hitgroup == 3):
          attackerStats.S_stomach += 1
        elif (hitgroup == 4):
          attackerStats.S_leftarm += 1
        elif (hitgroup == 5):
          attackerStats.S_rightarm += 1        
        elif (hitgroup == 6):
          attackerStats.S_leftleg += 1
        elif (hitgroup == 7):
          attackerStats.S_rightleg += 1
        else:
          logger.error("Stats returned invalid hitgroup: %d" % (event.getInt("hitgroup")))
          
      def _weaponFireCSS(self, event):  
        #need to make a new weapon stats line for player
        shooter = playerManager.findPlayers(event.getInt("userid"))[0]    
        weapon = event.getString("weapon")
        shooterStats = self.getPlayerStats(shooter).getStatsForWeapon(weapon)
        shooterStats.S_shotsFired += 1
        
      def _weaponFireDOD(self, event):  
        shooter = playerManager.findPlayers(event.getInt("attacker"))[0]    
        weapon = event.getString("weapon")
        shooterStats = self.getPlayerStats(shooter).getStatsForWeapon(weapon)
        shooterStats.S_shotsFired += 1
      
      def _printWeaponStats(self, player):
        for weaponStats in self.getPlayerStats(player).allWeaponStats.values():
          sdk.log("\"%s<%d><%s>\" triggered \"weaponstats\" (weapon \"%s\") (shots \"%d\") (hits \"%d\") (kills \"%d\") (headshots \"%d\") (tks \"%d\") (damage \"%d\") (deaths \"%d\")" % (player.name, player.uid, player.steamId, weaponStats.weaponName, weaponStats.S_shotsFired, weaponStats.S_hits, weaponStats.S_kills, weaponStats.S_headshots, weaponStats.S_tks, weaponStats.S_damage, weaponStats.S_deaths))
          sdk.log("\"%s<%d><%s>\" triggered \"weaponstats2\" (weapon \"%s\") (head \"%d\") (chest \"%d\") (stomach \"%d\") (leftarm \"%d\") (rightarm \"%d\") (leftleg \"%d\") (rightleg \"%d\")" % (player.name, player.uid, player.steamId, weaponStats.weaponName, weaponStats.S_head, weaponStats.S_chest, weaponStats.S_stomach, weaponStats.S_leftarm, weaponStats.S_rightarm, weaponStats.S_leftleg, weaponStats.S_rightleg))
          
      def _roundendCSS(self, event):
        #for player in playerManager.players:
        for player in playerManager.getPlayerSubset(client.SUBGROUP_IN_GAME_PEOPLE):
          self._printWeaponStats(player)      
          player.data[_PDATA_KEY_STATS] = PlayerStats()
    
      def _roundendDOD(self, event):
        #for player in playerManager.players:
        for player in playerManager.getPlayerSubset(client.SUBGROUP_IN_GAME_PEOPLE):
          self._printWeaponStats(player)      
          player.data[_PDATA_KEY_STATS] = PlayerStats()
      
      def _forceprintWeaponStatsDOD(self):
        #for player in playerManager.players:
        for player in playerManager.getPlayerSubset(client.SUBGROUP_IN_GAME_PEOPLE):
          self._printWeaponStats(player)      
          player.data[_PDATA_KEY_STATS] = PlayerStats()
          
    statisticsDaemon = StatisticsDaemon()
    after i finish dod, whats next? Tf2? Then l4d (when pstats supports it?)?

  8. Registered TeamPlayer
    Join Date
    10-29-07
    Posts
    4,953
    Post Thanks / Like
    Stat Links

    Stats
    #38

    Re: Stats

    I really don't think we need to duplicate all of that code; it leads to a maintenence nightmare of needing to change two places every time a fix or feature goes in.

    The differences bewteen DoD and CSS are not that large, most of the logic is the same. Using if statements is more appropriate. To speed it up, you can compare the mod type ahead of time so your just doing a boolean check.

    as in:
    Code:
    class StatisticsDaemon(object):
      def __init__(self):
        self.isDoD = False if modinfo.modName != "dod" else True
    ...
    Then you're later if checks are just checking if a boolean is true or false, which is very fast. It will save a lot of code and future headaches.

  9. Administrator Bunni's Avatar
    Join Date
    08-29-07
    Posts
    14,279
    Post Thanks / Like
    Blog Entries
    7
    Stat Links

    Stats Stats Stats Stats Stats
    Gamer IDs

    Steam ID: bunni Bunni's Originid: Dr_Bunni
    #39

    Re: Stats

    Quote Originally Posted by Ewok
    I really don't think we need to duplicate all of that code; it leads to a maintenence nightmare of needing to change two places every time a fix or feature goes in.

    The differences bewteen DoD and CSS are not that large, most of the logic is the same. Using if statements is more appropriate. To speed it up, you can compare the mod type ahead of time so your just doing a boolean check.

    as in:
    Code:
    class StatisticsDaemon(object):
      def __init__(self):
        self.isDoD = False if modinfo.modName != "dod" else True
    ...
    Then you're later if checks are just checking if a boolean is true or false, which is very fast. It will save a lot of code and future headaches.
    True, but what about when we add in more games?
    Even so doing the check for lets say... every weapon fired event (think of how many times 2 heavy's spraying in tf2 trigger weapon_fired O.o), seems a bit... unnecessary, no?

    As i said a few posts ago, could if-state it up, but then when more games are added more checks will be needed, event wise css, dod, tf2, and l4d all have similar yet different syntex
    Quote Originally Posted by tf2
    [edit] player_death

    Note: When a player dies
    Name: player_death
    Structure:
    short userid
    short attacker
    string weapon
    short weaponid
    long damagebits
    short customkill
    short assister
    short dominated
    short assister_dominated
    short revenge
    short assister_revenge
    string weapon_logclassname
    Quote Originally Posted by l4d
    player_death

    Note: When a client dies
    Name: player_death
    Structure:
    short userid
    long entityid
    short attacker
    string attackername
    long attackerentid
    bool headshot
    boot attackerisbot
    string victimname
    bool victimisbot
    bool abort
    long type
    float victim_x
    float victim_y
    float victim_z
    Quote Originally Posted by css
    player_death

    Note: When a client dies
    Name: player_death
    Structure:
    short userid
    short attacker
    string weapon
    bool headshot
    Quote Originally Posted by dod
    player_death

    Note: When a player dies
    Name: player_death
    Structure:
    short userid
    short attacker
    string weapon
    bool dominated
    bool revenge
    The current player_death hook would become monstrus looking at the game events. Numerious checks, we have to check game type when we log headshots since dod and tf2 do not track them, for l4d we have to deal with determining who was killed (infected, or surivior) then determine who killed them, (bot, special infected player, survivor (tk)). To encompass a single function do check all this and more is a unnecessary server workload, complicates the code, and will have to be done for nearly (probably all) hooks. Do we not need to keep hooks like weapon_fired and player_hurt (that may be fired many many times a second) and simplistic as possible? We dont want another mani lag outbreak

    With seperate events we do not need to change the code for the would-be same function everytime we add a new game. Whats worse, If the single method breaks, they all break. No redundancy. With separate functions if say a game pulled a similar move like dod did to orange box engine then that single function gets updated and not the single one for every game. So we can avoid, in a case similar to that, having to (after a update to the code) check and test it out in every game its implimented in. Last thing we need is to find out a l4d stats update broke tf2s stats... or something similar...

    true, it adds a maintenance nightmare, but saves the hassle of numerous unnecessary checks and either way (single or multi functions) if pstats does a update and changes syntex they all have to get updated anyways. This way, css is done, we know its working as long as its remains untouched...

    Thoughts?

    _________________________________________________
    (btw whats the best way for me to grab a setting from a cfg file?)

  10. Registered TeamPlayer
    Join Date
    10-29-07
    Posts
    4,953
    Post Thanks / Like
    Stat Links

    Stats
    #40

    Re: Stats

    In software, duplicate code is something to always be avoided. The costs of if statements is small, and doing a couple of extra ones doesn't really justify all of the duplicate code and issues that will create.

    The idea isn't to have simplistic functions, it's to create code that doesn't do unnecessary work. Because the contents of the events are inherently different, we don't have of a choice in that

    In practice, there are multiple techniques to use that get rid of the need for duplicate code, and you end up using all of them, not just one of them
    1) Single path with branches inside of it, but as you noted this can get messy
    2) Multiple paths, where a function pointer is given as the choice of which path to take.
    3) Break the work into smaller units, and use subclasses to implement the mod-specific work.
    4) Use variables to hold the dynamic aspects, initialize them early on, and then just use them in place of hard-coded choices. For instance, if the only difference is the name of the field in the event, you can store that in a variable early on, initialize that when the daemon first is created based on the mod, and then forever more just use the variable.


    All I'm saying is that we can solve this problem without duplicating the code using a combination of the above items. Just using #2 leads to too much code duplication, while just using #1 leads to messy code.

    It actually might work out really well to have a generic stats deamon, and then have mod specific subclasses of it that override key parts that are mod specific. That way if a mod uses the generic path, it works as needed, but if a mod has specific functionality needed, it overrides it. The other techniques can then be used on top of this base.

Page 4 of 8 FirstFirst 12345678 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Title