Crossfire Server, Trunk  R20513
time.c
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 
39 #define PBUFLEN 100
43 static uint32_t process_min_utime = 999999999;
49 static const char *const season_name[SEASONS_PER_YEAR+1] = {
50  "The Season of New Year",
51  "The Season of Growth",
52  "The Season of Harvest",
53  "The Season of Decay",
54  "The Season of the Blizzard",
55  "\n"
56 };
57 
59 static const char *const weekdays[DAYS_PER_WEEK] = {
60  "the Day of the Moon",
61  "the Day of the Bull",
62  "the Day of the Deception",
63  "the Day of Thunder",
64  "the Day of Freedom",
65  "the Day of the Great Gods",
66  "the Day of the Sun"
67 };
68 
70 static const char *const month_name[MONTHS_PER_YEAR] = {
71  "Month of Winter", /* 0 */
72  "Month of the Ice Dragon",
73  "Month of the Frost Giant",
74  "Month of Valriel",
75  "Month of Lythander",
76  "Month of the Harvest",
77  "Month of Gaea",
78  "Month of Futility",
79  "Month of the Dragon",
80  "Month of the Sun",
81  "Month of the Great Infernus",
82  "Month of Ruggilli",
83  "Month of the Dark Shades",
84  "Month of the Devourers",
85  "Month of Sorig",
86  "Month of the Ancient Darkness",
87  "Month of Gorokh"
88 };
89 
90 static const char *const periodsofday[PERIODS_PER_DAY] = {
91  "Night",
92  "Dawn",
93  "Morning",
94  "Noon",
95  "Evening",
96  "Dusk"
97 };
98 
102 const char *get_periodofday(const int index) {
103  return ((index >= 0) && (index < PERIODS_PER_DAY)) ? periodsofday[index] : NULL;
104 }
105 
109 const char *get_month_name(const int index) {
110  return ((index >= 0) && (index < MONTHS_PER_YEAR)) ? month_name[index] : NULL;
111 }
112 
116 const char *get_weekday(const int index) {
117  return ((index >= 0) && (index < DAYS_PER_WEEK)) ? weekdays[index] : NULL;
118 }
119 
123 const char *get_season_name(const int index) {
124  return ((index >= 0) && (index < (SEASONS_PER_YEAR+1))) ? season_name[index] : NULL;
125 }
126 
130 void reset_sleep(void) {
131  int i;
132 
133  for (i = 0; i < PBUFLEN; i++)
134  process_utime_save[i] = 0;
135  psaveind = 0;
136  process_max_utime = 0;
137  process_min_utime = 999999999;
138  process_tot_mtime = 0;
139  pticks = 0;
140 
141  clock_gettime(CLOCK_MONOTONIC, &game_time);
142 }
143 
147 static void log_time(uint32_t process_utime) {
148  pticks++;
149  if (++psaveind >= PBUFLEN)
150  psaveind = 0;
151  process_utime_save[psaveind] = process_utime;
152  if (process_utime > process_max_utime)
153  process_max_utime = process_utime;
154  if (process_utime < process_min_utime)
155  process_min_utime = process_utime;
156  process_tot_mtime += process_utime/1000;
157 }
158 
162 static long timespec_diff(struct timespec *end, struct timespec *start) {
163  long long sec = (long long)end->tv_sec - (long long)start->tv_sec;
164  long nsec = end->tv_nsec - start->tv_nsec;
165  return sec * 1e6 + nsec / 1e3;
166 }
167 
171 static void timespec_add(struct timespec *time, long usec) {
172  long nsec_sum = time->tv_nsec + usec * 1e3;
173  time->tv_sec += nsec_sum / 1e9;
174  time->tv_nsec = nsec_sum % (long)1e9;
175 }
176 
180 void sleep_delta(void) {
181  struct timespec now;
182  clock_gettime(CLOCK_MONOTONIC, &now);
183  long time_since_last_sleep = timespec_diff(&now, &game_time);
184  log_time(time_since_last_sleep);
185 
186  long sleep_time = max_time - time_since_last_sleep;
187  if (sleep_time > 0) {
188  usleep(sleep_time);
189  } else {
191  }
192 
193  // Add one tick length to the last tick time.
195 }
196 
203 void set_max_time(long t) {
204  max_time = t;
205 }
206 
207 extern unsigned long todtick;
208 
215 void get_tod(timeofday_t *tod) {
216  tod->year = todtick/HOURS_PER_YEAR;
219  tod->dayofweek = tod->day%DAYS_PER_WEEK;
220  tod->hour = todtick%HOURS_PER_DAY;
222  if (tod->minute > 58)
223  tod->minute = 58; /* it's imprecise at best anyhow */
224  tod->weekofmonth = tod->day/WEEKS_PER_MONTH;
225  if (tod->month < 3)
226  tod->season = 0;
227  else if (tod->month < 6)
228  tod->season = 1;
229  else if (tod->month < 9)
230  tod->season = 2;
231  else if (tod->month < 12)
232  tod->season = 3;
233  else
234  tod->season = 4;
235 
236  if (tod->hour < 5) /*until 4:59*/
237  tod->periodofday = 0;
238  else if (tod->hour < 8)
239  tod->periodofday = 1;
240  else if (tod->hour < 13)
241  tod->periodofday = 2;
242  else if (tod->hour < 15)
243  tod->periodofday = 3;
244  else if (tod->hour < 20)
245  tod->periodofday = 4;
246  else if (tod->hour < 23)
247  tod->periodofday = 5;
248  else /*back to night*/
249  tod->periodofday = 0;
250 }
251 
258 static void print_tod(object *op) {
259  timeofday_t tod;
260  const char *suf;
261  int day;
262  char buf1[128];
263 
264  get_tod(&tod);
265 
267  "It is %s, on %s", time_format_time(&tod, buf1, sizeof(buf1)), weekdays[tod.dayofweek]);
268 
269  day = tod.day+1;
270  if (day == 1 || ((day%10) == 1 && day > 20))
271  suf = "st";
272  else if (day == 2 || ((day%10) == 2 && day > 20))
273  suf = "nd";
274  else if (day == 3 || ((day%10) == 3 && day > 20))
275  suf = "rd";
276  else
277  suf = "th";
278 
280  "The %d%s Day of the %s, Year %d",
281  day, suf, month_name[tod.month], tod.year+1);
282 
284  "Time of Year: %s",
285  season_name[tod.season]);
286 }
287 
294 void time_info(object *op) {
295  int tot = 0, long_count = 0;
296  uint32_t maxt = 0, mint = 99999999, i;
297 
298  print_tod(op);
299 
300  if (!QUERY_FLAG(op, FLAG_WIZ))
301  return;
302 
305  "Statistics for last %d ticks:\n\tmin/avg/max = %d/%d/%d ms per tick",
307  process_max_utime / 1000);
308 
311  "\tticks longer than %d ms = %d (%d%%)", max_time / 1000,
313 
315  "Time last %d ticks:",
316  MIN(pticks, PBUFLEN));
317 
318  for (i = 0; i < MIN(pticks, PBUFLEN); i++) {
319  tot += process_utime_save[i];
320  if (process_utime_save[i] > maxt)
321  maxt = process_utime_save[i];
322  if (process_utime_save[i] < mint)
323  mint = process_utime_save[i];
324  if (process_utime_save[i] > max_time)
325  long_count++;
326  }
327 
328  assert(pticks > 0);
329 
331  "avg time=%dms max time=%dms min time=%dms",
332  tot/MIN(pticks, PBUFLEN)/1000, maxt/1000,
333  mint/1000);
334 
336  "ticks longer than max time (%dms) = %d (%d%%)",
337  max_time/1000, long_count,
338  100*long_count/MIN(pticks, PBUFLEN));
339 }
340 
344 long seconds(void) {
345  struct timespec now;
346  clock_gettime(CLOCK_REALTIME, &now);
347  return now.tv_sec;
348 }
349 
365 const char *time_format_time(const timeofday_t *tod, char *buf, size_t bufsize)
366 {
367  snprintf(buf, bufsize, "%d minute%s past %d o'clock %s",
368  tod->minute+1,
369  tod->minute+1 < 2 ? "" : "s",
370  tod->hour%14 == 0 ? 14 : tod->hour%14,
371  tod->hour >= 14 ? "pm" : "am");
372  return buf;
373 }
374 
378 int tick_length(float seconds) {
379  return (int)ceil(seconds * 1000000 / max_time);
380 }
#define DAYS_PER_WEEK
Definition: tod.h:13
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: main.c:315
#define PBUFLEN
Size of history buffer.
Definition: time.c:39
static void log_time(uint32_t process_utime)
Adds time to our history list.
Definition: time.c:147
Defines for the ingame clock, ticks management and weather system.
#define HOURS_PER_YEAR
Definition: tod.h:25
const char * get_season_name(const int index)
give access to season names
Definition: time.c:123
int minute
Definition: tod.h:38
uint32_t pticks
?
Definition: time.c:45
const char * get_weekday(const int index)
give access to weekday names
Definition: time.c:116
static uint32_t process_tot_mtime
?
Definition: time.c:44
static uint32_t process_utime_save[PBUFLEN]
Historic data.
Definition: time.c:40
Global type definitions and header inclusions.
static uint32_t process_utime_long_count
?
Definition: time.c:46
#define PERIODS_PER_DAY
Definition: tod.h:17
static uint32_t process_min_utime
Shortest cycle time.
Definition: time.c:43
static void timespec_add(struct timespec *time, long usec)
Add &#39;usec&#39; microseconds to the given timespec.
Definition: time.c:171
int tick_length(float seconds)
Calculate the number of ticks that correspond to real time.
Definition: time.c:378
int periodofday
Definition: tod.h:41
#define MIN(x, y)
Definition: compat.h:17
int year
Definition: tod.h:33
const char * get_month_name(const int index)
give access to month names
Definition: time.c:109
#define HOURS_PER_MONTH
Definition: tod.h:24
const char * time_format_time(const timeofday_t *tod, char *buf, size_t bufsize)
Formats a timestamp in Crossfire time.
Definition: time.c:365
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:379
#define DAYS_PER_MONTH
Definition: tod.h:21
#define snprintf
Definition: win32.h:46
int month
Definition: tod.h:34
void set_max_time(long t)
Sets the max speed.
Definition: time.c:203
static uint32_t psaveind
Index in process_utime_save.
Definition: time.c:41
long seconds(void)
Return wall clock time in seconds.
Definition: time.c:344
#define MAX_TIME
If you feel the game is too fast or too slow, change MAX_TIME.
Definition: config.h:245
static const char *const month_name[MONTHS_PER_YEAR]
Months.
Definition: time.c:70
int weekofmonth
Definition: tod.h:39
int day
Definition: tod.h:35
int dayofweek
Definition: tod.h:36
void time_info(object *op)
Players wants to know the time.
Definition: time.c:294
static long timespec_diff(struct timespec *end, struct timespec *start)
Return the difference between two timespec&#39;s in microseconds.
Definition: time.c:162
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:231
#define MSG_TYPE_COMMAND_DEBUG
Various debug type commands.
Definition: newclient.h:508
static void print_tod(object *op)
Prints the time.
Definition: time.c:258
void reset_sleep(void)
Initialise all variables used in the timing routines.
Definition: time.c:130
static const char *const periodsofday[PERIODS_PER_DAY]
Definition: time.c:90
unsigned int uint32_t
Definition: win32.h:162
static const char *const weekdays[DAYS_PER_WEEK]
Days of the week.
Definition: time.c:59
static const char *const season_name[SEASONS_PER_YEAR+1]
Ingame seasons.
Definition: time.c:49
void sleep_delta(void)
Sleep until the next tick.
Definition: time.c:180
void get_tod(timeofday_t *tod)
Computes the ingame time of the day.
Definition: time.c:215
static struct timespec game_time
Definition: time.c:36
#define HOURS_PER_DAY
Definition: tod.h:12
Represents the ingame time.
Definition: tod.h:32
#define MSG_TYPE_COMMAND_INFO
Generic info: resistances, etc.
Definition: newclient.h:506
const char * get_periodofday(const int index)
give access to weekday names
Definition: time.c:102
#define WEEKS_PER_MONTH
Definition: tod.h:14
uint32_t max_time
Gloabal variables:
Definition: time.c:35
int hour
Definition: tod.h:37
unsigned long todtick
Ingame time.
Definition: init.c:440
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
static uint32_t process_max_utime
Longest cycle time.
Definition: time.c:42
#define MONTHS_PER_YEAR
Definition: tod.h:15
#define PTICKS_PER_CLOCK
Definition: tod.h:9
#define SEASONS_PER_YEAR
Definition: tod.h:16
int season
Definition: tod.h:40