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.81 by root, Tue Nov 7 17:38:22 2006 UTC vs.
Revision 1.92 by root, Thu Dec 21 06:42:28 2006 UTC

16# work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode? 16# work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode?
17$YAML::Syck::ImplicitUnicode = 1; 17$YAML::Syck::ImplicitUnicode = 1;
18 18
19use strict; 19use strict;
20 20
21sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
22
23our %COMMAND = ();
24our %COMMAND_TIME = ();
25our %EXTCMD = ();
26
21_init_vars; 27_init_vars;
22 28
23our %COMMAND = ();
24our @EVENT; 29our @EVENT;
25our $LIBDIR = maps_directory "perl"; 30our $LIBDIR = datadir . "/ext";
26 31
27our $TICK = MAX_TIME * 1e-6; 32our $TICK = MAX_TIME * 1e-6;
28our $TICK_WATCHER; 33our $TICK_WATCHER;
29our $NEXT_TICK; 34our $NEXT_TICK;
30 35
31our %CFG; 36our %CFG;
32 37
33our $uptime; 38our $UPTIME; $UPTIME ||= time;
34
35$uptime ||= time;
36 39
37############################################################################# 40#############################################################################
38 41
39=head2 GLOBAL VARIABLES 42=head2 GLOBAL VARIABLES
40 43
41=over 4 44=over 4
45
46=item $cf::UPTIME
47
48The timestamp of the server start (so not actually an uptime).
42 49
43=item $cf::LIBDIR 50=item $cf::LIBDIR
44 51
45The perl library directory, where extensions and cf-specific modules can 52The perl library directory, where extensions and cf-specific modules can
46be found. It will be added to C<@INC> automatically. 53be found. It will be added to C<@INC> automatically.
71 78
72@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object'; 79@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
73 80
74# we bless all objects into (empty) derived classes to force a method lookup 81# we bless all objects into (empty) derived classes to force a method lookup
75# within the Safe compartment. 82# within the Safe compartment.
76for my $pkg (qw(cf::object cf::object::player cf::player cf::map cf::party cf::region cf::arch cf::living)) { 83for my $pkg (qw(
84 cf::object cf::object::player
85 cf::client cf::player
86 cf::arch cf::living
87 cf::map cf::party cf::region
88)) {
77 no strict 'refs'; 89 no strict 'refs';
78 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg; 90 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
79} 91}
80 92
81$Event::DIED = sub { 93$Event::DIED = sub {
83}; 95};
84 96
85my %ext_pkg; 97my %ext_pkg;
86my @exts; 98my @exts;
87my @hook; 99my @hook;
88my %command;
89my %extcmd;
90 100
91=head2 UTILITY FUNCTIONS 101=head2 UTILITY FUNCTIONS
92 102
93=over 4 103=over 4
94 104
142 152
143=item $map->attach ($attachment, key => $value...) 153=item $map->attach ($attachment, key => $value...)
144 154
145=item $map->detach ($attachment) 155=item $map->detach ($attachment)
146 156
157Attach/detach a pre-registered attachment to a client.
158
159=item $client->attach ($attachment, key => $value...)
160
161=item $client->detach ($attachment)
162
147Attach/detach a pre-registered attachment to a map. 163Attach/detach a pre-registered attachment to a map.
148 164
149=item $bool = $object->attached ($name) 165=item $bool = $object->attached ($name)
150 166
151=item $bool = $player->attached ($name) 167=item $bool = $player->attached ($name)
168
169=item $bool = $client->attached ($name)
152 170
153=item $bool = $map->attached ($name) 171=item $bool = $map->attached ($name)
154 172
155Checks wether the named attachment is currently attached to the object. 173Checks wether the named attachment is currently attached to the object.
156 174
203 221
204=item cf::attach_to_players ... 222=item cf::attach_to_players ...
205 223
206Attach handlers to all players. 224Attach handlers to all players.
207 225
226=item cf::attach_to_clients ...
227
228Attach handlers to all players.
229
208=item cf::attach_to_maps ... 230=item cf::attach_to_maps ...
209 231
210Attach handlers to all maps. 232Attach handlers to all maps.
211 233
212=item cf:register_attachment $name, ... 234=item cf:register_attachment $name, ...
228 250
229# the following variables are defined in .xs and must not be re-created 251# the following variables are defined in .xs and must not be re-created
230our @CB_GLOBAL = (); # registry for all global events 252our @CB_GLOBAL = (); # registry for all global events
231our @CB_OBJECT = (); # all objects (should not be used except in emergency) 253our @CB_OBJECT = (); # all objects (should not be used except in emergency)
232our @CB_PLAYER = (); 254our @CB_PLAYER = ();
255our @CB_CLIENT = ();
233our @CB_TYPE = (); # registry for type (cf-object class) based events 256our @CB_TYPE = (); # registry for type (cf-object class) based events
234our @CB_MAP = (); 257our @CB_MAP = ();
235 258
236my %attachment; 259my %attachment;
237 260
320 $res 343 $res
321} 344}
322 345
323*cf::object::attach = 346*cf::object::attach =
324*cf::player::attach = 347*cf::player::attach =
348*cf::client::attach =
325*cf::map::attach = sub { 349*cf::map::attach = sub {
326 my ($obj, $name, %arg) = @_; 350 my ($obj, $name, %arg) = @_;
327 351
328 _attach_attachment $obj, $name, %arg; 352 _attach_attachment $obj, $name, %arg;
329}; 353};
330 354
331# all those should be optimised 355# all those should be optimised
332*cf::object::detach = 356*cf::object::detach =
333*cf::player::detach = 357*cf::player::detach =
358*cf::client::detach =
334*cf::map::detach = sub { 359*cf::map::detach = sub {
335 my ($obj, $name) = @_; 360 my ($obj, $name) = @_;
336 361
337 delete $obj->{_attachment}{$name}; 362 delete $obj->{_attachment}{$name};
338 reattach ($obj); 363 reattach ($obj);
339}; 364};
340 365
341*cf::object::attached = 366*cf::object::attached =
342*cf::player::attached = 367*cf::player::attached =
368*cf::client::attached =
343*cf::map::attached = sub { 369*cf::map::attached = sub {
344 my ($obj, $name) = @_; 370 my ($obj, $name) = @_;
345 371
346 exists $obj->{_attachment}{$name} 372 exists $obj->{_attachment}{$name}
347}; 373};
363 389
364sub attach_to_players { 390sub attach_to_players {
365 _attach @CB_PLAYER, KLASS_PLAYER, @_ 391 _attach @CB_PLAYER, KLASS_PLAYER, @_
366} 392}
367 393
394sub attach_to_clients {
395 _attach @CB_CLIENT, KLASS_CLIENT, @_
396}
397
368sub attach_to_maps { 398sub attach_to_maps {
369 _attach @CB_MAP, KLASS_MAP, @_ 399 _attach @CB_MAP, KLASS_MAP, @_
370} 400}
371 401
372sub register_attachment { 402sub register_attachment {
377 407
378sub register_player_attachment { 408sub register_player_attachment {
379 my $name = shift; 409 my $name = shift;
380 410
381 $attachment{$name} = [[KLASS_PLAYER, @_]]; 411 $attachment{$name} = [[KLASS_PLAYER, @_]];
412}
413
414sub register_client_attachment {
415 my $name = shift;
416
417 $attachment{$name} = [[KLASS_CLIENT, @_]];
382} 418}
383 419
384sub register_map_attachment { 420sub register_map_attachment {
385 my $name = shift; 421 my $name = shift;
386 422
422 458
423=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...) 459=item $bool = $object->invoke (EVENT_OBJECT_XXX, ...)
424 460
425=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...) 461=item $bool = $player->invoke (EVENT_PLAYER_XXX, ...)
426 462
463=item $bool = $client->invoke (EVENT_CLIENT_XXX, ...)
464
427=item $bool = $map->invoke (EVENT_MAP_XXX, ...) 465=item $bool = $map->invoke (EVENT_MAP_XXX, ...)
428 466
429Generate a global/object/player/map-specific event with the given arguments. 467Generate a global/object/player/map-specific event with the given arguments.
430 468
431This API is preliminary (most likely, the EVENT_KLASS_xxx prefix will be 469This API is preliminary (most likely, the EVENT_KLASS_xxx prefix will be
440 478
441=head2 METHODS VALID FOR ALL CORE OBJECTS 479=head2 METHODS VALID FOR ALL CORE OBJECTS
442 480
443=over 4 481=over 4
444 482
445=item $object->valid, $player->valid, $map->valid 483=item $object->valid, $player->valid, $client->valid, $map->valid
446 484
447Just because you have a perl object does not mean that the corresponding 485Just because you have a perl object does not mean that the corresponding
448C-level object still exists. If you try to access an object that has no 486C-level object still exists. If you try to access an object that has no
449valid C counterpart anymore you get an exception at runtime. This method 487valid C counterpart anymore you get an exception at runtime. This method
450can be used to test for existence of the C object part without causing an 488can be used to test for existence of the C object part without causing an
454 492
455=cut 493=cut
456 494
457*cf::object::valid = 495*cf::object::valid =
458*cf::player::valid = 496*cf::player::valid =
497*cf::client::valid =
459*cf::map::valid = \&cf::_valid; 498*cf::map::valid = \&cf::_valid;
460 499
461############################################################################# 500#############################################################################
462# object support 501# object support
463 502
565 if exists $src->{_attachment}; 604 if exists $src->{_attachment};
566 }, 605 },
567; 606;
568 607
569############################################################################# 608#############################################################################
570# old plug-in events 609# command handling &c
571 610
572sub inject_event { 611=item cf::register_command $name => \&callback($ob,$args);
573 my $extension = shift;
574 my $event_code = shift;
575 612
576 my $cb = $hook[$event_code]{$extension} 613Register a callback for execution when the client sends the user command
577 or return; 614$name.
578 615
579 &$cb 616=cut
580}
581
582sub inject_global_event {
583 my $event = shift;
584
585 my $cb = $hook[$event]
586 or return;
587
588 List::Util::max map &$_, values %$cb
589}
590
591sub inject_command {
592 my ($name, $obj, $params) = @_;
593
594 for my $cmd (@{ $command{$name} }) {
595 $cmd->[1]->($obj, $params);
596 }
597
598 -1
599}
600 617
601sub register_command { 618sub register_command {
602 my ($name, $time, $cb) = @_; 619 my ($name, $cb) = @_;
603 620
604 my $caller = caller; 621 my $caller = caller;
605 #warn "registering command '$name/$time' to '$caller'"; 622 #warn "registering command '$name/$time' to '$caller'";
606 623
607 push @{ $command{$name} }, [$time, $cb, $caller]; 624 push @{ $COMMAND{$name} }, [$caller, $cb];
608 $COMMAND{"$name\000"} = List::Util::max map $_->[0], @{ $command{$name} };
609} 625}
626
627=item cf::register_extcmd $name => \&callback($pl,$packet);
628
629Register a callbackf ro execution when the client sends an extcmd packet.
630
631If the callback returns something, it is sent back as if reply was being
632called.
633
634=cut
610 635
611sub register_extcmd { 636sub register_extcmd {
612 my ($name, $cb) = @_; 637 my ($name, $cb) = @_;
613 638
614 my $caller = caller; 639 my $caller = caller;
615 #warn "registering extcmd '$name' to '$caller'"; 640 #warn "registering extcmd '$name' to '$caller'";
616 641
617 $extcmd{$name} = [$cb, $caller]; 642 $EXTCMD{$name} = [$cb, $caller];
618} 643}
644
645attach_to_players
646 on_command => sub {
647 my ($pl, $name, $params) = @_;
648
649 my $cb = $COMMAND{$name}
650 or return;
651
652 for my $cmd (@$cb) {
653 $cmd->[1]->($pl->ob, $params);
654 }
655
656 cf::override;
657 },
658 on_extcmd => sub {
659 my ($pl, $buf) = @_;
660
661 my $msg = eval { from_json $buf };
662
663 if (ref $msg) {
664 if (my $cb = $EXTCMD{$msg->{msgtype}}) {
665 if (my %reply = $cb->[0]->($pl, $msg)) {
666 $pl->ext_reply ($msg->{msgid}, %reply);
667 }
668 }
669 } else {
670 warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
671 }
672
673 cf::override;
674 },
675;
619 676
620sub register { 677sub register {
621 my ($base, $pkg) = @_; 678 my ($base, $pkg) = @_;
622 679
623 #TODO 680 #TODO
642 . "#line 1 \"$path\"\n{\n" 699 . "#line 1 \"$path\"\n{\n"
643 . (do { local $/; <$fh> }) 700 . (do { local $/; <$fh> })
644 . "\n};\n1"; 701 . "\n};\n1";
645 702
646 eval $source 703 eval $source
647 or die "$path: $@"; 704 or die $@ ? "$path: $@\n"
705 : "extension disabled.\n";
648 706
649 push @exts, $pkg; 707 push @exts, $pkg;
650 $ext_pkg{$base} = $pkg; 708 $ext_pkg{$base} = $pkg;
651 709
652# no strict 'refs'; 710# no strict 'refs';
665# for my $idx (0 .. $#PLUGIN_EVENT) { 723# for my $idx (0 .. $#PLUGIN_EVENT) {
666# delete $hook[$idx]{$pkg}; 724# delete $hook[$idx]{$pkg};
667# } 725# }
668 726
669 # remove commands 727 # remove commands
670 for my $name (keys %command) { 728 for my $name (keys %COMMAND) {
671 my @cb = grep $_->[2] ne $pkg, @{ $command{$name} }; 729 my @cb = grep $_->[0] ne $pkg, @{ $COMMAND{$name} };
672 730
673 if (@cb) { 731 if (@cb) {
674 $command{$name} = \@cb; 732 $COMMAND{$name} = \@cb;
675 $COMMAND{"$name\000"} = List::Util::max map $_->[0], @cb;
676 } else { 733 } else {
677 delete $command{$name};
678 delete $COMMAND{"$name\000"}; 734 delete $COMMAND{$name};
679 } 735 }
680 } 736 }
681 737
682 # remove extcmds 738 # remove extcmds
683 for my $name (grep $extcmd{$_}[1] eq $pkg, keys %extcmd) { 739 for my $name (grep $EXTCMD{$_}[1] eq $pkg, keys %EXTCMD) {
684 delete $extcmd{$name}; 740 delete $EXTCMD{$name};
685 } 741 }
686 742
687 if (my $cb = $pkg->can ("unload")) { 743 if (my $cb = $pkg->can ("unload")) {
688 eval { 744 eval {
689 $cb->($pkg); 745 $cb->($pkg);
693 749
694 Symbol::delete_package $pkg; 750 Symbol::delete_package $pkg;
695} 751}
696 752
697sub load_extensions { 753sub load_extensions {
698 my $LIBDIR = maps_directory "perl";
699
700 for my $ext (<$LIBDIR/*.ext>) { 754 for my $ext (<$LIBDIR/*.ext>) {
701 next unless -r $ext; 755 next unless -r $ext;
702 eval { 756 eval {
703 load_extension $ext; 757 load_extension $ext;
704 1 758 1
705 } or warn "$ext not loaded: $@"; 759 } or warn "$ext not loaded: $@";
706 } 760 }
707} 761}
708 762
709############################################################################# 763#############################################################################
710# extcmd framework, basically convert ext <msg>
711# into pkg::->on_extcmd_arg1 (...) while shortcutting a few
712
713attach_to_players
714 on_extcmd => sub {
715 my ($pl, $buf) = @_;
716
717 my $msg = eval { from_json $buf };
718
719 if (ref $msg) {
720 if (my $cb = $extcmd{$msg->{msgtype}}) {
721 if (my %reply = $cb->[0]->($pl, $msg)) {
722 $pl->ext_reply ($msg->{msgid}, %reply);
723 }
724 }
725 } else {
726 warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
727 }
728
729 cf::override;
730 },
731;
732
733#############################################################################
734# load/save/clean perl data associated with a map 764# load/save/clean perl data associated with a map
735 765
736*cf::mapsupport::on_clean = sub { 766*cf::mapsupport::on_clean = sub {
737 my ($map) = @_; 767 my ($map) = @_;
738 768
863 893
864=pod 894=pod
865 895
866The following fucntions and emthods are available within a safe environment: 896The following fucntions and emthods are available within a safe environment:
867 897
868 cf::object contr pay_amount pay_player 898 cf::object contr pay_amount pay_player map
869 cf::object::player player 899 cf::object::player player
870 cf::player peaceful 900 cf::player peaceful
901 cf::map trigger
871 902
872=cut 903=cut
873 904
874for ( 905for (
875 ["cf::object" => qw(contr pay_amount pay_player)], 906 ["cf::object" => qw(contr pay_amount pay_player map)],
876 ["cf::object::player" => qw(player)], 907 ["cf::object::player" => qw(player)],
877 ["cf::player" => qw(peaceful)], 908 ["cf::player" => qw(peaceful)],
909 ["cf::map" => qw(trigger)],
878) { 910) {
879 no strict 'refs'; 911 no strict 'refs';
880 my ($pkg, @funs) = @$_; 912 my ($pkg, @funs) = @$_;
881 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"}) 913 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
882 for @funs; 914 for @funs;
1022 sub db_sync() { 1054 sub db_sync() {
1023 db_save if $dirty; 1055 db_save if $dirty;
1024 undef $dirty; 1056 undef $dirty;
1025 } 1057 }
1026 1058
1027 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, cb => sub { 1059 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, data => WF_AUTOCANCEL, cb => sub {
1028 db_sync; 1060 db_sync;
1029 }); 1061 });
1030 1062
1031 sub db_dirty() { 1063 sub db_dirty() {
1032 $dirty = 1; 1064 $dirty = 1;
1082 1114
1083 $msg->("reloading..."); 1115 $msg->("reloading...");
1084 1116
1085 eval { 1117 eval {
1086 # cancel all watchers 1118 # cancel all watchers
1087 $_->cancel for Event::all_watchers; 1119 for (Event::all_watchers) {
1120 $_->cancel if $_->data & WF_AUTOCANCEL;
1121 }
1088 1122
1089 # unload all extensions 1123 # unload all extensions
1090 for (@exts) { 1124 for (@exts) {
1091 $msg->("unloading <$_>"); 1125 $msg->("unloading <$_>");
1092 unload_extension $_; 1126 unload_extension $_;
1152 warn $_[0]; 1186 warn $_[0];
1153 print "$_[0]\n"; 1187 print "$_[0]\n";
1154 }; 1188 };
1155} 1189}
1156 1190
1191register "<global>", __PACKAGE__;
1192
1157register_command "perl-reload", 0, sub { 1193register_command "perl-reload" => sub {
1158 my ($who, $arg) = @_; 1194 my ($who, $arg) = @_;
1159 1195
1160 if ($who->flag (FLAG_WIZ)) { 1196 if ($who->flag (FLAG_WIZ)) {
1161 _perl_reload { 1197 _perl_reload {
1162 warn $_[0]; 1198 warn $_[0];
1163 $who->message ($_[0]); 1199 $who->message ($_[0]);
1164 }; 1200 };
1165 } 1201 }
1166}; 1202};
1167 1203
1168register "<global>", __PACKAGE__;
1169
1170unshift @INC, $LIBDIR; 1204unshift @INC, $LIBDIR;
1171 1205
1172$TICK_WATCHER = Event->timer ( 1206$TICK_WATCHER = Event->timer (
1173 prio => 1, 1207 prio => 0,
1174 async => 1,
1175 at => $NEXT_TICK || 1, 1208 at => $NEXT_TICK || 1,
1209 data => WF_AUTOCANCEL,
1176 cb => sub { 1210 cb => sub {
1177 cf::server_tick; # one server iteration 1211 cf::server_tick; # one server iteration
1178 1212
1179 my $NOW = Event::time; 1213 my $NOW = Event::time;
1180 $NEXT_TICK += $TICK; 1214 $NEXT_TICK += $TICK;
1190IO::AIO::max_poll_time $TICK * 0.2; 1224IO::AIO::max_poll_time $TICK * 0.2;
1191 1225
1192Event->io (fd => IO::AIO::poll_fileno, 1226Event->io (fd => IO::AIO::poll_fileno,
1193 poll => 'r', 1227 poll => 'r',
1194 prio => 5, 1228 prio => 5,
1229 data => WF_AUTOCANCEL,
1195 cb => \&IO::AIO::poll_cb); 1230 cb => \&IO::AIO::poll_cb);
1196 1231
11971 12321
1198 1233

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines