<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40195 >

2008/4/7 Marko Lindqvist:
>
>   If modpack has less than MAX_PLAYERS playable nations, server can run
>  out of nations to assign to players and crash. Attached patch prevents
>  several such cases.

 - Allow starting game when num players == num nations
 - Also for S2_1

 Ready for commit. (If civilwar player creation needs similar fix,
I'll make separate ticket)


 - ML

diff -Nurd -X.diff_ignore freeciv/server/connecthand.c freeciv/server/connecthand.c
--- freeciv/server/connecthand.c	2008-04-08 15:32:21.000000000 +0300
+++ freeciv/server/connecthand.c	2008-05-04 19:19:01.000000000 +0300
@@ -475,7 +475,8 @@
 
       if (NULL == pplayer) {
         /* no uncontrolled player found */
-        if (game.info.nplayers >= game.info.max_players) {
+        if (game.info.nplayers >= game.info.max_players
+            || game.info.nplayers - server.nbarbarians >= server.playable_nations) {
           return FALSE;
         }
         assert(game.info.nplayers < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS);
diff -Nurd -X.diff_ignore freeciv/server/ruleset.c freeciv/server/ruleset.c
--- freeciv/server/ruleset.c	2008-04-09 18:54:09.000000000 +0300
+++ freeciv/server/ruleset.c	2008-05-04 19:19:01.000000000 +0300
@@ -2490,7 +2490,9 @@
 
     pl->is_playable = secfile_lookup_bool_default(file, TRUE,
 						  "%s.is_playable", sec[i]);
-
+    if (pl->is_playable) {
+      server.playable_nations++;
+    }
 
     /* Check barbarian type. Default is "None" meaning not a barbarian */    
     barb_type = secfile_lookup_str_default(file, "None",
@@ -3554,6 +3556,7 @@
 
   ruleset_data_free();
   reset_player_nations();
+  server.playable_nations = 0;
 
   openload_ruleset_file(&techfile, "techs");
   load_tech_names(&techfile);
@@ -3611,6 +3614,10 @@
 
   /* Build AI unit class cache corresponding to loaded rulesets */
   unit_class_ai_init();
+
+  /* We may need to adjust number of AI players if number of available
+   * nations changed */
+  aifill(game.info.aifill);
 }
 
 /**************************************************************************
diff -Nurd -X.diff_ignore freeciv/server/srv_main.c freeciv/server/srv_main.c
--- freeciv/server/srv_main.c	2008-04-17 10:49:41.000000000 +0300
+++ freeciv/server/srv_main.c	2008-05-04 19:19:01.000000000 +0300
@@ -1591,6 +1591,9 @@
 {
   int limit = MIN(amount, game.info.max_players);
 
+  /* Limit to nations provided by ruleset */
+  limit = MIN(limit, server.playable_nations);
+
   if (!game.info.is_new_game || S_S_INITIAL != server_state()) {
     return;
   }
@@ -2144,6 +2147,7 @@
 void server_game_init(void)
 {
   /* was redundantly in game_load() */
+  server.playable_nations = 0;
   server.nbarbarians = 0;
   server.identity_number = IDENTITY_NUMBER_SKIP;
 
diff -Nurd -X.diff_ignore freeciv/server/srv_main.h freeciv/server/srv_main.h
--- freeciv/server/srv_main.h	2008-03-10 19:54:21.000000000 +0200
+++ freeciv/server/srv_main.h	2008-05-04 19:19:01.000000000 +0300
@@ -60,6 +60,7 @@
  *
  * TODO: Lots more variables could be added here. */
 extern struct civserver {
+  int playable_nations;
   int nbarbarians;
 
   /* this counter creates all the city and unit numbers used.
diff -Nurd -X.diff_ignore freeciv/server/stdinhand.c freeciv/server/stdinhand.c
--- freeciv/server/stdinhand.c	2008-04-17 10:49:41.000000000 +0300
+++ freeciv/server/stdinhand.c	2008-05-04 19:19:42.000000000 +0300
@@ -817,13 +817,13 @@
 }
 
 /**************************************************************************
-...
+ Creates named AI player
 **************************************************************************/
 static bool create_ai_player(struct connection *caller, char *arg, bool check)
 {
   PlayerNameStatus PNameStatus;
   struct player *pplayer = NULL;
-   
+
   if (S_S_INITIAL != server_state())
   {
     cmd_reply(CMD_CREATE, caller, C_SYNTAX,
@@ -839,14 +839,19 @@
     }
   } players_iterate_end;
 
-  /* game.info.max_players is a limit on the number of non-observer players.
-   * MAX_NUM_PLAYERS is a limit on all players. */
-  if (game.info.nplayers >= MAX_NUM_PLAYERS) {
-    if (NULL == pplayer) {
+  if (NULL == pplayer) {
+    /* Check that we are not going over max players setting */
+    if (game.info.nplayers >= game.info.max_players) {
       cmd_reply(CMD_CREATE, caller, C_FAIL,
 	        _("Can't add more players, server is full."));
       return FALSE;
     }
+    /* Check that we have nations available */
+    if (game.info.nplayers - server.nbarbarians >= server.playable_nations) {
+      cmd_reply(CMD_CREATE, caller, C_FAIL,
+	        _("Can't add more players, not enough nations."));
+      return FALSE;
+    }
   }
 
   if ((PNameStatus = test_player_name(arg)) == PNameEmpty)
@@ -2965,12 +2970,13 @@
    * they first release. */
   if (!pplayer && !pconn->playing
       && (game.info.nplayers >= game.info.max_players
-          || game.info.nplayers >= MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS)) {
+          || game.info.nplayers - server.nbarbarians >= server.playable_nations)) {
     cmd_reply(CMD_TAKE, caller, C_FAIL,
               _("There is no free player slot for %s"),
               pconn->username);
     goto end;
   }
+  assert(game.info.nplayers < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS);
 
   res = TRUE;
   if (check) {
@@ -3808,6 +3814,10 @@
       start_cmd_reply(caller, notify,
                       _("Not enough players, game will not start."));
       return FALSE;
+    } else if (game.info.nplayers - server.nbarbarians > server.playable_nations) {
+      cmd_reply(CMD_START_GAME, caller, C_FAIL,
+		_("Not enough nations for all players, game will not start."));
+      return FALSE;
     } else if (check) {
       return TRUE;
     } else if (!caller) {
diff -Nurd -X.diff_ignore freeciv/common/game.c freeciv/common/game.c
--- freeciv/common/game.c	2008-01-22 03:47:26.000000000 +0200
+++ freeciv/common/game.c	2008-05-04 18:49:37.000000000 +0300
@@ -254,6 +254,7 @@
   game.info.government_when_anarchy_id = G_MAGIC;   /* flag */
 
   game.info.is_new_game   = TRUE;
+  game.playable_nations   = 0;
   game.fogofwar_old = game.info.fogofwar;
   game.simultaneous_phases_stored = GAME_DEFAULT_SIMULTANEOUS_PHASES;
   game.timeoutint    = GAME_DEFAULT_TIMEOUTINT;
diff -Nurd -X.diff_ignore freeciv/common/game.h freeciv/common/game.h
--- freeciv/common/game.h	2008-01-15 04:04:30.000000000 +0200
+++ freeciv/common/game.h	2008-05-04 18:50:31.000000000 +0300
@@ -85,6 +85,7 @@
   bool scorelog;
   int scoreturn;			/* next make_history_report() */
   int seed;
+  int playable_nations;
   bool fogofwar_old;	/* as the fog_of_war bit get changed by setting
 			   the server we need to remember the old setting */
   int ai_goal_government;	/* kludge */
diff -Nurd -X.diff_ignore freeciv/server/connecthand.c freeciv/server/connecthand.c
--- freeciv/server/connecthand.c	2008-04-02 22:48:51.000000000 +0300
+++ freeciv/server/connecthand.c	2008-05-04 18:56:28.000000000 +0300
@@ -457,7 +457,8 @@
 {
   /* if pplayer is NULL, attach to first non-connected player slot */
   if (!pplayer) {
-    if (game.info.nplayers >= game.info.max_players 
+    if (game.info.nplayers >= game.info.max_players
+        || game.info.nplayers - game.info.nbarbarians >= game.playable_nations
         || game.info.nplayers >= MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS) {
       return FALSE;
     } else {
diff -Nurd -X.diff_ignore freeciv/server/ruleset.c freeciv/server/ruleset.c
--- freeciv/server/ruleset.c	2008-04-01 22:16:20.000000000 +0300
+++ freeciv/server/ruleset.c	2008-05-04 18:57:27.000000000 +0300
@@ -2172,6 +2172,9 @@
 
     pl->is_playable = secfile_lookup_bool_default(file, TRUE,
 						  "%s.is_playable", sec[i]);
+    if (pl->is_playable) {
+      game.playable_nations++;
+    }
     pl->is_barbarian = secfile_lookup_bool_default(file, FALSE,
 						  "%s.is_barbarian", sec[i]);
 
@@ -3156,6 +3159,7 @@
 
   ruleset_data_free();
   reset_player_nations();
+  game.playable_nations = 0;
 
   openload_ruleset_file(&techfile, "techs");
   load_tech_names(&techfile);
@@ -3201,6 +3205,10 @@
 
   script_init();
   openload_script_file("script");
+
+  /* We may need to adjust number of AI players if number of available
+   * nations changed */
+  aifill(game.info.aifill);
 }
 
 /**************************************************************************
diff -Nurd -X.diff_ignore freeciv/server/srv_main.c freeciv/server/srv_main.c
--- freeciv/server/srv_main.c	2008-04-23 03:13:19.000000000 +0300
+++ freeciv/server/srv_main.c	2008-05-04 18:59:17.000000000 +0300
@@ -1556,6 +1556,9 @@
 
   amount = MIN(amount, game.info.max_players);
 
+  /* Limit to nations provided by ruleset */
+  amount = MIN(amount, game.playable_nations);
+
   while (game.info.nplayers < amount) {
     const int old_nplayers = game.info.nplayers;
     struct player *pplayer = player_by_number(old_nplayers);
diff -Nurd -X.diff_ignore freeciv/server/stdinhand.c freeciv/server/stdinhand.c
--- freeciv/server/stdinhand.c	2008-04-23 03:13:19.000000000 +0300
+++ freeciv/server/stdinhand.c	2008-05-04 19:13:57.000000000 +0300
@@ -833,14 +833,14 @@
 }
 
 /**************************************************************************
-...
+  Creates named AI player
 **************************************************************************/
 static bool create_ai_player(struct connection *caller, char *arg, bool check)
 {
   struct player *pplayer;
   PlayerNameStatus PNameStatus;
   bool ai_player_should_be_removed = FALSE;
-   
+
   if (S_S_INITIAL != server_state())
   {
     cmd_reply(CMD_CREATE, caller, C_SYNTAX,
@@ -850,7 +850,8 @@
 
   /* game.info.max_players is a limit on the number of non-observer players.
    * MAX_NUM_PLAYERS is a limit on all players. */
-  if (game.info.nplayers >= MAX_NUM_PLAYERS) {
+  if (game.info.nplayers >= MAX_NUM_PLAYERS
+      || game.info.nplayers - game.info.nbarbarians >= game.playable_nations) {
     /* Try emptying a slot if there is an ai player
      * created through the /aifill command */
     players_iterate(eplayer) {
@@ -860,7 +861,7 @@
       ai_player_should_be_removed = TRUE;
       break;
     } players_iterate_end;
-    
+
     if (!ai_player_should_be_removed) {
       cmd_reply(CMD_CREATE, caller, C_FAIL,
 	        _("Can't add more players, server is full."));
@@ -2957,12 +2958,13 @@
    * they first release. */
   if (!pplayer && !pconn->player
       && (game.info.nplayers >= game.info.max_players
-          || game.info.nplayers >= MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS)) {
+          || game.info.nplayers - game.info.nbarbarians >= game.playable_nations)) {
     cmd_reply(CMD_TAKE, caller, C_FAIL,
               _("There is no free player slot for %s"),
               pconn->username);
     goto end;
   }
+  assert(game.info.nplayers < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS);
 
   res = TRUE;
   if (check) {
@@ -3800,6 +3802,10 @@
       start_cmd_reply(caller, notify,
                       _("Not enough players, game will not start."));
       return FALSE;
+    } else if (game.info.nplayers - game.info.nbarbarians > game.playable_nations) {
+      cmd_reply(CMD_START_GAME, caller, C_FAIL,
+		_("Not enough nations for all players, game will not start."));
+      return FALSE;
     } else if (check) {
       return TRUE;
     } else if (!caller) {
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to