Complete.Org: Mailing Lists: Archives: freeciv-dev: February 2005:
[Freeciv-Dev] (PR#12219) fix bugs with real_timer_callback
Home

[Freeciv-Dev] (PR#12219) fix bugs with real_timer_callback

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#12219) fix bugs with real_timer_callback
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 11 Feb 2005 12:04:59 -0800
Reply-to: bugs@xxxxxxxxxxx

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

This patch fixes some bugs and makes real_timer_callback a lot more useful.

Currently there are several bugs here.

1.  real_time_callback decreases the seconds_to_turndone on every 2 
callbacks.  Each callback is 500 ms.  Great.  Except that the callbacks 
can lag, and when they do there is no attempt to catch up.  This _may_ 
be why when I play on pubserver the turn often ends when the timer says 
there's still plenty of time left.

2.  When switching focus units, we should restart the blink timer.  I 
think.  At least it should be possible for the focus unit code to run 
its own timer separate from the 1s-timer used by the timeout code.

This patch solves the problem in a fairly elegant and modular way.

1.  real_timer_callback isn't called at a fixed interval.  Rather each 
call to it returns the time until the next call.  The clients thus have 
to re-queue the timer (this is implemented for gtk2, xaw, and ftwl clients).

2.  The seconds until turn done value is hidden inside civclient.c. 
Users now access it via set_seconds_until_turndone() and 
get_seconds_until_turndone().  We keep a separate timer of 
time-passed-since-the-server-last-told-us-how-long-we-have so now the 
timer won't become inaccurate as time goes by.

3.  The blink-focus-unit code also keeps its own timer.  This timer is 
restarted when the focus unit changes and each time a blink is done (so 
unlike the timeout timer, this one is allowed to lag).

See also PR#12215.

-jason

Index: client/civclient.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/civclient.c,v
retrieving revision 1.212
diff -u -r1.212 civclient.c
--- client/civclient.c  22 Jan 2005 19:45:38 -0000      1.212
+++ client/civclient.c  11 Feb 2005 20:02:54 -0000
@@ -20,6 +20,7 @@
 #endif
 
 #include <assert.h>
+#include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
@@ -38,6 +39,7 @@
 #include "packets.h"
 #include "rand.h"
 #include "support.h"
+#include "timing.h"
 #include "version.h"
 
 #include "agents.h"
@@ -87,8 +89,6 @@
 
 static enum client_states client_state = CLIENT_BOOT_STATE;
 
-int seconds_to_turndone;
-
 /* TRUE if an end turn request is blocked by busy agents */
 bool waiting_for_end_turn = FALSE;
 
@@ -612,16 +612,60 @@
   return aconnection.established && aconnection.observer;
 }
 
+/* Seconds_to_turndone is the number of seconds the server has told us
+ * are left.  The timer tells exactly how much time has passed since the
+ * server gave us that data. */
+static double seconds_to_turndone = 0.0;
+static struct timer *turndone_timer;
+
+/* This value shows what value the timeout label is currently showing for
+ * the seconds-to-turndone. */
+static int seconds_shown_to_turndone;
+
+/**************************************************************************
+  Reset the number of seconds to turndone from an "authentic" source.
+
+  The seconds are taken as a double even though most callers will just
+  know an integer value.
+**************************************************************************/
+void set_seconds_to_turndone(double seconds)
+{
+  if (game.timeout > 0) {
+    seconds_to_turndone = seconds;
+    turndone_timer = renew_timer_start(turndone_timer, TIMER_USER,
+                                      TIMER_ACTIVE);
+
+    /* Maybe we should do an update_timeout_label here, but it doesn't
+     * seem to be necessary. */
+    seconds_shown_to_turndone = ceil(seconds) + 0.1;
+  }
+}
+
+/**************************************************************************
+  Return the number of seconds until turn-done.  Don't call this unless
+  game.timeout != 0.
+**************************************************************************/
+int get_seconds_to_turndone(void)
+{
+  if (game.timeout > 0) {
+    return seconds_shown_to_turndone;
+  } else {
+    /* This shouldn't happen. */
+    return FC_INFINITY;
+  }
+}
+
 /**************************************************************************
- This function should be called every 500ms. It lets the unit blink
- and update the timeout.
+  This function should be called at least once per second.  It does various
+  updates (idle animations and timeout updates).  It returns the number of
+  seconds until it should be called again.
 **************************************************************************/
-void real_timer_callback(void)
+double real_timer_callback(void)
 {
-  static bool flip = FALSE;
+  double time_until_next_call = 1.0;
 
   if (get_client_state() != CLIENT_GAME_RUNNING_STATE) {
-    return;
+    return time_until_next_call;
   }
 
   if (game.player_ptr->is_connected && game.player_ptr->is_alive &&
@@ -643,18 +687,26 @@
     }
   }
 
-  blink_active_unit();
+  if (get_unit_in_focus()) {
+    double blink_time = blink_active_unit();
 
-  if (flip) {
-    update_timeout_label();
-    if (seconds_to_turndone > 0) {
-      seconds_to_turndone--;
-    } else {
-      seconds_to_turndone = 0;
+    time_until_next_call = MIN(time_until_next_call, blink_time);
+  }
+
+  if (game.timeout > 0) {
+    double seconds = seconds_to_turndone - read_timer_seconds(turndone_timer);
+    int iseconds = ceil(seconds) + 0.1; /* Turn should end right on 0. */
+
+    if (iseconds < seconds_shown_to_turndone) {
+      seconds_shown_to_turndone = iseconds;
+      update_timeout_label();
     }
+
+    time_until_next_call = MIN(time_until_next_call,
+                              seconds - floor(seconds) + 0.001);
   }
 
-  flip = !flip;
+  return MAX(time_until_next_call, 0.0);
 }
 
 /**************************************************************************
Index: client/civclient.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/civclient.h,v
retrieving revision 1.38
diff -u -r1.38 civclient.h
--- client/civclient.h  12 Dec 2004 03:44:47 -0000      1.38
+++ client/civclient.h  11 Feb 2005 20:02:54 -0000
@@ -22,7 +22,7 @@
  * called. TIMER_INTERVAL has to stay 500 because real_timer_callback
  * also updates the timeout info.
  */
-#define TIMER_INTERVAL 500
+#define TIMER_INTERVAL (int)(real_timer_callback() * 1000)
 
 void handle_packet_input(void *packet, int type);
 
@@ -52,11 +52,11 @@
 extern bool waiting_for_end_turn;
 extern bool turn_done_sent;
 
-extern int seconds_to_turndone;
-
 void wait_till_request_got_processed(int request_id);
 bool client_is_observer(void);
-void real_timer_callback(void);
+void set_seconds_to_turndone(double seconds);
+int get_seconds_to_turndone(void);
+double real_timer_callback(void);
 bool can_client_issue_orders(void);
 bool can_client_change_view(void);
 bool can_meet_with_player(const struct player *pplayer);
Index: client/control.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/control.c,v
retrieving revision 1.155
diff -u -r1.155 control.c
--- client/control.c    9 Feb 2005 16:23:12 -0000       1.155
+++ client/control.c    11 Feb 2005 20:02:54 -0000
@@ -21,6 +21,7 @@
 #include "log.h"
 #include "map.h"
 #include "mem.h"
+#include "timing.h"
 
 #include "audio.h"
 #include "chatline_g.h"
@@ -394,26 +395,45 @@
 }
 
 /**************************************************************************
-...
+  Blink the active unit (if necessary).  Return the time until the next
+  blink (in seconds).
 **************************************************************************/
-void blink_active_unit(void)
+double blink_active_unit(void)
 {
   static bool is_shown;
   static struct unit *pblinking_unit;
-  struct unit *punit;
+  static struct timer *blink_timer = NULL;
+  const double blink_time = 0.5;
 
-  if ((punit = punit_focus)) {
+  struct unit *punit = punit_focus;
+  bool need_update = FALSE;
+
+  if (punit) {
     if (punit != pblinking_unit) {
+      
       /* When the focus unit changes, we reset the is_shown flag. */
       pblinking_unit = punit;
       is_shown = TRUE;
+      need_update = TRUE;
     } else {
-      /* Reverse the shown status. */
-      is_shown = !is_shown;
+      if (read_timer_seconds(blink_timer) > blink_time) {
+       /* Reverse the shown status. */
+       is_shown = !is_shown;
+       need_update = TRUE;
+      }
+    }
+    if (need_update) {
+      /* If we lag, we don't try to catch up.  Instead we just start a
+       * new blink_time on every update. */
+      blink_timer = renew_timer_start(blink_timer, TIMER_USER, TIMER_ACTIVE);
+      set_focus_unit_hidden_state(!is_shown);
+      refresh_unit_mapcanvas(punit, punit->tile, TRUE);
     }
-    set_focus_unit_hidden_state(!is_shown);
-    refresh_unit_mapcanvas(punit, punit->tile, TRUE);
+
+    return blink_time - read_timer_seconds(blink_timer);
   }
+
+  return blink_time;
 }
 
 /**************************************************************************
Index: client/control.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/control.h,v
retrieving revision 1.48
diff -u -r1.48 control.h
--- client/control.h    9 Feb 2005 16:23:12 -0000       1.48
+++ client/control.h    11 Feb 2005 20:02:54 -0000
@@ -112,7 +112,7 @@
 void update_unit_focus(void);
 struct unit *find_visible_unit(struct tile *ptile);
 void set_units_in_combat(struct unit *pattacker, struct unit *pdefender);
-void blink_active_unit(void);
+double blink_active_unit(void);
 void update_unit_pix_label(struct unit *punit);
 
 void process_caravan_arrival(struct unit *punit);
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.468
diff -u -r1.468 packhand.c
--- client/packhand.c   9 Feb 2005 17:15:17 -0000       1.468
+++ client/packhand.c   11 Feb 2005 20:02:55 -0000
@@ -766,7 +766,7 @@
   update_unit_info_label(get_unit_in_focus());
   update_menus();
 
-  seconds_to_turndone=game.timeout;
+  set_seconds_to_turndone(game.timeout);
 
 #if 0
   /* This information shouldn't be needed, but if it is this is the only
@@ -1362,11 +1362,9 @@
   boot_help = (can_client_change_view()
               && game.spacerace != pinfo->spacerace);
   game.spacerace=pinfo->spacerace;
-  if (game.timeout != 0) {
-    if (pinfo->seconds_to_turndone != 0)
-      seconds_to_turndone = pinfo->seconds_to_turndone;
-  } else
-    seconds_to_turndone = 0;
+  if (game.timeout != 0 && pinfo->seconds_to_turndone != 0) {
+    set_seconds_to_turndone(pinfo->seconds_to_turndone);
+  }
   if (boot_help) {
     boot_help_texts();         /* reboot, after setting game.spacerace */
   }
Index: client/text.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/text.c,v
retrieving revision 1.24
diff -u -r1.24 text.c
--- client/text.c       8 Feb 2005 21:36:49 -0000       1.24
+++ client/text.c       11 Feb 2005 20:02:55 -0000
@@ -639,7 +639,7 @@
   if (game.timeout <= 0) {
     add("%s", Q_("?timeout:off"));
   } else {
-    add("%s", format_duration(seconds_to_turndone));
+    add("%s", format_duration(get_seconds_to_turndone()));
   }
 
   RETURN;
Index: client/gui-ftwl/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-ftwl/gui_main.c,v
retrieving revision 1.9
diff -u -r1.9 gui_main.c
--- client/gui-ftwl/gui_main.c  22 Jan 2005 19:45:39 -0000      1.9
+++ client/gui-ftwl/gui_main.c  11 Feb 2005 20:02:55 -0000
@@ -68,9 +68,9 @@
 **************************************************************************/
 static void timer_callback(void *data)
 {
-  real_timer_callback();
-  //sw_add_timeout(TIMER_INTERVAL, timer_callback, NULL);
-  sw_add_timeout(1000, timer_callback, NULL);
+  double msec = real_timer_callback() * 1000;
+  //sw_add_timeout(1000, timer_callback, NULL);
+  sw_add_timeout(msec, timer_callback, NULL);
 }
 
 /**************************************************************************
Index: client/gui-gtk/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/gui_main.c,v
retrieving revision 1.161
diff -u -r1.161 gui_main.c
--- client/gui-gtk/gui_main.c   11 Feb 2005 16:57:59 -0000      1.161
+++ client/gui-gtk/gui_main.c   11 Feb 2005 20:02:55 -0000
@@ -1090,6 +1090,7 @@
 static gint timer_callback(gpointer data)
 {
   real_timer_callback();
+  freelog(LOG_ERROR, "FIXME: Need to update timer.");
   return TRUE;
 }
 
Index: client/gui-gtk-2.0/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/gui_main.c,v
retrieving revision 1.109
diff -u -r1.109 gui_main.c
--- client/gui-gtk-2.0/gui_main.c       11 Feb 2005 16:57:59 -0000      1.109
+++ client/gui-gtk-2.0/gui_main.c       11 Feb 2005 20:02:56 -0000
@@ -1387,8 +1387,11 @@
 **************************************************************************/
 static gint timer_callback(gpointer data)
 {
-  real_timer_callback();
-  return TRUE;
+  double seconds = real_timer_callback();
+
+  timer_id = gtk_timeout_add(seconds * 1000, timer_callback, NULL);
+
+  return FALSE;
 }
 
 /**************************************************************************
Index: client/gui-mui/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/gui_main.c,v
retrieving revision 1.90
diff -u -r1.90 gui_main.c
--- client/gui-mui/gui_main.c   11 Feb 2005 16:57:59 -0000      1.90
+++ client/gui-mui/gui_main.c   11 Feb 2005 20:02:56 -0000
@@ -144,6 +144,7 @@
 static void handle_timer(void)
 {
   real_timer_callback();
+  freelog(LOG_ERROR, "FIXME: Need to update timer.");
 }
 
 static BOOL connected;         /* TRUE, if connected to the server */
Index: client/gui-win32/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/gui_main.c,v
retrieving revision 1.40
diff -u -r1.40 gui_main.c
--- client/gui-win32/gui_main.c 11 Feb 2005 16:58:00 -0000      1.40
+++ client/gui-win32/gui_main.c 11 Feb 2005 20:02:56 -0000
@@ -516,6 +516,7 @@
   }
 
   real_timer_callback();
+  freelog(LOG_ERROR, "FIXME: Need to update timer.");
 }
 
 /**************************************************************************
Index: client/gui-xaw/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/gui_main.c,v
retrieving revision 1.101
diff -u -r1.101 gui_main.c
--- client/gui-xaw/gui_main.c   11 Feb 2005 16:58:00 -0000      1.101
+++ client/gui-xaw/gui_main.c   11 Feb 2005 20:02:56 -0000
@@ -851,9 +851,10 @@
 **************************************************************************/
 void timer_callback(XtPointer client_data, XtIntervalId * id)
 {
-  x_interval_id = XtAppAddTimeOut(app_context, TIMER_INTERVAL,
+  int msec = real_timer_callback() * 1000;
+
+  x_interval_id = XtAppAddTimeOut(app_context, msec,
                                  timer_callback, NULL);
-  real_timer_callback();
 }
 
 /**************************************************************************

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#12219) fix bugs with real_timer_callback, Jason Short <=