Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_time_c = 00003 * "$Id: time.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2006 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The authors can be reached via e-mail at crossfire-devel@real-time.com 00027 */ 00028 00034 #include <global.h> 00035 #include <tod.h> 00036 00037 #ifndef WIN32 /* ---win32 exclude header */ 00038 #include <stdio.h> 00039 #include <sys/types.h> 00040 #include <sys/time.h> 00041 #endif /* win32 */ 00042 00046 uint32 max_time = MAX_TIME; 00047 struct timeval last_time; 00048 00050 #define PBUFLEN 100 00051 static uint32 process_utime_save[PBUFLEN]; 00052 static uint32 psaveind; 00053 static uint32 process_max_utime = 0; 00054 static uint32 process_min_utime = 999999999; 00055 static uint32 process_tot_mtime; 00056 uint32 pticks; 00057 static uint32 process_utime_long_count; 00060 static const char *const season_name[SEASONS_PER_YEAR+1] = { 00061 "The Season of New Year", 00062 "The Season of Growth", 00063 "The Season of Harvest", 00064 "The Season of Decay", 00065 "The Season of the Blizzard", 00066 "\n" 00067 }; 00068 00070 static const char *const weekdays[DAYS_PER_WEEK] = { 00071 "the Day of the Moon", 00072 "the Day of the Bull", 00073 "the Day of the Deception", 00074 "the Day of Thunder", 00075 "the Day of Freedom", 00076 "the Day of the Great Gods", 00077 "the Day of the Sun" 00078 }; 00079 00081 static const char *const month_name[MONTHS_PER_YEAR] = { 00082 "Month of Winter", /* 0 */ 00083 "Month of the Ice Dragon", 00084 "Month of the Frost Giant", 00085 "Month of Valriel", 00086 "Month of Lythander", 00087 "Month of the Harvest", 00088 "Month of Gaea", 00089 "Month of Futility", 00090 "Month of the Dragon", 00091 "Month of the Sun", 00092 "Month of the Great Infernus", 00093 "Month of Ruggilli", 00094 "Month of the Dark Shades", 00095 "Month of the Devourers", 00096 "Month of Sorig", 00097 "Month of the Ancient Darkness", 00098 "Month of Gorokh" 00099 }; 00100 00101 static const char *const periodsofday[PERIODS_PER_DAY] = { 00102 "Night", 00103 "Dawn", 00104 "Morning", 00105 "Noon", 00106 "Evening", 00107 "Dusk" 00108 }; 00109 00113 const char *get_periodofday(const int index) { 00114 return ((index >= 0) && (index < PERIODS_PER_DAY)) ? periodsofday[index] : NULL; 00115 } 00116 00120 const char *get_month_name(const int index) { 00121 return ((index >= 0) && (index < MONTHS_PER_YEAR)) ? month_name[index] : NULL; 00122 } 00123 00127 const char *get_weekday(const int index) { 00128 return ((index >= 0) && (index < DAYS_PER_WEEK)) ? weekdays[index] : NULL; 00129 } 00130 00134 const char *get_season_name(const int index) { 00135 return ((index >= 0) && (index < (SEASONS_PER_YEAR+1))) ? season_name[index] : NULL; 00136 } 00137 00141 void reset_sleep(void) { 00142 int i; 00143 00144 for (i = 0; i < PBUFLEN; i++) 00145 process_utime_save[i] = 0; 00146 psaveind = 0; 00147 process_max_utime = 0; 00148 process_min_utime = 999999999; 00149 process_tot_mtime = 0; 00150 pticks = 0; 00151 00152 (void)GETTIMEOFDAY(&last_time); 00153 } 00154 00158 static void log_time(uint32 process_utime) { 00159 pticks++; 00160 if (++psaveind >= PBUFLEN) 00161 psaveind = 0; 00162 process_utime_save[psaveind] = process_utime; 00163 if (process_utime > process_max_utime) 00164 process_max_utime = process_utime; 00165 if (process_utime < process_min_utime) 00166 process_min_utime = process_utime; 00167 process_tot_mtime += process_utime/1000; 00168 } 00169 00175 int enough_elapsed_time(void) { 00176 static struct timeval new_time; 00177 uint32 elapsed_utime; 00178 00179 (void)GETTIMEOFDAY(&new_time); 00180 00181 elapsed_utime = (new_time.tv_sec-last_time.tv_sec)*1000000+new_time.tv_usec-last_time.tv_usec; 00182 if (elapsed_utime > max_time) { 00183 log_time(elapsed_utime); 00184 last_time.tv_sec = new_time.tv_sec; 00185 last_time.tv_usec = new_time.tv_usec; 00186 return 1; 00187 } 00188 return 0; 00189 } 00190 00195 void sleep_delta(void) { 00196 static struct timeval new_time; 00197 long sleep_sec, sleep_usec; 00198 00199 (void)GETTIMEOFDAY(&new_time); 00200 00201 sleep_sec = last_time.tv_sec-new_time.tv_sec; 00202 sleep_usec = max_time-(new_time.tv_usec-last_time.tv_usec); 00203 00204 /* This is very ugly, but probably the fastest for our use: */ 00205 while (sleep_usec < 0) { 00206 sleep_usec += 1000000; 00207 sleep_sec -= 1; 00208 } 00209 while (sleep_usec > 1000000) { 00210 sleep_usec -= 1000000; 00211 sleep_sec += 1; 00212 } 00213 00214 log_time((new_time.tv_sec-last_time.tv_sec)*1000000+new_time.tv_usec-last_time.tv_usec); 00215 00216 if (sleep_sec >= 0 && sleep_usec > 0) { 00217 static struct timeval sleep_time; 00218 00219 sleep_time.tv_sec = sleep_sec; 00220 sleep_time.tv_usec = sleep_usec; 00221 00222 #ifndef WIN32 /* 'select' doesn't work on Windows, 'Sleep' is used instead */ 00223 select(0, NULL, NULL, NULL, &sleep_time); 00224 #else 00225 if (sleep_time.tv_sec) 00226 Sleep(sleep_time.tv_sec*1000); 00227 Sleep((int)(sleep_time.tv_usec/1000.)); 00228 #endif 00229 } else 00230 process_utime_long_count++; 00231 /* 00232 * Set last_time to when we're expected to wake up: 00233 */ 00234 last_time.tv_usec += max_time; 00235 while (last_time.tv_usec > 1000000) { 00236 last_time.tv_usec -= 1000000; 00237 last_time.tv_sec++; 00238 } 00239 /* 00240 * Don't do too much catching up: 00241 * (Things can still get jerky on a slow/loaded computer) 00242 */ 00243 if (last_time.tv_sec*1000000+last_time.tv_usec < 00244 new_time.tv_sec*1000000+new_time.tv_usec) { 00245 last_time.tv_sec = new_time.tv_sec; 00246 last_time.tv_usec = new_time.tv_usec; 00247 } 00248 } 00249 00256 void set_max_time(long t) { 00257 max_time = t; 00258 } 00259 00260 extern unsigned long todtick; 00261 00268 void get_tod(timeofday_t *tod) { 00269 tod->year = todtick/HOURS_PER_YEAR; 00270 tod->month = (todtick/HOURS_PER_MONTH)%MONTHS_PER_YEAR; 00271 tod->day = (todtick%HOURS_PER_MONTH)/DAYS_PER_MONTH; 00272 tod->dayofweek = tod->day%DAYS_PER_WEEK; 00273 tod->hour = todtick%HOURS_PER_DAY; 00274 tod->minute = (pticks%PTICKS_PER_CLOCK)/(PTICKS_PER_CLOCK/58); 00275 if (tod->minute > 58) 00276 tod->minute = 58; /* it's imprecise at best anyhow */ 00277 tod->weekofmonth = tod->day/WEEKS_PER_MONTH; 00278 if (tod->month < 3) 00279 tod->season = 0; 00280 else if (tod->month < 6) 00281 tod->season = 1; 00282 else if (tod->month < 9) 00283 tod->season = 2; 00284 else if (tod->month < 12) 00285 tod->season = 3; 00286 else 00287 tod->season = 4; 00288 00289 if (tod->hour < 5) /*until 4:59*/ 00290 tod->periodofday = 0; 00291 else if (tod->hour < 8) 00292 tod->periodofday = 1; 00293 else if (tod->hour < 13) 00294 tod->periodofday = 2; 00295 else if (tod->hour < 15) 00296 tod->periodofday = 3; 00297 else if (tod->hour < 20) 00298 tod->periodofday = 4; 00299 else if (tod->hour < 23) 00300 tod->periodofday = 5; 00301 else /*back to night*/ 00302 tod->periodofday = 0; 00303 } 00304 00311 static void print_tod(object *op) { 00312 timeofday_t tod; 00313 const char *suf; 00314 int day; 00315 00316 get_tod(&tod); 00317 00318 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, 00319 "It is %d minute%s past %d o'clock %s, on %s", 00320 "It is %d minute%s past %d o'clock %s, on %s", 00321 tod.minute+1, ((tod.minute+1 < 2) ? "" : "s"), 00322 ((tod.hour%14 == 0) ? 14 : ((tod.hour)%14)), 00323 ((tod.hour >= 14) ? "pm" : "am"), 00324 weekdays[tod.dayofweek]); 00325 00326 day = tod.day+1; 00327 if (day == 1 || ((day%10) == 1 && day > 20)) 00328 suf = "st"; 00329 else if (day == 2 || ((day%10) == 2 && day > 20)) 00330 suf = "nd"; 00331 else if (day == 3 || ((day%10) == 3 && day > 20)) 00332 suf = "rd"; 00333 else 00334 suf = "th"; 00335 00336 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, 00337 "The %d%s Day of the %s, Year %d", 00338 "The %d%s Day of the %s, Year %d", 00339 day, suf, month_name[tod.month], tod.year+1); 00340 00341 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_INFO, 00342 "Time of Year: %s", 00343 "Time of Year: %s", 00344 season_name[tod.season]); 00345 } 00346 00353 void time_info(object *op) { 00354 int tot = 0, long_count = 0; 00355 uint32 maxt = 0, mint = 99999999, i; 00356 00357 print_tod(op); 00358 00359 if (!QUERY_FLAG(op, FLAG_WIZ)) 00360 return; 00361 00362 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, 00363 "Total time:", NULL); 00364 00365 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, 00366 "ticks=%d time=%d.%2d", 00367 "ticks=%d time=%d.%2d", 00368 pticks, process_tot_mtime/1000, process_tot_mtime%1000); 00369 00370 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, 00371 "avg time=%dms max time=%dms min time=%dms", 00372 "avg time=%dms max time=%dms min time=%dms", 00373 process_tot_mtime/pticks, process_max_utime/1000, 00374 process_min_utime/1000); 00375 00376 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, 00377 "ticks longer than max time (%dms) = %d (%d%%)", 00378 "ticks longer than max time (%dms) = %d (%d%%)", 00379 max_time/1000, 00380 process_utime_long_count, 100*process_utime_long_count/pticks); 00381 00382 00383 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, 00384 "Time last %d ticks:", 00385 "Time last %d ticks:", 00386 MIN(pticks, PBUFLEN)); 00387 00388 for (i = 0; i < MIN(pticks, PBUFLEN); i++) { 00389 tot += process_utime_save[i]; 00390 if (process_utime_save[i] > maxt) 00391 maxt = process_utime_save[i]; 00392 if (process_utime_save[i] < mint) 00393 mint = process_utime_save[i]; 00394 if (process_utime_save[i] > max_time) 00395 long_count++; 00396 } 00397 00398 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, 00399 "avg time=%dms max time=%dms min time=%dms", 00400 "avg time=%dms max time=%dms min time=%dms", 00401 tot/MIN(pticks, PBUFLEN)/1000, maxt/1000, 00402 mint/1000); 00403 00404 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, 00405 "ticks longer than max time (%dms) = %d (%d%%)", 00406 "ticks longer than max time (%dms) = %d (%d%%)", 00407 max_time/1000, long_count, 00408 100*long_count/MIN(pticks, PBUFLEN)); 00409 } 00410 00417 long seconds(void) { 00418 struct timeval now; 00419 00420 (void)GETTIMEOFDAY(&now); 00421 return now.tv_sec; 00422 }