Crossfire Server, Trunk
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;
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 }
print_tod
static void print_tod(object *op)
Definition: time.cpp:258
global.h
process_utime_save
static uint32_t process_utime_save[PBUFLEN]
Definition: time.cpp:42
DAYS_PER_WEEK
#define DAYS_PER_WEEK
Definition: tod.h:16
log_time
static void log_time(uint32_t process_utime)
Definition: time.cpp:149
PTICKS_PER_CLOCK
#define PTICKS_PER_CLOCK
Definition: tod.h:12
game_time
static struct timespec game_time
Definition: time.cpp:36
timeofday_t::year
int year
Definition: tod.h:39
time_info
void time_info(object *op)
Definition: time.cpp:294
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
timeofday_t::weekofmonth
int weekofmonth
Definition: tod.h:45
todtick
unsigned long todtick
Definition: time.cpp:38
MAX_TIME
#define MAX_TIME
Definition: config.h:254
HOURS_PER_DAY
#define HOURS_PER_DAY
Definition: tod.h:15
periodsofday
static const char *const periodsofday[PERIODS_PER_DAY]
Definition: time.cpp:92
timeofday_t
Definition: tod.h:38
time
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
Definition: arch-handbook.txt:206
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,...) PRINTF_ARGS(6
MIN
#define MIN(x, y)
Definition: compat.h:21
get_tod
void get_tod(timeofday_t *tod)
Definition: time.cpp:215
psaveind
static uint32_t psaveind
Definition: time.cpp:43
HOURS_PER_YEAR
#define HOURS_PER_YEAR
Definition: tod.h:28
WEEKS_PER_MONTH
#define WEEKS_PER_MONTH
Definition: tod.h:17
pticks
uint32_t pticks
Definition: time.cpp:47
buf
StringBuffer * buf
Definition: readable.cpp:1552
set_tick_duration
void set_tick_duration(long t)
Definition: time.cpp:205
time_format_time
const char * time_format_time(const timeofday_t *tod, char *buf, size_t bufsize)
Definition: time.cpp:365
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:393
get_season_name
const char * get_season_name(const int index)
Definition: time.cpp:125
MSG_TYPE_COMMAND_DEBUG
#define MSG_TYPE_COMMAND_DEBUG
Definition: newclient.h:517
timeofday_t::day
int day
Definition: tod.h:41
get_weekday
const char * get_weekday(const int index)
Definition: time.cpp:118
SEASONS_PER_YEAR
#define SEASONS_PER_YEAR
Definition: tod.h:19
timeofday_t::periodofday
int periodofday
Definition: tod.h:47
MSG_TYPE_COMMAND_INFO
#define MSG_TYPE_COMMAND_INFO
Definition: newclient.h:515
process_min_utime
static uint32_t process_min_utime
Definition: time.cpp:45
get_periodofday
const char * get_periodofday(const int index)
Definition: time.cpp:104
jump_time
void jump_time()
Definition: time.cpp:194
DAYS_PER_MONTH
#define DAYS_PER_MONTH
Definition: tod.h:24
season_name
static const char *const season_name[SEASONS_PER_YEAR+1]
Definition: time.cpp:51
timeofday_t::dayofweek
int dayofweek
Definition: tod.h:42
weekdays
static const char *const weekdays[DAYS_PER_WEEK]
Definition: time.cpp:61
timeofday_t::month
int month
Definition: tod.h:40
process_utime_long_count
static uint32_t process_utime_long_count
Definition: time.cpp:48
get_sleep_remaining
long get_sleep_remaining()
Definition: time.cpp:186
timeofday_t::season
int season
Definition: tod.h:46
seconds
long seconds(void)
Definition: time.cpp:344
tick_length
unsigned int tick_length(float seconds)
Definition: time.cpp:378
process_tot_mtime
static uint32_t process_tot_mtime
Definition: time.cpp:46
MONTHS_PER_YEAR
#define MONTHS_PER_YEAR
Definition: tod.h:18
timespec_diff
long timespec_diff(struct timespec *end, struct timespec *start)
Definition: time.cpp:163
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:251
timeofday_t::minute
int minute
Definition: tod.h:44
PERIODS_PER_DAY
#define PERIODS_PER_DAY
Definition: tod.h:20
give.op
op
Definition: give.py:33
Floor.t
t
Definition: Floor.py:62
timeofday_t::hour
int hour
Definition: tod.h:43
process_max_utime
static uint32_t process_max_utime
Definition: time.cpp:44
reset_sleep
void reset_sleep(void)
Definition: time.cpp:132
npc_dialog.index
int index
Definition: npc_dialog.py:102
tick_duration
uint32_t tick_duration
Definition: time.cpp:35
timespec_add
static void timespec_add(struct timespec *time, long usec)
Definition: time.cpp:172
get_month_name
const char * get_month_name(const int index)
Definition: time.cpp:111
now
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at it actually uses a mix of ASCII and binary data This handbook attempts to document various aspects of the Crossfire protocol As consult the README file to find out how to get in touch with helpful people via mailing and more History the communications plan was set to be a text based system It was up to the server and client to parse these messages and determine what to do These messages were assumed to be line per message At a reasonably early stage of Eric Anderson wrote a then the data itself you could send many data and after the other end could decode these commands This works fairly but I think the creation of numerous sub packets has some performance hit the eutl was not especially well so writing a client for a different platform became more Eric left to work on other products shortly after writing his which didn t really leave anyone with a full understanding of the socket code I have decided to remove the eutl dependency At least one advantage is that having this network related code directly in the client and server makes error handling a bit easier cleaner Packet Format the outside packet method the byte size for the size information is not included here Eutl originally used bytes for the size to bytes seems it makes a least some sense The actual data is something of the nature of the commands listed below It is a text followed by possible other data The remaining data can be binary it is up to the client and server to decode what it sent The commands as described below is just the data portion of the packet If writing a new remember that you must take into account the size of the packet There is no termination of other than knowing how long it should be For now
Definition: protocol.txt:71
month_name
static const char *const month_name[MONTHS_PER_YEAR]
Definition: time.cpp:72
tod.h
PBUFLEN
#define PBUFLEN
Definition: time.cpp:41
tick_game_time
void tick_game_time()
Definition: time.cpp:181