Anti-AFK System v1.8 (New Build)

A simple anti-afk system
Checks if a player is afk by periodically increasing a timer and when a player doesn't do any unit order for a period of time, that player is marked as afk in the afk player lists.

This system is fully configurable
This system is configured to work with any type of maps. Useful for AoS or Hero Arena types of maps

Initial setup:
*Will register playing players at startup excluding computers.

Requires:
- TimerUtils
- GetPlayerNameColored (just for coloring player names)
- OrderEvent
- JNGP (system is written in vJass)

Pros:
- Mostly configurable
- Efficient enough
- Simple (easy to understand for newbies)

Cons:
- You can't kick yourself!

APIs:
function RegisterAFKPlayer takes player p returns boolean
function RemoveAFKPlayer takes player p returns nothing
function ResetAFKPlayer takes player p returns nothing
function GetAFKTime takes player p returns real

System Code:
JASS:
/*
* Anti AFK library by jim7777
*   version 1.8
*
*  Allows you to retrieve and kick "Away from Keyboard" players.
*
*  Requires:
*    OrderEvent by Bribe            -   http://www.hiveworkshop.com/forums/jass-resources-412/snippet-order-event-190871/
*    GetPlayerColored by Ammorth    -   http://www.wc3c.net/showthread.php?t=101692
*
*   API:
*
*     function RegisterAFKPlayer takes player p returns boolean
*     function RemoveAFKPlayer takes player p returns nothing
*     function ResetAFKPlayer takes player p returns nothing
*     function GetAFKTime takes player p returns real
*/
library AntiAFK requires OrderEvent, GetPlayerColored
    globals
        private constant real INTERVAL = 1 //how often should we check for afk players? value should be in seconds
        private constant string AFK = "-afk" //the chat command to enter for checking afk players
        private constant string KICK = "-kickafk" //the chat comment to enter for kicking players 
        private constant integer MAX_TIME = 10 //the required amount of time (in seconds) to check if a player can be kicked
                                               // value should be greater than 1
        private constant integer MIN_TIME = 3 //the required amount of time (in seconds) to check if a player is afk
                                               // value should be greater than 1
    endglobals
    
    //! textmacro AntiAFK_OnKickHook
        /*
        * Add your hook functions here if we have successfully kicked a player 
        * variable p is the afk player and variable t is the player who kicked that afk player 
        * Default Value:
        
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,8,GetPlayerNameColored(p) + " was kicked by " + GetPlayerNameColored(t) + " for being afk!")
        call RemovePlayer(p,PLAYER_GAME_RESULT_VICTORY)
        
        //===============================================*/
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,8,GetPlayerNameColored(p) + " was kicked by " + GetPlayerNameColored(t) + " for being afk!")
        call RemovePlayer(p,PLAYER_GAME_RESULT_DEFEAT)
        //===============================================
    //! endtextmacro
    
//==== END OF CONFIGURABLES =====
    globals
        private hashtable ht = InitHashtable()
    endglobals
    
    private struct Afk
        player pl
        real dur
        
        static method KickPlayer takes player t, player p, integer id returns nothing
            call thistype(LoadInteger(ht,id,0)).destroy()
            call FlushChildHashtable(ht,id)
            //! runtextmacro AntiAFK_OnKickHook()
        endmethod
        
        static method CheckOutput takes nothing returns nothing
            local integer i = 0
            local integer int
            loop
                exitwhen i > 11
                if HaveSavedInteger(ht,i,0) then
                    set int = LoadInteger(ht,i,0)
                    set thistype(int).dur = thistype(int).dur + INTERVAL
                    if thistype(int).dur >= MAX_TIME and not HaveSavedBoolean(ht,i,0) then
                        call SaveBoolean(ht,i,0,true)
                        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,5,GetPlayerNameColored(thistype(int).pl) + " has been afk for " + R2S(thistype(LoadInteger(ht,i,0)).dur/60) + " minute(s). Type |CFF7EBFF1" + KICK + " " + I2S(i+1) + "|r to kick this player." )
                    endif
                endif
                set i = i + 1
            endloop
        endmethod
        
        static method OnChat takes nothing returns boolean
            local string str = GetEventPlayerChatString()
            local string st = ""
            local integer i = 0
            local integer int
            local player p = GetTriggerPlayer()
            if str == AFK then
                loop
                    exitwhen i > 11
                    if HaveSavedInteger(ht,i,0) then
                        set int = LoadInteger(ht,i,0)
                        if thistype(int).dur > MIN_TIME then
                            set st = st + GetPlayerNameColored(Player(i)) + " has been afk for " + R2S(thistype(int).dur/60) + " minute(s). \n"
                        endif
                    endif
                    set i = i + 1
                endloop
                if st == "" then
                    call DisplayTimedTextToPlayer(p,0,0,5,"No one is afk.")
                else
                    call DisplayTimedTextToPlayer(p,0,0,5,st)
                endif
                call DisplayTimedTextToPlayer(p,0,0,1," ")
            elseif SubString(str,0,StringLength(KICK)) == KICK then
                if S2I(SubString(str,StringLength(KICK)+1,2)) != 0 then
                    set int = S2I(SubString(str,StringLength(KICK)+1,2))
                    if int <= 12 and int > 0 then
                        set int = int - 1
                        if HaveSavedBoolean(ht,int,0) and int != GetPlayerId(p) then
                            call thistype.KickPlayer.execute(p,Player(int),int)
                        endif
                    endif
                elseif S2I(SubString(str,StringLength(KICK)+1,1)) != 0 then
                    set int = S2I(SubString(str,StringLength(KICK)+1,1))
                    if int <= 12 and int > 0 then
                        set int = int - 1
                        if HaveSavedBoolean(ht,int,0) and int != GetPlayerId(p) then
                            call thistype.KickPlayer.execute(p,Player(int),int)
                        endif
                    endif
                endif
            endif
            set p = null
            return false 
        endmethod
        
        static method OnOrder takes nothing returns boolean
            local integer id = GetPlayerId(GetTriggerPlayer())
            if HaveSavedInteger(ht,id,0) and thistype(LoadInteger(ht,id,0)).dur > (MIN_TIME-1) then
                set thistype(LoadInteger(ht,id,0)).dur = 0
                call RemoveSavedBoolean(ht,id,0)
            endif
            return false 
        endmethod
        
        static method register takes player p returns nothing
            local thistype dat
            local integer i = GetPlayerId(p)
            if not HaveSavedInteger(ht,i,0) and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
                set dat = thistype.allocate()
                call SaveInteger(ht,i,0,dat)
                set dat.pl = Player(i)
                set dat.dur = 0
            debug else
                debug call BJDebugMsg("[AntiAfk] Player " + GetPlayerName(Player(i)) + " cannot be registered!")
            endif
        endmethod
        
        static method onInit takes nothing returns nothing
            local integer i = 0
            local trigger t
            local thistype dat
            if MIN_TIME <= 1 or MAX_TIME <= 1 then
                debug call BJDebugMsg("[AntiAFK] Crashed! Invalid values for MIN_TIME or MAX_TIME")
                return
            endif
            set t = CreateTrigger()
            call RegisterAnyOrderEvent(function thistype.OnOrder)
            call TimerStart(CreateTimer(),INTERVAL,true,function thistype.CheckOutput)
            loop
                exitwhen i > 11
                call TriggerRegisterPlayerChatEvent(t,Player(i),"-",false)
                if GetPlayerController(Player(i)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and not HaveSavedInteger(ht,i,0) then
                    set dat = thistype.allocate()
                    call SaveInteger(ht,i,0,dat)
                    set dat.pl = Player(i)
                    set dat.dur = 0
                endif
                set i = i + 1
            endloop
            call TriggerAddCondition(t,Filter(function thistype.OnChat))
            set t = null
        endmethod
    endstruct
    
    function RegisterAFKPlayer takes player p returns nothing
        call Afk.register(p)
    endfunction
    
    function RemoveAFKPlayer takes player p returns nothing
        call Afk(LoadInteger(ht,GetPlayerId(p),0)).destroy()
        call FlushChildHashtable(ht,GetPlayerId(p))
    endfunction
    
    function ResetAFKPlayer takes player p returns nothing
        set Afk(LoadInteger(ht,GetPlayerId(p),0)).dur = 0
        call RemoveSavedBoolean(ht,GetPlayerId(p),0)
    endfunction
    
    function GetAFKTime takes player p returns real
        return Afk(LoadInteger(ht,GetPlayerId(p),0)).dur
    endfunction
endlibrary

Don't forget to send feedbacks,comments or suggestions :D
This system is somewhat simple but you can have an idea on how to work on an afk system (and maybe improve this one, just don't forget to leave credits!)


*v1.8
- Added new function: GetAFKTime
- Fixed bug wherein removed players can't be re-registered again.
- Only playing players can be registered using RegisterAFKPlayer function.
- Re-configured AntiAFK_OnKickHook macro.
- Structs are now being destroyed.
- Removed requirement of TimerUtils
*v1.7b
- Added new function: ResetAFKPlayer
*v1.7
- New build (Rebuilt whole system code). Most APIs were removed
*Uses one timer only
*Renamed global variables
*Uses hashtables instead of poor indexes (I call them "poor indexes")
*Uses textmacro for the hook (users! nevermind this thing)
*System will not initialize if MIN_TIME or MAX_TIME is set to 1
*Optimized code (improved efficiency and less code lines)
- Now requires Order Event
---------------------
*v1.6c
- Fixed bug where only computers are registered on start up (thanks to Klann)
*v1.6b
- Fixed some bugs
*v1.6
- Fixed bug with AFKSys_GetTime function showing (null)
- Optimized coding
- Improved coding (includes Bribe's suggestions).
- Now requires RegisterPlayerUnitEvent library by Magtheridon96
*v1.5d
- Improved coding.
- Fixed some test map only bugs.
*v1.5c
- Improved coding.
*v1.5b
- Improved coding (includes Bribe's suggestions).
*v1.5
- Added new function: AFKSys_ResetUnit
- Added some static if
- Improved coding of AFKSys_GetTime.
- Fixed some test map-only problems.
*v1.4
- Added new function: AFKSys_GetTime
- Reworked some parts of the system.
- Updated Test Map for the new function.
*v1.3b
- Auto remove leaving player's trigger will no longer be created when that function is disabled.
- Reverted a rework with the last version (v1.3)
*v1.3
- Minor fixings.
- Some reworked for the some functions.
- Added the player who kicked an afk player in the hook function. (variable name: kicker)
- Improved Coding (Bribe's suggestions)
*v1.2
- Fixed the bug that i failed to fix in v1.1 (the crash bug) damn that indention LOL
- Added support if you want to treat chat as an event to disable that player from being AFK (can be enabled or disabled).
*v1.1
- Fixed a bug causing a crash when you entered 0 as a value for -kickafk (thanks to geries)
- Added new function: AFKSys_GetSeconds
*v1.0
- Initial Release.


Keywords:
afk, anti, system, jim7777, vjass, kick, away, from, keyboard, noob, game, ruin
Contents

Anti-AFK system v1.8 (Map)

Reviews
14 Jan 2012 Bribe: While the bulk of this system could be reduced to simply catching issued orders in 95% of maps out there, this still adds some extra features that players can use if they want to. This system meets criteria for approval but you...

Moderator

M

Moderator

14 Jan 2012
Bribe: While the bulk of this system could be reduced to simply catching issued orders in 95% of maps out there, this still adds some extra features that players can use if they want to. This system meets criteria for approval but you really should invest in trimming down the code to only the necessary stuff (order events). Approved 2.5/5.
 
Level 13
Joined
Sep 13, 2010
Messages
550
Hmm sounds like good, btw we have few of them. I recommend to put in Chat Event and check camera position to make sure that player is AFK. Test...

Edit: I'm so sorry but I have found a bug! My Craft crashed.. That could be solved simply. About chat: I am sure that needs. If you try to flame in 4 lines it can take time... :D

if target <= MAX_PLAYERS and Player(target) != p then 148 line should be if target <= MAX_PLAYERS and target >= 0 and Player(target) != p then If I enter -kickafk 0 then I got error because player( target ) at first and creating player with -1 id is forbidden :)
 
Level 10
Joined
May 27, 2009
Messages
494
well i don't add that thing 'cause player might just shake down the camera so that the timer will reset and might bug with some camera systems out there

and also that chat event, might not be useful for maps which may take a long time to have units though. cinematics,preloads,etc

edit:
updated
 
Level 13
Joined
Sep 13, 2010
Messages
550
Off topic but about chat: In COD4 there is a mod called Zom Warfare and I was playing on a server which had Anti Afk system. So the thing is that when I was chatting with others for a longer time I was kicked due inactivity. It was kind annoying when I was at the first place and it is reseted... Also it is a nice idea to put something string to warn player that he is gone to AFK like You will be afk in 15 seconds and so on.

I seen your update and you made it soo quickly or haven't checked it so I think it is bad. It still crash. First I had to experiment that If a boolexpr is false it will not exit checking for more boolexpr like Player( target ) and here is where game crashes -> Player( -1 ) You should put a new condition that is especially filters that or change target != GetPlayerId( p )
 
Level 10
Joined
May 27, 2009
Messages
494
Off topic but about chat: In COD4 there is a mod called Zom Warfare and I was playing on a server which had Anti Afk system. So the thing is that when I was chatting with others for a longer time I was kicked due inactivity. It was kind annoying when I was at the first place and it is reseted... Also it is a nice idea to put something string to warn player that he is gone to AFK like You will be afk in 15 seconds and so on.

well i guess the chat thing maybe just a configurable like you can enable or disable it.

lol, warning a player who will go afk huh. weird... but you could use -afk command anyways.

--
yeah it still crash fixing it anyways
ok found it, little indention errors make me fail. LOL

edit:
fixed that thing (yes!)
and added the chat event, but disabled by default (user might think the system isn't working)
updated to v1.2
 
Level 13
Joined
Sep 13, 2010
Messages
550
Testing succesfull. No bugs found yet. :D Chat works right and I have no more... NO I have one more Idea!! What about unit selection? :D Hundreds of maps has that thing to wait for respawn and you can't do anything just selecting units and looking around i know AFKSys_RemovePlayer .... At the end you will get angry, hate me, report me, delete this :D

Oh and the spell title still 1.1 xD - fixed LOL
 
Level 4
Joined
Apr 1, 2011
Messages
96
I think this is a good idea. I'm sure many will use this for their maps because most people go afk without telling others. And others get angry at the afk guy without knowing it from the start(True Story).
- You can't kick yourself!
Anyway who would want to kick himself?

To admins: is this considered necroposting?
 
Level 10
Joined
May 27, 2009
Messages
494
perhaps a light version might do this.. but that thing might go to the jass section or people may just use a detect order library

but perhaps i won't go for detecting arrow key presses .. not all maps use arrow keys.. and some people might just keep on pressing arrow keys.. or should it be in a boolean D:
 
Level 9
Joined
Apr 7, 2010
Messages
480
i think you should add some text if player is successfully been kicked, ill be using this 5/5
 
Level 9
Joined
Apr 7, 2010
Messages
480
oh i get it now. kick is only applicable to computers which are not set through Scenario>Player Properties>Controller>Computer.
 
Top