From 40988fe93da65d70d3f559a41bec42fed7637680 Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Wed, 10 May 2023 06:43:56 +0300
Subject: [PATCH 10/10] Keep observes in sync with city investigation

See osdn #46186

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 client/packhand.c  | 60 ++++++++++++++++++++++++++++++++++++----------
 common/packets.def | 10 ++++++++
 fc_version         |  2 +-
 server/diplomats.c | 17 +++++++++++--
 4 files changed, 74 insertions(+), 15 deletions(-)

diff --git a/client/packhand.c b/client/packhand.c
index 49942b5a2a..6157c5889e 100644
--- a/client/packhand.c
+++ b/client/packhand.c
@@ -939,12 +939,12 @@ static void city_packet_common(struct city *pcity, struct tile *pcenter,
 
       unit_list_destroy(pcity->client.info_units_present);
       pcity->client.info_units_present =
-          pcity->client.collecting_info_units_present;
+        pcity->client.collecting_info_units_present;
       pcity->client.collecting_info_units_present = NULL;
 
       unit_list_destroy(pcity->client.info_units_supported);
       pcity->client.info_units_supported =
-          pcity->client.collecting_info_units_supported;
+        pcity->client.collecting_info_units_supported;
       pcity->client.collecting_info_units_supported = NULL;
     } else {
       /* We didn't get any unit, let's clear the unit lists. */
@@ -1883,6 +1883,40 @@ static bool handle_unit_packet_common(struct unit *packet_unit)
   return ret;
 }
 
+/****************************************************************************
+  Receive an investigate_started packet
+
+  Can't rely on generic packet_processing_started, as that works for
+  the requesting connection only, and not for observers.
+****************************************************************************/
+void handle_investigate_started(int unit_id, int city_id)
+{
+  struct city *pcity = game_city_by_number(city_id);
+
+  if (!pcity) {
+    log_error("Investigate city: unknown city id %d!",
+              city_id);
+    return;
+  }
+
+  /* Start collecting supported and present units. */
+
+  /* Ensure we are not already in an investigate cycle. */
+  fc_assert(pcity->client.collecting_info_units_supported == NULL);
+  fc_assert(pcity->client.collecting_info_units_present == NULL);
+  pcity->client.collecting_info_units_supported =
+    unit_list_new_full(unit_virtual_destroy);
+  pcity->client.collecting_info_units_present =
+    unit_list_new_full(unit_virtual_destroy);
+}
+
+/****************************************************************************
+  Receive an investigate_finished packet
+****************************************************************************/
+void handle_investigate_finished(int unit_id, int city_id)
+{
+}
+
 /****************************************************************************
   Receive a short_unit info packet.
 ****************************************************************************/
@@ -1906,21 +1940,23 @@ void handle_unit_short_info(const struct packet_unit_short_info *packet)
       return;
     }
 
-    /* New serial number: start collecting supported and present units. */
-    if (last_serial_num
-        != client.conn.client.request_id_of_currently_handled_packet) {
-      last_serial_num =
+    if (!has_capability("obsinv", client.conn.capability)) {
+      /* New serial number: start collecting supported and present units. */
+      if (last_serial_num
+          != client.conn.client.request_id_of_currently_handled_packet) {
+        last_serial_num =
           client.conn.client.request_id_of_currently_handled_packet;
-      /* Ensure we are not already in an investigate cycle. */
-      fc_assert(pcity->client.collecting_info_units_supported == NULL);
-      fc_assert(pcity->client.collecting_info_units_present == NULL);
-      pcity->client.collecting_info_units_supported =
+        /* Ensure we are not already in an investigate cycle. */
+        fc_assert(pcity->client.collecting_info_units_supported == NULL);
+        fc_assert(pcity->client.collecting_info_units_present == NULL);
+        pcity->client.collecting_info_units_supported =
           unit_list_new_full(unit_virtual_destroy);
-      pcity->client.collecting_info_units_present =
+        pcity->client.collecting_info_units_present =
           unit_list_new_full(unit_virtual_destroy);
+      }
     }
 
-    /* Okay, append a unit struct to the proper list. */
+    /* Append a unit struct to the proper list. */
     punit = unpackage_short_unit(packet);
     if (packet->packet_use == UNIT_INFO_CITY_SUPPORTED) {
       fc_assert(pcity->client.collecting_info_units_supported != NULL);
diff --git a/common/packets.def b/common/packets.def
index 82ee232029..a94e2a42fc 100644
--- a/common/packets.def
+++ b/common/packets.def
@@ -343,6 +343,16 @@ end
 PACKET_PROCESSING_FINISHED = 1; sc
 end
 
+PACKET_INVESTIGATE_STARTED = 21; sc, dsend
+  UNIT unit_id;
+  CITY city_id;
+end
+
+PACKET_INVESTIGATE_FINISHED = 22; sc, dsend
+  UNIT unit_id;
+  CITY city_id;
+end
+
 /************** Login/pregame/endgame packets **********************/
 
 # This packet is the first real (freeciv specific) packet send by the
diff --git a/fc_version b/fc_version
index 9f446a391e..d9f9483695 100755
--- a/fc_version
+++ b/fc_version
@@ -58,7 +58,7 @@ DEFAULT_FOLLOW_TAG=stable
 #     as long as possible.  We want to maintain network compatibility with
 #     the stable branch for as long as possible.
 NETWORK_CAPSTRING_MANDATORY="+Freeciv-2.6-network"
-NETWORK_CAPSTRING_OPTIONAL="techloss_forgiveness year32"
+NETWORK_CAPSTRING_OPTIONAL="techloss_forgiveness year32 obsinv"
 
 FREECIV_DISTRIBUTOR=""
 
diff --git a/server/diplomats.c b/server/diplomats.c
index e469e89ffd..9787a82d0e 100644
--- a/server/diplomats.c
+++ b/server/diplomats.c
@@ -19,6 +19,7 @@
 
 /* utility */
 #include "bitvector.h"
+#include "capability.h"
 #include "fcintl.h"
 #include "log.h"
 #include "rand.h"
@@ -176,13 +177,19 @@ void diplomat_investigate(struct player *pplayer, struct unit *pdiplomat,
 
   log_debug("investigate: unit: %d", pdiplomat->id);
 
+  conn_list_iterate(pplayer->connections, pconn) {
+    if (has_capability("obsinv", pconn->capability)) {
+      dsend_packet_investigate_started(pconn, pdiplomat->id, pcity->id);
+    }
+  } conn_list_iterate_end;
+
   /* Do It... */
   update_dumb_city(pplayer, pcity);
   /* Special case for a diplomat/spy investigating a city:
      The investigator needs to know the supported and present
      units of a city, whether or not they are fogged. So, we
      send a list of them all before sending the city info.
-     As this is a special case we bypass send_unit_info. */
+     As this is a special case we bypass send_unit_info(). */
   unit_list_iterate(pcity->units_supported, punit) {
     package_short_unit(punit, &unit_packet,
                        UNIT_INFO_CITY_SUPPORTED, pcity->id);
@@ -210,7 +217,7 @@ void diplomat_investigate(struct player *pplayer, struct unit *pdiplomat,
     pdiplomat->moves_left = 0;
   }
 
-  /* this may cause a diplomatic incident */
+  /* This may cause a diplomatic incident */
   action_consequence_success(ACTION_SPY_INVESTIGATE_CITY, pplayer, cplayer,
                              city_tile(pcity), city_link(pcity));
 
@@ -1476,6 +1483,12 @@ static bool diplomat_infiltrate_tile(struct player *pplayer,
     }
   } unit_list_iterate_end;
 
+  conn_list_iterate(pplayer->connections, pconn) {
+    if (has_capability("obsinv", pconn->capability)) {
+      dsend_packet_investigate_finished(pconn, pdiplomat->id, pcity->id);
+    }
+  } conn_list_iterate_end;
+
   return TRUE;
 }
 
-- 
2.39.2