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.94 by root, Thu Dec 21 23:02:54 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
866 851
867=pod 852=pod
868 853
869The following fucntions and emthods are available within a safe environment: 854The following fucntions and emthods are available within a safe environment:
870 855
871 cf::object contr pay_amount pay_player 856 cf::object contr pay_amount pay_player map
872 cf::object::player player 857 cf::object::player player
873 cf::player peaceful 858 cf::player peaceful
859 cf::map trigger
874 860
875=cut 861=cut
876 862
877for ( 863for (
878 ["cf::object" => qw(contr pay_amount pay_player)], 864 ["cf::object" => qw(contr pay_amount pay_player map)],
879 ["cf::object::player" => qw(player)], 865 ["cf::object::player" => qw(player)],
880 ["cf::player" => qw(peaceful)], 866 ["cf::player" => qw(peaceful)],
867 ["cf::map" => qw(trigger)],
881) { 868) {
882 no strict 'refs'; 869 no strict 'refs';
883 my ($pkg, @funs) = @$_; 870 my ($pkg, @funs) = @$_;
884 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"}) 871 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
885 for @funs; 872 for @funs;
1025 sub db_sync() { 1012 sub db_sync() {
1026 db_save if $dirty; 1013 db_save if $dirty;
1027 undef $dirty; 1014 undef $dirty;
1028 } 1015 }
1029 1016
1030 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, cb => sub { 1017 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, data => WF_AUTOCANCEL, cb => sub {
1031 db_sync; 1018 db_sync;
1032 }); 1019 });
1033 1020
1034 sub db_dirty() { 1021 sub db_dirty() {
1035 $dirty = 1; 1022 $dirty = 1;
1049 $DB->{$_[0]} = $_[1]; 1036 $DB->{$_[0]} = $_[1];
1050 } 1037 }
1051 db_dirty; 1038 db_dirty;
1052 } 1039 }
1053 1040
1054 attach_global 1041 cf::global->attach (
1055 prio => 10000, 1042 prio => 10000,
1056 on_cleanup => sub { 1043 on_cleanup => sub {
1057 db_sync; 1044 db_sync;
1058 }, 1045 },
1059 ; 1046 );
1060} 1047}
1061 1048
1062############################################################################# 1049#############################################################################
1063# the server's main() 1050# the server's main()
1064 1051
1085 1072
1086 $msg->("reloading..."); 1073 $msg->("reloading...");
1087 1074
1088 eval { 1075 eval {
1089 # cancel all watchers 1076 # cancel all watchers
1090 $_->cancel for Event::all_watchers; 1077 for (Event::all_watchers) {
1078 $_->cancel if $_->data & WF_AUTOCANCEL;
1079 }
1091 1080
1092 # unload all extensions 1081 # unload all extensions
1093 for (@exts) { 1082 for (@exts) {
1094 $msg->("unloading <$_>"); 1083 $msg->("unloading <$_>");
1095 unload_extension $_; 1084 unload_extension $_;
1155 warn $_[0]; 1144 warn $_[0];
1156 print "$_[0]\n"; 1145 print "$_[0]\n";
1157 }; 1146 };
1158} 1147}
1159 1148
1149register "<global>", __PACKAGE__;
1150
1160register_command "perl-reload", 0, sub { 1151register_command "perl-reload" => sub {
1161 my ($who, $arg) = @_; 1152 my ($who, $arg) = @_;
1162 1153
1163 if ($who->flag (FLAG_WIZ)) { 1154 if ($who->flag (FLAG_WIZ)) {
1164 _perl_reload { 1155 _perl_reload {
1165 warn $_[0]; 1156 warn $_[0];
1166 $who->message ($_[0]); 1157 $who->message ($_[0]);
1167 }; 1158 };
1168 } 1159 }
1169}; 1160};
1170 1161
1171register "<global>", __PACKAGE__;
1172
1173unshift @INC, $LIBDIR; 1162unshift @INC, $LIBDIR;
1174 1163
1175$TICK_WATCHER = Event->timer ( 1164$TICK_WATCHER = Event->timer (
1176 prio => 1, 1165 prio => 0,
1177 async => 1,
1178 at => $NEXT_TICK || 1, 1166 at => $NEXT_TICK || 1,
1167 data => WF_AUTOCANCEL,
1179 cb => sub { 1168 cb => sub {
1180 cf::server_tick; # one server iteration 1169 cf::server_tick; # one server iteration
1181 1170
1182 my $NOW = Event::time; 1171 my $NOW = Event::time;
1183 $NEXT_TICK += $TICK; 1172 $NEXT_TICK += $TICK;
1193IO::AIO::max_poll_time $TICK * 0.2; 1182IO::AIO::max_poll_time $TICK * 0.2;
1194 1183
1195Event->io (fd => IO::AIO::poll_fileno, 1184Event->io (fd => IO::AIO::poll_fileno,
1196 poll => 'r', 1185 poll => 'r',
1197 prio => 5, 1186 prio => 5,
1187 data => WF_AUTOCANCEL,
1198 cb => \&IO::AIO::poll_cb); 1188 cb => \&IO::AIO::poll_cb);
1199 1189
12001 11901
1201 1191

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines