]> jfr.im git - irc/gameservirc.git/commitdiff
Implemented a player timeout scheme
authorkainazzzo <redacted>
Wed, 7 Apr 2004 23:26:02 +0000 (23:26 +0000)
committerkainazzzo <redacted>
Wed, 7 Apr 2004 23:26:02 +0000 (23:26 +0000)
git-svn-id: https://svn.code.sf.net/p/gameservirc/code/trunk@165 bc333340-6410-0410-a689-9d09f3c113fa

gameserv/TODO
gameserv/config.cpp
gameserv/extern.h
gameserv/gameserv.cpp
gameserv/gameserv.example.conf
gameserv/player.cpp
gameserv/player.h
gameserv/tcpclient.cpp

index 254134e0f4d742ddae30aee648fea067545936b0..5b1666a9da1b17fb84c4f330188f422628c11338 100644 (file)
@@ -52,6 +52,7 @@ X = Finsihed
     versions of GameServ to be running on the same network using the same data.
 
 * Classes of players with special abilities like spells and such.
+       - Thieves can rob the bank if they're strong enough :)
 
 * Error handling
 
index d377ebd69da774afdfe0f5d14213c3e20ae75aee..c653fc4b9bfdd61dc9d7cda23e10803c8ab01a2e 100644 (file)
@@ -26,6 +26,8 @@ int updateperiod;             // Seconds until another player database update
 int forestfights;              // Forest fights per day
 int maxafightdistance;         // Max levels above a player they can fight player->player
 int maxbfightdistance;         // Max levels below a player they can fight player->player
+int maxidletime;               // Max time (in seconds) a player can be idle for
+int idlecheckperiod;           // Period for checking every player's idle time
 
 // Remote server stuff. This is used for the outgoing connection gameserv needs to make
 // to a real ircd.
@@ -77,7 +79,7 @@ int load_config_file(char *config)
 {
     char *buf, *directive, *value;
 
-    #define numdirectives 19
+    #define numdirectives 21
 
     unload_config_file();
 
@@ -109,6 +111,11 @@ int load_config_file(char *config)
                                "that you can fight player->player";
     directives[18].desc = "MAXBFIGHTDISTANCE - The maximum number of levels below you "\
                                "that you can fight player->player";
+    directives[19].desc = "MAXIDLETIME - The maximum amount of time (in seconds) "\
+                               "that a player can be idle before something happens";
+    directives[20].desc = "IDLECHECKPERIOD - The period (in seconds) in which the entire "\
+                               "players list will be checked for idlers. See also: "\
+                               "MAXIDLETIME";
 
     for (int count = 0; count < numdirectives; count++)
     {
@@ -274,6 +281,18 @@ int load_config_file(char *config)
            maxbfightdistance = stringtoint(value);
            directives[18].done = true;
        }
+       else if (stricmp(directive, "MAXIDLETIME") == 0)
+       {
+           value = strtok(NULL, " ");
+           maxidletime = stringtoint(value);
+           directives[19].done = true;
+       }
+       else if (stricmp(directive, "IDLECHECKPERIOD") == 0)
+       {
+           value = strtok(NULL, " ");
+           idlecheckperiod = stringtoint(value);
+           directives[20].done = true;
+       }
        else
        {
            #ifdef DEBUGMODE
index 8ce04dac78dae9597c5beda65268d11f5b2c6391..a92bf726ef9a87087225f9647d60adb6809ee0d8 100644 (file)
@@ -70,6 +70,8 @@ E int updateperiod;
 E int forestfights;
 E int maxafightdistance;
 E int maxbfightdistance;
+E int maxidletime;
+E int idlecheckperiod;
 
 /* config.cpp end */
 
@@ -77,6 +79,9 @@ E List<aClient> players[U_TABLE_SIZE];
 E List<aClient> clients[U_TABLE_SIZE];
 E Monster boss;
 
+/** tcpclient.cpp **/
+E void check_idles();
+
 /** List search functions **/
 E aClient *find(char *nick);
 E aClient *find(const char *nick);
@@ -89,6 +94,8 @@ E aClient *findIRCplayer(const char *nick);
 E aClient *findbyrealnick(char *realnick);
 #endif
 
+/** tcpclient.cpp **/
+
 /** Sock writing functions **/
 E void notice(const char *source, const char *dest, const char *fmt, ...);
 E void raw(const char *fmt, ...);
@@ -136,6 +143,9 @@ E Monster *getNewMonster(Monster *m);
 E void deleteMonster(Monster *m);
 E void refresh(Player *p);
 E void refreshall();
+E void updateTS(Player *p);
+E bool timedOut(Player *p);
+E void timeOutEvent(Player *p);
 E void reset(Player *p);
 E void resetall();
 
index 6d84fe470214ff9a4c14b68aee15a0af7887c058..0937cd705e5234bd3097fb750465d32567707a8c 100644 (file)
@@ -59,6 +59,10 @@ bool check_password(char *name, char *plaintext); // Finds a password for the gi
 /********** GameServ Booleans **********/
 
 bool shuttingdown;
+bool timedOut(Player *p);
+void  updateTS(Player *p);
+void timeOutEvent(Player *p);
+
 bool is_playing(char *u); // True if the given nickname in the clients list is playing.
 bool is_playing(aClient *user);
 
@@ -85,6 +89,7 @@ long int stringtoint(char *number);
 char *spaces(int len, char *seperator);
 void refresh(Player *p);
 void refreshall();
+void updateTS(Player *p);
 void reset(Player *p);
 void init_masters();
 void init_monsters();
@@ -646,7 +651,7 @@ void logout(aClient *user)
 void do_register(char *u)
 {
     char *password, *name;
-    aClient *user, *p;
+    aClient *user;
     name = strtok(NULL, " ");
     password = strtok(NULL, " ");
 
@@ -672,14 +677,14 @@ void do_register(char *u)
     }
     else if ((user = find(u)))
     {
-       p = findplayer(u);
-        if (!user->stats && !p)
+        if (!user->stats)
         {
            user->stats = new Player(user);
            user->stats->client = user; // Set the backwards pointer
            strcpy(user->stats->password, crypt(password, salt));
            strcpy(user->stats->name, name);
            unsigned long hv = HASH((unsigned char *) name, U_TABLE_SIZE);
+           updateTS(user->stats);
            players[hv].insertAtBack(user);
            notice(s_GameServ, u, "Player %s registered with password %s.", user->stats->name, password);
            notice(s_GameServ, u, "Write this password down. If you lose it, there is no way to retrieve it!");
@@ -737,6 +742,8 @@ void do_identify(char *u)
        #ifdef DEBUGMODE
            log("Setting data for identified");
        #endif
+       updateTS(user->stats);
+
        user->stats->setData(p->stats);
 
        #ifdef DEBUGMODE
@@ -769,7 +776,10 @@ void do_stats(char *u)
            return;
        }
        else
+       {
+           updateTS(user->stats);
            showstats(u, user->stats->name);
+       }
     }
     else
        showstats(u, nick);
@@ -967,18 +977,14 @@ bool is_playing(char *u)
 {
     aClient *user;
     if (!(user = find(u)))
-    {
        return false;
-    }
     else
-    {
-       return user->stats != NULL;
-    }
+       return is_playing(user);
 }
 
 bool is_playing(aClient *user)
 {
-    return user->stats != NULL && (stricmp(user->getNick(), "!NULL!") != 0);
+    return user->stats != NULL;
 }
 
 bool is_fighting(char *u)
@@ -986,17 +992,11 @@ bool is_fighting(char *u)
     aClient *user;
 
     if (!(user = find(u)))
-    {
        return false;
-    }
-    else if (user->stats)
-    {
-       return user->stats->fight != NULL || user->stats->battle != NULL 
-               || user->stats->master != NULL;
-    }
     else
-       return false;
+       return is_fighting(user);
 }
+
 bool is_fighting(aClient *user)
 {
     if (!is_playing(user))
@@ -1011,10 +1011,8 @@ bool player_fight(char *u)
 
     if (!(user = find(u)))
        return false;
-    else if (user->stats)
-       return user->stats->battle != NULL;
-    else
-       return false;
+    else 
+       return player_fight(user);
 }
 bool player_fight(aClient *user)
 {
@@ -1030,11 +1028,10 @@ bool master_fight(char *u)
 
     if (!(user = find(u)))
        return false;
-    else if (user->stats)
-       return user->stats->master != NULL;
     else
-       return false;
+       return master_fight(user);
 }
+
 bool master_fight(aClient *user)
 {
     if (!is_playing(user))
@@ -1052,16 +1049,22 @@ void do_fight(char *u)
     if (!nick)
     {
        notice(s_GameServ, u, "SYNTAX: /msg %S FIGHT PLAYER");
+       return;
     }
     else if (!(ni = find(u)))
     {
        notice(s_GameServ, u, "Fatal error. Contact a(n) %S admin. buf: %s", strtok(NULL, ""));
+       return;
     }
     else if (!is_playing(ni))
     {
        notice(s_GameServ, u, "You are not playing!");
+       return;
     }
-    else if (ni->stats->player_fights <= 0)
+
+    updateTS(ni->stats);
+
+    if (ni->stats->player_fights <= 0)
     {
        ni->stats->player_fights = 0; // just to be safe
        notice(s_GameServ, u, "You are out of player fights for the "\
@@ -1145,6 +1148,7 @@ void do_fight(char *u)
         display_players(ni);
     }
 }
+
 void do_use(char *u)
 {
     aClient *user;
@@ -1169,6 +1173,8 @@ void do_use(char *u)
        return;
     }
 
+    updateTS(user->stats);
+
     p = &user->stats->inventory;
 
     if (stricmp(item, "HEALTH") == 0)
@@ -1251,6 +1257,7 @@ void do_run(char *u)
         return;
     }
 
+    updateTS(user->stats);
     p = user->stats;
 
     if (p->battle)
@@ -1397,6 +1404,7 @@ void do_attack(char *u)
        // One has to be !NULL based on the previous else if
        // We wouldn't be here if they were all NULL
     }
+    updateTS(ni->stats);
 
     if (!player_fight(ni))
     {
@@ -1708,6 +1716,7 @@ void do_heal(char *u)
     if (!amount)
     {
        notice(s_GameServ, u, "SYNTAX: /msg %S HEAL {ALL | #}");
+       return;
     }
     else if (!(ni = find(u)))
     {
@@ -1727,12 +1736,16 @@ void do_heal(char *u)
     else if (is_fighting(ni))
     {
        notice(s_GameServ, u, "You can't heal in battle!");
+       return;
     }
     else if (ni->stats->hp >= ni->stats->maxhp)
     {
         notice(s_GameServ, u, "You don't need healing!");
+       return;
     }
-    else if (stricmp(amount, "ALL") == 0)
+
+    updateTS(ni->stats);
+    if (stricmp(amount, "ALL") == 0)
     {
         price = ni->stats->level * 3;
         if (ni->stats->gold < (ni->stats->maxhp - ni->stats->hp) * price)
@@ -1987,15 +2000,21 @@ void do_store(char *u)
        notice(s_GameServ, u, "SYNTAX: STORE LIST {ARMOR | WEAPONS}");
        notice(s_GameServ, u, "        \ 2STORE SELL {ARMOR | WEAPON}\ 2");
        notice(s_GameServ, u, "        \ 2STORE BUY {ARMOR | WEAPON} \1fNUMBER\1f\ 2");
+       return;
     }
     else if (!(user = find(u)) || !is_playing(user))
+    {
        notice(s_GameServ, u, "You must be playing to use the store!");
+       return;
+    }
     else if (!isAlive(user->stats))
     {
        notice(s_GameServ, u, "You are dead. Wait until tomorrow to purchase weapons and armor!");
        return;
     }
-    else if (stricmp(cmd, "LIST") == 0)
+    updateTS(user->stats);
+
+    if (stricmp(cmd, "LIST") == 0)
     {
        if (stricmp(item, "WEAPONS") == 0)
        {
@@ -2164,6 +2183,7 @@ void do_inventory(char *u)
        notice(s_GameServ, u, "You must be playing to check your inventory!");
        return;
     }
+    updateTS(user->stats);
     showinventory(user, user);
 }
 void showinventory(aClient *from, aClient *to)
@@ -2204,7 +2224,10 @@ void do_tavern(char *u)
        notice(s_GameServ, u, "You cannot go to the Tavern during a fight!");
        return;
     }
+
+    updateTS(user->stats);
     p = user->stats;
+
     if (!cmd)
     {
        notice(s_GameServ, u, "Welcome to Boot Liquors Mystic Apothecary");
@@ -2319,14 +2342,21 @@ void do_bank(char *u)
        notice (s_GameServ, u, "BANK BALANCE");
        return;
     }
-
-    user = find(u);
-    if (!is_playing(user))
+    else if (!(user = find(u)))
+    {
+       notice(s_GameServ, u, "Fatal Error. Couldn't find your aClient. Contact a(n) %S "\
+                               " admin for help");
+       log("Fatal Error. Couldn't find %s while executing do_bank()", u);
+       return; 
+    }
+    else if (!is_playing(user))
     {
        notice(s_GameServ, u, "You must be playing to use the bank!");
        return;
     }
-    else if (stricmp(cmd, "BALANCE") == 0)
+
+    updateTS(user->stats);
+    if (stricmp(cmd, "BALANCE") == 0)
     {
         showBankBalance(u);
         return;
@@ -2474,7 +2504,8 @@ void do_master(char *u)
        notice(s_GameServ, u, "You must be playing to see your master!");
        return;
     }
-    
+
+    updateTS(user->stats);
     char *cmd = strtok(NULL, " ");
     Player *p = user->stats;
     long int need = 0;
@@ -2709,6 +2740,34 @@ void reset(Player *p)
     p->reset();
 }
 
+void updateTS(Player *p)
+{
+    if (!p)
+       return;
+    p->lastcommand = time(NULL);
+}
+
+bool timedOut(Player *p)
+{
+    if (!p)
+       return false;
+    else
+       return ((time(NULL) - p->lastcommand) >= maxidletime);
+}
+
+void timeOutEvent(Player *p)
+{
+    aClient *user = p->client;
+
+    if (!user) // then they're not playing
+       return;
+
+    char *nick = user->getNick();
+
+    notice(s_GameServ, nick, "You just idle timed out");
+    logout(user);
+}
+
 void do_reset(char *u)
 {
     char *nick = strtok(NULL, " ");
index 92178718b08650e23db19915a328b8049e9be155..b06443623b1bea5b97f6072d64f2cf81800ca788 100644 (file)
@@ -90,5 +90,17 @@ maxafightdistance 2
 #      player fights only
 maxbfightdistance 1
 
+# This is the maximum time (in seconds) that a player may remain idle
+# before something naughty happens to them :)
+maxidletime 300
+
+# This is the period (in seconds) that gameserv will wait between
+# checking the entire players list for idlers.
+# Warning: bigger networks should not set this too low!
+# Minor Warning: This should be fairly close to the maxidletime, but
+#     it doesn't have to be. The farther the two are apart, the more
+#     random it gets.
+idlecheckperiod 300
+
 # Delete or comment this line so that GameServ will Load
 die You must read the entire config file!
index 7278cf844d98a43ff4b41418d7d2c86a2ddf9ad3..75ab302d4c485b113525cb149b29c9eb3f48851d 100644 (file)
@@ -26,9 +26,11 @@ void Player::reset()
     master = NULL;
     battle = NULL;
     flags = 0;
+    lastcommand = 0;
     setAlive(this);
     inventory.reset();
 }
+
 Player::Player()
 {
     name = new char[256];
@@ -123,6 +125,7 @@ void Player::setData(Player *right)
        flags = right->flags;
        inventory.setInventory(&right->inventory);
        client = right->client;
+       lastcommand = right->lastcommand;
     }
     else
     {
index c6c331bcf228712b7cbb89ec38a76bf094bc4696..92e95b4a66fb4be3212544e9df3c0b6f9bd85cc1 100644 (file)
@@ -40,6 +40,7 @@ public:
     int player_fights;          // Amount of player<->player fights for today
     char *password;            // Player's encrypted password
     Pouch inventory;           // This contains their potions, etc.
+    long int lastcommand;      // timestamp for the last command typed
 
     aClient *client;           // Pointer to the aClient this player is from
     Monster *fight;            // Pointer to the monster the player is currently fighting
index e276ae390a4e7c3ae034160c82bc0e2d287340ee..66f71391fdbdcdb8e66a0b9417fdb8423a7bf142 100644 (file)
@@ -46,6 +46,7 @@ List<aClient> clients[U_TABLE_SIZE];
 void save_day();
 void load_day();
 void prettyIntro();
+void check_idles();
 
 // Make this a daemon
 int daemon(int nochdir, int noclose);
@@ -57,6 +58,7 @@ int main(int argc, char *argv[])
 {
   char buffer[1024], buf[1024];
   int connected;
+  long lastidlecheck;
   char *cmd, *source = NULL, *conf = "gameserv.conf";
   srand(time(NULL));
 
@@ -121,6 +123,8 @@ int main(int argc, char *argv[])
   long int loadtime = time(NULL);
   long int currentTime;
   long int oldTime = loadtime;
+
+  lastidlecheck = loadtime;
   bool loaded = false;
 
   ignore_pipe();
@@ -211,6 +215,15 @@ int main(int argc, char *argv[])
                retry = 0; // Start the reconnection cycle over
            }
        }
+       else
+       {
+           long TIME = time(NULL);
+           if (TIME - lastidlecheck >= idlecheckperiod)
+           {
+               check_idles();
+               lastidlecheck = TIME;
+           }
+       }
 
        // Save the player data every updateperiod seconds
        currentTime = time(NULL);
@@ -546,6 +559,7 @@ aClient *findIRCplayer(const char *nick)
     }
     return NULL;
 }
+
 aClient *findplayer(const char *name)
 {
     ListNode <aClient> *newPtr;
@@ -561,6 +575,24 @@ aClient *findplayer(const char *name)
     return NULL;
 }
 
+void check_idles()
+{
+    ListNode <aClient> *newPtr;
+    Player *p = NULL;
+
+    for (int x = 0; x < U_TABLE_SIZE; x++)
+    {
+       for (newPtr = players[x].First(); newPtr; newPtr = newPtr->Next())
+       {
+           p = newPtr->getData()->stats;
+           if (timedOut(p))
+           {
+               timeOutEvent(p);
+           }
+       }
+    }
+}
+
 aClient *findbynick(const char *nick)
 {
     ListNode <aClient> *newPtr;