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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines