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.84 by root, Mon Dec 11 02:54:57 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
23our %COMMAND = ();
24our %COMMAND_TIME = ();
25our %EXTCMD = ();
26
21_init_vars; 27_init_vars;
22 28
23our %COMMAND = ();
24our @EVENT; 29our @EVENT;
25our $LIBDIR = maps_directory "perl"; 30our $LIBDIR = datadir . "/ext";
26 31
27our $TICK = MAX_TIME * 1e-6; 32our $TICK = MAX_TIME * 1e-6;
28our $TICK_WATCHER; 33our $TICK_WATCHER;
29our $NEXT_TICK; 34our $NEXT_TICK;
30 35
69 print STDERR "cfperl: $msg"; 74 print STDERR "cfperl: $msg";
70 LOG llevError, "cfperl: $msg"; 75 LOG llevError, "cfperl: $msg";
71 }; 76 };
72} 77}
73 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';
74@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object'; 84@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
75 85
76# 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
77# within the Safe compartment. 87# within the Safe compartment.
78for my $pkg (qw(cf::object cf::object::player cf::player cf::map cf::party cf::region cf::arch cf::living)) { 88for my $pkg (qw(
89 cf::global
90 cf::object cf::object::player
91 cf::client cf::player
92 cf::arch cf::living
93 cf::map cf::party cf::region
94)) {
79 no strict 'refs'; 95 no strict 'refs';
80 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg; 96 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
81} 97}
82 98
83$Event::DIED = sub { 99$Event::DIED = sub {
85}; 101};
86 102
87my %ext_pkg; 103my %ext_pkg;
88my @exts; 104my @exts;
89my @hook; 105my @hook;
90my %command;
91my %extcmd;
92 106
93=head2 UTILITY FUNCTIONS 107=head2 UTILITY FUNCTIONS
94 108
95=over 4 109=over 4
96 110
124 138
125=cut 139=cut
126 140
127############################################################################# 141#############################################################################
128 142
129=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+).
130 152
131=over 4 153=over 4
132 154
133=item $object->attach ($attachment, key => $value...)
134
135=item $object->detach ($attachment)
136
137Attach/detach a pre-registered attachment to an object.
138
139=item $player->attach ($attachment, key => $value...)
140
141=item $player->detach ($attachment)
142
143Attach/detach a pre-registered attachment to a player.
144
145=item $map->attach ($attachment, key => $value...) 155=item $attachable->attach ($attachment, key => $value...)
146 156
147=item $map->detach ($attachment) 157=item $attachable->detach ($attachment)
148 158
149Attach/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.
150 161
151=item $bool = $object->attached ($name) 162Example, attach a minesweeper attachment to the given object, making it a
16310x10 minesweeper game:
152 164
153=item $bool = $player->attached ($name) 165 $obj->attach (minesweeper => width => 10, height => 10);
154 166
155=item $bool = $map->attached ($name) 167=item $bool = $attachable->attached ($name)
156 168
157Checks wether the named attachment is currently attached to the object. 169Checks wether the named attachment is currently attached to the object.
158 170
159=item cf::attach_global ... 171=item cf::CLASS->attach ...
160 172
161Attach handlers for global events. 173=item cf::CLASS->detach ...
162 174
163This and all following C<attach_*>-functions expect any number of the 175Define an anonymous attachment and attach it to all objects of the given
164following 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:
165 209
166=over 4 210=over 4
167 211
168=item prio => $number 212=item prio => $number
169 213
171by another C<prio> setting). Lower priority handlers get executed 215by another C<prio> setting). Lower priority handlers get executed
172earlier. 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
173registered at priority C<-1000>, so lower priorities should not be used 217registered at priority C<-1000>, so lower priorities should not be used
174unless you know what you are doing. 218unless you know what you are doing.
175 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
176=item on_I<event> => \&cb 226=item on_I<event> => \&cb
177 227
178Call the given code reference whenever the named event happens (event is 228Call the given code reference whenever the named event happens (event is
179something 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
180handlers are recognised generally depends on the type of object these 230handlers are recognised generally depends on the type of object these
189package and register them. Only handlers for eevents supported by the 239package and register them. Only handlers for eevents supported by the
190object/class are recognised. 240object/class are recognised.
191 241
192=back 242=back
193 243
194=item cf::attach_to_type $object_type, $subtype, ... 244Example, define an attachment called "sockpuppet" that calls the given
245event handler when a monster attacks:
195 246
196Attach handlers for a specific object type (e.g. TRANSPORT) and 247 cf::object::attachment sockpuppet =>
197subtype. If C<$subtype> is zero or undef, matches all objects of the given 248 on_skill_attack => sub {
198type. 249 my ($self, $victim) = @_;
199 250 ...
200=item cf::attach_to_objects ... 251 }
201 252 }
202Attach handlers to all objects. Do not use this except for debugging or
203very rare events, as handlers are (obviously) called for I<all> objects in
204the game.
205
206=item cf::attach_to_players ...
207
208Attach handlers to all players.
209
210=item cf::attach_to_maps ...
211
212Attach handlers to all maps.
213
214=item cf:register_attachment $name, ...
215
216Register an attachment by name through which objects can refer to this
217attachment.
218
219=item cf:register_player_attachment $name, ...
220
221Register an attachment by name through which players can refer to this
222attachment.
223
224=item cf:register_map_attachment $name, ...
225
226Register an attachment by name through which maps can refer to this
227attachment.
228 253
229=cut 254=cut
230 255
231# 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
232our @CB_GLOBAL = (); # registry for all global events 257our @CB_GLOBAL = (); # registry for all global events
233our @CB_OBJECT = (); # all objects (should not be used except in emergency) 258our @CB_OBJECT = (); # all objects (should not be used except in emergency)
234our @CB_PLAYER = (); 259our @CB_PLAYER = ();
260our @CB_CLIENT = ();
235our @CB_TYPE = (); # registry for type (cf-object class) based events 261our @CB_TYPE = (); # registry for type (cf-object class) based events
236our @CB_MAP = (); 262our @CB_MAP = ();
237 263
238my %attachment; 264my %attachment;
239 265
240sub _attach_cb($\%$$$) { 266sub _attach_cb($$$$) {
241 my ($registry, $undo, $event, $prio, $cb) = @_; 267 my ($registry, $event, $prio, $cb) = @_;
242 268
243 use sort 'stable'; 269 use sort 'stable';
244 270
245 $cb = [$prio, $cb]; 271 $cb = [$prio, $cb];
246 272
247 @{$registry->[$event]} = sort 273 @{$registry->[$event]} = sort
248 { $a->[0] cmp $b->[0] } 274 { $a->[0] cmp $b->[0] }
249 @{$registry->[$event] || []}, $cb; 275 @{$registry->[$event] || []}, $cb;
250
251 push @{$undo->{cb}}, [$event, $cb];
252} 276}
253 277
254# attach handles attaching event callbacks 278# attach handles attaching event callbacks
255# 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
256# registry (== where the callback attaches to). 280# registry (== where the callback attaches to).
257sub _attach(\@$@) { 281sub _attach {
258 my ($registry, $klass, @arg) = @_; 282 my ($registry, $klass, @arg) = @_;
259 283
284 my $object_type;
260 my $prio = 0; 285 my $prio = 0;
261
262 my %undo = (
263 registry => $registry,
264 cb => [],
265 );
266
267 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;
268 287
269 while (@arg) { 288 while (@arg) {
270 my $type = shift @arg; 289 my $type = shift @arg;
271 290
272 if ($type eq "prio") { 291 if ($type eq "prio") {
273 $prio = shift @arg; 292 $prio = shift @arg;
274 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
275 } elsif ($type eq "package") { 303 } elsif ($type eq "package") {
276 my $pkg = shift @arg; 304 my $pkg = shift @arg;
277 305
278 while (my ($name, $id) = each %cb_id) { 306 while (my ($name, $id) = each %cb_id) {
279 if (my $cb = $pkg->can ($name)) { 307 if (my $cb = $pkg->can ($name)) {
280 _attach_cb $registry, %undo, $id, $prio, $cb; 308 _attach_cb $registry, $id, $prio, $cb;
281 } 309 }
282 } 310 }
283 311
284 } elsif (exists $cb_id{$type}) { 312 } elsif (exists $cb_id{$type}) {
285 _attach_cb $registry, %undo, $cb_id{$type}, $prio, shift @arg; 313 _attach_cb $registry, $cb_id{$type}, $prio, shift @arg;
286 314
287 } elsif (ref $type) { 315 } elsif (ref $type) {
288 warn "attaching objects not supported, ignoring.\n"; 316 warn "attaching objects not supported, ignoring.\n";
289 317
290 } else { 318 } else {
291 shift @arg; 319 shift @arg;
292 warn "attach argument '$type' not supported, ignoring.\n"; 320 warn "attach argument '$type' not supported, ignoring.\n";
293 } 321 }
294 } 322 }
295
296 \%undo
297} 323}
298 324
299sub _attach_attachment { 325sub _object_attach {
300 my ($obj, $name, %arg) = @_; 326 my ($obj, $name, %arg) = @_;
301 327
302 return if exists $obj->{_attachment}{$name}; 328 return if exists $obj->{_attachment}{$name};
303
304 my $res;
305 329
306 if (my $attach = $attachment{$name}) { 330 if (my $attach = $attachment{$name}) {
307 my $registry = $obj->registry; 331 my $registry = $obj->registry;
308 332
309 for (@$attach) { 333 for (@$attach) {
310 my ($klass, @attach) = @$_; 334 my ($klass, @attach) = @$_;
311 $res = _attach @$registry, $klass, @attach; 335 _attach $registry, $klass, @attach;
312 } 336 }
313 337
314 $obj->{$name} = \%arg; 338 $obj->{$name} = \%arg;
315 } else { 339 } else {
316 warn "object uses attachment '$name' that is not available, postponing.\n"; 340 warn "object uses attachment '$name' that is not available, postponing.\n";
317 } 341 }
318 342
319 $obj->{_attachment}{$name} = undef; 343 $obj->{_attachment}{$name} = undef;
320
321 $res->{attachment} = $name;
322 $res
323} 344}
324 345
325*cf::object::attach = 346sub cf::attachable::attach {
326*cf::player::attach = 347 if (ref $_[0]) {
327*cf::map::attach = sub { 348 _object_attach @_;
328 my ($obj, $name, %arg) = @_; 349 } else {
329 350 _attach shift->_attach_registry, @_;
330 _attach_attachment $obj, $name, %arg; 351 }
331}; 352};
332 353
333# all those should be optimised 354# all those should be optimised
334*cf::object::detach = 355sub cf::attachable::detach {
335*cf::player::detach =
336*cf::map::detach = sub {
337 my ($obj, $name) = @_; 356 my ($obj, $name) = @_;
338 357
358 if (ref $obj) {
339 delete $obj->{_attachment}{$name}; 359 delete $obj->{_attachment}{$name};
340 reattach ($obj); 360 reattach ($obj);
361 } else {
362 Carp::croak "cannot, currently, detach class attachments";
363 }
341}; 364};
342 365
343*cf::object::attached = 366sub cf::attachable::attached {
344*cf::player::attached =
345*cf::map::attached = sub {
346 my ($obj, $name) = @_; 367 my ($obj, $name) = @_;
347 368
348 exists $obj->{_attachment}{$name} 369 exists $obj->{_attachment}{$name}
349};
350
351sub attach_global {
352 _attach @CB_GLOBAL, KLASS_GLOBAL, @_
353} 370}
354 371
355sub attach_to_type { 372for my $klass (qw(GLOBAL OBJECT PLAYER CLIENT MAP)) {
356 my $type = shift; 373 eval "#line " . __LINE__ . " 'cf.pm'
357 my $subtype = shift; 374 sub cf::\L$klass\E::_attach_registry {
375 (\\\@CB_$klass, KLASS_$klass)
376 }
358 377
359 _attach @{$CB_TYPE[$type + $subtype * NUM_SUBTYPES]}, KLASS_OBJECT, @_ 378 sub cf::\L$klass\E::attachment {
360}
361
362sub attach_to_objects {
363 _attach @CB_OBJECT, KLASS_OBJECT, @_
364}
365
366sub attach_to_players {
367 _attach @CB_PLAYER, KLASS_PLAYER, @_
368}
369
370sub attach_to_maps {
371 _attach @CB_MAP, KLASS_MAP, @_
372}
373
374sub register_attachment {
375 my $name = shift; 379 my \$name = shift;
376 380
377 $attachment{$name} = [[KLASS_OBJECT, @_]];
378}
379
380sub register_player_attachment {
381 my $name = shift;
382
383 $attachment{$name} = [[KLASS_PLAYER, @_]];
384}
385
386sub register_map_attachment {
387 my $name = shift;
388
389 $attachment{$name} = [[KLASS_MAP, @_]]; 381 \$attachment{\$name} = [[KLASS_$klass, \@_]];
382 }
383 ";
384 die if $@;
390} 385}
391 386
392our $override; 387our $override;
393our @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?
394 389
424 419
425=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...) 420=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...)
426 421
427=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...) 422=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...)
428 423
424=item $bool = $client->invoke (EVENT_CLIENT_XXX, ...)
425
429=item $bool = $map->invoke (EVENT_MAP_XXX, ...) 426=item $bool = $map->invoke (EVENT_MAP_XXX, ...)
430 427
431Generate a global/object/player/map-specific event with the given arguments. 428Generate a global/object/player/map-specific event with the given arguments.
432 429
433This 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
438 435
439=cut 436=cut
440 437
441############################################################################# 438#############################################################################
442 439
443=head2 METHODS VALID FOR ALL CORE OBJECTS 440=head2 METHODS VALID FOR ALL ATTACHABLE OBJECTS
441
442Attachable objects includes objects, players, clients and maps.
444 443
445=over 4 444=over 4
446 445
447=item $object->valid, $player->valid, $map->valid 446=item $object->valid
448 447
449Just 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
450C-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
451valid C counterpart anymore you get an exception at runtime. This method 450valid C counterpart anymore you get an exception at runtime. This method
452can 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
454 453
455=back 454=back
456 455
457=cut 456=cut
458 457
459*cf::object::valid =
460*cf::player::valid =
461*cf::map::valid = \&cf::_valid;
462
463############################################################################# 458#############################################################################
464# object support 459# object support
465 460
466sub instantiate { 461sub instantiate {
467 my ($obj, $data) = @_; 462 my ($obj, $data) = @_;
486 481
487 for my $name (keys %{ $obj->{_attachment} || {} }) { 482 for my $name (keys %{ $obj->{_attachment} || {} }) {
488 if (my $attach = $attachment{$name}) { 483 if (my $attach = $attachment{$name}) {
489 for (@$attach) { 484 for (@$attach) {
490 my ($klass, @attach) = @$_; 485 my ($klass, @attach) = @$_;
491 _attach @$registry, $klass, @attach; 486 _attach $registry, $klass, @attach;
492 } 487 }
493 } else { 488 } else {
494 warn "object uses attachment '$name' that is not available, postponing.\n"; 489 warn "object uses attachment '$name' that is not available, postponing.\n";
495 } 490 }
496 } 491 }
552 } 547 }
553 548
554 () 549 ()
555} 550}
556 551
557attach_to_objects 552cf::object->attach (
558 prio => -1000000, 553 prio => -1000000,
559 on_clone => sub { 554 on_clone => sub {
560 my ($src, $dst) = @_; 555 my ($src, $dst) = @_;
561 556
562 @{$dst->registry} = @{$src->registry}; 557 @{$dst->registry} = @{$src->registry};
564 %$dst = %$src; 559 %$dst = %$src;
565 560
566 %{$dst->{_attachment}} = %{$src->{_attachment}} 561 %{$dst->{_attachment}} = %{$src->{_attachment}}
567 if exists $src->{_attachment}; 562 if exists $src->{_attachment};
568 }, 563 },
569; 564);
570 565
571############################################################################# 566#############################################################################
572# old plug-in events 567# command handling &c
573 568
574sub inject_event { 569=item cf::register_command $name => \&callback($ob,$args);
575 my $extension = shift;
576 my $event_code = shift;
577 570
578 my $cb = $hook[$event_code]{$extension} 571Register a callback for execution when the client sends the user command
579 or return; 572$name.
580 573
581 &$cb 574=cut
582}
583
584sub inject_global_event {
585 my $event = shift;
586
587 my $cb = $hook[$event]
588 or return;
589
590 List::Util::max map &$_, values %$cb
591}
592
593sub inject_command {
594 my ($name, $obj, $params) = @_;
595
596 for my $cmd (@{ $command{$name} }) {
597 $cmd->[1]->($obj, $params);
598 }
599
600 -1
601}
602 575
603sub register_command { 576sub register_command {
604 my ($name, $time, $cb) = @_; 577 my ($name, $cb) = @_;
605 578
606 my $caller = caller; 579 my $caller = caller;
607 #warn "registering command '$name/$time' to '$caller'"; 580 #warn "registering command '$name/$time' to '$caller'";
608 581
609 push @{ $command{$name} }, [$time, $cb, $caller]; 582 push @{ $COMMAND{$name} }, [$caller, $cb];
610 $COMMAND{"$name\000"} = List::Util::max map $_->[0], @{ $command{$name} };
611} 583}
584
585=item cf::register_extcmd $name => \&callback($pl,$packet);
586
587Register a callbackf ro execution when the client sends an extcmd packet.
588
589If the callback returns something, it is sent back as if reply was being
590called.
591
592=cut
612 593
613sub register_extcmd { 594sub register_extcmd {
614 my ($name, $cb) = @_; 595 my ($name, $cb) = @_;
615 596
616 my $caller = caller; 597 my $caller = caller;
617 #warn "registering extcmd '$name' to '$caller'"; 598 #warn "registering extcmd '$name' to '$caller'";
618 599
619 $extcmd{$name} = [$cb, $caller]; 600 $EXTCMD{$name} = [$cb, $caller];
620} 601}
602
603cf::player->attach (
604 on_command => sub {
605 my ($pl, $name, $params) = @_;
606
607 my $cb = $COMMAND{$name}
608 or return;
609
610 for my $cmd (@$cb) {
611 $cmd->[1]->($pl->ob, $params);
612 }
613
614 cf::override;
615 },
616 on_extcmd => sub {
617 my ($pl, $buf) = @_;
618
619 my $msg = eval { from_json $buf };
620
621 if (ref $msg) {
622 if (my $cb = $EXTCMD{$msg->{msgtype}}) {
623 if (my %reply = $cb->[0]->($pl, $msg)) {
624 $pl->ext_reply ($msg->{msgid}, %reply);
625 }
626 }
627 } else {
628 warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
629 }
630
631 cf::override;
632 },
633);
621 634
622sub register { 635sub register {
623 my ($base, $pkg) = @_; 636 my ($base, $pkg) = @_;
624 637
625 #TODO 638 #TODO
668# for my $idx (0 .. $#PLUGIN_EVENT) { 681# for my $idx (0 .. $#PLUGIN_EVENT) {
669# delete $hook[$idx]{$pkg}; 682# delete $hook[$idx]{$pkg};
670# } 683# }
671 684
672 # remove commands 685 # remove commands
673 for my $name (keys %command) { 686 for my $name (keys %COMMAND) {
674 my @cb = grep $_->[2] ne $pkg, @{ $command{$name} }; 687 my @cb = grep $_->[0] ne $pkg, @{ $COMMAND{$name} };
675 688
676 if (@cb) { 689 if (@cb) {
677 $command{$name} = \@cb; 690 $COMMAND{$name} = \@cb;
678 $COMMAND{"$name\000"} = List::Util::max map $_->[0], @cb;
679 } else { 691 } else {
680 delete $command{$name};
681 delete $COMMAND{"$name\000"}; 692 delete $COMMAND{$name};
682 } 693 }
683 } 694 }
684 695
685 # remove extcmds 696 # remove extcmds
686 for my $name (grep $extcmd{$_}[1] eq $pkg, keys %extcmd) { 697 for my $name (grep $EXTCMD{$_}[1] eq $pkg, keys %EXTCMD) {
687 delete $extcmd{$name}; 698 delete $EXTCMD{$name};
688 } 699 }
689 700
690 if (my $cb = $pkg->can ("unload")) { 701 if (my $cb = $pkg->can ("unload")) {
691 eval { 702 eval {
692 $cb->($pkg); 703 $cb->($pkg);
696 707
697 Symbol::delete_package $pkg; 708 Symbol::delete_package $pkg;
698} 709}
699 710
700sub load_extensions { 711sub load_extensions {
701 my $LIBDIR = maps_directory "perl";
702
703 for my $ext (<$LIBDIR/*.ext>) { 712 for my $ext (<$LIBDIR/*.ext>) {
704 next unless -r $ext; 713 next unless -r $ext;
705 eval { 714 eval {
706 load_extension $ext; 715 load_extension $ext;
707 1 716 1
708 } or warn "$ext not loaded: $@"; 717 } or warn "$ext not loaded: $@";
709 } 718 }
710} 719}
711 720
712############################################################################# 721#############################################################################
713# extcmd framework, basically convert ext <msg>
714# into pkg::->on_extcmd_arg1 (...) while shortcutting a few
715
716attach_to_players
717 on_extcmd => sub {
718 my ($pl, $buf) = @_;
719
720 my $msg = eval { from_json $buf };
721
722 if (ref $msg) {
723 if (my $cb = $extcmd{$msg->{msgtype}}) {
724 if (my %reply = $cb->[0]->($pl, $msg)) {
725 $pl->ext_reply ($msg->{msgid}, %reply);
726 }
727 }
728 } else {
729 warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
730 }
731
732 cf::override;
733 },
734;
735
736#############################################################################
737# load/save/clean perl data associated with a map 722# load/save/clean perl data associated with a map
738 723
739*cf::mapsupport::on_clean = sub { 724*cf::mapsupport::on_clean = sub {
740 my ($map) = @_; 725 my ($map) = @_;
741 726
743 defined $path or return; 728 defined $path or return;
744 729
745 unlink "$path.pst"; 730 unlink "$path.pst";
746}; 731};
747 732
748attach_to_maps prio => -10000, package => cf::mapsupport::; 733cf::map->attach (prio => -10000, package => cf::mapsupport::);
749 734
750############################################################################# 735#############################################################################
751# load/save perl data associated with player->ob objects 736# load/save perl data associated with player->ob objects
752 737
753sub all_objects(@) { 738sub all_objects(@) {
754 @_, map all_objects ($_->inv), @_ 739 @_, map all_objects ($_->inv), @_
755} 740}
756 741
757# TODO: compatibility cruft, remove when no longer needed 742# TODO: compatibility cruft, remove when no longer needed
758attach_to_players 743cf::player->attach (
759 on_load => sub { 744 on_load => sub {
760 my ($pl, $path) = @_; 745 my ($pl, $path) = @_;
761 746
762 for my $o (all_objects $pl->ob) { 747 for my $o (all_objects $pl->ob) {
763 if (my $value = $o->get_ob_key_value ("_perl_data")) { 748 if (my $value = $o->get_ob_key_value ("_perl_data")) {
765 750
766 %$o = %{ Storable::thaw pack "H*", $value }; 751 %$o = %{ Storable::thaw pack "H*", $value };
767 } 752 }
768 } 753 }
769 }, 754 },
770; 755);
771 756
772############################################################################# 757#############################################################################
773 758
774=head2 CORE EXTENSIONS 759=head2 CORE EXTENSIONS
775 760
776Functions and methods that extend core crossfire objects. 761Functions and methods that extend core crossfire objects.
762
763=head3 cf::player
777 764
778=over 4 765=over 4
779 766
780=item cf::player::exists $login 767=item cf::player::exists $login
781 768
786sub cf::player::exists($) { 773sub cf::player::exists($) {
787 cf::player::find $_[0] 774 cf::player::find $_[0]
788 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;
789} 776}
790 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
791=item $player_object->reply ($npc, $msg[, $flags]) 798=item $player_object->reply ($npc, $msg[, $flags])
792 799
793Sends 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>
794can 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
795dialogue with the given NPC character. 802dialogue with the given NPC character.
796 803
797=cut 804=cut
798 805
799# rough implementation of a future "reply" method that works 806# rough implementation of a future "reply" method that works
800# with dialog boxes. 807# with dialog boxes.
808#TODO: the first argument must go, split into a $npc->reply_to ( method
801sub cf::object::player::reply($$$;$) { 809sub cf::object::player::reply($$$;$) {
802 my ($self, $npc, $msg, $flags) = @_; 810 my ($self, $npc, $msg, $flags) = @_;
803 811
804 $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4; 812 $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
805 813
809 $msg = $npc->name . " says: $msg" if $npc; 817 $msg = $npc->name . " says: $msg" if $npc;
810 $self->message ($msg, $flags); 818 $self->message ($msg, $flags);
811 } 819 }
812} 820}
813 821
814=item $player->ext_reply ($msgid, $msgtype, %msg)
815
816Sends an ext reply to the player.
817
818=cut
819
820sub cf::player::ext_reply($$$%) {
821 my ($self, $id, %msg) = @_;
822
823 $msg{msgid} = $id;
824
825 $self->send ("ext " . to_json \%msg);
826}
827
828=item $player_object->may ("access") 822=item $player_object->may ("access")
829 823
830Returns wether the given player is authorized to access resource "access" 824Returns wether the given player is authorized to access resource "access"
831(e.g. "command_wizcast"). 825(e.g. "command_wizcast").
832 826
839 (ref $cf::CFG{"may_$access"} 833 (ref $cf::CFG{"may_$access"}
840 ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}} 834 ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
841 : $cf::CFG{"may_$access"}) 835 : $cf::CFG{"may_$access"})
842} 836}
843 837
844=cut 838=head3 cf::client
845 839
846############################################################################# 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
847 908
848=head2 SAFE SCRIPTING 909=head2 SAFE SCRIPTING
849 910
850Functions that provide a safe environment to compile and execute 911Functions that provide a safe environment to compile and execute
851snippets of perl code without them endangering the safety of the server 912snippets of perl code without them endangering the safety of the server
866 927
867=pod 928=pod
868 929
869The following fucntions and emthods are available within a safe environment: 930The following fucntions and emthods are available within a safe environment:
870 931
871 cf::object contr pay_amount pay_player 932 cf::object contr pay_amount pay_player map
872 cf::object::player player 933 cf::object::player player
873 cf::player peaceful 934 cf::player peaceful
935 cf::map trigger
874 936
875=cut 937=cut
876 938
877for ( 939for (
878 ["cf::object" => qw(contr pay_amount pay_player)], 940 ["cf::object" => qw(contr pay_amount pay_player map)],
879 ["cf::object::player" => qw(player)], 941 ["cf::object::player" => qw(player)],
880 ["cf::player" => qw(peaceful)], 942 ["cf::player" => qw(peaceful)],
943 ["cf::map" => qw(trigger)],
881) { 944) {
882 no strict 'refs'; 945 no strict 'refs';
883 my ($pkg, @funs) = @$_; 946 my ($pkg, @funs) = @$_;
884 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"}) 947 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
885 for @funs; 948 for @funs;
1025 sub db_sync() { 1088 sub db_sync() {
1026 db_save if $dirty; 1089 db_save if $dirty;
1027 undef $dirty; 1090 undef $dirty;
1028 } 1091 }
1029 1092
1030 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 {
1031 db_sync; 1094 db_sync;
1032 }); 1095 });
1033 1096
1034 sub db_dirty() { 1097 sub db_dirty() {
1035 $dirty = 1; 1098 $dirty = 1;
1049 $DB->{$_[0]} = $_[1]; 1112 $DB->{$_[0]} = $_[1];
1050 } 1113 }
1051 db_dirty; 1114 db_dirty;
1052 } 1115 }
1053 1116
1054 attach_global 1117 cf::global->attach (
1055 prio => 10000, 1118 prio => 10000,
1056 on_cleanup => sub { 1119 on_cleanup => sub {
1057 db_sync; 1120 db_sync;
1058 }, 1121 },
1059 ; 1122 );
1060} 1123}
1061 1124
1062############################################################################# 1125#############################################################################
1063# the server's main() 1126# the server's main()
1064 1127
1085 1148
1086 $msg->("reloading..."); 1149 $msg->("reloading...");
1087 1150
1088 eval { 1151 eval {
1089 # cancel all watchers 1152 # cancel all watchers
1090 $_->cancel for Event::all_watchers; 1153 for (Event::all_watchers) {
1154 $_->cancel if $_->data & WF_AUTOCANCEL;
1155 }
1091 1156
1092 # unload all extensions 1157 # unload all extensions
1093 for (@exts) { 1158 for (@exts) {
1094 $msg->("unloading <$_>"); 1159 $msg->("unloading <$_>");
1095 unload_extension $_; 1160 unload_extension $_;
1155 warn $_[0]; 1220 warn $_[0];
1156 print "$_[0]\n"; 1221 print "$_[0]\n";
1157 }; 1222 };
1158} 1223}
1159 1224
1225register "<global>", __PACKAGE__;
1226
1160register_command "perl-reload", 0, sub { 1227register_command "perl-reload" => sub {
1161 my ($who, $arg) = @_; 1228 my ($who, $arg) = @_;
1162 1229
1163 if ($who->flag (FLAG_WIZ)) { 1230 if ($who->flag (FLAG_WIZ)) {
1164 _perl_reload { 1231 _perl_reload {
1165 warn $_[0]; 1232 warn $_[0];
1166 $who->message ($_[0]); 1233 $who->message ($_[0]);
1167 }; 1234 };
1168 } 1235 }
1169}; 1236};
1170 1237
1171register "<global>", __PACKAGE__;
1172
1173unshift @INC, $LIBDIR; 1238unshift @INC, $LIBDIR;
1174 1239
1175$TICK_WATCHER = Event->timer ( 1240$TICK_WATCHER = Event->timer (
1176 prio => 1, 1241 prio => 0,
1177 async => 1,
1178 at => $NEXT_TICK || 1, 1242 at => $NEXT_TICK || 1,
1243 data => WF_AUTOCANCEL,
1179 cb => sub { 1244 cb => sub {
1180 cf::server_tick; # one server iteration 1245 cf::server_tick; # one server iteration
1181 1246
1182 my $NOW = Event::time; 1247 my $NOW = Event::time;
1183 $NEXT_TICK += $TICK; 1248 $NEXT_TICK += $TICK;
1193IO::AIO::max_poll_time $TICK * 0.2; 1258IO::AIO::max_poll_time $TICK * 0.2;
1194 1259
1195Event->io (fd => IO::AIO::poll_fileno, 1260Event->io (fd => IO::AIO::poll_fileno,
1196 poll => 'r', 1261 poll => 'r',
1197 prio => 5, 1262 prio => 5,
1263 data => WF_AUTOCANCEL,
1198 cb => \&IO::AIO::poll_cb); 1264 cb => \&IO::AIO::poll_cb);
1199 1265
12001 12661
1201 1267

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines