Crossfire Server  1.75.0
time.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 #include "global.h"
20 
21 #include <assert.h>
22 #include <math.h>
23 
24 #include "tod.h"
25 
26 #ifndef WIN32 /* ---win32 exclude header */
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <sys/time.h>
30 #endif /* win32 */
31 
36 static struct timespec game_time;
37 
38 unsigned long todtick;
39 
41 #define PBUFLEN 100
42 static uint32_t process_utime_save[PBUFLEN];
43 static uint32_t psaveind;
44 static uint32_t process_max_utime = 0;
45 static uint32_t process_min_utime = 999999999;
46 static uint32_t process_tot_mtime;
47 uint32_t pticks;
48 static uint32_t process_utime_long_count;
50 uint32_t last_time; //< Time to process last tick (in ms), externally-visible
51 
53 static const char *const season_name[SEASONS_PER_YEAR+1] = {
54  "The Season of New Year",
55  "The Season of Growth",
56  "The Season of Harvest",
57  "The Season of Decay",
58  "The Season of the Blizzard",
59  "\n"
60 };
61 
63 static const char *const weekdays[DAYS_PER_WEEK] = {
64  "the Day of the Moon",
65  "the Day of the Bull",
66  "the Day of the Deception",
67  "the Day of Thunder",
68  "the Day of Freedom",
69  "the Day of the Great Gods",
70  "the Day of the Sun"
71 };
72 
74 static const char *const month_name[MONTHS_PER_YEAR] = {
75  "Month of Winter", /* 0 */
76  "Month of the Ice Dragon",
77  "Month of the Frost Giant",
78  "Month of Valriel",
79  "Month of Lythander",
80  "Month of the Harvest",
81  "Month of Gaea",
82  "Month of Futility",
83  "Month of the Dragon",
84  "Month of the Sun",
85  "Month of the Great Infernus",
86  "Month of Ruggilli",
87  "Month of the Dark Shades",
88  "Month of the Devourers",
89  "Month of Sorig",
90  "Month of the Ancient Darkness",
91  "Month of Gorokh"
92 };
93 
94 static const char *const periodsofday[PERIODS_PER_DAY] = {
95  "Night",
96  "Dawn",
97  "Morning",
98  "Noon",
99  "Evening",
100  "Dusk"
101 };
102 
106 const char *get_periodofday(const int index) {
107  return ((index >= 0) && (index < PERIODS_PER_DAY)) ? periodsofday[index] : NULL;
108 }
109 
113 const char *get_month_name(const int index) {
114  return ((index >= 0) && (index < MONTHS_PER_YEAR)) ? month_name[index] : NULL;
115 }
116 
120 const char *get_weekday(const int index) {
121  return ((index >= 0) && (index < DAYS_PER_WEEK)) ? weekdays[index] : NULL;
122 }
123 
127 const char *get_season_name(const int index) {
128  return ((index >= 0) && (index < (SEASONS_PER_YEAR+1))) ? season_name[index] : NULL;
129 }
130 
134 void reset_sleep(void) {
135  int i;
136 
137  for (i = 0; i < PBUFLEN; i++)
138  process_utime_save[i] = 0;
139  psaveind = 0;
140  process_max_utime = 0;
141  process_min_utime = 999999999;
142  process_tot_mtime = 0;
143  pticks = 0;
144 
145  clock_gettime(CLOCK_MONOTONIC, &game_time);
146 }
147 
151 static void log_time(uint32_t process_utime) {
152  if (++psaveind >= PBUFLEN)
153  psaveind = 0;
154  process_utime_save[psaveind] = process_utime;
155  last_time = process_utime;
156  if (process_utime > process_max_utime)
157  process_max_utime = process_utime;
158  if (process_utime < process_min_utime)
159  process_min_utime = process_utime;
160  process_tot_mtime += process_utime/1000;
161 }
162 
166 long timespec_diff(struct timespec *end, struct timespec *start) {
167  double sec = difftime(end->tv_sec, start->tv_sec);
168  long nsec = end->tv_nsec - start->tv_nsec;
169  return (long)(sec * 1e6 + nsec / 1e3);
170 }
171 
175 static void timespec_add(struct timespec *time, long usec) {
176  long nsec_sum = time->tv_nsec + usec * 1e3;
177  time->tv_sec += nsec_sum / 1e9;
178  time->tv_nsec = nsec_sum % (long)1e9;
179 }
180 
181 /*
182  * Add one tick length to the last tick time.
183  */
186  pticks++;
187 }
188 
190  struct timespec now;
191  clock_gettime(CLOCK_MONOTONIC, &now);
192  long time_since_last_sleep = timespec_diff(&now, &game_time);
193  if (time_since_last_sleep >= 0)
194  log_time(time_since_last_sleep);
195  return tick_duration - time_since_last_sleep;
196 }
197 
198 void jump_time() {
200  clock_gettime(CLOCK_MONOTONIC, &game_time);
201 }
202 
209 void set_tick_duration(long t) {
210  tick_duration = t;
211 }
212 
219 void get_tod(timeofday_t *tod) {
220  tod->year = todtick/HOURS_PER_YEAR;
223  tod->dayofweek = tod->day%DAYS_PER_WEEK;
224  tod->hour = todtick%HOURS_PER_DAY;
226  if (tod->minute > 58)
227  tod->minute = 58; /* it's imprecise at best anyhow */
228  tod->weekofmonth = tod->day/WEEKS_PER_MONTH;
229  if (tod->month < 3)
230  tod->season = 0;
231  else if (tod->month < 6)
232  tod->season = 1;
233  else if (tod->month < 9)
234  tod->season = 2;
235  else if (tod->month < 12)
236  tod->season = 3;
237  else
238  tod->season = 4;
239 
240  if (tod->hour < 5) /*until 4:59*/
241  tod->periodofday = 0;
242  else if (tod->hour < 8)
243  tod->periodofday = 1;
244  else if (tod->hour < 13)
245  tod->periodofday = 2;
246  else if (tod->hour < 15)
247  tod->periodofday = 3;
248  else if (tod->hour < 20)
249  tod->periodofday = 4;
250  else if (tod->hour < 23)
251  tod->periodofday = 5;
252  else /*back to night*/
253  tod->periodofday = 0;
254 }
255 
262 static void print_tod(object *op) {
263  timeofday_t tod;
264  const char *suf;
265  int day;
266  char buf1[128];
267 
268  get_tod(&tod);
269 
271  "It is %s, on %s", time_format_time(&tod, buf1, sizeof(buf1)), weekdays[tod.dayofweek]);
272 
273  day = tod.day+1;
274  if (day == 1 || ((day%10) == 1 && day > 20))
275  suf = "st";
276  else if (day == 2 || ((day%10) == 2 && day > 20))
277  suf = "nd";
278  else if (day == 3 || ((day%10) == 3 && day > 20))
279  suf = "rd";
280  else
281  suf = "th";
282 
284  "The %d%s Day of the %s, Year %d",
285  day, suf, month_name[tod.month], tod.year+1);
286 
288  "Time of Year: %s",
289  season_name[tod.season]);
290 }
291 
298 void time_info(object *op) {
299  int tot = 0, long_count = 0;
300  uint32_t maxt = 0, mint = 99999999, i;
301 
302  print_tod(op);
303 
304  if (!QUERY_FLAG(op, FLAG_WIZ))
305  return;
306 
309  "Statistics for last %d ticks:\n\tmin/avg/max = %d/%d/%d ms per tick",
311  process_max_utime / 1000);
312 
315  "\tticks longer than %d ms = %d (%d%%)", tick_duration / 1000,
317 
319  "Time last %d ticks:",
320  MIN(pticks, PBUFLEN));
321 
322  for (i = 0; i < MIN(pticks, PBUFLEN); i++) {
323  tot += process_utime_save[i];
324  if (process_utime_save[i] > maxt)
325  maxt = process_utime_save[i];
326  if (process_utime_save[i] < mint)
327  mint = process_utime_save[i];
329  long_count++;
330  }
331 
332  assert(pticks > 0);
333 
335  "avg time=%dms max time=%dms min time=%dms",
336  tot/MIN(pticks, PBUFLEN)/1000, maxt/1000,
337  mint/1000);
338 
340  "ticks longer than max time (%dms) = %d (%d%%)",
341  tick_duration/1000, long_count,
342  100*long_count/MIN(pticks, PBUFLEN));
343 }
344 
348 long seconds(void) {
349  struct timespec now;
350  clock_gettime(CLOCK_REALTIME, &now);
351  return now.tv_sec;
352 }
353 
369 const char *time_format_time(const timeofday_t *tod, char *buf, size_t bufsize)
370 {
371  snprintf(buf, bufsize, "%d minute%s past %d o'clock %s",
372  tod->minute+1,
373  tod->minute+1 < 2 ? "" : "s",
374  tod->hour%14 == 0 ? 14 : tod->hour%14,
375  tod->hour >= 14 ? "pm" : "am");
376  return buf;
377 }
378 
382 unsigned int tick_length(float seconds) {
383  return (int)ceil(seconds * 1000000 / tick_duration);
384 }
385 
386 float ticks_to_seconds(int ticks) {
387  return ticks / (1000000.0 / tick_duration);
388 }
#define DAYS_PER_WEEK
Definition: tod.h:16
const char * get_periodofday(const int index)
give access to weekday names
Definition: time.cpp:106
const char * get_month_name(const int index)
give access to month names
Definition: time.cpp:113
unsigned long todtick
Game world time, in in-game hours.
Definition: time.cpp:38
Defines for the ingame clock, ticks management and weather system.
#define HOURS_PER_YEAR
Definition: tod.h:28
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
int day
Definition: tod.h:41
static uint32_t process_tot_mtime
?
Definition: time.cpp:46
long get_sleep_remaining()
Definition: time.cpp:189
int month
Definition: tod.h:40
Represents the ingame time.
Definition: tod.h:38
void time_info(object *op)
Players wants to know the time.
Definition: time.cpp:298
Global type definitions and header inclusions.
#define PERIODS_PER_DAY
Definition: tod.h:20
long timespec_diff(struct timespec *end, struct timespec *start)
Return the difference between two timespec&#39;s in microseconds.
Definition: time.cpp:166
#define MIN(x, y)
Definition: compat.h:21
#define HOURS_PER_MONTH
Definition: tod.h:27
int minute
Definition: tod.h:44
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:420
int periodofday
Definition: tod.h:47
static uint32_t psaveind
Index in process_utime_save.
Definition: time.cpp:43
static const char *const season_name[SEASONS_PER_YEAR+1]
Ingame seasons.
Definition: time.cpp:53
#define DAYS_PER_MONTH
Definition: tod.h:24
void set_tick_duration(long t)
Sets the tick duration.
Definition: time.cpp:209
uint32_t last_time
Definition: time.cpp:50
#define QUERY_FLAG(xyz, p)
Definition: define.h:386
int dayofweek
Definition: tod.h:42
#define PBUFLEN
Size of history buffer.
Definition: time.cpp:41
#define MAX_TIME
If you feel the game is too fast or too slow, change MAX_TIME.
Definition: config.h:254
static void log_time(uint32_t process_utime)
Adds time to our history list.
Definition: time.cpp:151
int hour
Definition: tod.h:43
int weekofmonth
Definition: tod.h:45
static uint32_t process_utime_long_count
Number of times server couldn&#39;t keep up with game time (tried to sleep for a negative time) ...
Definition: time.cpp:48
static const char *const periodsofday[PERIODS_PER_DAY]
Definition: time.cpp:94
void tick_game_time()
Definition: time.cpp:184
uint32_t pticks
Number of ticks since time reset.
Definition: time.cpp:47
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
long seconds(void)
Return wall clock time in seconds.
Definition: time.cpp:348
#define MSG_TYPE_COMMAND_DEBUG
Various debug type commands.
Definition: newclient.h:549
static uint32_t process_min_utime
Shortest cycle time.
Definition: time.cpp:45
uint32_t tick_duration
Gloabal variables:
Definition: time.cpp:35
static struct timespec game_time
Definition: time.cpp:36
const char * time_format_time(const timeofday_t *tod, char *buf, size_t bufsize)
Formats a timestamp in Crossfire time.
Definition: time.cpp:369
void get_tod(timeofday_t *tod)
Computes the ingame time of the day.
Definition: time.cpp:219
static uint32_t process_max_utime
Longest cycle time.
Definition: time.cpp:44
#define HOURS_PER_DAY
Definition: tod.h:15
static const char *const weekdays[DAYS_PER_WEEK]
Days of the week.
Definition: time.cpp:63
int year
Definition: tod.h:39
void reset_sleep(void)
Initialise all variables used in the timing routines.
Definition: time.cpp:134
static void print_tod(object *op)
Prints the time.
Definition: time.cpp:262
int season
Definition: tod.h:46
#define MSG_TYPE_COMMAND_INFO
Generic info: resistances, etc.
Definition: newclient.h:547
#define WEEKS_PER_MONTH
Definition: tod.h:17
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
const char * get_season_name(const int index)
give access to season names
Definition: time.cpp:127
void jump_time()
Definition: time.cpp:198
static void timespec_add(struct timespec *time, long usec)
Add &#39;usec&#39; microseconds to the given timespec.
Definition: time.cpp:175
StringBuffer * buf
Definition: readable.cpp:1563
#define MONTHS_PER_YEAR
Definition: tod.h:18
float ticks_to_seconds(int ticks)
Definition: time.cpp:386
static uint32_t process_utime_save[PBUFLEN]
Historic data.
Definition: time.cpp:42
#define PTICKS_PER_CLOCK
Number of ticks per in-game hour.
Definition: tod.h:12
#define SEASONS_PER_YEAR
Definition: tod.h:19
static const char *const month_name[MONTHS_PER_YEAR]
Months.
Definition: time.cpp:74
unsigned int tick_length(float seconds)
Calculate the number of ticks that correspond to real time.
Definition: time.cpp:382
const char * get_weekday(const int index)
give access to weekday names
Definition: time.cpp:120