Author: pepeto
Date: Sun Nov  2 19:41:30 2014
New Revision: 26956

URL: http://svn.gna.org/viewcvs/freeciv?rev=26956&view=rev
Log:
Do not ask the client to remove unseen units when players break up an alliance.

Reported by Sveinung Kvilhaugsvik <sveinung>

See gna bug #22795

Modified:
    trunk/server/diplhand.c
    trunk/server/plrhand.c
    trunk/server/plrhand.h
    trunk/server/unittools.c
    trunk/server/unittools.h

Modified: trunk/server/diplhand.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/diplhand.c?rev=26956&r1=26955&r2=26956&view=diff
==============================================================================
--- trunk/server/diplhand.c     (original)
+++ trunk/server/diplhand.c     Sun Nov  2 19:41:30 2014
@@ -403,6 +403,7 @@
       struct player_diplstate *ds_destgiver
         = player_diplstate_get(pdest, pgiver);
       enum diplstate_type old_diplstate = ds_giverdest->type;
+      struct unit_list *pgiver_seen_units, *pdest_seen_units;
 
       switch (pclause->type) {
       case CLAUSE_EMBASSY:
@@ -520,6 +521,10 @@
          break;
        }
       case CLAUSE_CEASEFIRE:
+        if (old_diplstate == DS_ALLIANCE) {
+          pgiver_seen_units = get_seen_units(pgiver, pdest);
+          pdest_seen_units = get_seen_units(pdest, pgiver);
+        }
         ds_giverdest->type = DS_CEASEFIRE;
         ds_giverdest->turns_left = TURNS_LEFT;
         ds_destgiver->type = DS_CEASEFIRE;
@@ -530,13 +535,21 @@
         notify_player(pdest, NULL, E_TREATY_CEASEFIRE, ftc_server,
                       _("You agree on a cease-fire with %s."),
                       player_name(pgiver));
-       if (old_diplstate == DS_ALLIANCE) {
-         update_players_after_alliance_breakup(pgiver, pdest);
-       }
+        if (old_diplstate == DS_ALLIANCE) {
+          update_players_after_alliance_breakup(pgiver, pdest,
+                                                pgiver_seen_units,
+                                                pdest_seen_units);
+          unit_list_destroy(pgiver_seen_units);
+          unit_list_destroy(pdest_seen_units);
+        }
 
         worker_refresh_required = TRUE;
        break;
       case CLAUSE_PEACE:
+        if (old_diplstate == DS_ALLIANCE) {
+          pgiver_seen_units = get_seen_units(pgiver, pdest);
+          pdest_seen_units = get_seen_units(pdest, pgiver);
+        }
         ds_giverdest->type = DS_ARMISTICE;
         ds_destgiver->type = DS_ARMISTICE;
         ds_giverdest->turns_left = TURNS_LEFT;
@@ -567,9 +580,13 @@
                       nation_plural_for_player(pgiver),
                       TURNS_LEFT,
                       nation_adjective_for_player(pgiver));
-       if (old_diplstate == DS_ALLIANCE) {
-         update_players_after_alliance_breakup(pgiver, pdest);
-       }
+        if (old_diplstate == DS_ALLIANCE) {
+          update_players_after_alliance_breakup(pgiver, pdest,
+                                                pgiver_seen_units,
+                                                pdest_seen_units);
+          unit_list_destroy(pgiver_seen_units);
+          unit_list_destroy(pdest_seen_units);
+        }
 
         worker_refresh_required = TRUE;
        break;

Modified: trunk/server/plrhand.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/plrhand.c?rev=26956&r1=26955&r2=26956&view=diff
==============================================================================
--- trunk/server/plrhand.c      (original)
+++ trunk/server/plrhand.c      Sun Nov  2 19:41:30 2014
@@ -567,21 +567,28 @@
   }
 }
 
-/**************************************************************************
+/****************************************************************************
   After the alliance is breaken, we need to do two things:
   - Inform clients that they cannot see units inside the former's ally
     cities
   - Remove units stacked together
-**************************************************************************/
-void update_players_after_alliance_breakup(struct player* pplayer,
-                                          struct player* pplayer2)
+  Note that you shouldn't use the units listed in 'pplayer_seen_units'
+  and 'pplayer2_seen_units' after calling this function because these
+  units might have died during the process.
+****************************************************************************/
+void update_players_after_alliance_breakup(struct player *pplayer,
+                                           struct player *pplayer2,
+                                           const struct unit_list
+                                               *pplayer_seen_units,
+                                           const struct unit_list
+                                               *pplayer2_seen_units)
 {
   /* The client needs updated diplomatic state, because it is used
    * during calculation of new states of occupied flags in cities */
    send_player_all_c(pplayer, NULL);
    send_player_all_c(pplayer2, NULL);
-   remove_allied_visibility(pplayer, pplayer2);
-   remove_allied_visibility(pplayer2, pplayer);    
+   remove_allied_visibility(pplayer, pplayer2, pplayer_seen_units);
+   remove_allied_visibility(pplayer2, pplayer, pplayer2_seen_units);
    resolve_unit_stacks(pplayer, pplayer2, TRUE);
 }
 
@@ -646,6 +653,7 @@
   bool repeat = FALSE;
   struct player *pplayer2 = player_by_number(other_player_id);
   struct player_diplstate *ds_plrplr2, *ds_plr2plr;
+  struct unit_list *pplayer_seen_units, *pplayer2_seen_units;
 
   if (NULL == pplayer2) {
     return;
@@ -704,6 +712,11 @@
   ds_plrplr2 = player_diplstate_get(pplayer, pplayer2);
   ds_plr2plr = player_diplstate_get(pplayer2, pplayer);
 
+  if (old_type == DS_ALLIANCE) {
+    pplayer_seen_units = get_seen_units(pplayer, pplayer2);
+    pplayer2_seen_units = get_seen_units(pplayer2, pplayer);
+  }
+
   /* do the change */
   ds_plrplr2->type = ds_plr2plr->type = new_type;
   ds_plrplr2->turns_left = ds_plr2plr->turns_left = 16;
@@ -716,7 +729,11 @@
   /* If the old state was alliance, the players' units can share tiles
      illegally, and we need to call resolve_unit_stacks() */
   if (old_type == DS_ALLIANCE) {
-    update_players_after_alliance_breakup(pplayer, pplayer2);
+    update_players_after_alliance_breakup(pplayer, pplayer2,
+                                          pplayer_seen_units,
+                                          pplayer2_seen_units);
+    unit_list_destroy(pplayer_seen_units);
+    unit_list_destroy(pplayer2_seen_units);
   }
 
   /* if there's a reason to cancel the pact, do it without penalty */
@@ -745,17 +762,6 @@
 
   send_player_all_c(pplayer, NULL);
   send_player_all_c(pplayer2, NULL);
-
-  if (old_type == DS_ALLIANCE) {
-    /* Inform clients about units that have been hidden.  Units in cities
-     * and transporters are visible to allies but not visible once the
-     * alliance is broken.  We have to call this after resolve_unit_stacks
-     * because that function may change units' locations.  It also sends
-     * out new city info packets to tell the client about occupied cities,
-     * so it should also come after the send_player_all_c calls above. */
-    remove_allied_visibility(pplayer, pplayer2);
-    remove_allied_visibility(pplayer2, pplayer);
-  }
 
   /* 
    * Refresh all cities which have a unit of the other side within

Modified: trunk/server/plrhand.h
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/plrhand.h?rev=26956&r1=26955&r2=26956&view=diff
==============================================================================
--- trunk/server/plrhand.h      (original)
+++ trunk/server/plrhand.h      Sun Nov  2 19:41:30 2014
@@ -13,12 +13,13 @@
 #ifndef FC__PLRHAND_H
 #define FC__PLRHAND_H
 
-struct section_file;
 struct connection;
 struct conn_list;
+struct nation_type;
+struct player;
 struct rgbcolor;
-struct player;
-struct nation_type;
+struct section_file;
+struct unit_list;
 
 enum plr_info_level { INFO_MINIMUM, INFO_MEETING, INFO_EMBASSY, INFO_FULL };
 
@@ -115,8 +116,12 @@
 bool civil_war_triggered(struct player *pplayer);
 struct player *civil_war(struct player *pplayer);
 
-void update_players_after_alliance_breakup(struct player* pplayer,
-                                          struct player* pplayer2);
+void update_players_after_alliance_breakup(struct player *pplayer,
+                                           struct player *pplayer2,
+                                           const struct unit_list
+                                               *pplayer_seen_units,
+                                           const struct unit_list
+                                               *pplayer2_seen_units);
 
 /* Player counts, total player_count() is in common/player.c */
 int barbarian_count(void);

Modified: trunk/server/unittools.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/unittools.c?rev=26956&r1=26955&r2=26956&view=diff
==============================================================================
--- trunk/server/unittools.c    (original)
+++ trunk/server/unittools.c    Sun Nov  2 19:41:30 2014
@@ -1275,22 +1275,37 @@
 }
 
 /****************************************************************************
+  Returns the list of the units owned by 'aplayer' seen by 'pplayer'. The
+  returned pointer is newly allocated and should be freed by the caller,
+  using unit_list_destroy().
+****************************************************************************/
+struct unit_list *get_seen_units(const struct player *pplayer,
+                                 const struct player *aplayer)
+{
+  struct unit_list *seen_units = unit_list_new();
+
+  unit_list_iterate(aplayer->units, punit) {
+    if (can_player_see_unit(pplayer, punit)) {
+      unit_list_append(seen_units, punit);
+    }
+  } unit_list_iterate_end;
+
+  return seen_units;
+}
+
+/****************************************************************************
   When two players cancel an alliance, a lot of units that were visible may
   no longer be visible (this includes units in transporters and cities).
   Call this function to inform the clients that these units are no longer
-  visible.  Note that this function should be called _after_
-  resolve_unit_stacks().
+  visible. Pass the list of seen units returned by get_seen_units() before
+  alliance was broken up.
 ****************************************************************************/
-void remove_allied_visibility(struct player* pplayer, struct player* aplayer)
-{
-  unit_list_iterate(aplayer->units, punit) {
-    /* We don't know exactly which units have been hidden.  But only a unit
-     * whose tile is visible but who aren't visible themselves are
-     * candidates.  This solution just tells the client to drop all such
-     * units.  If any of these are unknown to the client the client will
-     * just ignore them. */
-    if (map_is_known_and_seen(unit_tile(punit), pplayer, V_MAIN) &&
-        !can_player_see_unit(pplayer, punit)) {
+void remove_allied_visibility(struct player *pplayer, struct player *aplayer,
+                              const struct unit_list *seen_units)
+{
+  unit_list_iterate(seen_units, punit) {
+    /* We need to hide units previously seen by the client. */
+    if (!can_player_see_unit(pplayer, punit)) {
       unit_goes_out_of_sight(pplayer, punit);
     }
   } unit_list_iterate_end;

Modified: trunk/server/unittools.h
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/unittools.h?rev=26956&r1=26955&r2=26956&view=diff
==============================================================================
--- trunk/server/unittools.h    (original)
+++ trunk/server/unittools.h    Sun Nov  2 19:41:30 2014
@@ -99,7 +99,10 @@
                          bool verbose);
 void resolve_unit_stacks(struct player *pplayer, struct player *aplayer,
                          bool verbose);
-void remove_allied_visibility(struct player* pplayer, struct player* aplayer);
+struct unit_list *get_seen_units(const struct player *pplayer,
+                                 const struct player *aplayer);
+void remove_allied_visibility(struct player *pplayer, struct player *aplayer,
+                              const struct unit_list *seen_units);
 void give_allied_visibility(struct player *pplayer, struct player *aplayer);
 int get_unit_vision_at(struct unit *punit, struct tile *ptile,
                       enum vision_layer vlayer);


_______________________________________________
Freeciv-commits mailing list
Freeciv-commits@gna.org
https://mail.gna.org/listinfo/freeciv-commits

Reply via email to