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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines