ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
(Generate patch)

Comparing deliantra/server/lib/cf.pm (file contents):
Revision 1.71 by root, Sun Oct 1 10:59:30 2006 UTC vs.
Revision 1.106 by root, Sun Dec 31 17:29:22 2006 UTC

1package cf; 1package cf;
2
3use utf8;
4use strict;
2 5
3use Symbol; 6use Symbol;
4use List::Util; 7use List::Util;
5use Storable; 8use Storable;
6use Opcode; 9use Opcode;
7use Safe; 10use Safe;
8use Safe::Hole; 11use Safe::Hole;
9 12
13use Coro 3.3;
14use Coro::Event;
15use Coro::Timer;
16use Coro::Signal;
17use Coro::Semaphore;
18use Coro::AIO;
19
20use Fcntl;
21use IO::AIO 2.31 ();
22use YAML::Syck ();
10use Time::HiRes; 23use Time::HiRes;
11use Event; 24
12$Event::Eval = 1; # no idea why this is required, but it is 25use Event; $Event::Eval = 1; # no idea why this is required, but it is
13 26
14use strict; 27# work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode?
28$YAML::Syck::ImplicitUnicode = 1;
15 29
16_init_vars; 30$Coro::main->prio (2); # run main coroutine ("the server") with very high priority
17 31
32sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
33
18our %COMMAND = (); 34our %COMMAND = ();
35our %COMMAND_TIME = ();
36our %EXTCMD = ();
37
19our @EVENT; 38our @EVENT;
20our $LIBDIR = maps_directory "perl"; 39our $LIBDIR = datadir . "/ext";
21 40
22our $TICK = MAX_TIME * 1e-6; 41our $TICK = MAX_TIME * 1e-6;
23our $TICK_WATCHER; 42our $TICK_WATCHER;
24our $NEXT_TICK; 43our $NEXT_TICK;
44our $NOW;
25 45
26our %CFG; 46our %CFG;
27 47
48our $UPTIME; $UPTIME ||= time;
49our $RUNTIME;
50
51our %MAP; # all maps
52our $LINK_MAP; # the special {link} map
53our $FREEZE;
54
55binmode STDOUT;
56binmode STDERR;
57
58# read virtual server time, if available
59unless ($RUNTIME || !-e cf::localdir . "/runtime") {
60 open my $fh, "<", cf::localdir . "/runtime"
61 or die "unable to read runtime file: $!";
62 $RUNTIME = <$fh> + 0.;
63}
64
65mkdir cf::localdir;
66mkdir cf::localdir . "/" . cf::playerdir;
67mkdir cf::localdir . "/" . cf::tmpdir;
68mkdir cf::localdir . "/" . cf::uniquedir;
69
70our %EXT_CORO;
71
28############################################################################# 72#############################################################################
29 73
30=head2 GLOBAL VARIABLES 74=head2 GLOBAL VARIABLES
31 75
32=over 4 76=over 4
77
78=item $cf::UPTIME
79
80The timestamp of the server start (so not actually an uptime).
81
82=item $cf::RUNTIME
83
84The time this server has run, starts at 0 and is increased by $cf::TICK on
85every server tick.
33 86
34=item $cf::LIBDIR 87=item $cf::LIBDIR
35 88
36The perl library directory, where extensions and cf-specific modules can 89The perl library directory, where extensions and cf-specific modules can
37be found. It will be added to C<@INC> automatically. 90be found. It will be added to C<@INC> automatically.
91
92=item $cf::NOW
93
94The time of the last (current) server tick.
38 95
39=item $cf::TICK 96=item $cf::TICK
40 97
41The interval between server ticks, in seconds. 98The interval between server ticks, in seconds.
42 99
50=cut 107=cut
51 108
52BEGIN { 109BEGIN {
53 *CORE::GLOBAL::warn = sub { 110 *CORE::GLOBAL::warn = sub {
54 my $msg = join "", @_; 111 my $msg = join "", @_;
112 utf8::encode $msg;
113
55 $msg .= "\n" 114 $msg .= "\n"
56 unless $msg =~ /\n$/; 115 unless $msg =~ /\n$/;
57 116
58 print STDERR "cfperl: $msg";
59 LOG llevError, "cfperl: $msg"; 117 LOG llevError, "cfperl: $msg";
60 }; 118 };
61} 119}
62 120
121@safe::cf::global::ISA = @cf::global::ISA = 'cf::attachable';
122@safe::cf::object::ISA = @cf::object::ISA = 'cf::attachable';
123@safe::cf::player::ISA = @cf::player::ISA = 'cf::attachable';
124@safe::cf::client::ISA = @cf::client::ISA = 'cf::attachable';
125@safe::cf::map::ISA = @cf::map::ISA = 'cf::attachable';
63@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object'; 126@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
64 127
65# we bless all objects into (empty) derived classes to force a method lookup 128# we bless all objects into (empty) derived classes to force a method lookup
66# within the Safe compartment. 129# within the Safe compartment.
67for my $pkg (qw(cf::object cf::object::player cf::player cf::map cf::party cf::region cf::arch cf::living)) { 130for my $pkg (qw(
131 cf::global cf::attachable
132 cf::object cf::object::player
133 cf::client cf::player
134 cf::arch cf::living
135 cf::map cf::party cf::region
136)) {
68 no strict 'refs'; 137 no strict 'refs';
69 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg; 138 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
70} 139}
71 140
72$Event::DIED = sub { 141$Event::DIED = sub {
74}; 143};
75 144
76my %ext_pkg; 145my %ext_pkg;
77my @exts; 146my @exts;
78my @hook; 147my @hook;
79my %command;
80my %extcmd;
81 148
82=head2 UTILITY FUNCTIONS 149=head2 UTILITY FUNCTIONS
83 150
84=over 4 151=over 4
85 152
107sub to_json($) { 174sub to_json($) {
108 $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs 175 $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs
109 JSON::Syck::Dump $_[0] 176 JSON::Syck::Dump $_[0]
110} 177}
111 178
179=item cf::sync_job { BLOCK }
180
181The design of crossfire+ requires that the main coro ($Coro::main) is
182always able to handle events or runnable, as crossfire+ is only partly
183reentrant. Thus "blocking" it by e.g. waiting for I/O is not acceptable.
184
185If it must be done, put the blocking parts into C<sync_job>. This will run
186the given BLOCK in another coroutine while waiting for the result. The
187server will be frozen during this time, so the block should either finish
188fast or be very important.
189
190=cut
191
192sub sync_job(&) {
193 my ($job) = @_;
194
195 my $busy = 1;
196 my @res;
197
198 # TODO: use suspend/resume instead
199 local $FREEZE = 1;
200
201 my $coro = Coro::async {
202 @res = eval { $job->() };
203 warn $@ if $@;
204 undef $busy;
205 };
206
207 if ($Coro::current == $Coro::main) {
208 $coro->prio (Coro::PRIO_MAX);
209 while ($busy) {
210 Coro::cede_notself;
211 Event::one_event unless Coro::nready;
212 }
213 } else {
214 $coro->join;
215 }
216
217 wantarray ? @res : $res[0]
218}
219
220=item $coro = cf::coro { BLOCK }
221
222Creates and returns a new coro. This coro is automcatially being canceled
223when the extension calling this is being unloaded.
224
225=cut
226
227sub coro(&) {
228 my $cb = shift;
229
230 my $coro; $coro = async {
231 eval {
232 $cb->();
233 };
234 warn $@ if $@;
235 };
236
237 $coro->on_destroy (sub {
238 delete $EXT_CORO{$coro+0};
239 });
240 $EXT_CORO{$coro+0} = $coro;
241
242 $coro
243}
244
112=back 245=back
113 246
114=cut 247=cut
115 248
116############################################################################# 249#############################################################################
117 250
118=head2 EVENTS AND OBJECT ATTACHMENTS 251=head2 ATTACHABLE OBJECTS
252
253Many objects in crossfire are so-called attachable objects. That means you can
254attach callbacks/event handlers (a collection of which is called an "attachment")
255to it. All such attachable objects support the following methods.
256
257In the following description, CLASS can be any of C<global>, C<object>
258C<player>, C<client> or C<map> (i.e. the attachable objects in
259crossfire+).
119 260
120=over 4 261=over 4
121 262
122=item $object->attach ($attachment, key => $value...)
123
124=item $object->detach ($attachment)
125
126Attach/detach a pre-registered attachment to an object.
127
128=item $player->attach ($attachment, key => $value...)
129
130=item $player->detach ($attachment)
131
132Attach/detach a pre-registered attachment to a player.
133
134=item $map->attach ($attachment, key => $value...) 263=item $attachable->attach ($attachment, key => $value...)
135 264
136=item $map->detach ($attachment) 265=item $attachable->detach ($attachment)
137 266
138Attach/detach a pre-registered attachment to a map. 267Attach/detach a pre-registered attachment to a specific object and give it
268the specified key/value pairs as arguments.
139 269
140=item $bool = $object->attached ($name) 270Example, attach a minesweeper attachment to the given object, making it a
27110x10 minesweeper game:
141 272
142=item $bool = $player->attached ($name) 273 $obj->attach (minesweeper => width => 10, height => 10);
143 274
144=item $bool = $map->attached ($name) 275=item $bool = $attachable->attached ($name)
145 276
146Checks wether the named attachment is currently attached to the object. 277Checks wether the named attachment is currently attached to the object.
147 278
148=item cf::attach_global ... 279=item cf::CLASS->attach ...
149 280
150Attach handlers for global events. 281=item cf::CLASS->detach ...
151 282
152This and all following C<attach_*>-functions expect any number of the 283Define an anonymous attachment and attach it to all objects of the given
153following handler/hook descriptions: 284CLASS. See the next function for an explanation of its arguments.
285
286You can attach to global events by using the C<cf::global> class.
287
288Example, log all player logins:
289
290 cf::player->attach (
291 on_login => sub {
292 my ($pl) = @_;
293 ...
294 },
295 );
296
297Example, attach to the jeweler skill:
298
299 cf::object->attach (
300 type => cf::SKILL,
301 subtype => cf::SK_JEWELER,
302 on_use_skill => sub {
303 my ($sk, $ob, $part, $dir, $msg) = @_;
304 ...
305 },
306 );
307
308=item cf::CLASS::attachment $name, ...
309
310Register an attachment by C<$name> through which attachable objects of the
311given CLASS can refer to this attachment.
312
313Some classes such as crossfire maps and objects can specify attachments
314that are attached at load/instantiate time, thus the need for a name.
315
316These calls expect any number of the following handler/hook descriptions:
154 317
155=over 4 318=over 4
156 319
157=item prio => $number 320=item prio => $number
158 321
160by another C<prio> setting). Lower priority handlers get executed 323by another C<prio> setting). Lower priority handlers get executed
161earlier. The default priority is C<0>, and many built-in handlers are 324earlier. The default priority is C<0>, and many built-in handlers are
162registered at priority C<-1000>, so lower priorities should not be used 325registered at priority C<-1000>, so lower priorities should not be used
163unless you know what you are doing. 326unless you know what you are doing.
164 327
328=item type => $type
329
330(Only for C<< cf::object->attach >> calls), limits the attachment to the
331given type of objects only (the additional parameter C<subtype> can be
332used to further limit to the given subtype).
333
165=item on_I<event> => \&cb 334=item on_I<event> => \&cb
166 335
167Call the given code reference whenever the named event happens (event is 336Call the given code reference whenever the named event happens (event is
168something like C<instantiate>, C<apply>, C<use_skill> and so on, and which 337something like C<instantiate>, C<apply>, C<use_skill> and so on, and which
169handlers are recognised generally depends on the type of object these 338handlers are recognised generally depends on the type of object these
178package and register them. Only handlers for eevents supported by the 347package and register them. Only handlers for eevents supported by the
179object/class are recognised. 348object/class are recognised.
180 349
181=back 350=back
182 351
183=item cf::attach_to_type $object_type, $subtype, ... 352Example, define an attachment called "sockpuppet" that calls the given
353event handler when a monster attacks:
184 354
185Attach handlers for a specific object type (e.g. TRANSPORT) and 355 cf::object::attachment sockpuppet =>
186subtype. If C<$subtype> is zero or undef, matches all objects of the given 356 on_skill_attack => sub {
187type. 357 my ($self, $victim) = @_;
188 358 ...
189=item cf::attach_to_objects ...
190
191Attach handlers to all objects. Do not use this except for debugging or
192very rare events, as handlers are (obviously) called for I<all> objects in
193the game.
194
195=item cf::attach_to_players ...
196
197Attach handlers to all players.
198
199=item cf::attach_to_maps ...
200
201Attach handlers to all maps.
202
203=item cf:register_attachment $name, ...
204
205Register an attachment by name through which objects can refer to this
206attachment.
207
208=item cf:register_player_attachment $name, ...
209
210Register an attachment by name through which players can refer to this
211attachment.
212
213=item cf:register_map_attachment $name, ...
214
215Register an attachment by name through which maps can refer to this
216attachment.
217
218=cut
219
220# the following variables are defined in .xs and must not be re-created
221our @CB_GLOBAL = (); # registry for all global events
222our @CB_OBJECT = (); # all objects (should not be used except in emergency)
223our @CB_PLAYER = ();
224our @CB_TYPE = (); # registry for type (cf-object class) based events
225our @CB_MAP = ();
226
227my %attachment;
228
229sub _attach_cb($\%$$$) {
230 my ($registry, $undo, $event, $prio, $cb) = @_;
231
232 use sort 'stable';
233
234 $cb = [$prio, $cb];
235
236 @{$registry->[$event]} = sort
237 { $a->[0] cmp $b->[0] }
238 @{$registry->[$event] || []}, $cb;
239
240 push @{$undo->{cb}}, [$event, $cb];
241}
242
243# attach handles attaching event callbacks
244# the only thing the caller has to do is pass the correct
245# registry (== where the callback attaches to).
246sub _attach(\@$@) {
247 my ($registry, $klass, @arg) = @_;
248
249 my $prio = 0;
250
251 my %undo = (
252 registry => $registry,
253 cb => [],
254 );
255
256 my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
257
258 while (@arg) {
259 my $type = shift @arg;
260
261 if ($type eq "prio") {
262 $prio = shift @arg;
263
264 } elsif ($type eq "package") {
265 my $pkg = shift @arg;
266
267 while (my ($name, $id) = each %cb_id) {
268 if (my $cb = $pkg->can ($name)) {
269 _attach_cb $registry, %undo, $id, $prio, $cb;
270 }
271 } 359 }
272
273 } elsif (exists $cb_id{$type}) {
274 _attach_cb $registry, %undo, $cb_id{$type}, $prio, shift @arg;
275
276 } elsif (ref $type) {
277 warn "attaching objects not supported, ignoring.\n";
278
279 } else {
280 shift @arg;
281 warn "attach argument '$type' not supported, ignoring.\n";
282 }
283 }
284
285 \%undo
286}
287
288sub _attach_attachment {
289 my ($obj, $name, %arg) = @_;
290
291 return if exists $obj->{_attachment}{$name};
292
293 my $res;
294
295 if (my $attach = $attachment{$name}) {
296 my $registry = $obj->registry;
297
298 for (@$attach) {
299 my ($klass, @attach) = @$_;
300 $res = _attach @$registry, $klass, @attach;
301 }
302
303 $obj->{$name} = \%arg;
304 } else {
305 warn "object uses attachment '$name' that is not available, postponing.\n";
306 }
307
308 $obj->{_attachment}{$name} = undef;
309
310 $res->{attachment} = $name;
311 $res
312}
313
314*cf::object::attach =
315*cf::player::attach =
316*cf::map::attach = sub {
317 my ($obj, $name, %arg) = @_;
318
319 _attach_attachment $obj, $name, %arg;
320};
321
322# all those should be optimised
323*cf::object::detach =
324*cf::player::detach =
325*cf::map::detach = sub {
326 my ($obj, $name) = @_;
327
328 delete $obj->{_attachment}{$name};
329 reattach ($obj);
330};
331
332*cf::object::attached =
333*cf::player::attached =
334*cf::map::attached = sub {
335 my ($obj, $name) = @_;
336
337 exists $obj->{_attachment}{$name}
338};
339
340sub attach_global {
341 _attach @CB_GLOBAL, KLASS_GLOBAL, @_
342}
343
344sub attach_to_type {
345 my $type = shift;
346 my $subtype = shift;
347
348 _attach @{$CB_TYPE[$type + $subtype * NUM_SUBTYPES]}, KLASS_OBJECT, @_
349}
350
351sub attach_to_objects {
352 _attach @CB_OBJECT, KLASS_OBJECT, @_
353}
354
355sub attach_to_players {
356 _attach @CB_PLAYER, KLASS_PLAYER, @_
357}
358
359sub attach_to_maps {
360 _attach @CB_MAP, KLASS_MAP, @_
361}
362
363sub register_attachment {
364 my $name = shift;
365
366 $attachment{$name} = [[KLASS_OBJECT, @_]];
367}
368
369sub register_player_attachment {
370 my $name = shift;
371
372 $attachment{$name} = [[KLASS_PLAYER, @_]];
373}
374
375sub register_map_attachment {
376 my $name = shift;
377
378 $attachment{$name} = [[KLASS_MAP, @_]];
379}
380
381our $override;
382our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
383
384sub override {
385 $override = 1;
386 @invoke_results = ();
387}
388
389sub do_invoke {
390 my $event = shift;
391 my $callbacks = shift;
392
393 @invoke_results = ();
394
395 local $override;
396
397 for (@$callbacks) {
398 eval { &{$_->[1]} };
399
400 if ($@) {
401 warn "$@";
402 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
403 override;
404 }
405
406 return 1 if $override;
407 }
408
409 0 360 }
410}
411 361
412=item $bool = cf::invoke EVENT_GLOBAL_XXX, ... 362=item $attachable->valid
413
414=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...)
415
416=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...)
417
418=item $bool = $map->invoke (EVENT_MAP_XXX, ...)
419
420Generate a global/object/player/map-specific event with the given arguments.
421
422This API is preliminary (most likely, the EVENT_KLASS_xxx prefix will be
423removed in future versions), and there is no public API to access override
424results (if you must, access C<@cf::invoke_results> directly).
425
426=back
427
428=cut
429
430#############################################################################
431
432=head2 METHODS VALID FOR ALL CORE OBJECTS
433
434=over 4
435
436=item $object->valid, $player->valid, $map->valid
437 363
438Just because you have a perl object does not mean that the corresponding 364Just because you have a perl object does not mean that the corresponding
439C-level object still exists. If you try to access an object that has no 365C-level object still exists. If you try to access an object that has no
440valid C counterpart anymore you get an exception at runtime. This method 366valid C counterpart anymore you get an exception at runtime. This method
441can be used to test for existence of the C object part without causing an 367can be used to test for existence of the C object part without causing an
442exception. 368exception.
443 369
370=cut
371
372# the following variables are defined in .xs and must not be re-created
373our @CB_GLOBAL = (); # registry for all global events
374our @CB_ATTACHABLE = (); # registry for all attachables
375our @CB_OBJECT = (); # all objects (should not be used except in emergency)
376our @CB_PLAYER = ();
377our @CB_CLIENT = ();
378our @CB_TYPE = (); # registry for type (cf-object class) based events
379our @CB_MAP = ();
380
381my %attachment;
382
383sub _attach_cb($$$$) {
384 my ($registry, $event, $prio, $cb) = @_;
385
386 use sort 'stable';
387
388 $cb = [$prio, $cb];
389
390 @{$registry->[$event]} = sort
391 { $a->[0] cmp $b->[0] }
392 @{$registry->[$event] || []}, $cb;
393}
394
395# hack
396my %attachable_klass = map +($_ => 1), KLASS_OBJECT, KLASS_CLIENT, KLASS_PLAYER, KLASS_MAP;
397
398# attach handles attaching event callbacks
399# the only thing the caller has to do is pass the correct
400# registry (== where the callback attaches to).
401sub _attach {
402 my ($registry, $klass, @arg) = @_;
403
404 my $object_type;
405 my $prio = 0;
406 my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
407
408 #TODO: get rid of this hack
409 if ($attachable_klass{$klass}) {
410 %cb_id = (%cb_id, map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == KLASS_ATTACHABLE, 0 .. $#EVENT);
411 }
412
413 while (@arg) {
414 my $type = shift @arg;
415
416 if ($type eq "prio") {
417 $prio = shift @arg;
418
419 } elsif ($type eq "type") {
420 $object_type = shift @arg;
421 $registry = $CB_TYPE[$object_type] ||= [];
422
423 } elsif ($type eq "subtype") {
424 defined $object_type or Carp::croak "subtype specified without type";
425 my $object_subtype = shift @arg;
426 $registry = $CB_TYPE[$object_type + $object_subtype * NUM_SUBTYPES] ||= [];
427
428 } elsif ($type eq "package") {
429 my $pkg = shift @arg;
430
431 while (my ($name, $id) = each %cb_id) {
432 if (my $cb = $pkg->can ($name)) {
433 _attach_cb $registry, $id, $prio, $cb;
434 }
435 }
436
437 } elsif (exists $cb_id{$type}) {
438 _attach_cb $registry, $cb_id{$type}, $prio, shift @arg;
439
440 } elsif (ref $type) {
441 warn "attaching objects not supported, ignoring.\n";
442
443 } else {
444 shift @arg;
445 warn "attach argument '$type' not supported, ignoring.\n";
446 }
447 }
448}
449
450sub _object_attach {
451 my ($obj, $name, %arg) = @_;
452
453 return if exists $obj->{_attachment}{$name};
454
455 if (my $attach = $attachment{$name}) {
456 my $registry = $obj->registry;
457
458 for (@$attach) {
459 my ($klass, @attach) = @$_;
460 _attach $registry, $klass, @attach;
461 }
462
463 $obj->{$name} = \%arg;
464 } else {
465 warn "object uses attachment '$name' that is not available, postponing.\n";
466 }
467
468 $obj->{_attachment}{$name} = undef;
469}
470
471sub cf::attachable::attach {
472 if (ref $_[0]) {
473 _object_attach @_;
474 } else {
475 _attach shift->_attach_registry, @_;
476 }
477};
478
479# all those should be optimised
480sub cf::attachable::detach {
481 my ($obj, $name) = @_;
482
483 if (ref $obj) {
484 delete $obj->{_attachment}{$name};
485 reattach ($obj);
486 } else {
487 Carp::croak "cannot, currently, detach class attachments";
488 }
489};
490
491sub cf::attachable::attached {
492 my ($obj, $name) = @_;
493
494 exists $obj->{_attachment}{$name}
495}
496
497for my $klass (qw(ATTACHABLE GLOBAL OBJECT PLAYER CLIENT MAP)) {
498 eval "#line " . __LINE__ . " 'cf.pm'
499 sub cf::\L$klass\E::_attach_registry {
500 (\\\@CB_$klass, KLASS_$klass)
501 }
502
503 sub cf::\L$klass\E::attachment {
504 my \$name = shift;
505
506 \$attachment{\$name} = [[KLASS_$klass, \@_]];
507 }
508 ";
509 die if $@;
510}
511
512our $override;
513our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
514
515sub override {
516 $override = 1;
517 @invoke_results = ();
518}
519
520sub do_invoke {
521 my $event = shift;
522 my $callbacks = shift;
523
524 @invoke_results = ();
525
526 local $override;
527
528 for (@$callbacks) {
529 eval { &{$_->[1]} };
530
531 if ($@) {
532 warn "$@";
533 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
534 override;
535 }
536
537 return 1 if $override;
538 }
539
540 0
541}
542
543=item $bool = cf::global::invoke (EVENT_CLASS_XXX, ...)
544
545=item $bool = $attachable->invoke (EVENT_CLASS_XXX, ...)
546
547Generate an object-specific event with the given arguments.
548
549This API is preliminary (most likely, the EVENT_CLASS_xxx prefix will be
550removed in future versions), and there is no public API to access override
551results (if you must, access C<@cf::invoke_results> directly).
552
444=back 553=back
445 554
446=cut 555=cut
447
448*cf::object::valid =
449*cf::player::valid =
450*cf::map::valid = \&cf::_valid;
451 556
452############################################################################# 557#############################################################################
453# object support 558# object support
454 559
455sub instantiate {
456 my ($obj, $data) = @_;
457
458 $data = from_json $data;
459
460 for (@$data) {
461 my ($name, $args) = @$_;
462
463 $obj->attach ($name, %{$args || {} });
464 }
465}
466
467# basically do the same as instantiate, without calling instantiate
468sub reattach { 560sub reattach {
561 # basically do the same as instantiate, without calling instantiate
469 my ($obj) = @_; 562 my ($obj) = @_;
563
470 my $registry = $obj->registry; 564 my $registry = $obj->registry;
471 565
472 @$registry = (); 566 @$registry = ();
473 567
474 delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} }; 568 delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} };
475 569
476 for my $name (keys %{ $obj->{_attachment} || {} }) { 570 for my $name (keys %{ $obj->{_attachment} || {} }) {
477 if (my $attach = $attachment{$name}) { 571 if (my $attach = $attachment{$name}) {
478 for (@$attach) { 572 for (@$attach) {
479 my ($klass, @attach) = @$_; 573 my ($klass, @attach) = @$_;
480 _attach @$registry, $klass, @attach; 574 _attach $registry, $klass, @attach;
481 } 575 }
482 } else { 576 } else {
483 warn "object uses attachment '$name' that is not available, postponing.\n"; 577 warn "object uses attachment '$name' that is not available, postponing.\n";
484 } 578 }
485 } 579 }
486} 580}
487 581
488sub object_freezer_save { 582cf::attachable->attach (
489 my ($filename, $rdata, $objs) = @_;
490
491 if (length $$rdata) {
492 warn sprintf "saving %s (%d,%d)\n",
493 $filename, length $$rdata, scalar @$objs;
494
495 if (open my $fh, ">:raw", "$filename~") {
496 chmod SAVE_MODE, $fh;
497 syswrite $fh, $$rdata;
498 close $fh;
499
500 if (@$objs && open my $fh, ">:raw", "$filename.pst~") {
501 chmod SAVE_MODE, $fh;
502 syswrite $fh, Storable::nfreeze { version => 1, objs => $objs };
503 close $fh;
504 rename "$filename.pst~", "$filename.pst";
505 } else {
506 unlink "$filename.pst";
507 }
508
509 rename "$filename~", $filename;
510 } else {
511 warn "FATAL: $filename~: $!\n";
512 }
513 } else {
514 unlink $filename;
515 unlink "$filename.pst";
516 }
517}
518
519sub object_thawer_load {
520 my ($filename) = @_;
521
522 local $/;
523
524 my $av;
525
526 #TODO: use sysread etc.
527 if (open my $data, "<:raw:perlio", $filename) {
528 $data = <$data>;
529 if (open my $pst, "<:raw:perlio", "$filename.pst") {
530 $av = eval { (Storable::thaw <$pst>)->{objs} };
531 }
532 return ($data, $av);
533 }
534
535 ()
536}
537
538attach_to_objects
539 prio => -1000000, 583 prio => -1000000,
584 on_instantiate => sub {
585 my ($obj, $data) = @_;
586
587 $data = from_json $data;
588
589 for (@$data) {
590 my ($name, $args) = @$_;
591
592 $obj->attach ($name, %{$args || {} });
593 }
594 },
595 on_reattach => \&reattach,
540 on_clone => sub { 596 on_clone => sub {
541 my ($src, $dst) = @_; 597 my ($src, $dst) = @_;
542 598
543 @{$dst->registry} = @{$src->registry}; 599 @{$dst->registry} = @{$src->registry};
544 600
545 %$dst = %$src; 601 %$dst = %$src;
546 602
547 %{$dst->{_attachment}} = %{$src->{_attachment}} 603 %{$dst->{_attachment}} = %{$src->{_attachment}}
548 if exists $src->{_attachment}; 604 if exists $src->{_attachment};
549 }, 605 },
550; 606);
607
608sub object_freezer_save {
609 my ($filename, $rdata, $objs) = @_;
610
611 sync_job {
612 if (length $$rdata) {
613 warn sprintf "saving %s (%d,%d)\n",
614 $filename, length $$rdata, scalar @$objs;
615
616 if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) {
617 chmod SAVE_MODE, $fh;
618 aio_write $fh, 0, (length $$rdata), $$rdata, 0;
619 aio_fsync $fh;
620 close $fh;
621
622 if (@$objs) {
623 if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) {
624 chmod SAVE_MODE, $fh;
625 my $data = Storable::nfreeze { version => 1, objs => $objs };
626 aio_write $fh, 0, (length $data), $data, 0;
627 aio_fsync $fh;
628 close $fh;
629 aio_rename "$filename.pst~", "$filename.pst";
630 }
631 } else {
632 aio_unlink "$filename.pst";
633 }
634
635 aio_rename "$filename~", $filename;
636 } else {
637 warn "FATAL: $filename~: $!\n";
638 }
639 } else {
640 aio_unlink $filename;
641 aio_unlink "$filename.pst";
642 }
643 }
644}
645
646sub object_freezer_as_string {
647 my ($rdata, $objs) = @_;
648
649 use Data::Dumper;
650
651 $$rdata . Dumper $objs
652}
653
654sub object_thawer_load {
655 my ($filename) = @_;
656
657 my ($data, $av);
658
659 (aio_load $filename, $data) >= 0
660 or return;
661
662 unless (aio_stat "$filename.pst") {
663 (aio_load "$filename.pst", $av) >= 0
664 or return;
665 $av = eval { (Storable::thaw <$av>)->{objs} };
666 }
667
668 return ($data, $av);
669}
551 670
552############################################################################# 671#############################################################################
553# old plug-in events 672# command handling &c
554 673
555sub inject_event { 674=item cf::register_command $name => \&callback($ob,$args);
556 my $extension = shift;
557 my $event_code = shift;
558 675
559 my $cb = $hook[$event_code]{$extension} 676Register a callback for execution when the client sends the user command
560 or return; 677$name.
561 678
562 &$cb 679=cut
563}
564
565sub inject_global_event {
566 my $event = shift;
567
568 my $cb = $hook[$event]
569 or return;
570
571 List::Util::max map &$_, values %$cb
572}
573
574sub inject_command {
575 my ($name, $obj, $params) = @_;
576
577 for my $cmd (@{ $command{$name} }) {
578 $cmd->[1]->($obj, $params);
579 }
580
581 -1
582}
583 680
584sub register_command { 681sub register_command {
585 my ($name, $time, $cb) = @_; 682 my ($name, $cb) = @_;
586 683
587 my $caller = caller; 684 my $caller = caller;
588 #warn "registering command '$name/$time' to '$caller'"; 685 #warn "registering command '$name/$time' to '$caller'";
589 686
590 push @{ $command{$name} }, [$time, $cb, $caller]; 687 push @{ $COMMAND{$name} }, [$caller, $cb];
591 $COMMAND{"$name\000"} = List::Util::max map $_->[0], @{ $command{$name} };
592} 688}
689
690=item cf::register_extcmd $name => \&callback($pl,$packet);
691
692Register a callbackf ro execution when the client sends an extcmd packet.
693
694If the callback returns something, it is sent back as if reply was being
695called.
696
697=cut
593 698
594sub register_extcmd { 699sub register_extcmd {
595 my ($name, $cb) = @_; 700 my ($name, $cb) = @_;
596 701
597 my $caller = caller; 702 my $caller = caller;
598 #warn "registering extcmd '$name' to '$caller'"; 703 #warn "registering extcmd '$name' to '$caller'";
599 704
600 $extcmd{$name} = [$cb, $caller]; 705 $EXTCMD{$name} = [$cb, $caller];
601} 706}
707
708cf::player->attach (
709 on_command => sub {
710 my ($pl, $name, $params) = @_;
711
712 my $cb = $COMMAND{$name}
713 or return;
714
715 for my $cmd (@$cb) {
716 $cmd->[1]->($pl->ob, $params);
717 }
718
719 cf::override;
720 },
721 on_extcmd => sub {
722 my ($pl, $buf) = @_;
723
724 my $msg = eval { from_json $buf };
725
726 if (ref $msg) {
727 if (my $cb = $EXTCMD{$msg->{msgtype}}) {
728 if (my %reply = $cb->[0]->($pl, $msg)) {
729 $pl->ext_reply ($msg->{msgid}, %reply);
730 }
731 }
732 } else {
733 warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
734 }
735
736 cf::override;
737 },
738);
602 739
603sub register { 740sub register {
604 my ($base, $pkg) = @_; 741 my ($base, $pkg) = @_;
605 742
606 #TODO 743 #TODO
625 . "#line 1 \"$path\"\n{\n" 762 . "#line 1 \"$path\"\n{\n"
626 . (do { local $/; <$fh> }) 763 . (do { local $/; <$fh> })
627 . "\n};\n1"; 764 . "\n};\n1";
628 765
629 eval $source 766 eval $source
630 or die "$path: $@"; 767 or die $@ ? "$path: $@\n"
768 : "extension disabled.\n";
631 769
632 push @exts, $pkg; 770 push @exts, $pkg;
633 $ext_pkg{$base} = $pkg; 771 $ext_pkg{$base} = $pkg;
634 772
635# no strict 'refs'; 773# no strict 'refs';
648# for my $idx (0 .. $#PLUGIN_EVENT) { 786# for my $idx (0 .. $#PLUGIN_EVENT) {
649# delete $hook[$idx]{$pkg}; 787# delete $hook[$idx]{$pkg};
650# } 788# }
651 789
652 # remove commands 790 # remove commands
653 for my $name (keys %command) { 791 for my $name (keys %COMMAND) {
654 my @cb = grep $_->[2] ne $pkg, @{ $command{$name} }; 792 my @cb = grep $_->[0] ne $pkg, @{ $COMMAND{$name} };
655 793
656 if (@cb) { 794 if (@cb) {
657 $command{$name} = \@cb; 795 $COMMAND{$name} = \@cb;
658 $COMMAND{"$name\000"} = List::Util::max map $_->[0], @cb;
659 } else { 796 } else {
660 delete $command{$name};
661 delete $COMMAND{"$name\000"}; 797 delete $COMMAND{$name};
662 } 798 }
663 } 799 }
664 800
665 # remove extcmds 801 # remove extcmds
666 for my $name (grep $extcmd{$_}[1] eq $pkg, keys %extcmd) { 802 for my $name (grep $EXTCMD{$_}[1] eq $pkg, keys %EXTCMD) {
667 delete $extcmd{$name}; 803 delete $EXTCMD{$name};
668 } 804 }
669 805
670 if (my $cb = $pkg->can ("unload")) { 806 if (my $cb = $pkg->can ("unload")) {
671 eval { 807 eval {
672 $cb->($pkg); 808 $cb->($pkg);
676 812
677 Symbol::delete_package $pkg; 813 Symbol::delete_package $pkg;
678} 814}
679 815
680sub load_extensions { 816sub load_extensions {
681 my $LIBDIR = maps_directory "perl";
682
683 for my $ext (<$LIBDIR/*.ext>) { 817 for my $ext (<$LIBDIR/*.ext>) {
684 next unless -r $ext; 818 next unless -r $ext;
685 eval { 819 eval {
686 load_extension $ext; 820 load_extension $ext;
687 1 821 1
688 } or warn "$ext not loaded: $@"; 822 } or warn "$ext not loaded: $@";
689 } 823 }
690} 824}
691 825
692############################################################################# 826#############################################################################
693# extcmd framework, basically convert ext <msg>
694# into pkg::->on_extcmd_arg1 (...) while shortcutting a few
695
696attach_to_players
697 on_extcmd => sub {
698 my ($pl, $buf) = @_;
699
700 my $msg = eval { from_json $buf };
701
702 if (ref $msg) {
703 if (my $cb = $extcmd{$msg->{msgtype}}) {
704 if (my %reply = $cb->[0]->($pl, $msg)) {
705 $pl->ext_reply ($msg->{msgid}, %reply);
706 }
707 }
708 } else {
709 warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
710 }
711
712 cf::override;
713 },
714;
715
716#############################################################################
717# load/save/clean perl data associated with a map 827# load/save/clean perl data associated with a map
718 828
719*cf::mapsupport::on_clean = sub { 829*cf::mapsupport::on_clean = sub {
720 my ($map) = @_; 830 my ($map) = @_;
721 831
723 defined $path or return; 833 defined $path or return;
724 834
725 unlink "$path.pst"; 835 unlink "$path.pst";
726}; 836};
727 837
728attach_to_maps prio => -10000, package => cf::mapsupport::; 838cf::map->attach (prio => -10000, package => cf::mapsupport::);
729 839
730############################################################################# 840#############################################################################
731# load/save perl data associated with player->ob objects 841# load/save perl data associated with player->ob objects
732 842
733sub all_objects(@) { 843sub all_objects(@) {
734 @_, map all_objects ($_->inv), @_ 844 @_, map all_objects ($_->inv), @_
735} 845}
736 846
737# TODO: compatibility cruft, remove when no longer needed 847# TODO: compatibility cruft, remove when no longer needed
738attach_to_players 848cf::player->attach (
739 on_load => sub { 849 on_load => sub {
740 my ($pl, $path) = @_; 850 my ($pl, $path) = @_;
741 851
742 for my $o (all_objects $pl->ob) { 852 for my $o (all_objects $pl->ob) {
743 if (my $value = $o->get_ob_key_value ("_perl_data")) { 853 if (my $value = $o->get_ob_key_value ("_perl_data")) {
745 855
746 %$o = %{ Storable::thaw pack "H*", $value }; 856 %$o = %{ Storable::thaw pack "H*", $value };
747 } 857 }
748 } 858 }
749 }, 859 },
750; 860);
751 861
752############################################################################# 862#############################################################################
753 863
754=head2 CORE EXTENSIONS 864=head2 CORE EXTENSIONS
755 865
756Functions and methods that extend core crossfire objects. 866Functions and methods that extend core crossfire objects.
867
868=head3 cf::player
757 869
758=over 4 870=over 4
759 871
760=item cf::player::exists $login 872=item cf::player::exists $login
761 873
766sub cf::player::exists($) { 878sub cf::player::exists($) {
767 cf::player::find $_[0] 879 cf::player::find $_[0]
768 or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2; 880 or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2;
769} 881}
770 882
883=item $player->ext_reply ($msgid, $msgtype, %msg)
884
885Sends an ext reply to the player.
886
887=cut
888
889sub cf::player::ext_reply($$$%) {
890 my ($self, $id, %msg) = @_;
891
892 $msg{msgid} = $id;
893
894 $self->send ("ext " . to_json \%msg);
895}
896
897=back
898
899=head3 cf::object::player
900
901=over 4
902
771=item $player->reply ($npc, $msg[, $flags]) 903=item $player_object->reply ($npc, $msg[, $flags])
772 904
773Sends a message to the player, as if the npc C<$npc> replied. C<$npc> 905Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
774can be C<undef>. Does the right thing when the player is currently in a 906can be C<undef>. Does the right thing when the player is currently in a
775dialogue with the given NPC character. 907dialogue with the given NPC character.
776 908
777=cut 909=cut
778 910
779# rough implementation of a future "reply" method that works 911# rough implementation of a future "reply" method that works
780# with dialog boxes. 912# with dialog boxes.
913#TODO: the first argument must go, split into a $npc->reply_to ( method
781sub cf::object::player::reply($$$;$) { 914sub cf::object::player::reply($$$;$) {
782 my ($self, $npc, $msg, $flags) = @_; 915 my ($self, $npc, $msg, $flags) = @_;
783 916
784 $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4; 917 $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
785 918
789 $msg = $npc->name . " says: $msg" if $npc; 922 $msg = $npc->name . " says: $msg" if $npc;
790 $self->message ($msg, $flags); 923 $self->message ($msg, $flags);
791 } 924 }
792} 925}
793 926
794=item $player->ext_reply ($msgid, $msgtype, %msg) 927=item $player_object->may ("access")
795 928
796Sends an ext reply to the player. 929Returns wether the given player is authorized to access resource "access"
930(e.g. "command_wizcast").
797 931
798=cut 932=cut
799 933
800sub cf::player::ext_reply($$$%) { 934sub cf::object::player::may {
935 my ($self, $access) = @_;
936
937 $self->flag (cf::FLAG_WIZ) ||
938 (ref $cf::CFG{"may_$access"}
939 ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
940 : $cf::CFG{"may_$access"})
941}
942
943=head3 cf::client
944
945=over 4
946
947=item $client->send_drawinfo ($text, $flags)
948
949Sends a drawinfo packet to the client. Circumvents output buffering so
950should not be used under normal circumstances.
951
952=cut
953
954sub cf::client::send_drawinfo {
955 my ($self, $text, $flags) = @_;
956
957 utf8::encode $text;
958 $self->send_packet (sprintf "drawinfo %d %s", $flags, $text);
959}
960
961
962=item $success = $client->query ($flags, "text", \&cb)
963
964Queues a query to the client, calling the given callback with
965the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
966C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
967
968Queries can fail, so check the return code. Or don't, as queries will become
969reliable at some point in the future.
970
971=cut
972
973sub cf::client::query {
974 my ($self, $flags, $text, $cb) = @_;
975
976 return unless $self->state == ST_PLAYING
977 || $self->state == ST_SETUP
978 || $self->state == ST_CUSTOM;
979
980 $self->state (ST_CUSTOM);
981
982 utf8::encode $text;
983 push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
984
985 $self->send_packet ($self->{query_queue}[0][0])
986 if @{ $self->{query_queue} } == 1;
987}
988
989cf::client->attach (
990 on_reply => sub {
991 my ($ns, $msg) = @_;
992
993 # this weird shuffling is so that direct followup queries
994 # get handled first
995 my $queue = delete $ns->{query_queue};
996
997 (shift @$queue)->[1]->($msg);
998
999 push @{ $ns->{query_queue} }, @$queue;
1000
1001 if (@{ $ns->{query_queue} } == @$queue) {
1002 if (@$queue) {
1003 $ns->send_packet ($ns->{query_queue}[0][0]);
1004 } else {
1005 $ns->state (ST_PLAYING) if $ns->state == ST_CUSTOM;
1006 }
1007 }
1008 },
1009);
1010
1011=item $client->coro (\&cb)
1012
1013Create a new coroutine, running the specified callback. The coroutine will
1014be automatically cancelled when the client gets destroyed (e.g. on logout,
1015or loss of connection).
1016
1017=cut
1018
1019sub cf::client::coro {
801 my ($self, $id, %msg) = @_; 1020 my ($self, $cb) = @_;
802 1021
803 $msg{msgid} = $id; 1022 my $coro; $coro = async {
1023 eval {
1024 $cb->();
1025 };
1026 warn $@ if $@;
1027 };
804 1028
805 $self->send ("ext " . to_json \%msg); 1029 $coro->on_destroy (sub {
1030 delete $self->{_coro}{$coro+0};
1031 });
1032
1033 $self->{_coro}{$coro+0} = $coro;
1034
1035 $coro
806} 1036}
1037
1038cf::client->attach (
1039 on_destroy => sub {
1040 my ($ns) = @_;
1041
1042 $_->cancel for values %{ (delete $ns->{_coro}) || {} };
1043 },
1044);
807 1045
808=back 1046=back
809 1047
810=cut
811
812#############################################################################
813 1048
814=head2 SAFE SCRIPTING 1049=head2 SAFE SCRIPTING
815 1050
816Functions that provide a safe environment to compile and execute 1051Functions that provide a safe environment to compile and execute
817snippets of perl code without them endangering the safety of the server 1052snippets of perl code without them endangering the safety of the server
818itself. Looping constructs, I/O operators and other built-in functionality 1053itself. Looping constructs, I/O operators and other built-in functionality
819is not available in the safe scripting environment, and the number of 1054is not available in the safe scripting environment, and the number of
820functions and methods that cna be called is greatly reduced. 1055functions and methods that can be called is greatly reduced.
821 1056
822=cut 1057=cut
823 1058
824our $safe = new Safe "safe"; 1059our $safe = new Safe "safe";
825our $safe_hole = new Safe::Hole; 1060our $safe_hole = new Safe::Hole;
832 1067
833=pod 1068=pod
834 1069
835The following fucntions and emthods are available within a safe environment: 1070The following fucntions and emthods are available within a safe environment:
836 1071
837 cf::object contr pay_amount pay_player 1072 cf::object contr pay_amount pay_player map
838 cf::object::player player 1073 cf::object::player player
839 cf::player peaceful 1074 cf::player peaceful
1075 cf::map trigger
840 1076
841=cut 1077=cut
842 1078
843for ( 1079for (
844 ["cf::object" => qw(contr pay_amount pay_player)], 1080 ["cf::object" => qw(contr pay_amount pay_player map)],
845 ["cf::object::player" => qw(player)], 1081 ["cf::object::player" => qw(player)],
846 ["cf::player" => qw(peaceful)], 1082 ["cf::player" => qw(peaceful)],
1083 ["cf::map" => qw(trigger)],
847) { 1084) {
848 no strict 'refs'; 1085 no strict 'refs';
849 my ($pkg, @funs) = @$_; 1086 my ($pkg, @funs) = @$_;
850 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"}) 1087 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
851 for @funs; 1088 for @funs;
961 1198
962Immediately write the database to disk I<if it is dirty>. 1199Immediately write the database to disk I<if it is dirty>.
963 1200
964=cut 1201=cut
965 1202
1203our $DB;
1204
966{ 1205{
967 my $db;
968 my $path = cf::localdir . "/database.pst"; 1206 my $path = cf::localdir . "/database.pst";
969 1207
970 sub db_load() { 1208 sub db_load() {
971 warn "loading database $path\n";#d# remove later 1209 warn "loading database $path\n";#d# remove later
972 $db = stat $path ? Storable::retrieve $path : { }; 1210 $DB = stat $path ? Storable::retrieve $path : { };
973 } 1211 }
974 1212
975 my $pid; 1213 my $pid;
976 1214
977 sub db_save() { 1215 sub db_save() {
978 warn "saving database $path\n";#d# remove later 1216 warn "saving database $path\n";#d# remove later
979 waitpid $pid, 0 if $pid; 1217 waitpid $pid, 0 if $pid;
980 if (0 == ($pid = fork)) { 1218 if (0 == ($pid = fork)) {
981 $db->{_meta}{version} = 1; 1219 $DB->{_meta}{version} = 1;
982 Storable::nstore $db, "$path~"; 1220 Storable::nstore $DB, "$path~";
983 rename "$path~", $path; 1221 rename "$path~", $path;
984 cf::_exit 0 if defined $pid; 1222 cf::_exit 0 if defined $pid;
985 } 1223 }
986 } 1224 }
987 1225
990 sub db_sync() { 1228 sub db_sync() {
991 db_save if $dirty; 1229 db_save if $dirty;
992 undef $dirty; 1230 undef $dirty;
993 } 1231 }
994 1232
995 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, cb => sub { 1233 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, data => WF_AUTOCANCEL, cb => sub {
996 db_sync; 1234 db_sync;
997 }); 1235 });
998 1236
999 sub db_dirty() { 1237 sub db_dirty() {
1000 $dirty = 1; 1238 $dirty = 1;
1001 $idle->start; 1239 $idle->start;
1002 } 1240 }
1003 1241
1004 sub db_get($;$) { 1242 sub db_get($;$) {
1005 @_ >= 2 1243 @_ >= 2
1006 ? $db->{$_[0]}{$_[1]} 1244 ? $DB->{$_[0]}{$_[1]}
1007 : ($db->{$_[0]} ||= { }) 1245 : ($DB->{$_[0]} ||= { })
1008 } 1246 }
1009 1247
1010 sub db_put($$;$) { 1248 sub db_put($$;$) {
1011 if (@_ >= 3) { 1249 if (@_ >= 3) {
1012 $db->{$_[0]}{$_[1]} = $_[2]; 1250 $DB->{$_[0]}{$_[1]} = $_[2];
1013 } else { 1251 } else {
1014 $db->{$_[0]} = $_[1]; 1252 $DB->{$_[0]} = $_[1];
1015 } 1253 }
1016 db_dirty; 1254 db_dirty;
1017 } 1255 }
1018 1256
1019 attach_global 1257 cf::global->attach (
1020 prio => 10000, 1258 prio => 10000,
1021 on_cleanup => sub { 1259 on_cleanup => sub {
1022 db_sync; 1260 db_sync;
1023 }, 1261 },
1024 ; 1262 );
1025} 1263}
1026 1264
1027############################################################################# 1265#############################################################################
1028# the server's main() 1266# the server's main()
1029 1267
1268sub cfg_load {
1269 open my $fh, "<:utf8", cf::confdir . "/config"
1270 or return;
1271
1272 local $/;
1273 *CFG = YAML::Syck::Load <$fh>;
1274}
1275
1030sub main { 1276sub main {
1277 cfg_load;
1031 db_load; 1278 db_load;
1032 load_extensions; 1279 load_extensions;
1033 Event::loop; 1280 Event::loop;
1034} 1281}
1035 1282
1036############################################################################# 1283#############################################################################
1037# initialisation 1284# initialisation
1038 1285
1039sub _perl_reload(&) { 1286sub _perl_reload() {
1040 my ($msg) = @_; 1287 # can/must only be called in main
1288 if ($Coro::current != $Coro::main) {
1289 warn "can only reload from main coroutine\n";
1290 return;
1291 }
1041 1292
1042 $msg->("reloading..."); 1293 warn "reloading...";
1294
1295 local $FREEZE = 1;
1296 cf::emergency_save;
1043 1297
1044 eval { 1298 eval {
1299 # if anything goes wrong in here, we should simply crash as we already saved
1300
1045 # cancel all watchers 1301 # cancel all watchers
1046 $_->cancel for Event::all_watchers; 1302 for (Event::all_watchers) {
1303 $_->cancel if $_->data & WF_AUTOCANCEL;
1304 }
1305
1306 # cancel all extension coros
1307 $_->cancel for values %EXT_CORO;
1308 %EXT_CORO = ();
1047 1309
1048 # unload all extensions 1310 # unload all extensions
1049 for (@exts) { 1311 for (@exts) {
1050 $msg->("unloading <$_>"); 1312 warn "unloading <$_>";
1051 unload_extension $_; 1313 unload_extension $_;
1052 } 1314 }
1053 1315
1054 # unload all modules loaded from $LIBDIR 1316 # unload all modules loaded from $LIBDIR
1055 while (my ($k, $v) = each %INC) { 1317 while (my ($k, $v) = each %INC) {
1056 next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/; 1318 next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
1057 1319
1058 $msg->("removing <$k>"); 1320 warn "removing <$k>";
1059 delete $INC{$k}; 1321 delete $INC{$k};
1060 1322
1061 $k =~ s/\.pm$//; 1323 $k =~ s/\.pm$//;
1062 $k =~ s/\//::/g; 1324 $k =~ s/\//::/g;
1063 1325
1068 Symbol::delete_package $k; 1330 Symbol::delete_package $k;
1069 } 1331 }
1070 1332
1071 # sync database to disk 1333 # sync database to disk
1072 cf::db_sync; 1334 cf::db_sync;
1335 IO::AIO::flush;
1073 1336
1074 # get rid of safe::, as good as possible 1337 # get rid of safe::, as good as possible
1075 Symbol::delete_package "safe::$_" 1338 Symbol::delete_package "safe::$_"
1076 for qw(cf::object cf::object::player cf::player cf::map cf::party cf::region); 1339 for qw(cf::attachable cf::object cf::object::player cf::client cf::player cf::map cf::party cf::region);
1077 1340
1078 # remove register_script_function callbacks 1341 # remove register_script_function callbacks
1079 # TODO 1342 # TODO
1080 1343
1081 # unload cf.pm "a bit" 1344 # unload cf.pm "a bit"
1084 # don't, removes xs symbols, too, 1347 # don't, removes xs symbols, too,
1085 # and global variables created in xs 1348 # and global variables created in xs
1086 #Symbol::delete_package __PACKAGE__; 1349 #Symbol::delete_package __PACKAGE__;
1087 1350
1088 # reload cf.pm 1351 # reload cf.pm
1089 $msg->("reloading cf.pm"); 1352 warn "reloading cf.pm";
1090 require cf; 1353 require cf;
1354 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
1091 1355
1092 # load database again 1356 # load config and database again
1357 cf::cfg_load;
1093 cf::db_load; 1358 cf::db_load;
1094 1359
1095 # load extensions 1360 # load extensions
1096 $msg->("load extensions"); 1361 warn "load extensions";
1097 cf::load_extensions; 1362 cf::load_extensions;
1098 1363
1099 # reattach attachments to objects 1364 # reattach attachments to objects
1100 $msg->("reattach"); 1365 warn "reattach";
1101 _global_reattach; 1366 _global_reattach;
1102 }; 1367 };
1103 $msg->($@) if $@;
1104 1368
1105 $msg->("reloaded"); 1369 if ($@) {
1370 warn $@;
1371 warn "error while reloading, exiting.";
1372 exit 1;
1373 }
1374
1375 warn "reloaded successfully";
1106}; 1376};
1107 1377
1108sub perl_reload() { 1378sub perl_reload() {
1109 _perl_reload { 1379 _perl_reload;
1110 warn $_[0];
1111 print "$_[0]\n";
1112 };
1113} 1380}
1114 1381
1382register "<global>", __PACKAGE__;
1383
1115register_command "perl-reload", 0, sub { 1384register_command "perl-reload" => sub {
1116 my ($who, $arg) = @_; 1385 my ($who, $arg) = @_;
1117 1386
1118 if ($who->flag (FLAG_WIZ)) { 1387 if ($who->flag (FLAG_WIZ)) {
1388 $who->message ("reloading...");
1119 _perl_reload { 1389 _perl_reload;
1120 warn $_[0];
1121 $who->message ($_[0]);
1122 };
1123 } 1390 }
1124}; 1391};
1125 1392
1126register "<global>", __PACKAGE__;
1127
1128unshift @INC, $LIBDIR; 1393unshift @INC, $LIBDIR;
1129 1394
1130$TICK_WATCHER = Event->timer ( 1395$TICK_WATCHER = Event->timer (
1396 reentrant => 0,
1131 prio => 1, 1397 prio => 0,
1132 at => $NEXT_TICK || 1, 1398 at => $NEXT_TICK || $TICK,
1399 data => WF_AUTOCANCEL,
1133 cb => sub { 1400 cb => sub {
1401 unless ($FREEZE) {
1134 cf::server_tick; # one server iteration 1402 cf::server_tick; # one server iteration
1403 $RUNTIME += $TICK;
1404 }
1135 1405
1136 my $NOW = Event::time;
1137 $NEXT_TICK += $TICK; 1406 $NEXT_TICK += $TICK;
1138 1407
1139 # if we are delayed by four ticks, skip them all 1408 # if we are delayed by four ticks or more, skip them all
1140 $NEXT_TICK = $NOW if $NOW >= $NEXT_TICK + $TICK * 4; 1409 $NEXT_TICK = Event::time if Event::time >= $NEXT_TICK + $TICK * 4;
1141 1410
1142 $TICK_WATCHER->at ($NEXT_TICK); 1411 $TICK_WATCHER->at ($NEXT_TICK);
1143 $TICK_WATCHER->start; 1412 $TICK_WATCHER->start;
1144 }, 1413 },
1145); 1414);
1146 1415
1416IO::AIO::max_poll_time $TICK * 0.2;
1417
1418Event->io (fd => IO::AIO::poll_fileno,
1419 poll => 'r',
1420 prio => 5,
1421 data => WF_AUTOCANCEL,
1422 cb => \&IO::AIO::poll_cb);
1423
1424# we must not ever block the main coroutine
1425$Coro::idle = sub {
1426 #Carp::cluck "FATAL: Coro::idle was called, major BUG\n";#d#
1427 warn "FATAL: Coro::idle was called, major BUG\n";
1428 (Coro::unblock_sub {
1429 Event::one_event;
1430 })->();
1431};
1432
11471 14331
1148 1434

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines