ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/main.C
Revision: 1.94
Committed: Wed Mar 14 04:12:29 2007 UTC (17 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.93: +1 -3 lines
Log Message:
- rewrote more face handling code
- automatically send smooth faces, as the client will need them anyways
  and it makes little sense to wait for the client to axk for it. of course,
  gcfclient suffers from weird ordering problems again.
- UP_OBJ_FACE was often abused in situations where other things changed,
  updated lots of spaces, probably more to be done.
- update_smooth became so small that inlining it actually clarified
  the code. similar for update_space, which is not inlined for other reasons.
- faces were not initialised properly
- add versioncheck for face data
- rewrite invisibility handling a bit: god finger etc. now makes you blink,
  blinking routine has changed to be less annoying and more useful while
  still indicating invisibleness.

File Contents

# Content
1 /*
2 * CrossFire, A Multiplayer game
3 *
4 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5 * Copyright (C) 2001-2003 Mark Wedel & Crossfire Development Team
6 * Copyright (C) 1992 Frank Tore Johansen
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * The authors can be reached via e-mail at <crossfire@schmorp.de>
23 */
24
25 #include <global.h>
26 #include <object.h>
27 #include <tod.h>
28
29 #include <sproto.h>
30 #include <time.h>
31
32 #include <../random_maps/random_map.h>
33 #include <../random_maps/rproto.h>
34 #include "path.h"
35
36 static char days[7][4] = {
37 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
38 };
39
40 void
41 version (object *op)
42 {
43 if (op)
44 clear_win_info (op);
45
46 new_draw_info_format (NDI_UNIQUE, 0, op, "This is Crossfire+ v%s", VERSION);
47
48 new_draw_info (NDI_UNIQUE, 0, op, "Authors and contributors to this program:");
49 new_draw_info (NDI_UNIQUE, 0, op, "Marc A. Lehmann <pcg@goof.com>");
50 new_draw_info (NDI_UNIQUE, 0, op, "Robin Redeker <elmex@x-paste.de>");
51 new_draw_info (NDI_UNIQUE, 0, op, "Pippijn van Steenhoven <pip88nl@gmail.com>");
52 new_draw_info (NDI_UNIQUE, 0, op, "");
53 new_draw_info (NDI_UNIQUE, 0, op, "Authors and contributors to the original Crossfire:");
54 new_draw_info (NDI_UNIQUE, 0, op, "Mark Wedel <mwedel@sonic.net>");
55 new_draw_info (NDI_UNIQUE, 0, op, "Frank Tore Johansen <frankj@ifi.uio.no>");
56 new_draw_info (NDI_UNIQUE, 0, op, "Kjetil Torgrim Homme <kjetilho@ifi.uio.no>");
57 new_draw_info (NDI_UNIQUE, 0, op, "Tyler Van Gorder <tvangod@ecst.csuchico.edu>");
58 new_draw_info (NDI_UNIQUE, 0, op, "Tony Elmroth <elmroth@cd.chalmers.se>");
59 new_draw_info (NDI_UNIQUE, 0, op, "Dougal Scott <dougal.scott@fcit.monasu.edu.au>");
60 new_draw_info (NDI_UNIQUE, 0, op, "William <wchuang@athena.mit.edu>");
61 new_draw_info (NDI_UNIQUE, 0, op, "Geoff Bailey <ftww@cs.su.oz.au>");
62 new_draw_info (NDI_UNIQUE, 0, op, "Kjetil Wiekhorst Jørgensen <jorgens@flipper.pvv.unit.no>");
63 new_draw_info (NDI_UNIQUE, 0, op, "Cameron Blackwood <c.blackwood@rdt.monash.edu.au>");
64 new_draw_info (NDI_UNIQUE, 0, op, "Joseph L. Traub <jtraub+@cmu.edu>");
65 new_draw_info (NDI_UNIQUE, 0, op, "Rupert G. Goldie <rgg@aaii.oz.au>");
66 new_draw_info (NDI_UNIQUE, 0, op, "Eric A. Anderson <eanders+@cmu.edu>");
67 new_draw_info (NDI_UNIQUE, 0, op, "Rickard Eneqvist <eneq@Prag.DoCS.UU.SE>");
68 new_draw_info (NDI_UNIQUE, 0, op, "Jarkko Sonninen <Jarkko.Sonninen@lut.fi>");
69 new_draw_info (NDI_UNIQUE, 0, op, "Karl Holland <kholland@sunlab.cit.cornell.du>");
70 new_draw_info (NDI_UNIQUE, 0, op, "Mikael Lundgren <vick@bern.docs.uu.se>");
71 new_draw_info (NDI_UNIQUE, 0, op, "Mikael Olsson <mol@meryl.csd.uu.se>");
72 new_draw_info (NDI_UNIQUE, 0, op, "Tero Haatanen <Tero.Haatanen@lut.fi>");
73 new_draw_info (NDI_UNIQUE, 0, op, "Lasse Ylitalo <ylitalo@student.docs.uu.se>");
74 new_draw_info (NDI_UNIQUE, 0, op, "Niilo Neuvo <anipa@guru.magic.fi>");
75 new_draw_info (NDI_UNIQUE, 0, op, "Markku J{rvinen <mta@modeemi.cs.tut.fi>");
76 new_draw_info (NDI_UNIQUE, 0, op, "Sylvain Meunier <meunier@inf.enst.fr>");
77 new_draw_info (NDI_UNIQUE, 0, op, "Jason Fosback <jfosback@darmok.uoregon.edu>");
78 new_draw_info (NDI_UNIQUE, 0, op, "Carl Edman <cedman@capitalist.princeton.edu>");
79 new_draw_info (NDI_UNIQUE, 0, op, "Charles Henrich <henrich@crh.cl.msu.edu>");
80 new_draw_info (NDI_UNIQUE, 0, op, "Gregor Schmid <schmid@fb3-s7.math.tu-berlin.de>");
81 new_draw_info (NDI_UNIQUE, 0, op, "Raphael Quinet <quinet@montefiore.ulg.ac.be>");
82 new_draw_info (NDI_UNIQUE, 0, op, "Jari Vanhala <jam@modeemi.cs.tut.fi>");
83 new_draw_info (NDI_UNIQUE, 0, op, "Tero Kivinen <kivinen@joker.cs.hut.fi>");
84 new_draw_info (NDI_UNIQUE, 0, op, "Peter Mardahl <peterm@soda.berkeley.edu>");
85 new_draw_info (NDI_UNIQUE, 0, op, "Matthew Zeher <matt@cs.odu.edu>");
86 new_draw_info (NDI_UNIQUE, 0, op, "Scott R. Turner <srt@sun-dimas.aero.org>");
87 new_draw_info (NDI_UNIQUE, 0, op, "Ben Fennema <huma@netcom.com>");
88 new_draw_info (NDI_UNIQUE, 0, op, "Nick Williams <njw@cs.city.ac.uk>");
89 new_draw_info (NDI_UNIQUE, 0, op, "Laurent Wacrenier <Wacren@Gin.ObsPM.Fr>");
90 new_draw_info (NDI_UNIQUE, 0, op, "Brian Thomas <thomas@astro.psu.edu>");
91 new_draw_info (NDI_UNIQUE, 0, op, "John Steven Moerk <jsm@axon.ksc.nasa.gov>");
92 new_draw_info (NDI_UNIQUE, 0, op, "Delbecq David <david.delbecq@mailandnews.com>");
93 new_draw_info (NDI_UNIQUE, 0, op, "Chachkoff Yann <yann.chachkoff@mailandnews.com>\n");
94 new_draw_info (NDI_UNIQUE, 0, op, "");
95 new_draw_info (NDI_UNIQUE, 0, op, "Images and art:");
96 new_draw_info (NDI_UNIQUE, 0, op, "Peter Gardner");
97 new_draw_info (NDI_UNIQUE, 0, op, "David Gervais <david_eg@mail.com>");
98 new_draw_info (NDI_UNIQUE, 0, op, "Mitsuhiro Itakura <ita@gold.koma.jaeri.go.jp>");
99 new_draw_info (NDI_UNIQUE, 0, op, "Hansjoerg Malthaner <hansjoerg.malthaner@danet.de>");
100 new_draw_info (NDI_UNIQUE, 0, op, "Mårten Woxberg <maxmc@telia.com>");
101 new_draw_info (NDI_UNIQUE, 0, op, "");
102 new_draw_info (NDI_UNIQUE, 0, op, "And many more!");
103 }
104
105 /* This is a basic little function to put the player back to his
106 * savebed. We do some error checking - its possible that the
107 * savebed map may no longer exist, so we make sure the player
108 * goes someplace.
109 */
110 void
111 enter_player_savebed (object *op)
112 {
113 object *tmp = object::create ();
114 EXIT_PATH (tmp) = op->contr->savebed_map;
115 EXIT_X (tmp) = op->contr->bed_x;
116 EXIT_Y (tmp) = op->contr->bed_y;
117 op->enter_exit (tmp);
118 tmp->destroy ();
119 }
120
121 /*
122 * enter_map(): Moves the player and pets from current map (if any) to
123 * new map. map, x, y must be set. map is the map we are moving the
124 * player to - it could be the map he just came from if the load failed for
125 * whatever reason. If default map coordinates are to be used, then
126 * the function that calls this should figure them out.
127 */
128 void
129 object::enter_map (maptile *newmap, int x, int y)
130 {
131 if (destroyed () || !newmap || newmap->in_memory != MAP_IN_MEMORY)
132 return;
133
134 if (out_of_map (newmap, x, y))
135 {
136 LOG (llevError, "enter_map: supplied coordinates are not within the map! (%s: %d, %d)\n", &newmap->path, x, y);
137 x = newmap->enter_x;
138 y = newmap->enter_y;
139 if (out_of_map (newmap, x, y))
140 {
141 LOG (llevError, "enter_map: map %s provides invalid default enter location (%d, %d) > (%d, %d)\n",
142 &newmap->path, x, y, newmap->width, newmap->height);
143 new_draw_info (NDI_UNIQUE, 0, this, "The exit is closed");
144 return;
145 }
146 }
147
148 if (contr && map != newmap && map)
149 if (INVOKE_MAP (LEAVE, map, ARG_PLAYER (contr)))
150 return;
151
152 // remove, so stupid ob_locked does not trigger a failure
153 remove ();
154
155 /* try to find a spot for the player */
156 if (ob_blocked (this, newmap, x, y))
157 { /* First choice blocked */
158 /* We try to find a spot for the player, starting closest in.
159 * We could use find_first_free_spot, but that doesn't randomize it at all,
160 * So for example, if the north space is free, you would always end up there even
161 * if other spaces around are available.
162 * Note that for the second and third calls, we could start at a position other
163 * than one, but then we could end up on the other side of walls and so forth.
164 */
165 int i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE1 + 1);
166
167 if (i == -1)
168 {
169 i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE2 + 1);
170 if (i == -1)
171 i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE);
172 }
173
174 if (i != -1)
175 {
176 x += freearr_x[i];
177 y += freearr_y[i];
178 }
179 else
180 /* not much we can do in this case. */
181 LOG (llevInfo, "enter_map: Could not find free spot for player - will dump on top of object (%s: %d, %d)\n", &newmap->path, x, y);
182 }
183
184 if (contr && map != newmap)
185 {
186 if (INVOKE_PLAYER (MAP_CHANGE, contr, ARG_MAP (newmap), ARG_INT (x), ARG_INT (y)))
187 return;
188
189 if (INVOKE_MAP (ENTER, newmap, ARG_PLAYER (contr), ARG_INT (x), ARG_INT (y)))
190 return;
191 }
192
193 this->x = x;
194 this->y = y;
195 map = newmap;
196
197 insert_ob_in_map (this, map, 0, INS_NO_WALK_ON);
198
199 enemy = 0;
200
201 if (contr)
202 {
203 contr->maplevel = newmap->path;
204 contr->count = 0;
205 }
206
207 /* Update any golems */
208 if (type == PLAYER && contr->ranges[range_golem])
209 {
210 int i = find_free_spot (contr->ranges[range_golem], newmap, x, y, 1, SIZEOFFREE);
211
212 if (i < 0)
213 {
214 contr->ranges[range_golem]->destroy ();
215 contr->ranges[range_golem] = 0;
216 }
217 else
218 {
219 newmap->insert (contr->ranges[range_golem], x + freearr_x[i], y + freearr_y[i]);
220
221 contr->ranges[range_golem]->direction =
222 find_dir_2 (x - contr->ranges[range_golem]->x, y - contr->ranges[range_golem]->y);
223 }
224 }
225
226 /* since the players map is already loaded, we don't need to worry
227 * about pending objects.
228 */
229 remove_all_pets (newmap);
230 }
231
232 /* process_players1 and process_players2 do all the player related stuff.
233 * I moved it out of process events and process_map. This was to some
234 * extent for debugging as well as to get a better idea of the time used
235 * by the various functions. process_players1() does the processing before
236 * objects have been updated, process_players2() does the processing that
237 * is needed after the players have been updated.
238 */
239 static void
240 process_players1 ()
241 {
242 /* Basically, we keep looping until all the players have done their actions. */
243 for (int flag = 1; flag != 0;)
244 {
245 flag = 0;
246 for_all_players (pl)
247 {
248 pl->refcnt_chk ();
249
250 if (!pl->ob || !pl->ns || !pl->ob->active)
251 continue;
252
253 if (pl->ob->speed_left > 0 && pl->ns)
254 if (handle_newcs_player (pl->ob))
255 flag = 1;
256
257 /* If the player is not actively playing, don't make a
258 * backup save - nothing to save anyway. Plus, the
259 * map may not longer be valid. This can happen when the
260 * player quits - they exist for purposes of tracking on the map,
261 * but don't actually reside on any actual map.
262 */
263 if (QUERY_FLAG (pl->ob, FLAG_REMOVED))
264 continue;
265 } /* end of for loop for all the players */
266 } /* for flag */
267
268 for_all_players (pl)
269 {
270 if (!pl->ob || !pl->ns || !pl->ob->active)
271 continue;
272
273 if (settings.casting_time)
274 {
275 if (pl->ob->casting_time > 0)
276 {
277 pl->ob->casting_time--;
278 pl->ob->start_holding = 1;
279 }
280
281 /* set spell_state so we can update the range in stats field */
282 if ((pl->ob->casting_time == 0) && (pl->ob->start_holding == 1))
283 pl->ob->start_holding = 0;
284 }
285
286 do_some_living (pl->ob);
287 }
288 }
289
290 static void
291 process_players2 ()
292 {
293 /* Then check if any players should use weapon-speed instead of speed */
294 for_all_players (pl)
295 {
296 /* The code that did weapon_sp handling here was out of place -
297 * this isn't called until after the player has finished there
298 * actions, and is thus out of place. All we do here is bounds
299 * checking.
300 */
301 if (pl->has_hit)
302 {
303 if (pl->ob->speed_left > pl->weapon_sp)
304 pl->ob->speed_left = pl->weapon_sp;
305
306 /* This needs to be here - if the player is running, we need to
307 * clear this each tick, but new commands are not being received
308 * so execute_newserver_command() is never called
309 */
310 pl->has_hit = 0;
311 }
312 else if (pl->ob->speed_left > pl->ob->speed)
313 pl->ob->speed_left = pl->ob->speed;
314 }
315 }
316
317 void
318 process_events ()
319 {
320 process_players1 ();
321
322 for_all_actives (op)
323 {
324 /* Now process op */
325 if (QUERY_FLAG (op, FLAG_FREED))
326 {
327 LOG (llevError, "BUG: process_events(): Free object on list\n");
328 op->set_speed (0);
329 continue;
330 }
331
332 /* I've seen occasional crashes due to this - the object is removed,
333 * and thus the map it points to (last map it was on) may be bogus
334 * The real bug is to try to find out the cause of this - someone
335 * is probably calling remove_ob without either an insert_ob or
336 * free_object afterwards, leaving an object dangling. But I'd
337 * rather log this and continue on instead of crashing.
338 * Don't remove players - when a player quits, the object is in
339 * sort of a limbo, of removed, but something we want to keep
340 * around.
341 */
342 if (QUERY_FLAG (op, FLAG_REMOVED) && op->type != PLAYER && op->map && op->map->in_memory != MAP_IN_MEMORY)
343 {
344 LOG (llevError, "BUG: process_events(): Removed object on list\n");
345 char *dump = dump_object (op);
346 LOG (llevError, dump);
347 free (dump);
348 op->destroy ();
349 continue;
350 }
351
352 if (!op->has_active_speed ())
353 {
354 LOG (llevError, "BUG: process_events(): Object %s has no speed (%f), "
355 "but is on active list\n", op->debug_desc (), op->speed);
356 op->set_speed (0);
357 continue;
358 }
359
360 if (op->map == NULL && op->env == NULL && op->name && op->type != MAP)
361 {
362 LOG (llevError, "BUG: process_events(): Object without map or "
363 "inventory is on active list: %s (%d)\n", &op->name, op->count);
364 op->set_speed (0);
365 continue;
366 }
367
368 /* Animate the object. Bug or feature that anim_speed
369 * is based on ticks, and not the creatures speed?
370 */
371 if (op->anim_speed && op->last_anim >= op->anim_speed)
372 {
373 animate_object (op, op->type == PLAYER ? op->facing : op->direction);
374
375 op->last_anim = 1;
376 }
377 else
378 op->last_anim++;
379
380 if (op->speed_left > 0)
381 {
382 #if 0
383 /* I've seen occasional crashes in move_symptom() with it
384 * crashing because op is removed - add some debugging to
385 * track if it is removed at this point.
386 * This unfortunately is a bit too verbose it seems - not sure
387 * why - I think what happens is a map is freed or something and
388 * some objects get 'lost' - removed never to be reclaimed.
389 * removed objects generally shouldn't exist.
390 */
391 if (QUERY_FLAG (op, FLAG_REMOVED))
392 {
393 LOG (llevDebug, "process_events: calling process_object with removed object %s\n", op->name ? op->name : "null");
394 }
395 #endif
396 --op->speed_left;
397 process_object (op);
398
399 if (op->destroyed ())
400 continue;
401 }
402
403 if (settings.casting_time == TRUE && op->casting_time > 0)
404 op->casting_time--;
405
406 if (op->speed_left <= 0)
407 op->speed_left += FABS (op->speed);
408 }
409
410 process_players2 ();
411 }
412
413 /* clean up everything before exiting */
414 void
415 emergency_save ()
416 {
417 LOG (llevDebug, "emergency save begin.\n");
418
419 cfperl_emergency_save ();
420
421 LOG (llevDebug, "saving book archive.\n");
422 write_book_archive ();
423
424 LOG (llevDebug, "emergency save done.\n");
425 }
426
427 // send all clients some informational text
428 static void
429 cleanup_inform (const char *cause, bool make_core)
430 {
431 int flags = NDI_UNIQUE | NDI_ALL | (make_core ? NDI_RED : NDI_GREEN);
432
433 new_draw_info_format (flags, 0, 0, "The server will now shutdown.\n");
434 new_draw_info_format (flags, 0, 0, "Cause for this shutdown: %s\n", cause);
435
436 if (make_core)
437 new_draw_info_format (flags, 0, 0, "This is considered a crash, but all maps and players have been saved.\n");
438 else
439 new_draw_info_format (flags, 0, 0, "This is considered to be a clean shutdown, and all maps and players will be saved now.\n");
440
441 new_draw_info_format (flags, 0, 0, "%s\n", CLEANUP_MESSAGE);
442
443 flush_sockets ();
444 }
445
446 /* clean up everything before exiting */
447 void
448 cleanup (const char *cause, bool make_core)
449 {
450 if (make_core)
451 fork_abort (cause);
452
453 LOG (llevError, "cleanup cause: %s\n", cause);
454
455 if (!make_core)
456 cleanup_inform (cause, make_core);
457
458 LOG (llevDebug, "cleanup begin.\n");
459
460 if (init_done && !in_cleanup)
461 {
462 in_cleanup = true;
463 emergency_save ();
464 }
465 else
466 in_cleanup = true;
467
468 LOG (llevDebug, "running cleanup handlers.\n");
469 INVOKE_GLOBAL (CLEANUP);
470
471 LOG (llevDebug, "cleanup done.\n");
472
473 if (make_core)
474 {
475 cleanup_inform (cause, make_core);
476 cfperl_cleanup (make_core);
477 _exit (1);
478 }
479 else
480 {
481 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_GREEN, 0, 0, "Maps and players successfully saved, exiting.\n");
482 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_GREEN, 0, 0, "And again: " CLEANUP_MESSAGE "\n");
483 flush_sockets ();
484 cfperl_cleanup (make_core);
485 _exit (0);
486 }
487 }
488
489 int
490 forbid_play (void)
491 {
492 #if !defined(_IBMR2) && !defined(___IBMR2) && defined(PERM_FILE)
493 char buf[MAX_BUF], day[MAX_BUF];
494 FILE *fp;
495 time_t clock;
496 struct tm *tm;
497 int i, start, stop, forbit = 0, comp;
498
499 clock = time (NULL);
500 tm = (struct tm *) localtime (&clock);
501
502 sprintf (buf, "%s/%s", settings.confdir, PERM_FILE);
503 if ((fp = open_and_uncompress (buf, 0, &comp)) == NULL)
504 return 0;
505
506 while (fgets (buf, MAX_BUF, fp))
507 {
508 if (buf[0] == '#')
509 continue;
510
511 if (!strncmp (buf, "msg", 3))
512 {
513 if (forbit)
514 while (fgets (buf, MAX_BUF, fp)) /* print message */
515 fputs (buf, logfile);
516 break;
517 }
518 else if (sscanf (buf, "%s %d%*c%d\n", day, &start, &stop) != 3)
519 {
520 LOG (llevDebug, "Warning: Incomplete line in permission file ignored.\n");
521 continue;
522 }
523
524 for (i = 0; i < 7; i++)
525 {
526 if (!strncmp (buf, days[i], 3) && (tm->tm_wday == i) && (tm->tm_hour >= start) && (tm->tm_hour < stop))
527 forbit = 1;
528 }
529 }
530
531 close_and_delete (fp, comp);
532
533 return forbit;
534 #else
535 return 0;
536 #endif
537 }
538
539 /*
540 * do_specials() is a collection of functions to call from time to time.
541 * Modified 2000-1-14 MSW to use the global pticks count to determine how
542 * often to do things. This will allow us to spred them out more often.
543 * I use prime numbers for the factor count - in that way, it is less likely
544 * these actions will fall on the same tick (compared to say using 500/2500/15000
545 * which would mean on that 15,000 tick count a whole bunch of stuff gets
546 * done). Of course, there can still be times where multiple specials are
547 * done on the same tick, but that will happen very infrequently
548 *
549 * I also think this code makes it easier to see how often we really are
550 * doing the various things.
551 */
552
553 extern unsigned long todtick;
554
555 void
556 do_specials (void)
557 {
558 if (!(pticks % PTICKS_PER_CLOCK))
559 tick_the_clock ();
560
561 if (!(pticks % 7))
562 shstr::gc ();
563
564 if (!(pticks % 2503))
565 fix_weight (); /* Hack to fix weightproblems caused by bugs */
566
567 if (!(pticks % 5003))
568 write_book_archive ();
569
570 if (!(pticks % 5009))
571 clean_friendly_list ();
572
573 if (!(pticks % 5011))
574 obsolete_parties ();
575
576 if (!(pticks % 12503))
577 fix_luck ();
578 }
579
580 void
581 server_tick ()
582 {
583 // first do the user visible stuff
584 doeric_server ();
585 INVOKE_GLOBAL (CLOCK);
586 process_events (); /* "do" something with objects with speed */
587 flush_sockets ();
588
589 // then do some bookkeeping, should not really be here
590 do_specials (); /* Routines called from time to time. */
591 attachable::check_mortals ();
592
593 ++pticks;
594 }
595
596 #if 0
597 // used fro benchmarking (x86/amd64-specific)
598 typedef unsigned long tval;
599 typedef unsigned long long stamp64;
600
601 extern inline tval
602 stamp (void)
603 {
604 tval tsc;
605 asm volatile ("rdtsc":"=a" (tsc)::"edx");
606
607 return tsc;
608 }
609
610 extern inline tval
611 measure (tval t)
612 {
613 tval tsc;
614 asm volatile ("rdtsc":"=a" (tsc)::"edx");
615
616 if (tsc > t)
617 return tsc - t;
618 else
619 return t - tsc;
620 }
621
622 int
623 main (int argc, char **argv)
624 {
625 rand_gen rg(0);
626 tval fastest = 0x7fffffff;
627 for (int loop = 10000; loop--; )
628 {
629 tval s = stamp ();
630 volatile int i = rg.get_int(25);
631 fastest = min (fastest, measure (s));
632 }
633
634 //printf ("fastest %d\n", fastest);
635 for (int i = 0; i < 1024*1024*3; ++i)
636 {
637 char c = rg.get_int (256);
638 write (2, &c, 1);
639 }
640 }
641
642 #else
643
644 // normal main
645 int
646 main (int argc, char **argv)
647 {
648 settings.argc = argc;
649 settings.argv = argv;
650
651 init (argc, argv);
652
653 initPlugins ();
654
655 for (;;)
656 cfperl_main ();
657 }
658 #endif
659