From 4353675544ff4e03891aec63794fae35c87f2a6f Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Sun, 4 Jan 2026 09:37:22 +0200
Subject: [PATCH 54/54] Add sanity checking method to AI interface

See RM #1837

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 ai/classic/classicai.c | 11 +++++++++++
 ai/default/daiplayer.c |  9 ++++++++-
 ai/default/daiplayer.h |  2 ++
 ai/tex/texai.c         | 10 ++++++++++
 common/ai.h            |  3 +++
 doc/README.AI_modules  |  5 +++++
 server/sanitycheck.c   |  5 +++++
 server/sanitycheck.h   |  3 ++-
 8 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/ai/classic/classicai.c b/ai/classic/classicai.c
index 1cffae1bbc..5923c87055 100644
--- a/ai/classic/classicai.c
+++ b/ai/classic/classicai.c
@@ -589,6 +589,16 @@ static void cai_revolution_start(struct player *pplayer)
   dai_revolution_start(deftype, pplayer);
 }
 
+/**********************************************************************//**
+  Call default ai with classic ai type as parameter.
+**************************************************************************/
+static void cai_sanity_check(struct player *pplayer)
+{
+  struct ai_type *deftype = classic_ai_get_self();
+
+  dai_sanity_check(deftype, pplayer);
+}
+
 /**********************************************************************//**
   Setup player ai_funcs function pointers.
 **************************************************************************/
@@ -702,6 +712,7 @@ bool fc_ai_classic_setup(struct ai_type *ai)
   /* ai->funcs.unit_info = NULL; */
 
   ai->funcs.revolution_start = cai_revolution_start;
+  ai->funcs.check_sanity = cai_sanity_check;
 
   return TRUE;
 }
diff --git a/ai/default/daiplayer.c b/ai/default/daiplayer.c
index a9de9e0e3d..32f662646a 100644
--- a/ai/default/daiplayer.c
+++ b/ai/default/daiplayer.c
@@ -169,7 +169,7 @@ void dai_player_copy(struct ai_type *ait,
 }
 
 /**********************************************************************//**
-  Ai got control of the player.
+  AI got control of the player.
 **************************************************************************/
 void dai_gained_control(struct ai_type *ait, struct player *pplayer)
 {
@@ -186,3 +186,10 @@ void dai_gained_control(struct ai_type *ait, struct player *pplayer)
 
   dai_assess_danger_player(ait, &(wld.map), pplayer);
 }
+
+/**********************************************************************//**
+  Run sanity checking for the AI player.
+**************************************************************************/
+void dai_sanity_check(struct ai_type *ait, struct player *pplayer)
+{
+}
diff --git a/ai/default/daiplayer.h b/ai/default/daiplayer.h
index 6fae4006e7..b554f971cc 100644
--- a/ai/default/daiplayer.h
+++ b/ai/default/daiplayer.h
@@ -39,6 +39,8 @@ void dai_player_copy(struct ai_type *ait,
                      struct player *original, struct player *created);
 void dai_gained_control(struct ai_type *ait, struct player *pplayer);
 
+void dai_sanity_check(struct ai_type *ait, struct player *pplayer);
+
 static inline struct ai_city *def_ai_city_data(const struct city *pcity,
                                                struct ai_type *deftype)
 {
diff --git a/ai/tex/texai.c b/ai/tex/texai.c
index 3b647b5646..95d598d666 100644
--- a/ai/tex/texai.c
+++ b/ai/tex/texai.c
@@ -575,6 +575,15 @@ static void texwai_revolution_start(struct player *pplayer)
   TEXAI_TFUNC(dai_revolution_start, pplayer);
 }
 
+/**********************************************************************//**
+  Call default ai with tex ai type as parameter.
+**************************************************************************/
+static void texwai_sanity_check(struct player *pplayer)
+{
+  TEXAI_AIT;
+  TEXAI_TFUNC(dai_sanity_check, pplayer);
+}
+
 /**********************************************************************//**
   Return module capability string
 **************************************************************************/
@@ -686,6 +695,7 @@ bool fc_ai_tex_setup(struct ai_type *ai)
   ai->funcs.unit_info = texai_unit_changed;
 
   ai->funcs.revolution_start = texwai_revolution_start;
+  ai->funcs.check_sanity = texwai_sanity_check;
 
   return TRUE;
 }
diff --git a/common/ai.h b/common/ai.h
index 0e4d8c8e21..ca78142d5f 100644
--- a/common/ai.h
+++ b/common/ai.h
@@ -319,6 +319,9 @@ struct ai_type
     /* Called for player AI when revolution starts. */
     void (*revolution_start)(struct player *pplayer);
 
+    /* Called for player AI once a turn, in sanitychecking phase */
+    void (*check_sanity)(struct player *pplayer);
+
     /* These are here reserving space for future optional callbacks.
      * This way we don't need to change the mandatory capability of the AI module
      * interface when adding such callbacks, but existing modules just have these
diff --git a/doc/README.AI_modules b/doc/README.AI_modules
index f4b80e406b..38a43d24f2 100644
--- a/doc/README.AI_modules
+++ b/doc/README.AI_modules
@@ -119,6 +119,11 @@ it in for custom ai types to use by passing configure option --with-ai-lib
 6. Callback interface ChangeLog
 -------------------------------
 
+New in Freeciv 3.4:
+-------------------
+- Added 'check_sanity', called once a turn when sanity checking enabled
+
+
 New in Freeciv 3.2:
 -------------------
 - Added 'revolution_start', called when player's revolution gets activated
diff --git a/server/sanitycheck.c b/server/sanitycheck.c
index e6d6b0627d..2f7bb47778 100644
--- a/server/sanitycheck.c
+++ b/server/sanitycheck.c
@@ -20,6 +20,7 @@
 #include "log.h"
 
 /* common */
+#include "ai.h"
 #include "city.h"
 #include "game.h"
 #include "government.h"
@@ -689,6 +690,10 @@ void real_sanity_check(const char *file, const char *function, int line)
   check_teams(file, function, line);
   check_researches(file, function, line);
   check_connections(file, function, line);
+
+  players_iterate(pplayer) {
+    CALL_PLR_AI_FUNC(check_sanity, pplayer, pplayer);
+  } players_iterate_end;
 }
 
 /**********************************************************************//**
diff --git a/server/sanitycheck.h b/server/sanitycheck.h
index 19a15793c1..338080a9aa 100644
--- a/server/sanitycheck.h
+++ b/server/sanitycheck.h
@@ -13,6 +13,7 @@
 #ifndef FC__SANITYCHECK_H
 #define FC__SANITYCHECK_H
 
+/* common */
 #include "fc_types.h"
 
 #if ((IS_BETA_VERSION || IS_DEVEL_VERSION) && !defined(FREECIV_NDEBUG)) \
@@ -45,4 +46,4 @@ void real_sanity_check( const char *file, const char *function, int line);
 #endif /* SANITY_CHECKING */
 
 
-#endif  /* FC__SANITYCHECK_H */
+#endif /* FC__SANITYCHECK_H */
-- 
2.51.0

