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.80 by root, Tue Nov 7 16:30:55 2006 UTC vs.
Revision 1.88 by root, Fri Dec 15 19:29:18 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_socket 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
528sub object_freezer_as_string { 538sub object_freezer_as_string {
529 my ($rdata, $objs) = @_; 539 my ($rdata, $objs) = @_;
530 540
531 use Data::Dumper; 541 use Data::Dumper;
532 542
533 "$$rdata\n" . Dumper $objs 543 $$rdata . Dumper $objs
534} 544}
535 545
536sub object_thawer_load { 546sub object_thawer_load {
537 my ($filename) = @_; 547 my ($filename) = @_;
538 548
565 if exists $src->{_attachment}; 575 if exists $src->{_attachment};
566 }, 576 },
567; 577;
568 578
569############################################################################# 579#############################################################################
570# old plug-in events 580# command handling &c
571 581
572sub inject_event { 582=item cf::register_command $name => \&callback($ob,$args);
573 my $extension = shift;
574 my $event_code = shift;
575 583
576 my $cb = $hook[$event_code]{$extension} 584Register a callback for execution when the client sends the user command
577 or return; 585$name.
578 586
579 &$cb 587=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 588
601sub register_command { 589sub register_command {
602 my ($name, $time, $cb) = @_; 590 my ($name, $cb) = @_;
603 591
604 my $caller = caller; 592 my $caller = caller;
605 #warn "registering command '$name/$time' to '$caller'"; 593 #warn "registering command '$name/$time' to '$caller'";
606 594
607 push @{ $command{$name} }, [$time, $cb, $caller]; 595 push @{ $COMMAND{$name} }, [$caller, $cb];
608 $COMMAND{"$name\000"} = List::Util::max map $_->[0], @{ $command{$name} };
609} 596}
597
598=item cf::register_extcmd $name => \&callback($pl,$packet);
599
600Register a callbackf ro execution when the client sends an extcmd packet.
601
602If the callback returns something, it is sent back as if reply was being
603called.
604
605=cut
610 606
611sub register_extcmd { 607sub register_extcmd {
612 my ($name, $cb) = @_; 608 my ($name, $cb) = @_;
613 609
614 my $caller = caller; 610 my $caller = caller;
615 #warn "registering extcmd '$name' to '$caller'"; 611 #warn "registering extcmd '$name' to '$caller'";
616 612
617 $extcmd{$name} = [$cb, $caller]; 613 $EXTCMD{$name} = [$cb, $caller];
618} 614}
615
616attach_to_players
617 on_command => sub {
618 my ($pl, $name, $params) = @_;
619
620 my $cb = $COMMAND{$name}
621 or return;
622
623 for my $cmd (@$cb) {
624 $cmd->[1]->($pl->ob, $params);
625 }
626
627 cf::override;
628 },
629 on_extcmd => sub {
630 my ($pl, $buf) = @_;
631
632 my $msg = eval { from_json $buf };
633
634 if (ref $msg) {
635 if (my $cb = $EXTCMD{$msg->{msgtype}}) {
636 if (my %reply = $cb->[0]->($pl, $msg)) {
637 $pl->ext_reply ($msg->{msgid}, %reply);
638 }
639 }
640 } else {
641 warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
642 }
643
644 cf::override;
645 },
646;
619 647
620sub register { 648sub register {
621 my ($base, $pkg) = @_; 649 my ($base, $pkg) = @_;
622 650
623 #TODO 651 #TODO
642 . "#line 1 \"$path\"\n{\n" 670 . "#line 1 \"$path\"\n{\n"
643 . (do { local $/; <$fh> }) 671 . (do { local $/; <$fh> })
644 . "\n};\n1"; 672 . "\n};\n1";
645 673
646 eval $source 674 eval $source
647 or die "$path: $@"; 675 or die $@ ? "$path: $@\n"
676 : "extension disabled.\n";
648 677
649 push @exts, $pkg; 678 push @exts, $pkg;
650 $ext_pkg{$base} = $pkg; 679 $ext_pkg{$base} = $pkg;
651 680
652# no strict 'refs'; 681# no strict 'refs';
665# for my $idx (0 .. $#PLUGIN_EVENT) { 694# for my $idx (0 .. $#PLUGIN_EVENT) {
666# delete $hook[$idx]{$pkg}; 695# delete $hook[$idx]{$pkg};
667# } 696# }
668 697
669 # remove commands 698 # remove commands
670 for my $name (keys %command) { 699 for my $name (keys %COMMAND) {
671 my @cb = grep $_->[2] ne $pkg, @{ $command{$name} }; 700 my @cb = grep $_->[0] ne $pkg, @{ $COMMAND{$name} };
672 701
673 if (@cb) { 702 if (@cb) {
674 $command{$name} = \@cb; 703 $COMMAND{$name} = \@cb;
675 $COMMAND{"$name\000"} = List::Util::max map $_->[0], @cb;
676 } else { 704 } else {
677 delete $command{$name};
678 delete $COMMAND{"$name\000"}; 705 delete $COMMAND{$name};
679 } 706 }
680 } 707 }
681 708
682 # remove extcmds 709 # remove extcmds
683 for my $name (grep $extcmd{$_}[1] eq $pkg, keys %extcmd) { 710 for my $name (grep $EXTCMD{$_}[1] eq $pkg, keys %EXTCMD) {
684 delete $extcmd{$name}; 711 delete $EXTCMD{$name};
685 } 712 }
686 713
687 if (my $cb = $pkg->can ("unload")) { 714 if (my $cb = $pkg->can ("unload")) {
688 eval { 715 eval {
689 $cb->($pkg); 716 $cb->($pkg);
693 720
694 Symbol::delete_package $pkg; 721 Symbol::delete_package $pkg;
695} 722}
696 723
697sub load_extensions { 724sub load_extensions {
698 my $LIBDIR = maps_directory "perl";
699
700 for my $ext (<$LIBDIR/*.ext>) { 725 for my $ext (<$LIBDIR/*.ext>) {
701 next unless -r $ext; 726 next unless -r $ext;
702 eval { 727 eval {
703 load_extension $ext; 728 load_extension $ext;
704 1 729 1
705 } or warn "$ext not loaded: $@"; 730 } or warn "$ext not loaded: $@";
706 } 731 }
707} 732}
708
709#############################################################################
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
733############################################################################# 734#############################################################################
734# load/save/clean perl data associated with a map 735# load/save/clean perl data associated with a map
735 736
736*cf::mapsupport::on_clean = sub { 737*cf::mapsupport::on_clean = sub {
1022 sub db_sync() { 1023 sub db_sync() {
1023 db_save if $dirty; 1024 db_save if $dirty;
1024 undef $dirty; 1025 undef $dirty;
1025 } 1026 }
1026 1027
1027 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, cb => sub { 1028 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, data => WF_AUTOCANCEL, cb => sub {
1028 db_sync; 1029 db_sync;
1029 }); 1030 });
1030 1031
1031 sub db_dirty() { 1032 sub db_dirty() {
1032 $dirty = 1; 1033 $dirty = 1;
1082 1083
1083 $msg->("reloading..."); 1084 $msg->("reloading...");
1084 1085
1085 eval { 1086 eval {
1086 # cancel all watchers 1087 # cancel all watchers
1087 $_->cancel for Event::all_watchers; 1088 for (Event::all_watchers) {
1089 $_->cancel if $_->data & WF_AUTOCANCEL;
1090 }
1088 1091
1089 # unload all extensions 1092 # unload all extensions
1090 for (@exts) { 1093 for (@exts) {
1091 $msg->("unloading <$_>"); 1094 $msg->("unloading <$_>");
1092 unload_extension $_; 1095 unload_extension $_;
1152 warn $_[0]; 1155 warn $_[0];
1153 print "$_[0]\n"; 1156 print "$_[0]\n";
1154 }; 1157 };
1155} 1158}
1156 1159
1160register "<global>", __PACKAGE__;
1161
1157register_command "perl-reload", 0, sub { 1162register_command "perl-reload" => sub {
1158 my ($who, $arg) = @_; 1163 my ($who, $arg) = @_;
1159 1164
1160 if ($who->flag (FLAG_WIZ)) { 1165 if ($who->flag (FLAG_WIZ)) {
1161 _perl_reload { 1166 _perl_reload {
1162 warn $_[0]; 1167 warn $_[0];
1163 $who->message ($_[0]); 1168 $who->message ($_[0]);
1164 }; 1169 };
1165 } 1170 }
1166}; 1171};
1167 1172
1168register "<global>", __PACKAGE__;
1169
1170unshift @INC, $LIBDIR; 1173unshift @INC, $LIBDIR;
1171 1174
1172$TICK_WATCHER = Event->timer ( 1175$TICK_WATCHER = Event->timer (
1173 prio => 1, 1176 prio => 1,
1174 async => 1, 1177 async => 1,
1175 at => $NEXT_TICK || 1, 1178 at => $NEXT_TICK || 1,
1179 data => WF_AUTOCANCEL,
1176 cb => sub { 1180 cb => sub {
1177 cf::server_tick; # one server iteration 1181 cf::server_tick; # one server iteration
1178 1182
1179 my $NOW = Event::time; 1183 my $NOW = Event::time;
1180 $NEXT_TICK += $TICK; 1184 $NEXT_TICK += $TICK;
1190IO::AIO::max_poll_time $TICK * 0.2; 1194IO::AIO::max_poll_time $TICK * 0.2;
1191 1195
1192Event->io (fd => IO::AIO::poll_fileno, 1196Event->io (fd => IO::AIO::poll_fileno,
1193 poll => 'r', 1197 poll => 'r',
1194 prio => 5, 1198 prio => 5,
1199 data => WF_AUTOCANCEL,
1195 cb => \&IO::AIO::poll_cb); 1200 cb => \&IO::AIO::poll_cb);
1196 1201
11971 12021
1198 1203

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines