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.95 by root, Fri Dec 22 02:04:20 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
764Functions and methods that extend core crossfire objects. 761Functions and methods that extend core crossfire objects.
762
763=head3 cf::player
765 764
766=over 4 765=over 4
767 766
768=item cf::player::exists $login 767=item cf::player::exists $login
769 768
774sub cf::player::exists($) { 773sub cf::player::exists($) {
775 cf::player::find $_[0] 774 cf::player::find $_[0]
776 or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2; 775 or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2;
777} 776}
778 777
778=item $player->ext_reply ($msgid, $msgtype, %msg)
779
780Sends an ext reply to the player.
781
782=cut
783
784sub cf::player::ext_reply($$$%) {
785 my ($self, $id, %msg) = @_;
786
787 $msg{msgid} = $id;
788
789 $self->send ("ext " . to_json \%msg);
790}
791
792=back
793
794=head3 cf::object::player
795
796=over 4
797
779=item $object->reply ($npc, $msg[, $flags]) 798=item $player_object->reply ($npc, $msg[, $flags])
780 799
781Sends a message to the player, as if the npc C<$npc> replied. C<$npc> 800Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
782can be C<undef>. Does the right thing when the player is currently in a 801can be C<undef>. Does the right thing when the player is currently in a
783dialogue with the given NPC character. 802dialogue with the given NPC character.
784 803
785=cut 804=cut
786 805
787# rough implementation of a future "reply" method that works 806# rough implementation of a future "reply" method that works
788# with dialog boxes. 807# with dialog boxes.
808#TODO: the first argument must go, split into a $npc->reply_to ( method
789sub cf::object::player::reply($$$;$) { 809sub cf::object::player::reply($$$;$) {
790 my ($self, $npc, $msg, $flags) = @_; 810 my ($self, $npc, $msg, $flags) = @_;
791 811
792 $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4; 812 $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
793 813
797 $msg = $npc->name . " says: $msg" if $npc; 817 $msg = $npc->name . " says: $msg" if $npc;
798 $self->message ($msg, $flags); 818 $self->message ($msg, $flags);
799 } 819 }
800} 820}
801 821
802=item $player->ext_reply ($msgid, $msgtype, %msg) 822=item $player_object->may ("access")
803 823
804Sends an ext reply to the player. 824Returns wether the given player is authorized to access resource "access"
825(e.g. "command_wizcast").
805 826
806=cut 827=cut
807 828
808sub cf::player::ext_reply($$$%) { 829sub cf::object::player::may {
809 my ($self, $id, %msg) = @_; 830 my ($self, $access) = @_;
810 831
811 $msg{msgid} = $id; 832 $self->flag (cf::FLAG_WIZ) ||
812 833 (ref $cf::CFG{"may_$access"}
813 $self->send ("ext " . to_json \%msg); 834 ? scalar grep $self->name eq $_, @{$cf::CFG{"may_$access"}}
835 : $cf::CFG{"may_$access"})
814} 836}
837
838=head3 cf::client
839
840=over 4
841
842=item $client->send_drawinfo ($text, $flags)
843
844Sends a drawinfo packet to the client. Circumvents output buffering so
845should not be used under normal circumstances.
846
847=cut
848
849sub cf::client::send_drawinfo {
850 my ($self, $text, $flags) = @_;
851
852 utf8::encode $text;
853 $self->send_packet (sprintf "drawinfo %d %s", $flags, $text);
854}
855
856
857=item $success = $client->query ($flags, "text", \&cb)
858
859Queues a query to the client, calling the given callback with
860the reply text on a reply. flags can be C<cf::CS_QUERY_YESNO>,
861C<cf::CS_QUERY_SINGLECHAR> or C<cf::CS_QUERY_HIDEINPUT> or C<0>.
862
863Queries can fail, so check the return code. Or don't, as queries will become
864reliable at some point in the future.
865
866=cut
867
868sub cf::client::query {
869 my ($self, $flags, $text, $cb) = @_;
870
871 return unless $self->state == ST_PLAYING
872 || $self->state == ST_SETUP
873 || $self->state == ST_CUSTOM;
874
875 $self->state (ST_CUSTOM);
876
877 utf8::encode $text;
878 push @{ $self->{query_queue} }, [(sprintf "query %d %s", $flags, $text), $cb];
879
880 $self->send_packet ($self->{query_queue}[0][0])
881 if @{ $self->{query_queue} } == 1;
882}
883
884cf::client->attach (
885 on_reply => sub {
886 my ($ns, $msg) = @_;
887
888 # this weird shuffling is so that direct followup queries
889 # get handled first
890 my $queue = delete $ns->{query_queue};
891
892 (shift @$queue)->[1]->($msg);
893
894 push @{ $ns->{query_queue} }, @$queue;
895
896 if (@{ $ns->{query_queue} } == @$queue) {
897 if (@$queue) {
898 $ns->send_packet ($ns->{query_queue}[0][0]);
899 } else {
900 $ns->state (ST_PLAYING);
901 }
902 }
903 },
904);
815 905
816=back 906=back
817 907
818=cut
819
820#############################################################################
821 908
822=head2 SAFE SCRIPTING 909=head2 SAFE SCRIPTING
823 910
824Functions that provide a safe environment to compile and execute 911Functions that provide a safe environment to compile and execute
825snippets of perl code without them endangering the safety of the server 912snippets of perl code without them endangering the safety of the server
826itself. Looping constructs, I/O operators and other built-in functionality 913itself. Looping constructs, I/O operators and other built-in functionality
827is not available in the safe scripting environment, and the number of 914is not available in the safe scripting environment, and the number of
828functions and methods that cna be called is greatly reduced. 915functions and methods that can be called is greatly reduced.
829 916
830=cut 917=cut
831 918
832our $safe = new Safe "safe"; 919our $safe = new Safe "safe";
833our $safe_hole = new Safe::Hole; 920our $safe_hole = new Safe::Hole;
840 927
841=pod 928=pod
842 929
843The following fucntions and emthods are available within a safe environment: 930The following fucntions and emthods are available within a safe environment:
844 931
845 cf::object contr pay_amount pay_player 932 cf::object contr pay_amount pay_player map
846 cf::object::player player 933 cf::object::player player
847 cf::player peaceful 934 cf::player peaceful
935 cf::map trigger
848 936
849=cut 937=cut
850 938
851for ( 939for (
852 ["cf::object" => qw(contr pay_amount pay_player)], 940 ["cf::object" => qw(contr pay_amount pay_player map)],
853 ["cf::object::player" => qw(player)], 941 ["cf::object::player" => qw(player)],
854 ["cf::player" => qw(peaceful)], 942 ["cf::player" => qw(peaceful)],
943 ["cf::map" => qw(trigger)],
855) { 944) {
856 no strict 'refs'; 945 no strict 'refs';
857 my ($pkg, @funs) = @$_; 946 my ($pkg, @funs) = @$_;
858 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"}) 947 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
859 for @funs; 948 for @funs;
969 1058
970Immediately write the database to disk I<if it is dirty>. 1059Immediately write the database to disk I<if it is dirty>.
971 1060
972=cut 1061=cut
973 1062
1063our $DB;
1064
974{ 1065{
975 my $db;
976 my $path = cf::localdir . "/database.pst"; 1066 my $path = cf::localdir . "/database.pst";
977 1067
978 sub db_load() { 1068 sub db_load() {
979 warn "loading database $path\n";#d# remove later 1069 warn "loading database $path\n";#d# remove later
980 $db = stat $path ? Storable::retrieve $path : { }; 1070 $DB = stat $path ? Storable::retrieve $path : { };
981 } 1071 }
982 1072
983 my $pid; 1073 my $pid;
984 1074
985 sub db_save() { 1075 sub db_save() {
986 warn "saving database $path\n";#d# remove later 1076 warn "saving database $path\n";#d# remove later
987 waitpid $pid, 0 if $pid; 1077 waitpid $pid, 0 if $pid;
988 if (0 == ($pid = fork)) { 1078 if (0 == ($pid = fork)) {
989 $db->{_meta}{version} = 1; 1079 $DB->{_meta}{version} = 1;
990 Storable::nstore $db, "$path~"; 1080 Storable::nstore $DB, "$path~";
991 rename "$path~", $path; 1081 rename "$path~", $path;
992 cf::_exit 0 if defined $pid; 1082 cf::_exit 0 if defined $pid;
993 } 1083 }
994 } 1084 }
995 1085
998 sub db_sync() { 1088 sub db_sync() {
999 db_save if $dirty; 1089 db_save if $dirty;
1000 undef $dirty; 1090 undef $dirty;
1001 } 1091 }
1002 1092
1003 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, cb => sub { 1093 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, data => WF_AUTOCANCEL, cb => sub {
1004 db_sync; 1094 db_sync;
1005 }); 1095 });
1006 1096
1007 sub db_dirty() { 1097 sub db_dirty() {
1008 $dirty = 1; 1098 $dirty = 1;
1009 $idle->start; 1099 $idle->start;
1010 } 1100 }
1011 1101
1012 sub db_get($;$) { 1102 sub db_get($;$) {
1013 @_ >= 2 1103 @_ >= 2
1014 ? $db->{$_[0]}{$_[1]} 1104 ? $DB->{$_[0]}{$_[1]}
1015 : ($db->{$_[0]} ||= { }) 1105 : ($DB->{$_[0]} ||= { })
1016 } 1106 }
1017 1107
1018 sub db_put($$;$) { 1108 sub db_put($$;$) {
1019 if (@_ >= 3) { 1109 if (@_ >= 3) {
1020 $db->{$_[0]}{$_[1]} = $_[2]; 1110 $DB->{$_[0]}{$_[1]} = $_[2];
1021 } else { 1111 } else {
1022 $db->{$_[0]} = $_[1]; 1112 $DB->{$_[0]} = $_[1];
1023 } 1113 }
1024 db_dirty; 1114 db_dirty;
1025 } 1115 }
1026 1116
1027 attach_global 1117 cf::global->attach (
1028 prio => 10000, 1118 prio => 10000,
1029 on_cleanup => sub { 1119 on_cleanup => sub {
1030 db_sync; 1120 db_sync;
1031 }, 1121 },
1032 ; 1122 );
1033} 1123}
1034 1124
1035############################################################################# 1125#############################################################################
1036# the server's main() 1126# the server's main()
1037 1127
1058 1148
1059 $msg->("reloading..."); 1149 $msg->("reloading...");
1060 1150
1061 eval { 1151 eval {
1062 # cancel all watchers 1152 # cancel all watchers
1063 $_->cancel for Event::all_watchers; 1153 for (Event::all_watchers) {
1154 $_->cancel if $_->data & WF_AUTOCANCEL;
1155 }
1064 1156
1065 # unload all extensions 1157 # unload all extensions
1066 for (@exts) { 1158 for (@exts) {
1067 $msg->("unloading <$_>"); 1159 $msg->("unloading <$_>");
1068 unload_extension $_; 1160 unload_extension $_;
1128 warn $_[0]; 1220 warn $_[0];
1129 print "$_[0]\n"; 1221 print "$_[0]\n";
1130 }; 1222 };
1131} 1223}
1132 1224
1225register "<global>", __PACKAGE__;
1226
1133register_command "perl-reload", 0, sub { 1227register_command "perl-reload" => sub {
1134 my ($who, $arg) = @_; 1228 my ($who, $arg) = @_;
1135 1229
1136 if ($who->flag (FLAG_WIZ)) { 1230 if ($who->flag (FLAG_WIZ)) {
1137 _perl_reload { 1231 _perl_reload {
1138 warn $_[0]; 1232 warn $_[0];
1139 $who->message ($_[0]); 1233 $who->message ($_[0]);
1140 }; 1234 };
1141 } 1235 }
1142}; 1236};
1143 1237
1144register "<global>", __PACKAGE__;
1145
1146unshift @INC, $LIBDIR; 1238unshift @INC, $LIBDIR;
1147 1239
1148$TICK_WATCHER = Event->timer ( 1240$TICK_WATCHER = Event->timer (
1149 prio => 1, 1241 prio => 0,
1150 at => $NEXT_TICK || 1, 1242 at => $NEXT_TICK || 1,
1243 data => WF_AUTOCANCEL,
1151 cb => sub { 1244 cb => sub {
1152 cf::server_tick; # one server iteration 1245 cf::server_tick; # one server iteration
1153 1246
1154 my $NOW = Event::time; 1247 my $NOW = Event::time;
1155 $NEXT_TICK += $TICK; 1248 $NEXT_TICK += $TICK;
1156 1249
1157 # if we are delayed by four ticks, skip them all 1250 # if we are delayed by four ticks or more, skip them all
1158 $NEXT_TICK = $NOW if $NOW >= $NEXT_TICK + $TICK * 4; 1251 $NEXT_TICK = $NOW if $NOW >= $NEXT_TICK + $TICK * 4;
1159 1252
1160 $TICK_WATCHER->at ($NEXT_TICK); 1253 $TICK_WATCHER->at ($NEXT_TICK);
1161 $TICK_WATCHER->start; 1254 $TICK_WATCHER->start;
1162 }, 1255 },
1163); 1256);
1164 1257
1258IO::AIO::max_poll_time $TICK * 0.2;
1259
1260Event->io (fd => IO::AIO::poll_fileno,
1261 poll => 'r',
1262 prio => 5,
1263 data => WF_AUTOCANCEL,
1264 cb => \&IO::AIO::poll_cb);
1265
11651 12661
1166 1267

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines