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.74 by root, Sun Oct 1 15:59:29 2006 UTC vs.
Revision 1.94 by root, Thu Dec 21 23:02:54 2006 UTC

5use Storable; 5use Storable;
6use Opcode; 6use Opcode;
7use Safe; 7use Safe;
8use Safe::Hole; 8use Safe::Hole;
9 9
10use IO::AIO ();
10use YAML::Syck (); 11use YAML::Syck ();
11use Time::HiRes; 12use Time::HiRes;
12use Event; 13use Event;
13$Event::Eval = 1; # no idea why this is required, but it is 14$Event::Eval = 1; # no idea why this is required, but it is
14 15
15# 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?
16$YAML::Syck::ImplicitUnicode = 1; 17$YAML::Syck::ImplicitUnicode = 1;
17 18
18use strict; 19use strict;
19 20
21sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
22
23our %COMMAND = ();
24our %COMMAND_TIME = ();
25our %EXTCMD = ();
26
20_init_vars; 27_init_vars;
21 28
22our %COMMAND = ();
23our @EVENT; 29our @EVENT;
24our $LIBDIR = maps_directory "perl"; 30our $LIBDIR = datadir . "/ext";
25 31
26our $TICK = MAX_TIME * 1e-6; 32our $TICK = MAX_TIME * 1e-6;
27our $TICK_WATCHER; 33our $TICK_WATCHER;
28our $NEXT_TICK; 34our $NEXT_TICK;
29 35
30our %CFG; 36our %CFG;
31 37
38our $UPTIME; $UPTIME ||= time;
39
32############################################################################# 40#############################################################################
33 41
34=head2 GLOBAL VARIABLES 42=head2 GLOBAL VARIABLES
35 43
36=over 4 44=over 4
45
46=item $cf::UPTIME
47
48The timestamp of the server start (so not actually an uptime).
37 49
38=item $cf::LIBDIR 50=item $cf::LIBDIR
39 51
40The perl library directory, where extensions and cf-specific modules can 52The perl library directory, where extensions and cf-specific modules can
41be found. It will be added to C<@INC> automatically. 53be found. It will be added to C<@INC> automatically.
62 print STDERR "cfperl: $msg"; 74 print STDERR "cfperl: $msg";
63 LOG llevError, "cfperl: $msg"; 75 LOG llevError, "cfperl: $msg";
64 }; 76 };
65} 77}
66 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';
67@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object'; 84@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
68 85
69# 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
70# within the Safe compartment. 87# within the Safe compartment.
71for 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)) {
72 no strict 'refs'; 95 no strict 'refs';
73 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg; 96 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
74} 97}
75 98
76$Event::DIED = sub { 99$Event::DIED = sub {
78}; 101};
79 102
80my %ext_pkg; 103my %ext_pkg;
81my @exts; 104my @exts;
82my @hook; 105my @hook;
83my %command;
84my %extcmd;
85 106
86=head2 UTILITY FUNCTIONS 107=head2 UTILITY FUNCTIONS
87 108
88=over 4 109=over 4
89 110
117 138
118=cut 139=cut
119 140
120############################################################################# 141#############################################################################
121 142
122=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+).
123 152
124=over 4 153=over 4
125 154
126=item $object->attach ($attachment, key => $value...)
127
128=item $object->detach ($attachment)
129
130Attach/detach a pre-registered attachment to an object.
131
132=item $player->attach ($attachment, key => $value...)
133
134=item $player->detach ($attachment)
135
136Attach/detach a pre-registered attachment to a player.
137
138=item $map->attach ($attachment, key => $value...) 155=item $attachable->attach ($attachment, key => $value...)
139 156
140=item $map->detach ($attachment) 157=item $attachable->detach ($attachment)
141 158
142Attach/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.
143 161
144=item $bool = $object->attached ($name) 162Example, attach a minesweeper attachment to the given object, making it a
16310x10 minesweeper game:
145 164
146=item $bool = $player->attached ($name) 165 $obj->attach (minesweeper => width => 10, height => 10);
147 166
148=item $bool = $map->attached ($name) 167=item $bool = $attachable->attached ($name)
149 168
150Checks wether the named attachment is currently attached to the object. 169Checks wether the named attachment is currently attached to the object.
151 170
152=item cf::attach_global ... 171=item cf::CLASS->attach ...
153 172
154Attach handlers for global events. 173=item cf::CLASS->detach ...
155 174
156This and all following C<attach_*>-functions expect any number of the 175Define an anonymous attachment and attach it to all objects of the given
157following 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:
158 209
159=over 4 210=over 4
160 211
161=item prio => $number 212=item prio => $number
162 213
164by another C<prio> setting). Lower priority handlers get executed 215by another C<prio> setting). Lower priority handlers get executed
165earlier. 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
166registered at priority C<-1000>, so lower priorities should not be used 217registered at priority C<-1000>, so lower priorities should not be used
167unless you know what you are doing. 218unless you know what you are doing.
168 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
169=item on_I<event> => \&cb 226=item on_I<event> => \&cb
170 227
171Call the given code reference whenever the named event happens (event is 228Call the given code reference whenever the named event happens (event is
172something 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
173handlers are recognised generally depends on the type of object these 230handlers are recognised generally depends on the type of object these
182package and register them. Only handlers for eevents supported by the 239package and register them. Only handlers for eevents supported by the
183object/class are recognised. 240object/class are recognised.
184 241
185=back 242=back
186 243
187=item cf::attach_to_type $object_type, $subtype, ... 244Example, define an attachment called "sockpuppet" that calls the given
245event handler when a monster attacks:
188 246
189Attach handlers for a specific object type (e.g. TRANSPORT) and 247 cf::object::attachment sockpuppet =>
190subtype. If C<$subtype> is zero or undef, matches all objects of the given 248 on_skill_attack => sub {
191type. 249 my ($self, $victim) = @_;
192 250 ...
193=item cf::attach_to_objects ... 251 }
194 252 }
195Attach handlers to all objects. Do not use this except for debugging or
196very rare events, as handlers are (obviously) called for I<all> objects in
197the game.
198
199=item cf::attach_to_players ...
200
201Attach handlers to all players.
202
203=item cf::attach_to_maps ...
204
205Attach handlers to all maps.
206
207=item cf:register_attachment $name, ...
208
209Register an attachment by name through which objects can refer to this
210attachment.
211
212=item cf:register_player_attachment $name, ...
213
214Register an attachment by name through which players can refer to this
215attachment.
216
217=item cf:register_map_attachment $name, ...
218
219Register an attachment by name through which maps can refer to this
220attachment.
221 253
222=cut 254=cut
223 255
224# 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
225our @CB_GLOBAL = (); # registry for all global events 257our @CB_GLOBAL = (); # registry for all global events
226our @CB_OBJECT = (); # all objects (should not be used except in emergency) 258our @CB_OBJECT = (); # all objects (should not be used except in emergency)
227our @CB_PLAYER = (); 259our @CB_PLAYER = ();
260our @CB_CLIENT = ();
228our @CB_TYPE = (); # registry for type (cf-object class) based events 261our @CB_TYPE = (); # registry for type (cf-object class) based events
229our @CB_MAP = (); 262our @CB_MAP = ();
230 263
231my %attachment; 264my %attachment;
232 265
233sub _attach_cb($\%$$$) { 266sub _attach_cb($$$$) {
234 my ($registry, $undo, $event, $prio, $cb) = @_; 267 my ($registry, $event, $prio, $cb) = @_;
235 268
236 use sort 'stable'; 269 use sort 'stable';
237 270
238 $cb = [$prio, $cb]; 271 $cb = [$prio, $cb];
239 272
240 @{$registry->[$event]} = sort 273 @{$registry->[$event]} = sort
241 { $a->[0] cmp $b->[0] } 274 { $a->[0] cmp $b->[0] }
242 @{$registry->[$event] || []}, $cb; 275 @{$registry->[$event] || []}, $cb;
243
244 push @{$undo->{cb}}, [$event, $cb];
245} 276}
246 277
247# attach handles attaching event callbacks 278# attach handles attaching event callbacks
248# 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
249# registry (== where the callback attaches to). 280# registry (== where the callback attaches to).
250sub _attach(\@$@) { 281sub _attach {
251 my ($registry, $klass, @arg) = @_; 282 my ($registry, $klass, @arg) = @_;
252 283
284 my $object_type;
253 my $prio = 0; 285 my $prio = 0;
254
255 my %undo = (
256 registry => $registry,
257 cb => [],
258 );
259
260 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;
261 287
262 while (@arg) { 288 while (@arg) {
263 my $type = shift @arg; 289 my $type = shift @arg;
264 290
265 if ($type eq "prio") { 291 if ($type eq "prio") {
266 $prio = shift @arg; 292 $prio = shift @arg;
267 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
268 } elsif ($type eq "package") { 303 } elsif ($type eq "package") {
269 my $pkg = shift @arg; 304 my $pkg = shift @arg;
270 305
271 while (my ($name, $id) = each %cb_id) { 306 while (my ($name, $id) = each %cb_id) {
272 if (my $cb = $pkg->can ($name)) { 307 if (my $cb = $pkg->can ($name)) {
273 _attach_cb $registry, %undo, $id, $prio, $cb; 308 _attach_cb $registry, $id, $prio, $cb;
274 } 309 }
275 } 310 }
276 311
277 } elsif (exists $cb_id{$type}) { 312 } elsif (exists $cb_id{$type}) {
278 _attach_cb $registry, %undo, $cb_id{$type}, $prio, shift @arg; 313 _attach_cb $registry, $cb_id{$type}, $prio, shift @arg;
279 314
280 } elsif (ref $type) { 315 } elsif (ref $type) {
281 warn "attaching objects not supported, ignoring.\n"; 316 warn "attaching objects not supported, ignoring.\n";
282 317
283 } else { 318 } else {
284 shift @arg; 319 shift @arg;
285 warn "attach argument '$type' not supported, ignoring.\n"; 320 warn "attach argument '$type' not supported, ignoring.\n";
286 } 321 }
287 } 322 }
288
289 \%undo
290} 323}
291 324
292sub _attach_attachment { 325sub _object_attach {
293 my ($obj, $name, %arg) = @_; 326 my ($obj, $name, %arg) = @_;
294 327
295 return if exists $obj->{_attachment}{$name}; 328 return if exists $obj->{_attachment}{$name};
296
297 my $res;
298 329
299 if (my $attach = $attachment{$name}) { 330 if (my $attach = $attachment{$name}) {
300 my $registry = $obj->registry; 331 my $registry = $obj->registry;
301 332
302 for (@$attach) { 333 for (@$attach) {
303 my ($klass, @attach) = @$_; 334 my ($klass, @attach) = @$_;
304 $res = _attach @$registry, $klass, @attach; 335 _attach $registry, $klass, @attach;
305 } 336 }
306 337
307 $obj->{$name} = \%arg; 338 $obj->{$name} = \%arg;
308 } else { 339 } else {
309 warn "object uses attachment '$name' that is not available, postponing.\n"; 340 warn "object uses attachment '$name' that is not available, postponing.\n";
310 } 341 }
311 342
312 $obj->{_attachment}{$name} = undef; 343 $obj->{_attachment}{$name} = undef;
313
314 $res->{attachment} = $name;
315 $res
316} 344}
317 345
318*cf::object::attach = 346sub cf::attachable::attach {
319*cf::player::attach = 347 if (ref $_[0]) {
320*cf::map::attach = sub { 348 _object_attach @_;
321 my ($obj, $name, %arg) = @_; 349 } else {
322 350 _attach shift->_attach_registry, @_;
323 _attach_attachment $obj, $name, %arg; 351 }
324}; 352};
325 353
326# all those should be optimised 354# all those should be optimised
327*cf::object::detach = 355sub cf::attachable::detach {
328*cf::player::detach =
329*cf::map::detach = sub {
330 my ($obj, $name) = @_; 356 my ($obj, $name) = @_;
331 357
358 if (ref $obj) {
332 delete $obj->{_attachment}{$name}; 359 delete $obj->{_attachment}{$name};
333 reattach ($obj); 360 reattach ($obj);
361 } else {
362 Carp::croak "cannot, currently, detach class attachments";
363 }
334}; 364};
335 365
336*cf::object::attached = 366sub cf::attachable::attached {
337*cf::player::attached =
338*cf::map::attached = sub {
339 my ($obj, $name) = @_; 367 my ($obj, $name) = @_;
340 368
341 exists $obj->{_attachment}{$name} 369 exists $obj->{_attachment}{$name}
342};
343
344sub attach_global {
345 _attach @CB_GLOBAL, KLASS_GLOBAL, @_
346} 370}
347 371
348sub attach_to_type { 372for my $klass (qw(GLOBAL OBJECT PLAYER CLIENT MAP)) {
349 my $type = shift; 373 eval "#line " . __LINE__ . " 'cf.pm'
350 my $subtype = shift; 374 sub cf::\L$klass\E::_attach_registry {
375 (\\\@CB_$klass, KLASS_$klass)
376 }
351 377
352 _attach @{$CB_TYPE[$type + $subtype * NUM_SUBTYPES]}, KLASS_OBJECT, @_ 378 sub cf::\L$klass\E::attachment {
353}
354
355sub attach_to_objects {
356 _attach @CB_OBJECT, KLASS_OBJECT, @_
357}
358
359sub attach_to_players {
360 _attach @CB_PLAYER, KLASS_PLAYER, @_
361}
362
363sub attach_to_maps {
364 _attach @CB_MAP, KLASS_MAP, @_
365}
366
367sub register_attachment {
368 my $name = shift; 379 my \$name = shift;
369 380
370 $attachment{$name} = [[KLASS_OBJECT, @_]];
371}
372
373sub register_player_attachment {
374 my $name = shift;
375
376 $attachment{$name} = [[KLASS_PLAYER, @_]];
377}
378
379sub register_map_attachment {
380 my $name = shift;
381
382 $attachment{$name} = [[KLASS_MAP, @_]]; 381 \$attachment{\$name} = [[KLASS_$klass, \@_]];
382 }
383 ";
384 die if $@;
383} 385}
384 386
385our $override; 387our $override;
386our @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?
387 389
417 419
418=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...) 420=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...)
419 421
420=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...) 422=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...)
421 423
424=item $bool = $client->invoke (EVENT_CLIENT_XXX, ...)
425
422=item $bool = $map->invoke (EVENT_MAP_XXX, ...) 426=item $bool = $map->invoke (EVENT_MAP_XXX, ...)
423 427
424Generate a global/object/player/map-specific event with the given arguments. 428Generate a global/object/player/map-specific event with the given arguments.
425 429
426This 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
431 435
432=cut 436=cut
433 437
434############################################################################# 438#############################################################################
435 439
436=head2 METHODS VALID FOR ALL CORE OBJECTS 440=head2 METHODS VALID FOR ALL ATTACHABLE OBJECTS
441
442Attachable objects includes objects, players, clients and maps.
437 443
438=over 4 444=over 4
439 445
440=item $object->valid, $player->valid, $map->valid 446=item $object->valid
441 447
442Just 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
443C-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
444valid C counterpart anymore you get an exception at runtime. This method 450valid C counterpart anymore you get an exception at runtime. This method
445can 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
447 453
448=back 454=back
449 455
450=cut 456=cut
451 457
452*cf::object::valid =
453*cf::player::valid =
454*cf::map::valid = \&cf::_valid;
455
456############################################################################# 458#############################################################################
457# object support 459# object support
458 460
459sub instantiate { 461sub instantiate {
460 my ($obj, $data) = @_; 462 my ($obj, $data) = @_;
479 481
480 for my $name (keys %{ $obj->{_attachment} || {} }) { 482 for my $name (keys %{ $obj->{_attachment} || {} }) {
481 if (my $attach = $attachment{$name}) { 483 if (my $attach = $attachment{$name}) {
482 for (@$attach) { 484 for (@$attach) {
483 my ($klass, @attach) = @$_; 485 my ($klass, @attach) = @$_;
484 _attach @$registry, $klass, @attach; 486 _attach $registry, $klass, @attach;
485 } 487 }
486 } else { 488 } else {
487 warn "object uses attachment '$name' that is not available, postponing.\n"; 489 warn "object uses attachment '$name' that is not available, postponing.\n";
488 } 490 }
489 } 491 }
518 unlink $filename; 520 unlink $filename;
519 unlink "$filename.pst"; 521 unlink "$filename.pst";
520 } 522 }
521} 523}
522 524
525sub object_freezer_as_string {
526 my ($rdata, $objs) = @_;
527
528 use Data::Dumper;
529
530 $$rdata . Dumper $objs
531}
532
523sub object_thawer_load { 533sub object_thawer_load {
524 my ($filename) = @_; 534 my ($filename) = @_;
525 535
526 local $/; 536 local $/;
527 537
537 } 547 }
538 548
539 () 549 ()
540} 550}
541 551
542attach_to_objects 552cf::object->attach (
543 prio => -1000000, 553 prio => -1000000,
544 on_clone => sub { 554 on_clone => sub {
545 my ($src, $dst) = @_; 555 my ($src, $dst) = @_;
546 556
547 @{$dst->registry} = @{$src->registry}; 557 @{$dst->registry} = @{$src->registry};
549 %$dst = %$src; 559 %$dst = %$src;
550 560
551 %{$dst->{_attachment}} = %{$src->{_attachment}} 561 %{$dst->{_attachment}} = %{$src->{_attachment}}
552 if exists $src->{_attachment}; 562 if exists $src->{_attachment};
553 }, 563 },
554; 564);
555 565
556############################################################################# 566#############################################################################
557# old plug-in events 567# command handling &c
558 568
559sub inject_event { 569=item cf::register_command $name => \&callback($ob,$args);
560 my $extension = shift;
561 my $event_code = shift;
562 570
563 my $cb = $hook[$event_code]{$extension} 571Register a callback for execution when the client sends the user command
564 or return; 572$name.
565 573
566 &$cb 574=cut
567}
568
569sub inject_global_event {
570 my $event = shift;
571
572 my $cb = $hook[$event]
573 or return;
574
575 List::Util::max map &$_, values %$cb
576}
577
578sub inject_command {
579 my ($name, $obj, $params) = @_;
580
581 for my $cmd (@{ $command{$name} }) {
582 $cmd->[1]->($obj, $params);
583 }
584
585 -1
586}
587 575
588sub register_command { 576sub register_command {
589 my ($name, $time, $cb) = @_; 577 my ($name, $cb) = @_;
590 578
591 my $caller = caller; 579 my $caller = caller;
592 #warn "registering command '$name/$time' to '$caller'"; 580 #warn "registering command '$name/$time' to '$caller'";
593 581
594 push @{ $command{$name} }, [$time, $cb, $caller]; 582 push @{ $COMMAND{$name} }, [$caller, $cb];
595 $COMMAND{"$name\000"} = List::Util::max map $_->[0], @{ $command{$name} };
596} 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
597 593
598sub register_extcmd { 594sub register_extcmd {
599 my ($name, $cb) = @_; 595 my ($name, $cb) = @_;
600 596
601 my $caller = caller; 597 my $caller = caller;
602 #warn "registering extcmd '$name' to '$caller'"; 598 #warn "registering extcmd '$name' to '$caller'";
603 599
604 $extcmd{$name} = [$cb, $caller]; 600 $EXTCMD{$name} = [$cb, $caller];
605} 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);
606 634
607sub register { 635sub register {
608 my ($base, $pkg) = @_; 636 my ($base, $pkg) = @_;
609 637
610 #TODO 638 #TODO
629 . "#line 1 \"$path\"\n{\n" 657 . "#line 1 \"$path\"\n{\n"
630 . (do { local $/; <$fh> }) 658 . (do { local $/; <$fh> })
631 . "\n};\n1"; 659 . "\n};\n1";
632 660
633 eval $source 661 eval $source
634 or die "$path: $@"; 662 or die $@ ? "$path: $@\n"
663 : "extension disabled.\n";
635 664
636 push @exts, $pkg; 665 push @exts, $pkg;
637 $ext_pkg{$base} = $pkg; 666 $ext_pkg{$base} = $pkg;
638 667
639# no strict 'refs'; 668# no strict 'refs';
652# for my $idx (0 .. $#PLUGIN_EVENT) { 681# for my $idx (0 .. $#PLUGIN_EVENT) {
653# delete $hook[$idx]{$pkg}; 682# delete $hook[$idx]{$pkg};
654# } 683# }
655 684
656 # remove commands 685 # remove commands
657 for my $name (keys %command) { 686 for my $name (keys %COMMAND) {
658 my @cb = grep $_->[2] ne $pkg, @{ $command{$name} }; 687 my @cb = grep $_->[0] ne $pkg, @{ $COMMAND{$name} };
659 688
660 if (@cb) { 689 if (@cb) {
661 $command{$name} = \@cb; 690 $COMMAND{$name} = \@cb;
662 $COMMAND{"$name\000"} = List::Util::max map $_->[0], @cb;
663 } else { 691 } else {
664 delete $command{$name};
665 delete $COMMAND{"$name\000"}; 692 delete $COMMAND{$name};
666 } 693 }
667 } 694 }
668 695
669 # remove extcmds 696 # remove extcmds
670 for my $name (grep $extcmd{$_}[1] eq $pkg, keys %extcmd) { 697 for my $name (grep $EXTCMD{$_}[1] eq $pkg, keys %EXTCMD) {
671 delete $extcmd{$name}; 698 delete $EXTCMD{$name};
672 } 699 }
673 700
674 if (my $cb = $pkg->can ("unload")) { 701 if (my $cb = $pkg->can ("unload")) {
675 eval { 702 eval {
676 $cb->($pkg); 703 $cb->($pkg);
680 707
681 Symbol::delete_package $pkg; 708 Symbol::delete_package $pkg;
682} 709}
683 710
684sub load_extensions { 711sub load_extensions {
685 my $LIBDIR = maps_directory "perl";
686
687 for my $ext (<$LIBDIR/*.ext>) { 712 for my $ext (<$LIBDIR/*.ext>) {
688 next unless -r $ext; 713 next unless -r $ext;
689 eval { 714 eval {
690 load_extension $ext; 715 load_extension $ext;
691 1 716 1
692 } or warn "$ext not loaded: $@"; 717 } or warn "$ext not loaded: $@";
693 } 718 }
694} 719}
695 720
696############################################################################# 721#############################################################################
697# extcmd framework, basically convert ext <msg>
698# into pkg::->on_extcmd_arg1 (...) while shortcutting a few
699
700attach_to_players
701 on_extcmd => sub {
702 my ($pl, $buf) = @_;
703
704 my $msg = eval { from_json $buf };
705
706 if (ref $msg) {
707 if (my $cb = $extcmd{$msg->{msgtype}}) {
708 if (my %reply = $cb->[0]->($pl, $msg)) {
709 $pl->ext_reply ($msg->{msgid}, %reply);
710 }
711 }
712 } else {
713 warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
714 }
715
716 cf::override;
717 },
718;
719
720#############################################################################
721# load/save/clean perl data associated with a map 722# load/save/clean perl data associated with a map
722 723
723*cf::mapsupport::on_clean = sub { 724*cf::mapsupport::on_clean = sub {
724 my ($map) = @_; 725 my ($map) = @_;
725 726
727 defined $path or return; 728 defined $path or return;
728 729
729 unlink "$path.pst"; 730 unlink "$path.pst";
730}; 731};
731 732
732attach_to_maps prio => -10000, package => cf::mapsupport::; 733cf::map->attach (prio => -10000, package => cf::mapsupport::);
733 734
734############################################################################# 735#############################################################################
735# load/save perl data associated with player->ob objects 736# load/save perl data associated with player->ob objects
736 737
737sub all_objects(@) { 738sub all_objects(@) {
738 @_, map all_objects ($_->inv), @_ 739 @_, map all_objects ($_->inv), @_
739} 740}
740 741
741# TODO: compatibility cruft, remove when no longer needed 742# TODO: compatibility cruft, remove when no longer needed
742attach_to_players 743cf::player->attach (
743 on_load => sub { 744 on_load => sub {
744 my ($pl, $path) = @_; 745 my ($pl, $path) = @_;
745 746
746 for my $o (all_objects $pl->ob) { 747 for my $o (all_objects $pl->ob) {
747 if (my $value = $o->get_ob_key_value ("_perl_data")) { 748 if (my $value = $o->get_ob_key_value ("_perl_data")) {
749 750
750 %$o = %{ Storable::thaw pack "H*", $value }; 751 %$o = %{ Storable::thaw pack "H*", $value };
751 } 752 }
752 } 753 }
753 }, 754 },
754; 755);
755 756
756############################################################################# 757#############################################################################
757 758
758=head2 CORE EXTENSIONS 759=head2 CORE EXTENSIONS
759 760
770sub cf::player::exists($) { 771sub cf::player::exists($) {
771 cf::player::find $_[0] 772 cf::player::find $_[0]
772 or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2; 773 or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2;
773} 774}
774 775
775=item $player->reply ($npc, $msg[, $flags]) 776=item $player_object->reply ($npc, $msg[, $flags])
776 777
777Sends a message to the player, as if the npc C<$npc> replied. C<$npc> 778Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
778can be C<undef>. Does the right thing when the player is currently in a 779can be C<undef>. Does the right thing when the player is currently in a
779dialogue with the given NPC character. 780dialogue with the given NPC character.
780 781
807 $msg{msgid} = $id; 808 $msg{msgid} = $id;
808 809
809 $self->send ("ext " . to_json \%msg); 810 $self->send ("ext " . to_json \%msg);
810} 811}
811 812
812=back 813=item $player_object->may ("access")
814
815Returns wether the given player is authorized to access resource "access"
816(e.g. "command_wizcast").
817
818=cut
819
820sub cf::object::player::may {
821 my ($self, $access) = @_;
822
823 $self->flag (cf::FLAG_WIZ) ||
824 (ref $cf::CFG{"may_$access"}
825 ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
826 : $cf::CFG{"may_$access"})
827}
813 828
814=cut 829=cut
815 830
816############################################################################# 831#############################################################################
817 832
819 834
820Functions that provide a safe environment to compile and execute 835Functions that provide a safe environment to compile and execute
821snippets of perl code without them endangering the safety of the server 836snippets of perl code without them endangering the safety of the server
822itself. Looping constructs, I/O operators and other built-in functionality 837itself. Looping constructs, I/O operators and other built-in functionality
823is not available in the safe scripting environment, and the number of 838is not available in the safe scripting environment, and the number of
824functions and methods that cna be called is greatly reduced. 839functions and methods that can be called is greatly reduced.
825 840
826=cut 841=cut
827 842
828our $safe = new Safe "safe"; 843our $safe = new Safe "safe";
829our $safe_hole = new Safe::Hole; 844our $safe_hole = new Safe::Hole;
836 851
837=pod 852=pod
838 853
839The following fucntions and emthods are available within a safe environment: 854The following fucntions and emthods are available within a safe environment:
840 855
841 cf::object contr pay_amount pay_player 856 cf::object contr pay_amount pay_player map
842 cf::object::player player 857 cf::object::player player
843 cf::player peaceful 858 cf::player peaceful
859 cf::map trigger
844 860
845=cut 861=cut
846 862
847for ( 863for (
848 ["cf::object" => qw(contr pay_amount pay_player)], 864 ["cf::object" => qw(contr pay_amount pay_player map)],
849 ["cf::object::player" => qw(player)], 865 ["cf::object::player" => qw(player)],
850 ["cf::player" => qw(peaceful)], 866 ["cf::player" => qw(peaceful)],
867 ["cf::map" => qw(trigger)],
851) { 868) {
852 no strict 'refs'; 869 no strict 'refs';
853 my ($pkg, @funs) = @$_; 870 my ($pkg, @funs) = @$_;
854 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"}) 871 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
855 for @funs; 872 for @funs;
965 982
966Immediately write the database to disk I<if it is dirty>. 983Immediately write the database to disk I<if it is dirty>.
967 984
968=cut 985=cut
969 986
987our $DB;
988
970{ 989{
971 my $db;
972 my $path = cf::localdir . "/database.pst"; 990 my $path = cf::localdir . "/database.pst";
973 991
974 sub db_load() { 992 sub db_load() {
975 warn "loading database $path\n";#d# remove later 993 warn "loading database $path\n";#d# remove later
976 $db = stat $path ? Storable::retrieve $path : { }; 994 $DB = stat $path ? Storable::retrieve $path : { };
977 } 995 }
978 996
979 my $pid; 997 my $pid;
980 998
981 sub db_save() { 999 sub db_save() {
982 warn "saving database $path\n";#d# remove later 1000 warn "saving database $path\n";#d# remove later
983 waitpid $pid, 0 if $pid; 1001 waitpid $pid, 0 if $pid;
984 if (0 == ($pid = fork)) { 1002 if (0 == ($pid = fork)) {
985 $db->{_meta}{version} = 1; 1003 $DB->{_meta}{version} = 1;
986 Storable::nstore $db, "$path~"; 1004 Storable::nstore $DB, "$path~";
987 rename "$path~", $path; 1005 rename "$path~", $path;
988 cf::_exit 0 if defined $pid; 1006 cf::_exit 0 if defined $pid;
989 } 1007 }
990 } 1008 }
991 1009
994 sub db_sync() { 1012 sub db_sync() {
995 db_save if $dirty; 1013 db_save if $dirty;
996 undef $dirty; 1014 undef $dirty;
997 } 1015 }
998 1016
999 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 {
1000 db_sync; 1018 db_sync;
1001 }); 1019 });
1002 1020
1003 sub db_dirty() { 1021 sub db_dirty() {
1004 $dirty = 1; 1022 $dirty = 1;
1005 $idle->start; 1023 $idle->start;
1006 } 1024 }
1007 1025
1008 sub db_get($;$) { 1026 sub db_get($;$) {
1009 @_ >= 2 1027 @_ >= 2
1010 ? $db->{$_[0]}{$_[1]} 1028 ? $DB->{$_[0]}{$_[1]}
1011 : ($db->{$_[0]} ||= { }) 1029 : ($DB->{$_[0]} ||= { })
1012 } 1030 }
1013 1031
1014 sub db_put($$;$) { 1032 sub db_put($$;$) {
1015 if (@_ >= 3) { 1033 if (@_ >= 3) {
1016 $db->{$_[0]}{$_[1]} = $_[2]; 1034 $DB->{$_[0]}{$_[1]} = $_[2];
1017 } else { 1035 } else {
1018 $db->{$_[0]} = $_[1]; 1036 $DB->{$_[0]} = $_[1];
1019 } 1037 }
1020 db_dirty; 1038 db_dirty;
1021 } 1039 }
1022 1040
1023 attach_global 1041 cf::global->attach (
1024 prio => 10000, 1042 prio => 10000,
1025 on_cleanup => sub { 1043 on_cleanup => sub {
1026 db_sync; 1044 db_sync;
1027 }, 1045 },
1028 ; 1046 );
1029} 1047}
1030 1048
1031############################################################################# 1049#############################################################################
1032# the server's main() 1050# the server's main()
1033 1051
1054 1072
1055 $msg->("reloading..."); 1073 $msg->("reloading...");
1056 1074
1057 eval { 1075 eval {
1058 # cancel all watchers 1076 # cancel all watchers
1059 $_->cancel for Event::all_watchers; 1077 for (Event::all_watchers) {
1078 $_->cancel if $_->data & WF_AUTOCANCEL;
1079 }
1060 1080
1061 # unload all extensions 1081 # unload all extensions
1062 for (@exts) { 1082 for (@exts) {
1063 $msg->("unloading <$_>"); 1083 $msg->("unloading <$_>");
1064 unload_extension $_; 1084 unload_extension $_;
1124 warn $_[0]; 1144 warn $_[0];
1125 print "$_[0]\n"; 1145 print "$_[0]\n";
1126 }; 1146 };
1127} 1147}
1128 1148
1149register "<global>", __PACKAGE__;
1150
1129register_command "perl-reload", 0, sub { 1151register_command "perl-reload" => sub {
1130 my ($who, $arg) = @_; 1152 my ($who, $arg) = @_;
1131 1153
1132 if ($who->flag (FLAG_WIZ)) { 1154 if ($who->flag (FLAG_WIZ)) {
1133 _perl_reload { 1155 _perl_reload {
1134 warn $_[0]; 1156 warn $_[0];
1135 $who->message ($_[0]); 1157 $who->message ($_[0]);
1136 }; 1158 };
1137 } 1159 }
1138}; 1160};
1139 1161
1140register "<global>", __PACKAGE__;
1141
1142unshift @INC, $LIBDIR; 1162unshift @INC, $LIBDIR;
1143 1163
1144$TICK_WATCHER = Event->timer ( 1164$TICK_WATCHER = Event->timer (
1145 prio => 1, 1165 prio => 0,
1146 at => $NEXT_TICK || 1, 1166 at => $NEXT_TICK || 1,
1167 data => WF_AUTOCANCEL,
1147 cb => sub { 1168 cb => sub {
1148 cf::server_tick; # one server iteration 1169 cf::server_tick; # one server iteration
1149 1170
1150 my $NOW = Event::time; 1171 my $NOW = Event::time;
1151 $NEXT_TICK += $TICK; 1172 $NEXT_TICK += $TICK;
1152 1173
1153 # if we are delayed by four ticks, skip them all 1174 # if we are delayed by four ticks or more, skip them all
1154 $NEXT_TICK = $NOW if $NOW >= $NEXT_TICK + $TICK * 4; 1175 $NEXT_TICK = $NOW if $NOW >= $NEXT_TICK + $TICK * 4;
1155 1176
1156 $TICK_WATCHER->at ($NEXT_TICK); 1177 $TICK_WATCHER->at ($NEXT_TICK);
1157 $TICK_WATCHER->start; 1178 $TICK_WATCHER->start;
1158 }, 1179 },
1159); 1180);
1160 1181
1182IO::AIO::max_poll_time $TICK * 0.2;
1183
1184Event->io (fd => IO::AIO::poll_fileno,
1185 poll => 'r',
1186 prio => 5,
1187 data => WF_AUTOCANCEL,
1188 cb => \&IO::AIO::poll_cb);
1189
11611 11901
1162 1191

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines