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.86 by root, Thu Dec 14 05:09:32 2006 UTC vs.
Revision 1.95 by root, Fri Dec 22 02:04:20 2006 UTC

16# work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode? 16# work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode?
17$YAML::Syck::ImplicitUnicode = 1; 17$YAML::Syck::ImplicitUnicode = 1;
18 18
19use strict; 19use strict;
20 20
21sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
22
21our %COMMAND = (); 23our %COMMAND = ();
22our %COMMAND_TIME = (); 24our %COMMAND_TIME = ();
23our %EXTCMD = (); 25our %EXTCMD = ();
24 26
25_init_vars; 27_init_vars;
26 28
27our @EVENT; 29our @EVENT;
28our $LIBDIR = maps_directory "perl"; 30our $LIBDIR = datadir . "/ext";
29 31
30our $TICK = MAX_TIME * 1e-6; 32our $TICK = MAX_TIME * 1e-6;
31our $TICK_WATCHER; 33our $TICK_WATCHER;
32our $NEXT_TICK; 34our $NEXT_TICK;
33 35
72 print STDERR "cfperl: $msg"; 74 print STDERR "cfperl: $msg";
73 LOG llevError, "cfperl: $msg"; 75 LOG llevError, "cfperl: $msg";
74 }; 76 };
75} 77}
76 78
79@safe::cf::global::ISA = @cf::global::ISA = 'cf::attachable';
80@safe::cf::object::ISA = @cf::object::ISA = 'cf::attachable';
81@safe::cf::player::ISA = @cf::player::ISA = 'cf::attachable';
82@safe::cf::client::ISA = @cf::client::ISA = 'cf::attachable';
83@safe::cf::map::ISA = @cf::map::ISA = 'cf::attachable';
77@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object'; 84@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
78 85
79# we bless all objects into (empty) derived classes to force a method lookup 86# we bless all objects into (empty) derived classes to force a method lookup
80# within the Safe compartment. 87# within the Safe compartment.
81for my $pkg (qw( 88for my $pkg (qw(
89 cf::global
82 cf::object cf::object::player 90 cf::object cf::object::player
83 cf::client_socket cf::player 91 cf::client cf::player
84 cf::arch cf::living 92 cf::arch cf::living
85 cf::map cf::party cf::region 93 cf::map cf::party cf::region
86)) { 94)) {
87 no strict 'refs'; 95 no strict 'refs';
88 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg; 96 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
130 138
131=cut 139=cut
132 140
133############################################################################# 141#############################################################################
134 142
135=head2 EVENTS AND OBJECT ATTACHMENTS 143=head2 ATTACHABLE OBJECTS
144
145Many objects in crossfire are so-called attachable objects. That means you can
146attach callbacks/event handlers (a collection of which is called an "attachment")
147to it. All such attachable objects support the following methods.
148
149In the following description, CLASS can be any of C<global>, C<object>
150C<player>, C<client> or C<map> (i.e. the attachable objects in
151crossfire+).
136 152
137=over 4 153=over 4
138 154
139=item $object->attach ($attachment, key => $value...)
140
141=item $object->detach ($attachment)
142
143Attach/detach a pre-registered attachment to an object.
144
145=item $player->attach ($attachment, key => $value...)
146
147=item $player->detach ($attachment)
148
149Attach/detach a pre-registered attachment to a player.
150
151=item $map->attach ($attachment, key => $value...) 155=item $attachable->attach ($attachment, key => $value...)
152 156
153=item $map->detach ($attachment) 157=item $attachable->detach ($attachment)
154 158
155Attach/detach a pre-registered attachment to a map. 159Attach/detach a pre-registered attachment to a specific object and give it
160the specified key/value pairs as arguments.
156 161
157=item $bool = $object->attached ($name) 162Example, attach a minesweeper attachment to the given object, making it a
16310x10 minesweeper game:
158 164
159=item $bool = $player->attached ($name) 165 $obj->attach (minesweeper => width => 10, height => 10);
160 166
161=item $bool = $map->attached ($name) 167=item $bool = $attachable->attached ($name)
162 168
163Checks wether the named attachment is currently attached to the object. 169Checks wether the named attachment is currently attached to the object.
164 170
165=item cf::attach_global ... 171=item cf::CLASS->attach ...
166 172
167Attach handlers for global events. 173=item cf::CLASS->detach ...
168 174
169This and all following C<attach_*>-functions expect any number of the 175Define an anonymous attachment and attach it to all objects of the given
170following handler/hook descriptions: 176CLASS. See the next function for an explanation of its arguments.
177
178You can attach to global events by using the C<cf::global> class.
179
180Example, log all player logins:
181
182 cf::player->attach (
183 on_login => sub {
184 my ($pl) = @_;
185 ...
186 },
187 );
188
189Example, attach to the jeweler skill:
190
191 cf::object->attach (
192 type => cf::SKILL,
193 subtype => cf::SK_JEWELER,
194 on_use_skill => sub {
195 my ($sk, $ob, $part, $dir, $msg) = @_;
196 ...
197 },
198 );
199
200=item cf::CLASS::attachment $name, ...
201
202Register an attachment by C<$name> through which attachable objects of the
203given CLASS can refer to this attachment.
204
205Some classes such as crossfire maps and objects can specify attachments
206that are attached at load/instantiate time, thus the need for a name.
207
208These calls expect any number of the following handler/hook descriptions:
171 209
172=over 4 210=over 4
173 211
174=item prio => $number 212=item prio => $number
175 213
177by another C<prio> setting). Lower priority handlers get executed 215by another C<prio> setting). Lower priority handlers get executed
178earlier. The default priority is C<0>, and many built-in handlers are 216earlier. The default priority is C<0>, and many built-in handlers are
179registered at priority C<-1000>, so lower priorities should not be used 217registered at priority C<-1000>, so lower priorities should not be used
180unless you know what you are doing. 218unless you know what you are doing.
181 219
220=item type => $type
221
222(Only for C<< cf::object->attach >> calls), limits the attachment to the
223given type of objects only (the additional parameter C<subtype> can be
224used to further limit to the given subtype).
225
182=item on_I<event> => \&cb 226=item on_I<event> => \&cb
183 227
184Call the given code reference whenever the named event happens (event is 228Call the given code reference whenever the named event happens (event is
185something like C<instantiate>, C<apply>, C<use_skill> and so on, and which 229something like C<instantiate>, C<apply>, C<use_skill> and so on, and which
186handlers are recognised generally depends on the type of object these 230handlers are recognised generally depends on the type of object these
195package and register them. Only handlers for eevents supported by the 239package and register them. Only handlers for eevents supported by the
196object/class are recognised. 240object/class are recognised.
197 241
198=back 242=back
199 243
200=item cf::attach_to_type $object_type, $subtype, ... 244Example, define an attachment called "sockpuppet" that calls the given
245event handler when a monster attacks:
201 246
202Attach handlers for a specific object type (e.g. TRANSPORT) and 247 cf::object::attachment sockpuppet =>
203subtype. If C<$subtype> is zero or undef, matches all objects of the given 248 on_skill_attack => sub {
204type. 249 my ($self, $victim) = @_;
205 250 ...
206=item cf::attach_to_objects ... 251 }
207 252 }
208Attach handlers to all objects. Do not use this except for debugging or
209very rare events, as handlers are (obviously) called for I<all> objects in
210the game.
211
212=item cf::attach_to_players ...
213
214Attach handlers to all players.
215
216=item cf::attach_to_maps ...
217
218Attach handlers to all maps.
219
220=item cf:register_attachment $name, ...
221
222Register an attachment by name through which objects can refer to this
223attachment.
224
225=item cf:register_player_attachment $name, ...
226
227Register an attachment by name through which players can refer to this
228attachment.
229
230=item cf:register_map_attachment $name, ...
231
232Register an attachment by name through which maps can refer to this
233attachment.
234 253
235=cut 254=cut
236 255
237# the following variables are defined in .xs and must not be re-created 256# the following variables are defined in .xs and must not be re-created
238our @CB_GLOBAL = (); # registry for all global events 257our @CB_GLOBAL = (); # registry for all global events
239our @CB_OBJECT = (); # all objects (should not be used except in emergency) 258our @CB_OBJECT = (); # all objects (should not be used except in emergency)
240our @CB_PLAYER = (); 259our @CB_PLAYER = ();
260our @CB_CLIENT = ();
241our @CB_TYPE = (); # registry for type (cf-object class) based events 261our @CB_TYPE = (); # registry for type (cf-object class) based events
242our @CB_MAP = (); 262our @CB_MAP = ();
243 263
244my %attachment; 264my %attachment;
245 265
246sub _attach_cb($\%$$$) { 266sub _attach_cb($$$$) {
247 my ($registry, $undo, $event, $prio, $cb) = @_; 267 my ($registry, $event, $prio, $cb) = @_;
248 268
249 use sort 'stable'; 269 use sort 'stable';
250 270
251 $cb = [$prio, $cb]; 271 $cb = [$prio, $cb];
252 272
253 @{$registry->[$event]} = sort 273 @{$registry->[$event]} = sort
254 { $a->[0] cmp $b->[0] } 274 { $a->[0] cmp $b->[0] }
255 @{$registry->[$event] || []}, $cb; 275 @{$registry->[$event] || []}, $cb;
256
257 push @{$undo->{cb}}, [$event, $cb];
258} 276}
259 277
260# attach handles attaching event callbacks 278# attach handles attaching event callbacks
261# the only thing the caller has to do is pass the correct 279# the only thing the caller has to do is pass the correct
262# registry (== where the callback attaches to). 280# registry (== where the callback attaches to).
263sub _attach(\@$@) { 281sub _attach {
264 my ($registry, $klass, @arg) = @_; 282 my ($registry, $klass, @arg) = @_;
265 283
284 my $object_type;
266 my $prio = 0; 285 my $prio = 0;
267
268 my %undo = (
269 registry => $registry,
270 cb => [],
271 );
272
273 my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT; 286 my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
274 287
275 while (@arg) { 288 while (@arg) {
276 my $type = shift @arg; 289 my $type = shift @arg;
277 290
278 if ($type eq "prio") { 291 if ($type eq "prio") {
279 $prio = shift @arg; 292 $prio = shift @arg;
280 293
294 } elsif ($type eq "type") {
295 $object_type = shift @arg;
296 $registry = $CB_TYPE[$object_type] ||= [];
297
298 } elsif ($type eq "subtype") {
299 defined $object_type or Carp::croak "subtype specified without type";
300 my $object_subtype = shift @arg;
301 $registry = $CB_TYPE[$object_type + $object_subtype * NUM_SUBTYPES] ||= [];
302
281 } elsif ($type eq "package") { 303 } elsif ($type eq "package") {
282 my $pkg = shift @arg; 304 my $pkg = shift @arg;
283 305
284 while (my ($name, $id) = each %cb_id) { 306 while (my ($name, $id) = each %cb_id) {
285 if (my $cb = $pkg->can ($name)) { 307 if (my $cb = $pkg->can ($name)) {
286 _attach_cb $registry, %undo, $id, $prio, $cb; 308 _attach_cb $registry, $id, $prio, $cb;
287 } 309 }
288 } 310 }
289 311
290 } elsif (exists $cb_id{$type}) { 312 } elsif (exists $cb_id{$type}) {
291 _attach_cb $registry, %undo, $cb_id{$type}, $prio, shift @arg; 313 _attach_cb $registry, $cb_id{$type}, $prio, shift @arg;
292 314
293 } elsif (ref $type) { 315 } elsif (ref $type) {
294 warn "attaching objects not supported, ignoring.\n"; 316 warn "attaching objects not supported, ignoring.\n";
295 317
296 } else { 318 } else {
297 shift @arg; 319 shift @arg;
298 warn "attach argument '$type' not supported, ignoring.\n"; 320 warn "attach argument '$type' not supported, ignoring.\n";
299 } 321 }
300 } 322 }
301
302 \%undo
303} 323}
304 324
305sub _attach_attachment { 325sub _object_attach {
306 my ($obj, $name, %arg) = @_; 326 my ($obj, $name, %arg) = @_;
307 327
308 return if exists $obj->{_attachment}{$name}; 328 return if exists $obj->{_attachment}{$name};
309
310 my $res;
311 329
312 if (my $attach = $attachment{$name}) { 330 if (my $attach = $attachment{$name}) {
313 my $registry = $obj->registry; 331 my $registry = $obj->registry;
314 332
315 for (@$attach) { 333 for (@$attach) {
316 my ($klass, @attach) = @$_; 334 my ($klass, @attach) = @$_;
317 $res = _attach @$registry, $klass, @attach; 335 _attach $registry, $klass, @attach;
318 } 336 }
319 337
320 $obj->{$name} = \%arg; 338 $obj->{$name} = \%arg;
321 } else { 339 } else {
322 warn "object uses attachment '$name' that is not available, postponing.\n"; 340 warn "object uses attachment '$name' that is not available, postponing.\n";
323 } 341 }
324 342
325 $obj->{_attachment}{$name} = undef; 343 $obj->{_attachment}{$name} = undef;
326
327 $res->{attachment} = $name;
328 $res
329} 344}
330 345
331*cf::object::attach = 346sub cf::attachable::attach {
332*cf::player::attach = 347 if (ref $_[0]) {
333*cf::map::attach = sub { 348 _object_attach @_;
334 my ($obj, $name, %arg) = @_; 349 } else {
335 350 _attach shift->_attach_registry, @_;
336 _attach_attachment $obj, $name, %arg; 351 }
337}; 352};
338 353
339# all those should be optimised 354# all those should be optimised
340*cf::object::detach = 355sub cf::attachable::detach {
341*cf::player::detach =
342*cf::map::detach = sub {
343 my ($obj, $name) = @_; 356 my ($obj, $name) = @_;
344 357
358 if (ref $obj) {
345 delete $obj->{_attachment}{$name}; 359 delete $obj->{_attachment}{$name};
346 reattach ($obj); 360 reattach ($obj);
361 } else {
362 Carp::croak "cannot, currently, detach class attachments";
363 }
347}; 364};
348 365
349*cf::object::attached = 366sub cf::attachable::attached {
350*cf::player::attached =
351*cf::map::attached = sub {
352 my ($obj, $name) = @_; 367 my ($obj, $name) = @_;
353 368
354 exists $obj->{_attachment}{$name} 369 exists $obj->{_attachment}{$name}
355};
356
357sub attach_global {
358 _attach @CB_GLOBAL, KLASS_GLOBAL, @_
359} 370}
360 371
361sub attach_to_type { 372for my $klass (qw(GLOBAL OBJECT PLAYER CLIENT MAP)) {
362 my $type = shift; 373 eval "#line " . __LINE__ . " 'cf.pm'
363 my $subtype = shift; 374 sub cf::\L$klass\E::_attach_registry {
375 (\\\@CB_$klass, KLASS_$klass)
376 }
364 377
365 _attach @{$CB_TYPE[$type + $subtype * NUM_SUBTYPES]}, KLASS_OBJECT, @_ 378 sub cf::\L$klass\E::attachment {
366}
367
368sub attach_to_objects {
369 _attach @CB_OBJECT, KLASS_OBJECT, @_
370}
371
372sub attach_to_players {
373 _attach @CB_PLAYER, KLASS_PLAYER, @_
374}
375
376sub attach_to_maps {
377 _attach @CB_MAP, KLASS_MAP, @_
378}
379
380sub register_attachment {
381 my $name = shift; 379 my \$name = shift;
382 380
383 $attachment{$name} = [[KLASS_OBJECT, @_]];
384}
385
386sub register_player_attachment {
387 my $name = shift;
388
389 $attachment{$name} = [[KLASS_PLAYER, @_]];
390}
391
392sub register_map_attachment {
393 my $name = shift;
394
395 $attachment{$name} = [[KLASS_MAP, @_]]; 381 \$attachment{\$name} = [[KLASS_$klass, \@_]];
382 }
383 ";
384 die if $@;
396} 385}
397 386
398our $override; 387our $override;
399our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals? 388our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
400 389
430 419
431=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...) 420=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...)
432 421
433=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...) 422=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...)
434 423
424=item $bool = $client->invoke (EVENT_CLIENT_XXX, ...)
425
435=item $bool = $map->invoke (EVENT_MAP_XXX, ...) 426=item $bool = $map->invoke (EVENT_MAP_XXX, ...)
436 427
437Generate a global/object/player/map-specific event with the given arguments. 428Generate a global/object/player/map-specific event with the given arguments.
438 429
439This API is preliminary (most likely, the EVENT_KLASS_xxx prefix will be 430This API is preliminary (most likely, the EVENT_KLASS_xxx prefix will be
444 435
445=cut 436=cut
446 437
447############################################################################# 438#############################################################################
448 439
449=head2 METHODS VALID FOR ALL CORE OBJECTS 440=head2 METHODS VALID FOR ALL ATTACHABLE OBJECTS
441
442Attachable objects includes objects, players, clients and maps.
450 443
451=over 4 444=over 4
452 445
453=item $object->valid, $player->valid, $map->valid 446=item $object->valid
454 447
455Just because you have a perl object does not mean that the corresponding 448Just because you have a perl object does not mean that the corresponding
456C-level object still exists. If you try to access an object that has no 449C-level object still exists. If you try to access an object that has no
457valid C counterpart anymore you get an exception at runtime. This method 450valid C counterpart anymore you get an exception at runtime. This method
458can be used to test for existence of the C object part without causing an 451can be used to test for existence of the C object part without causing an
460 453
461=back 454=back
462 455
463=cut 456=cut
464 457
465*cf::object::valid =
466*cf::player::valid =
467*cf::map::valid = \&cf::_valid;
468
469############################################################################# 458#############################################################################
470# object support 459# object support
471 460
472sub instantiate { 461sub instantiate {
473 my ($obj, $data) = @_; 462 my ($obj, $data) = @_;
492 481
493 for my $name (keys %{ $obj->{_attachment} || {} }) { 482 for my $name (keys %{ $obj->{_attachment} || {} }) {
494 if (my $attach = $attachment{$name}) { 483 if (my $attach = $attachment{$name}) {
495 for (@$attach) { 484 for (@$attach) {
496 my ($klass, @attach) = @$_; 485 my ($klass, @attach) = @$_;
497 _attach @$registry, $klass, @attach; 486 _attach $registry, $klass, @attach;
498 } 487 }
499 } else { 488 } else {
500 warn "object uses attachment '$name' that is not available, postponing.\n"; 489 warn "object uses attachment '$name' that is not available, postponing.\n";
501 } 490 }
502 } 491 }
558 } 547 }
559 548
560 () 549 ()
561} 550}
562 551
563attach_to_objects 552cf::object->attach (
564 prio => -1000000, 553 prio => -1000000,
565 on_clone => sub { 554 on_clone => sub {
566 my ($src, $dst) = @_; 555 my ($src, $dst) = @_;
567 556
568 @{$dst->registry} = @{$src->registry}; 557 @{$dst->registry} = @{$src->registry};
570 %$dst = %$src; 559 %$dst = %$src;
571 560
572 %{$dst->{_attachment}} = %{$src->{_attachment}} 561 %{$dst->{_attachment}} = %{$src->{_attachment}}
573 if exists $src->{_attachment}; 562 if exists $src->{_attachment};
574 }, 563 },
575; 564);
576 565
577############################################################################# 566#############################################################################
578# command handling &c 567# command handling &c
579 568
580=item cf::register_command $name => \&callback($ob,$args); 569=item cf::register_command $name => \&callback($ob,$args);
609 #warn "registering extcmd '$name' to '$caller'"; 598 #warn "registering extcmd '$name' to '$caller'";
610 599
611 $EXTCMD{$name} = [$cb, $caller]; 600 $EXTCMD{$name} = [$cb, $caller];
612} 601}
613 602
614attach_to_players 603cf::player->attach (
615 on_command => sub { 604 on_command => sub {
616 my ($pl, $name, $params) = @_; 605 my ($pl, $name, $params) = @_;
617 606
618 my $cb = $COMMAND{$name} 607 my $cb = $COMMAND{$name}
619 or return; 608 or return;
639 warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n"; 628 warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
640 } 629 }
641 630
642 cf::override; 631 cf::override;
643 }, 632 },
644; 633);
645 634
646sub register { 635sub register {
647 my ($base, $pkg) = @_; 636 my ($base, $pkg) = @_;
648 637
649 #TODO 638 #TODO
718 707
719 Symbol::delete_package $pkg; 708 Symbol::delete_package $pkg;
720} 709}
721 710
722sub load_extensions { 711sub load_extensions {
723 my $LIBDIR = maps_directory "perl";
724
725 for my $ext (<$LIBDIR/*.ext>) { 712 for my $ext (<$LIBDIR/*.ext>) {
726 next unless -r $ext; 713 next unless -r $ext;
727 eval { 714 eval {
728 load_extension $ext; 715 load_extension $ext;
729 1 716 1
741 defined $path or return; 728 defined $path or return;
742 729
743 unlink "$path.pst"; 730 unlink "$path.pst";
744}; 731};
745 732
746attach_to_maps prio => -10000, package => cf::mapsupport::; 733cf::map->attach (prio => -10000, package => cf::mapsupport::);
747 734
748############################################################################# 735#############################################################################
749# load/save perl data associated with player->ob objects 736# load/save perl data associated with player->ob objects
750 737
751sub all_objects(@) { 738sub all_objects(@) {
752 @_, map all_objects ($_->inv), @_ 739 @_, map all_objects ($_->inv), @_
753} 740}
754 741
755# TODO: compatibility cruft, remove when no longer needed 742# TODO: compatibility cruft, remove when no longer needed
756attach_to_players 743cf::player->attach (
757 on_load => sub { 744 on_load => sub {
758 my ($pl, $path) = @_; 745 my ($pl, $path) = @_;
759 746
760 for my $o (all_objects $pl->ob) { 747 for my $o (all_objects $pl->ob) {
761 if (my $value = $o->get_ob_key_value ("_perl_data")) { 748 if (my $value = $o->get_ob_key_value ("_perl_data")) {
763 750
764 %$o = %{ Storable::thaw pack "H*", $value }; 751 %$o = %{ Storable::thaw pack "H*", $value };
765 } 752 }
766 } 753 }
767 }, 754 },
768; 755);
769 756
770############################################################################# 757#############################################################################
771 758
772=head2 CORE EXTENSIONS 759=head2 CORE EXTENSIONS
773 760
774Functions and methods that extend core crossfire objects. 761Functions and methods that extend core crossfire objects.
762
763=head3 cf::player
775 764
776=over 4 765=over 4
777 766
778=item cf::player::exists $login 767=item cf::player::exists $login
779 768
784sub cf::player::exists($) { 773sub cf::player::exists($) {
785 cf::player::find $_[0] 774 cf::player::find $_[0]
786 or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2; 775 or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2;
787} 776}
788 777
778=item $player->ext_reply ($msgid, $msgtype, %msg)
779
780Sends an ext reply to the player.
781
782=cut
783
784sub cf::player::ext_reply($$$%) {
785 my ($self, $id, %msg) = @_;
786
787 $msg{msgid} = $id;
788
789 $self->send ("ext " . to_json \%msg);
790}
791
792=back
793
794=head3 cf::object::player
795
796=over 4
797
789=item $player_object->reply ($npc, $msg[, $flags]) 798=item $player_object->reply ($npc, $msg[, $flags])
790 799
791Sends a message to the player, as if the npc C<$npc> replied. C<$npc> 800Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
792can be C<undef>. Does the right thing when the player is currently in a 801can be C<undef>. Does the right thing when the player is currently in a
793dialogue with the given NPC character. 802dialogue with the given NPC character.
794 803
795=cut 804=cut
796 805
797# rough implementation of a future "reply" method that works 806# rough implementation of a future "reply" method that works
798# with dialog boxes. 807# with dialog boxes.
808#TODO: the first argument must go, split into a $npc->reply_to ( method
799sub cf::object::player::reply($$$;$) { 809sub cf::object::player::reply($$$;$) {
800 my ($self, $npc, $msg, $flags) = @_; 810 my ($self, $npc, $msg, $flags) = @_;
801 811
802 $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4; 812 $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
803 813
807 $msg = $npc->name . " says: $msg" if $npc; 817 $msg = $npc->name . " says: $msg" if $npc;
808 $self->message ($msg, $flags); 818 $self->message ($msg, $flags);
809 } 819 }
810} 820}
811 821
812=item $player->ext_reply ($msgid, $msgtype, %msg)
813
814Sends an ext reply to the player.
815
816=cut
817
818sub cf::player::ext_reply($$$%) {
819 my ($self, $id, %msg) = @_;
820
821 $msg{msgid} = $id;
822
823 $self->send ("ext " . to_json \%msg);
824}
825
826=item $player_object->may ("access") 822=item $player_object->may ("access")
827 823
828Returns wether the given player is authorized to access resource "access" 824Returns wether the given player is authorized to access resource "access"
829(e.g. "command_wizcast"). 825(e.g. "command_wizcast").
830 826
837 (ref $cf::CFG{"may_$access"} 833 (ref $cf::CFG{"may_$access"}
838 ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}} 834 ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
839 : $cf::CFG{"may_$access"}) 835 : $cf::CFG{"may_$access"})
840} 836}
841 837
842=cut 838=head3 cf::client
843 839
844############################################################################# 840=over 4
841
842=item $client->send_drawinfo ($text, $flags)
843
844Sends a drawinfo packet to the client. Circumvents output buffering so
845should not be used under normal circumstances.
846
847=cut
848
849sub cf::client::send_drawinfo {
850 my ($self, $text, $flags) = @_;
851
852 utf8::encode $text;
853 $self->send_packet (sprintf "drawinfo %d %s", $flags, $text);
854}
855
856
857=item $success = $client->query ($flags, "text", \&cb)
858
859Queues a query to the client, calling the given callback with
860the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
861C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
862
863Queries can fail, so check the return code. Or don't, as queries will become
864reliable at some point in the future.
865
866=cut
867
868sub cf::client::query {
869 my ($self, $flags, $text, $cb) = @_;
870
871 return unless $self->state == ST_PLAYING
872 || $self->state == ST_SETUP
873 || $self->state == ST_CUSTOM;
874
875 $self->state (ST_CUSTOM);
876
877 utf8::encode $text;
878 push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
879
880 $self->send_packet ($self->{query_queue}[0][0])
881 if @{ $self->{query_queue} } == 1;
882}
883
884cf::client->attach (
885 on_reply => sub {
886 my ($ns, $msg) = @_;
887
888 # this weird shuffling is so that direct followup queries
889 # get handled first
890 my $queue = delete $ns->{query_queue};
891
892 (shift @$queue)->[1]->($msg);
893
894 push @{ $ns->{query_queue} }, @$queue;
895
896 if (@{ $ns->{query_queue} } == @$queue) {
897 if (@$queue) {
898 $ns->send_packet ($ns->{query_queue}[0][0]);
899 } else {
900 $ns->state (ST_PLAYING);
901 }
902 }
903 },
904);
905
906=back
907
845 908
846=head2 SAFE SCRIPTING 909=head2 SAFE SCRIPTING
847 910
848Functions that provide a safe environment to compile and execute 911Functions that provide a safe environment to compile and execute
849snippets of perl code without them endangering the safety of the server 912snippets of perl code without them endangering the safety of the server
864 927
865=pod 928=pod
866 929
867The following fucntions and emthods are available within a safe environment: 930The following fucntions and emthods are available within a safe environment:
868 931
869 cf::object contr pay_amount pay_player 932 cf::object contr pay_amount pay_player map
870 cf::object::player player 933 cf::object::player player
871 cf::player peaceful 934 cf::player peaceful
935 cf::map trigger
872 936
873=cut 937=cut
874 938
875for ( 939for (
876 ["cf::object" => qw(contr pay_amount pay_player)], 940 ["cf::object" => qw(contr pay_amount pay_player map)],
877 ["cf::object::player" => qw(player)], 941 ["cf::object::player" => qw(player)],
878 ["cf::player" => qw(peaceful)], 942 ["cf::player" => qw(peaceful)],
943 ["cf::map" => qw(trigger)],
879) { 944) {
880 no strict 'refs'; 945 no strict 'refs';
881 my ($pkg, @funs) = @$_; 946 my ($pkg, @funs) = @$_;
882 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"}) 947 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
883 for @funs; 948 for @funs;
1023 sub db_sync() { 1088 sub db_sync() {
1024 db_save if $dirty; 1089 db_save if $dirty;
1025 undef $dirty; 1090 undef $dirty;
1026 } 1091 }
1027 1092
1028 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, cb => sub { 1093 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, data => WF_AUTOCANCEL, cb => sub {
1029 db_sync; 1094 db_sync;
1030 }); 1095 });
1031 1096
1032 sub db_dirty() { 1097 sub db_dirty() {
1033 $dirty = 1; 1098 $dirty = 1;
1047 $DB->{$_[0]} = $_[1]; 1112 $DB->{$_[0]} = $_[1];
1048 } 1113 }
1049 db_dirty; 1114 db_dirty;
1050 } 1115 }
1051 1116
1052 attach_global 1117 cf::global->attach (
1053 prio => 10000, 1118 prio => 10000,
1054 on_cleanup => sub { 1119 on_cleanup => sub {
1055 db_sync; 1120 db_sync;
1056 }, 1121 },
1057 ; 1122 );
1058} 1123}
1059 1124
1060############################################################################# 1125#############################################################################
1061# the server's main() 1126# the server's main()
1062 1127
1083 1148
1084 $msg->("reloading..."); 1149 $msg->("reloading...");
1085 1150
1086 eval { 1151 eval {
1087 # cancel all watchers 1152 # cancel all watchers
1088 $_->cancel for Event::all_watchers; 1153 for (Event::all_watchers) {
1154 $_->cancel if $_->data & WF_AUTOCANCEL;
1155 }
1089 1156
1090 # unload all extensions 1157 # unload all extensions
1091 for (@exts) { 1158 for (@exts) {
1092 $msg->("unloading <$_>"); 1159 $msg->("unloading <$_>");
1093 unload_extension $_; 1160 unload_extension $_;
1169}; 1236};
1170 1237
1171unshift @INC, $LIBDIR; 1238unshift @INC, $LIBDIR;
1172 1239
1173$TICK_WATCHER = Event->timer ( 1240$TICK_WATCHER = Event->timer (
1174 prio => 1, 1241 prio => 0,
1175 async => 1,
1176 at => $NEXT_TICK || 1, 1242 at => $NEXT_TICK || 1,
1243 data => WF_AUTOCANCEL,
1177 cb => sub { 1244 cb => sub {
1178 cf::server_tick; # one server iteration 1245 cf::server_tick; # one server iteration
1179 1246
1180 my $NOW = Event::time; 1247 my $NOW = Event::time;
1181 $NEXT_TICK += $TICK; 1248 $NEXT_TICK += $TICK;
1191IO::AIO::max_poll_time $TICK * 0.2; 1258IO::AIO::max_poll_time $TICK * 0.2;
1192 1259
1193Event->io (fd => IO::AIO::poll_fileno, 1260Event->io (fd => IO::AIO::poll_fileno,
1194 poll => 'r', 1261 poll => 'r',
1195 prio => 5, 1262 prio => 5,
1263 data => WF_AUTOCANCEL,
1196 cb => \&IO::AIO::poll_cb); 1264 cb => \&IO::AIO::poll_cb);
1197 1265
11981 12661
1199 1267

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines