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.87 by root, Thu Dec 14 22:45:40 2006 UTC vs.
Revision 1.93 by root, Thu Dec 21 22:41:35 2006 UTC

25our %EXTCMD = (); 25our %EXTCMD = ();
26 26
27_init_vars; 27_init_vars;
28 28
29our @EVENT; 29our @EVENT;
30our $LIBDIR = maps_directory "perl"; 30our $LIBDIR = datadir . "/ext";
31 31
32our $TICK = MAX_TIME * 1e-6; 32our $TICK = MAX_TIME * 1e-6;
33our $TICK_WATCHER; 33our $TICK_WATCHER;
34our $NEXT_TICK; 34our $NEXT_TICK;
35 35
74 print STDERR "cfperl: $msg"; 74 print STDERR "cfperl: $msg";
75 LOG llevError, "cfperl: $msg"; 75 LOG llevError, "cfperl: $msg";
76 }; 76 };
77} 77}
78 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';
79@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object'; 84@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
80 85
81# 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
82# within the Safe compartment. 87# within the Safe compartment.
83for my $pkg (qw( 88for my $pkg (qw(
89 cf::global
84 cf::object cf::object::player 90 cf::object cf::object::player
85 cf::client_socket cf::player 91 cf::client cf::player
86 cf::arch cf::living 92 cf::arch cf::living
87 cf::map cf::party cf::region 93 cf::map cf::party cf::region
88)) { 94)) {
89 no strict 'refs'; 95 no strict 'refs';
90 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg; 96 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
132 138
133=cut 139=cut
134 140
135############################################################################# 141#############################################################################
136 142
137=head2 EVENTS AND OBJECT ATTACHMENTS 143=head2 ATTACHABLE OBJECTS
144
145You can define and attach attachments to each "attachable" object in
146crossfire+ (objects, players, clients, maps and the special "global"
147class). In the following description, CLASS can be any of C<global>,
148C<object> C<player>, C<client> or C<map>.
138 149
139=over 4 150=over 4
140 151
141=item $object->attach ($attachment, key => $value...) 152=item cf::CLASS::attachment $name, ...
142 153
143=item $object->detach ($attachment) 154Register an attachment by name through which attachable objects can refer
155to this attachment.
144 156
145Attach/detach a pre-registered attachment to an object.
146
147=item $player->attach ($attachment, key => $value...)
148
149=item $player->detach ($attachment)
150
151Attach/detach a pre-registered attachment to a player.
152
153=item $map->attach ($attachment, key => $value...)
154
155=item $map->detach ($attachment)
156
157Attach/detach a pre-registered attachment to a map.
158
159=item $bool = $object->attached ($name)
160
161=item $bool = $player->attached ($name)
162
163=item $bool = $map->attached ($name) 157=item $bool = $attachable->attached ($name)
164 158
165Checks wether the named attachment is currently attached to the object. 159Checks wether the named attachment is currently attached to the object.
166 160
167=item cf::attach_global ... 161=item $attachable->attach ($attachment, key => $value...)
168 162
169Attach handlers for global events. 163=item $attachable->detach ($attachment)
170 164
171This and all following C<attach_*>-functions expect any number of the 165Attach/detach a pre-registered attachment either to a specific object
172following handler/hook descriptions: 166(C<$attachable>) or all objects of the given class (if C<$attachable> is a
167class in a static method call).
168
169You can attach to global events by using the C<cf::global> class.
170
171These method calls expect any number of the following handler/hook
172descriptions:
173 173
174=over 4 174=over 4
175 175
176=item prio => $number 176=item prio => $number
177 177
179by another C<prio> setting). Lower priority handlers get executed 179by another C<prio> setting). Lower priority handlers get executed
180earlier. The default priority is C<0>, and many built-in handlers are 180earlier. The default priority is C<0>, and many built-in handlers are
181registered at priority C<-1000>, so lower priorities should not be used 181registered at priority C<-1000>, so lower priorities should not be used
182unless you know what you are doing. 182unless you know what you are doing.
183 183
184=item type => $type
185
186(Only for C<< cf::object->attach >> calls), limits the attachment to the
187given type of objects only (the additional parameter C<subtype> can be
188used to further limit to the given subtype).
189
184=item on_I<event> => \&cb 190=item on_I<event> => \&cb
185 191
186Call the given code reference whenever the named event happens (event is 192Call the given code reference whenever the named event happens (event is
187something like C<instantiate>, C<apply>, C<use_skill> and so on, and which 193something like C<instantiate>, C<apply>, C<use_skill> and so on, and which
188handlers are recognised generally depends on the type of object these 194handlers are recognised generally depends on the type of object these
197package and register them. Only handlers for eevents supported by the 203package and register them. Only handlers for eevents supported by the
198object/class are recognised. 204object/class are recognised.
199 205
200=back 206=back
201 207
202=item cf::attach_to_type $object_type, $subtype, ...
203
204Attach handlers for a specific object type (e.g. TRANSPORT) and
205subtype. If C<$subtype> is zero or undef, matches all objects of the given
206type.
207
208=item cf::attach_to_objects ...
209
210Attach handlers to all objects. Do not use this except for debugging or
211very rare events, as handlers are (obviously) called for I<all> objects in
212the game.
213
214=item cf::attach_to_players ...
215
216Attach handlers to all players.
217
218=item cf::attach_to_maps ...
219
220Attach handlers to all maps.
221
222=item cf:register_attachment $name, ...
223
224Register an attachment by name through which objects can refer to this
225attachment.
226
227=item cf:register_player_attachment $name, ...
228
229Register an attachment by name through which players can refer to this
230attachment.
231
232=item cf:register_map_attachment $name, ...
233
234Register an attachment by name through which maps can refer to this
235attachment.
236
237=cut 208=cut
238 209
239# the following variables are defined in .xs and must not be re-created 210# the following variables are defined in .xs and must not be re-created
240our @CB_GLOBAL = (); # registry for all global events 211our @CB_GLOBAL = (); # registry for all global events
241our @CB_OBJECT = (); # all objects (should not be used except in emergency) 212our @CB_OBJECT = (); # all objects (should not be used except in emergency)
242our @CB_PLAYER = (); 213our @CB_PLAYER = ();
214our @CB_CLIENT = ();
243our @CB_TYPE = (); # registry for type (cf-object class) based events 215our @CB_TYPE = (); # registry for type (cf-object class) based events
244our @CB_MAP = (); 216our @CB_MAP = ();
245 217
246my %attachment; 218my %attachment;
247 219
248sub _attach_cb($\%$$$) { 220sub _attach_cb($$$$) {
249 my ($registry, $undo, $event, $prio, $cb) = @_; 221 my ($registry, $event, $prio, $cb) = @_;
250 222
251 use sort 'stable'; 223 use sort 'stable';
252 224
253 $cb = [$prio, $cb]; 225 $cb = [$prio, $cb];
254 226
255 @{$registry->[$event]} = sort 227 @{$registry->[$event]} = sort
256 { $a->[0] cmp $b->[0] } 228 { $a->[0] cmp $b->[0] }
257 @{$registry->[$event] || []}, $cb; 229 @{$registry->[$event] || []}, $cb;
258
259 push @{$undo->{cb}}, [$event, $cb];
260} 230}
261 231
262# attach handles attaching event callbacks 232# attach handles attaching event callbacks
263# the only thing the caller has to do is pass the correct 233# the only thing the caller has to do is pass the correct
264# registry (== where the callback attaches to). 234# registry (== where the callback attaches to).
265sub _attach(\@$@) { 235sub _attach {
266 my ($registry, $klass, @arg) = @_; 236 my ($registry, $klass, @arg) = @_;
267 237
238 my $object_type;
268 my $prio = 0; 239 my $prio = 0;
269
270 my %undo = (
271 registry => $registry,
272 cb => [],
273 );
274
275 my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT; 240 my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
276 241
277 while (@arg) { 242 while (@arg) {
278 my $type = shift @arg; 243 my $type = shift @arg;
279 244
280 if ($type eq "prio") { 245 if ($type eq "prio") {
281 $prio = shift @arg; 246 $prio = shift @arg;
282 247
248 } elsif ($type eq "type") {
249 $object_type = shift @arg;
250 $registry = $CB_TYPE[$object_type] ||= [];
251
252 } elsif ($type eq "subtype") {
253 defined $object_type or Carp::croak "subtype specified without type";
254 my $object_subtype = shift @arg;
255 $registry = $CB_TYPE[$object_type + $object_subtype * NUM_SUBTYPES] ||= [];
256
283 } elsif ($type eq "package") { 257 } elsif ($type eq "package") {
284 my $pkg = shift @arg; 258 my $pkg = shift @arg;
285 259
286 while (my ($name, $id) = each %cb_id) { 260 while (my ($name, $id) = each %cb_id) {
287 if (my $cb = $pkg->can ($name)) { 261 if (my $cb = $pkg->can ($name)) {
288 _attach_cb $registry, %undo, $id, $prio, $cb; 262 _attach_cb $registry, $id, $prio, $cb;
289 } 263 }
290 } 264 }
291 265
292 } elsif (exists $cb_id{$type}) { 266 } elsif (exists $cb_id{$type}) {
293 _attach_cb $registry, %undo, $cb_id{$type}, $prio, shift @arg; 267 _attach_cb $registry, $cb_id{$type}, $prio, shift @arg;
294 268
295 } elsif (ref $type) { 269 } elsif (ref $type) {
296 warn "attaching objects not supported, ignoring.\n"; 270 warn "attaching objects not supported, ignoring.\n";
297 271
298 } else { 272 } else {
299 shift @arg; 273 shift @arg;
300 warn "attach argument '$type' not supported, ignoring.\n"; 274 warn "attach argument '$type' not supported, ignoring.\n";
301 } 275 }
302 } 276 }
303
304 \%undo
305} 277}
306 278
307sub _attach_attachment { 279sub _object_attach {
308 my ($obj, $name, %arg) = @_; 280 my ($obj, $name, %arg) = @_;
309 281
310 return if exists $obj->{_attachment}{$name}; 282 return if exists $obj->{_attachment}{$name};
311
312 my $res;
313 283
314 if (my $attach = $attachment{$name}) { 284 if (my $attach = $attachment{$name}) {
315 my $registry = $obj->registry; 285 my $registry = $obj->registry;
316 286
317 for (@$attach) { 287 for (@$attach) {
318 my ($klass, @attach) = @$_; 288 my ($klass, @attach) = @$_;
319 $res = _attach @$registry, $klass, @attach; 289 _attach $registry, $klass, @attach;
320 } 290 }
321 291
322 $obj->{$name} = \%arg; 292 $obj->{$name} = \%arg;
323 } else { 293 } else {
324 warn "object uses attachment '$name' that is not available, postponing.\n"; 294 warn "object uses attachment '$name' that is not available, postponing.\n";
325 } 295 }
326 296
327 $obj->{_attachment}{$name} = undef; 297 $obj->{_attachment}{$name} = undef;
328
329 $res->{attachment} = $name;
330 $res
331} 298}
332 299
333*cf::object::attach = 300sub cf::attachable::attach {
334*cf::player::attach = 301 if (ref $_[0]) {
335*cf::map::attach = sub { 302 _object_attach @_;
336 my ($obj, $name, %arg) = @_; 303 } else {
337 304 _attach shift->_attach_registry, @_;
338 _attach_attachment $obj, $name, %arg; 305 }
339}; 306};
340 307
341# all those should be optimised 308# all those should be optimised
342*cf::object::detach = 309sub cf::attachable::detach {
343*cf::player::detach =
344*cf::map::detach = sub {
345 my ($obj, $name) = @_; 310 my ($obj, $name) = @_;
346 311
312 if (ref $obj) {
347 delete $obj->{_attachment}{$name}; 313 delete $obj->{_attachment}{$name};
348 reattach ($obj); 314 reattach ($obj);
315 } else {
316 Carp::croak "cannot, currently, detach class attachments";
317 }
349}; 318};
350 319
351*cf::object::attached = 320sub cf::attachable::attached {
352*cf::player::attached =
353*cf::map::attached = sub {
354 my ($obj, $name) = @_; 321 my ($obj, $name) = @_;
355 322
356 exists $obj->{_attachment}{$name} 323 exists $obj->{_attachment}{$name}
357};
358
359sub attach_global {
360 _attach @CB_GLOBAL, KLASS_GLOBAL, @_
361} 324}
362 325
363sub attach_to_type { 326for my $klass (qw(GLOBAL OBJECT PLAYER CLIENT MAP)) {
364 my $type = shift; 327 eval "#line " . __LINE__ . " 'cf.pm'
365 my $subtype = shift; 328 sub cf::\L$klass\E::_attach_registry {
329 (\\\@CB_$klass, KLASS_$klass)
330 }
366 331
367 _attach @{$CB_TYPE[$type + $subtype * NUM_SUBTYPES]}, KLASS_OBJECT, @_ 332 sub cf::\L$klass\E::attachment {
368}
369
370sub attach_to_objects {
371 _attach @CB_OBJECT, KLASS_OBJECT, @_
372}
373
374sub attach_to_players {
375 _attach @CB_PLAYER, KLASS_PLAYER, @_
376}
377
378sub attach_to_maps {
379 _attach @CB_MAP, KLASS_MAP, @_
380}
381
382sub register_attachment {
383 my $name = shift; 333 my \$name = shift;
384 334
385 $attachment{$name} = [[KLASS_OBJECT, @_]];
386}
387
388sub register_player_attachment {
389 my $name = shift;
390
391 $attachment{$name} = [[KLASS_PLAYER, @_]];
392}
393
394sub register_map_attachment {
395 my $name = shift;
396
397 $attachment{$name} = [[KLASS_MAP, @_]]; 335 \$attachment{\$name} = [[KLASS_$klass, \@_]];
336 }
337 ";
338 die if $@;
398} 339}
399 340
400our $override; 341our $override;
401our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals? 342our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
402 343
432 373
433=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...) 374=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...)
434 375
435=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...) 376=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...)
436 377
378=item $bool = $client->invoke (EVENT_CLIENT_XXX, ...)
379
437=item $bool = $map->invoke (EVENT_MAP_XXX, ...) 380=item $bool = $map->invoke (EVENT_MAP_XXX, ...)
438 381
439Generate a global/object/player/map-specific event with the given arguments. 382Generate a global/object/player/map-specific event with the given arguments.
440 383
441This API is preliminary (most likely, the EVENT_KLASS_xxx prefix will be 384This API is preliminary (most likely, the EVENT_KLASS_xxx prefix will be
446 389
447=cut 390=cut
448 391
449############################################################################# 392#############################################################################
450 393
451=head2 METHODS VALID FOR ALL CORE OBJECTS 394=head2 METHODS VALID FOR ALL ATTACHABLE OBJECTS
395
396Attachable objects includes objects, players, clients and maps.
452 397
453=over 4 398=over 4
454 399
455=item $object->valid, $player->valid, $map->valid 400=item $object->valid
456 401
457Just because you have a perl object does not mean that the corresponding 402Just because you have a perl object does not mean that the corresponding
458C-level object still exists. If you try to access an object that has no 403C-level object still exists. If you try to access an object that has no
459valid C counterpart anymore you get an exception at runtime. This method 404valid C counterpart anymore you get an exception at runtime. This method
460can be used to test for existence of the C object part without causing an 405can be used to test for existence of the C object part without causing an
462 407
463=back 408=back
464 409
465=cut 410=cut
466 411
467*cf::object::valid =
468*cf::player::valid =
469*cf::map::valid = \&cf::_valid;
470
471############################################################################# 412#############################################################################
472# object support 413# object support
473 414
474sub instantiate { 415sub instantiate {
475 my ($obj, $data) = @_; 416 my ($obj, $data) = @_;
494 435
495 for my $name (keys %{ $obj->{_attachment} || {} }) { 436 for my $name (keys %{ $obj->{_attachment} || {} }) {
496 if (my $attach = $attachment{$name}) { 437 if (my $attach = $attachment{$name}) {
497 for (@$attach) { 438 for (@$attach) {
498 my ($klass, @attach) = @$_; 439 my ($klass, @attach) = @$_;
499 _attach @$registry, $klass, @attach; 440 _attach $registry, $klass, @attach;
500 } 441 }
501 } else { 442 } else {
502 warn "object uses attachment '$name' that is not available, postponing.\n"; 443 warn "object uses attachment '$name' that is not available, postponing.\n";
503 } 444 }
504 } 445 }
560 } 501 }
561 502
562 () 503 ()
563} 504}
564 505
565attach_to_objects 506cf::object->attach (
566 prio => -1000000, 507 prio => -1000000,
567 on_clone => sub { 508 on_clone => sub {
568 my ($src, $dst) = @_; 509 my ($src, $dst) = @_;
569 510
570 @{$dst->registry} = @{$src->registry}; 511 @{$dst->registry} = @{$src->registry};
572 %$dst = %$src; 513 %$dst = %$src;
573 514
574 %{$dst->{_attachment}} = %{$src->{_attachment}} 515 %{$dst->{_attachment}} = %{$src->{_attachment}}
575 if exists $src->{_attachment}; 516 if exists $src->{_attachment};
576 }, 517 },
577; 518);
578 519
579############################################################################# 520#############################################################################
580# command handling &c 521# command handling &c
581 522
582=item cf::register_command $name => \&callback($ob,$args); 523=item cf::register_command $name => \&callback($ob,$args);
611 #warn "registering extcmd '$name' to '$caller'"; 552 #warn "registering extcmd '$name' to '$caller'";
612 553
613 $EXTCMD{$name} = [$cb, $caller]; 554 $EXTCMD{$name} = [$cb, $caller];
614} 555}
615 556
616attach_to_players 557cf::player->attach (
617 on_command => sub { 558 on_command => sub {
618 my ($pl, $name, $params) = @_; 559 my ($pl, $name, $params) = @_;
619 560
620 my $cb = $COMMAND{$name} 561 my $cb = $COMMAND{$name}
621 or return; 562 or return;
641 warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n"; 582 warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
642 } 583 }
643 584
644 cf::override; 585 cf::override;
645 }, 586 },
646; 587);
647 588
648sub register { 589sub register {
649 my ($base, $pkg) = @_; 590 my ($base, $pkg) = @_;
650 591
651 #TODO 592 #TODO
720 661
721 Symbol::delete_package $pkg; 662 Symbol::delete_package $pkg;
722} 663}
723 664
724sub load_extensions { 665sub load_extensions {
725 my $LIBDIR = maps_directory "perl";
726
727 for my $ext (<$LIBDIR/*.ext>) { 666 for my $ext (<$LIBDIR/*.ext>) {
728 next unless -r $ext; 667 next unless -r $ext;
729 eval { 668 eval {
730 load_extension $ext; 669 load_extension $ext;
731 1 670 1
743 defined $path or return; 682 defined $path or return;
744 683
745 unlink "$path.pst"; 684 unlink "$path.pst";
746}; 685};
747 686
748attach_to_maps prio => -10000, package => cf::mapsupport::; 687cf::map->attach (prio => -10000, package => cf::mapsupport::);
749 688
750############################################################################# 689#############################################################################
751# load/save perl data associated with player->ob objects 690# load/save perl data associated with player->ob objects
752 691
753sub all_objects(@) { 692sub all_objects(@) {
754 @_, map all_objects ($_->inv), @_ 693 @_, map all_objects ($_->inv), @_
755} 694}
756 695
757# TODO: compatibility cruft, remove when no longer needed 696# TODO: compatibility cruft, remove when no longer needed
758attach_to_players 697cf::player->attach (
759 on_load => sub { 698 on_load => sub {
760 my ($pl, $path) = @_; 699 my ($pl, $path) = @_;
761 700
762 for my $o (all_objects $pl->ob) { 701 for my $o (all_objects $pl->ob) {
763 if (my $value = $o->get_ob_key_value ("_perl_data")) { 702 if (my $value = $o->get_ob_key_value ("_perl_data")) {
765 704
766 %$o = %{ Storable::thaw pack "H*", $value }; 705 %$o = %{ Storable::thaw pack "H*", $value };
767 } 706 }
768 } 707 }
769 }, 708 },
770; 709);
771 710
772############################################################################# 711#############################################################################
773 712
774=head2 CORE EXTENSIONS 713=head2 CORE EXTENSIONS
775 714
866 805
867=pod 806=pod
868 807
869The following fucntions and emthods are available within a safe environment: 808The following fucntions and emthods are available within a safe environment:
870 809
871 cf::object contr pay_amount pay_player 810 cf::object contr pay_amount pay_player map
872 cf::object::player player 811 cf::object::player player
873 cf::player peaceful 812 cf::player peaceful
813 cf::map trigger
874 814
875=cut 815=cut
876 816
877for ( 817for (
878 ["cf::object" => qw(contr pay_amount pay_player)], 818 ["cf::object" => qw(contr pay_amount pay_player map)],
879 ["cf::object::player" => qw(player)], 819 ["cf::object::player" => qw(player)],
880 ["cf::player" => qw(peaceful)], 820 ["cf::player" => qw(peaceful)],
821 ["cf::map" => qw(trigger)],
881) { 822) {
882 no strict 'refs'; 823 no strict 'refs';
883 my ($pkg, @funs) = @$_; 824 my ($pkg, @funs) = @$_;
884 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"}) 825 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
885 for @funs; 826 for @funs;
1049 $DB->{$_[0]} = $_[1]; 990 $DB->{$_[0]} = $_[1];
1050 } 991 }
1051 db_dirty; 992 db_dirty;
1052 } 993 }
1053 994
1054 attach_global 995 cf::global->attach (
1055 prio => 10000, 996 prio => 10000,
1056 on_cleanup => sub { 997 on_cleanup => sub {
1057 db_sync; 998 db_sync;
1058 }, 999 },
1059 ; 1000 );
1060} 1001}
1061 1002
1062############################################################################# 1003#############################################################################
1063# the server's main() 1004# the server's main()
1064 1005
1173}; 1114};
1174 1115
1175unshift @INC, $LIBDIR; 1116unshift @INC, $LIBDIR;
1176 1117
1177$TICK_WATCHER = Event->timer ( 1118$TICK_WATCHER = Event->timer (
1178 prio => 1, 1119 prio => 0,
1179 async => 1,
1180 at => $NEXT_TICK || 1, 1120 at => $NEXT_TICK || 1,
1181 data => WF_AUTOCANCEL, 1121 data => WF_AUTOCANCEL,
1182 cb => sub { 1122 cb => sub {
1183 cf::server_tick; # one server iteration 1123 cf::server_tick; # one server iteration
1184 1124

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines