Crossfire Server, Branch 1.12  R12190
time.c
Go to the documentation of this file.
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 }