Crossfire Server, Trunk
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 
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;
51 static const char *const season_name[SEASONS_PER_YEAR+1] = {
52  "The Season of New Year",
53  "The Season of Growth",
54  "The Season of Harvest",
55  "The Season of Decay",
56  "The Season of the Blizzard",
57  "\n"
58 };
59 
61 static const char *const weekdays[DAYS_PER_WEEK] = {
62  "the Day of the Moon",
63  "the Day of the Bull",
64  "the Day of the Deception",
65  "the Day of Thunder",
66  "the Day of Freedom",
67  "the Day of the Great Gods",
68  "the Day of the Sun"
69 };
70 
72 static const char *const month_name[MONTHS_PER_YEAR] = {
73  "Month of Winter", /* 0 */
74  "Month of the Ice Dragon",
75  "Month of the Frost Giant",
76  "Month of Valriel",
77  "Month of Lythander",
78  "Month of the Harvest",
79  "Month of Gaea",
80  "Month of Futility",
81  "Month of the Dragon",
82  "Month of the Sun",
83  "Month of the Great Infernus",
84  "Month of Ruggilli",
85  "Month of the Dark Shades",
86  "Month of the Devourers",
87  "Month of Sorig",
88  "Month of the Ancient Darkness",
89  "Month of Gorokh"
90 };
91 
92 static const char *const periodsofday[PERIODS_PER_DAY] = {
93  "Night",
94  "Dawn",
95  "Morning",
96  "Noon",
97  "Evening",
98  "Dusk"
99 };
100 
104 const char *get_periodofday(const int index) {
105  return ((index >= 0) && (index < PERIODS_PER_DAY)) ? periodsofday[index] : NULL;
106 }
107 
111 const char *get_month_name(const int index) {
112  return ((index >= 0) && (index < MONTHS_PER_YEAR)) ? month_name[index] : NULL;
113 }
114 
118 const char *get_weekday(const int index) {
119  return ((index >= 0) && (index < DAYS_PER_WEEK)) ? weekdays[index] : NULL;
120 }
121 
125 const char *get_season_name(const int index) {
126  return ((index >= 0) && (index < (SEASONS_PER_YEAR+1))) ? season_name[index] : NULL;
127 }
128 
132 void reset_sleep(void) {
133  int i;
134 
135  for (i = 0; i < PBUFLEN; i++)
136  process_utime_save[i] = 0;
137  psaveind = 0;
138  process_max_utime = 0;
139  process_min_utime = 999999999;
140  process_tot_mtime = 0;
141  pticks = 0;
142 
143  clock_gettime(CLOCK_MONOTONIC, &game_time);
144 }
145 
149 static void log_time(uint32_t process_utime) {
150  if (++psaveind >= PBUFLEN)
151  psaveind = 0;
152  process_utime_save[psaveind] = process_utime;
153  if (process_utime > process_max_utime)
154  process_max_utime = process_utime;
155  if (process_utime < process_min_utime)
156  process_min_utime = process_utime;
157  process_tot_mtime += process_utime/1000;
158 }
159 
163 long timespec_diff(struct timespec *end, struct timespec *start) {
164  long long sec = (long long)end->tv_sec - (long long)start->tv_sec;
165  long nsec = end->tv_nsec - start->tv_nsec;
166  return sec * 1e6 + nsec / 1e3;
167 }
168 
172 static void timespec_add(struct timespec *time, long usec) {
173  long nsec_sum = time->tv_nsec + usec * 1e3;
174  time->tv_sec += nsec_sum / 1e9;
175  time->tv_nsec = nsec_sum % (long)1e9;
176 }
177 
178 /*
179  * Add one tick length to the last tick time.
180  */
183  pticks++;
184 }
185 
187  struct timespec now;
188  clock_gettime(CLOCK_MONOTONIC, &now);
189  long time_since_last_sleep = timespec_diff(&now, &game_time);
190  log_time(time_since_last_sleep);
191  return tick_duration - time_since_last_sleep;
192 }
193 
194 void jump_time() {
196  clock_gettime(CLOCK_MONOTONIC, &game_time);
197 }
198 
205 void set_tick_duration(long t) {
206  tick_duration = t;
207 }
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%%)", tick_duration / 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];
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  tick_duration/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 unsigned int tick_length(float seconds) {
379  return (int)ceil(seconds * 1000000 / tick_duration);
380 }
get_month_name
const char * get_month_name(const int index)
Definition: time.c:111
_timeofday::month
int month
Definition: tod.h:40
global.h
DAYS_PER_WEEK
#define DAYS_PER_WEEK
Definition: tod.h:16
time_info
void time_info(object *op)
Definition: time.c:294
psaveind
static uint32_t psaveind
Definition: time.c:43
PTICKS_PER_CLOCK
#define PTICKS_PER_CLOCK
Definition: tod.h:12
set_tick_duration
void set_tick_duration(long t)
Definition: time.c:205
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
game_time
static struct timespec game_time
Definition: time.c:36
tick_game_time
void tick_game_time()
Definition: time.c:181
_timeofday::day
int day
Definition: tod.h:41
get_sleep_remaining
long get_sleep_remaining()
Definition: time.c:186
MAX_TIME
#define MAX_TIME
Definition: config.h:246
HOURS_PER_DAY
#define HOURS_PER_DAY
Definition: tod.h:15
get_periodofday
const char * get_periodofday(const int index)
Definition: time.c:104
weekdays
static const char *const weekdays[DAYS_PER_WEEK]
Definition: time.c:61
month_name
static const char *const month_name[MONTHS_PER_YEAR]
Definition: time.c:72
_timeofday::year
int year
Definition: tod.h:39
MIN
#define MIN(x, y)
Definition: compat.h:21
tick_length
unsigned int tick_length(float seconds)
Definition: time.c:378
_timeofday::periodofday
int periodofday
Definition: tod.h:47
HOURS_PER_YEAR
#define HOURS_PER_YEAR
Definition: tod.h:28
season_name
static const char *const season_name[SEASONS_PER_YEAR+1]
Definition: time.c:51
_timeofday::dayofweek
int dayofweek
Definition: tod.h:42
WEEKS_PER_MONTH
#define WEEKS_PER_MONTH
Definition: tod.h:17
print_tod
static void print_tod(object *op)
Definition: time.c:258
_timeofday
Definition: tod.h:38
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:404
periodsofday
static const char *const periodsofday[PERIODS_PER_DAY]
Definition: time.c:92
reset_sleep
void reset_sleep(void)
Definition: time.c:132
MSG_TYPE_COMMAND_DEBUG
#define MSG_TYPE_COMMAND_DEBUG
Definition: newclient.h:528
_timeofday::season
int season
Definition: tod.h:46
get_tod
void get_tod(timeofday_t *tod)
Definition: time.c:215
SEASONS_PER_YEAR
#define SEASONS_PER_YEAR
Definition: tod.h:19
MSG_TYPE_COMMAND_INFO
#define MSG_TYPE_COMMAND_INFO
Definition: newclient.h:526
_timeofday::weekofmonth
int weekofmonth
Definition: tod.h:45
todtick
unsigned long todtick
Definition: time.c:38
DAYS_PER_MONTH
#define DAYS_PER_MONTH
Definition: tod.h:24
process_max_utime
static uint32_t process_max_utime
Definition: time.c:44
tick_duration
uint32_t tick_duration
Definition: time.c:35
PBUFLEN
#define PBUFLEN
Definition: time.c:41
timespec_diff
long timespec_diff(struct timespec *end, struct timespec *start)
Definition: time.c:163
MONTHS_PER_YEAR
#define MONTHS_PER_YEAR
Definition: tod.h:18
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
HOURS_PER_MONTH
#define HOURS_PER_MONTH
Definition: tod.h:27
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
Floor.t
t
Definition: Floor.py:62
pticks
uint32_t pticks
Definition: time.c:47
process_utime_long_count
static uint32_t process_utime_long_count
Definition: time.c:48
timespec_add
static void timespec_add(struct timespec *time, long usec)
Definition: time.c:172
log_time
static void log_time(uint32_t process_utime)
Definition: time.c:149
process_min_utime
static uint32_t process_min_utime
Definition: time.c:45
PERIODS_PER_DAY
#define PERIODS_PER_DAY
Definition: tod.h:20
give.op
op
Definition: give.py:33
get_season_name
const char * get_season_name(const int index)
Definition: time.c:125
npc_dialog.index
int index
Definition: npc_dialog.py:102
buf
StringBuffer * buf
Definition: readable.c:1610
process_utime_save
static uint32_t process_utime_save[PBUFLEN]
Definition: time.c:42
process_tot_mtime
static uint32_t process_tot_mtime
Definition: time.c:46
seconds
long seconds(void)
Definition: time.c:344
get_weekday
const char * get_weekday(const int index)
Definition: time.c:118
jump_time
void jump_time()
Definition: time.c:194
_timeofday::minute
int minute
Definition: tod.h:44
tod.h
time_format_time
const char * time_format_time(const timeofday_t *tod, char *buf, size_t bufsize)
Definition: time.c:365
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:319
_timeofday::hour
int hour
Definition: tod.h:43