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.60 by root, Thu Aug 31 06:23:19 2006 UTC vs.
Revision 1.71 by root, Sun Oct 1 10:59:30 2006 UTC

11use Event; 11use Event;
12$Event::Eval = 1; # no idea why this is required, but it is 12$Event::Eval = 1; # no idea why this is required, but it is
13 13
14use strict; 14use strict;
15 15
16_reload_1; 16_init_vars;
17 17
18our %COMMAND = (); 18our %COMMAND = ();
19our @EVENT; 19our @EVENT;
20our %PROP_TYPE;
21our %PROP_IDX;
22our $LIBDIR = maps_directory "perl"; 20our $LIBDIR = maps_directory "perl";
23 21
24our $TICK = MAX_TIME * 1e-6; 22our $TICK = MAX_TIME * 1e-6;
25our $TICK_WATCHER; 23our $TICK_WATCHER;
26our $NEXT_TICK; 24our $NEXT_TICK;
25
26our %CFG;
27
28#############################################################################
29
30=head2 GLOBAL VARIABLES
31
32=over 4
33
34=item $cf::LIBDIR
35
36The perl library directory, where extensions and cf-specific modules can
37be found. It will be added to C<@INC> automatically.
38
39=item $cf::TICK
40
41The interval between server ticks, in seconds.
42
43=item %cf::CFG
44
45Configuration for the server, loaded from C</etc/crossfire/config>, or
46from wherever your confdir points to.
47
48=back
49
50=cut
27 51
28BEGIN { 52BEGIN {
29 *CORE::GLOBAL::warn = sub { 53 *CORE::GLOBAL::warn = sub {
30 my $msg = join "", @_; 54 my $msg = join "", @_;
31 $msg .= "\n" 55 $msg .= "\n"
34 print STDERR "cfperl: $msg"; 58 print STDERR "cfperl: $msg";
35 LOG llevError, "cfperl: $msg"; 59 LOG llevError, "cfperl: $msg";
36 }; 60 };
37} 61}
38 62
39my %ignore_set = (MAP_PROP_PATH => 1); # I hate the plug-in api. Deeply!
40
41# generate property mutators
42sub prop_gen {
43 my ($prefix, $class) = @_;
44
45 no strict 'refs';
46
47 for my $prop (keys %PROP_TYPE) {
48 $prop =~ /^\Q$prefix\E_(.*$)/ or next;
49 my $sub = lc $1;
50
51 my $type = $PROP_TYPE{$prop};
52 my $idx = $PROP_IDX {$prop};
53
54 *{"$class\::get_$sub"} = *{"$class\::$sub"} = sub {
55 $_[0]->get_property ($type, $idx)
56 };
57
58 *{"$class\::set_$sub"} = sub {
59 $_[0]->set_property ($type, $idx, $_[1]);
60 } unless $ignore_set{$prop};
61 }
62}
63
64# auto-generate most of the API
65
66prop_gen OBJECT_PROP => "cf::object";
67# CFAPI_OBJECT_ANIMATION?
68prop_gen PLAYER_PROP => "cf::object::player";
69
70prop_gen MAP_PROP => "cf::map";
71prop_gen ARCH_PROP => "cf::arch";
72
73@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object'; 63@safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
74 64
75# we bless all objects into (empty) derived classes to force a method lookup 65# we bless all objects into (empty) derived classes to force a method lookup
76# within the Safe compartment. 66# within the Safe compartment.
77for my $pkg (qw(cf::object cf::object::player cf::player cf::map cf::party cf::region cf::arch cf::living)) { 67for my $pkg (qw(cf::object cf::object::player cf::player cf::map cf::party cf::region cf::arch cf::living)) {
87my @exts; 77my @exts;
88my @hook; 78my @hook;
89my %command; 79my %command;
90my %extcmd; 80my %extcmd;
91 81
92############################################################################# 82=head2 UTILITY FUNCTIONS
93# utility functions 83
84=over 4
85
86=cut
94 87
95use JSON::Syck (); # TODO# replace by JSON::PC once working 88use JSON::Syck (); # TODO# replace by JSON::PC once working
89
90=item $ref = cf::from_json $json
91
92Converts a JSON string into the corresponding perl data structure.
93
94=cut
96 95
97sub from_json($) { 96sub from_json($) {
98 $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs 97 $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs
99 JSON::Syck::Load $_[0] 98 JSON::Syck::Load $_[0]
100} 99}
101 100
101=item $json = cf::to_json $ref
102
103Converts a perl data structure into its JSON representation.
104
105=cut
106
102sub to_json($) { 107sub to_json($) {
103 $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs 108 $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs
104 JSON::Syck::Dump $_[0] 109 JSON::Syck::Dump $_[0]
105} 110}
106 111
107############################################################################# 112=back
108# "new" plug-in system
109 113
114=cut
115
116#############################################################################
117
110=head3 EVENTS AND OBJECT ATTACHMENTS 118=head2 EVENTS AND OBJECT ATTACHMENTS
111 119
112=over 4 120=over 4
113 121
114=item $object->attach ($attachment, key => $value...) 122=item $object->attach ($attachment, key => $value...)
115 123
389 for (@$callbacks) { 397 for (@$callbacks) {
390 eval { &{$_->[1]} }; 398 eval { &{$_->[1]} };
391 399
392 if ($@) { 400 if ($@) {
393 warn "$@"; 401 warn "$@";
394 warn "... while processing $EVENT[$event][0] event, skipping processing altogether.\n"; 402 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
395 override; 403 override;
396 } 404 }
397 405
398 return 1 if $override; 406 return 1 if $override;
399 } 407 }
415removed in future versions), and there is no public API to access override 423removed in future versions), and there is no public API to access override
416results (if you must, access C<@cf::invoke_results> directly). 424results (if you must, access C<@cf::invoke_results> directly).
417 425
418=back 426=back
419 427
420=head2 methods valid for all pointers 428=cut
429
430#############################################################################
431
432=head2 METHODS VALID FOR ALL CORE OBJECTS
421 433
422=over 4 434=over 4
423 435
424=item $object->valid 436=item $object->valid, $player->valid, $map->valid
425
426=item $player->valid
427
428=item $map->valid
429 437
430Just because you have a perl object does not mean that the corresponding 438Just because you have a perl object does not mean that the corresponding
431C-level object still exists. If you try to access an object that has no 439C-level object still exists. If you try to access an object that has no
432valid C counterpart anymore you get an exception at runtime. This method 440valid C counterpart anymore you get an exception at runtime. This method
433can be used to test for existence of the C object part without causing an 441can be used to test for existence of the C object part without causing an
509} 517}
510 518
511sub object_thawer_load { 519sub object_thawer_load {
512 my ($filename) = @_; 520 my ($filename) = @_;
513 521
522 local $/;
523
524 my $av;
525
526 #TODO: use sysread etc.
527 if (open my $data, "<:raw:perlio", $filename) {
528 $data = <$data>;
514 open my $fh, "<:raw:perlio", "$filename.pst" 529 if (open my $pst, "<:raw:perlio", "$filename.pst") {
515 or return; 530 $av = eval { (Storable::thaw <$pst>)->{objs} };
531 }
532 return ($data, $av);
533 }
516 534
517 eval { local $/; (Storable::thaw <$fh>)->{objs} } 535 ()
518} 536}
519 537
520attach_to_objects 538attach_to_objects
521 prio => -1000000, 539 prio => -1000000,
522 on_clone => sub { 540 on_clone => sub {
668 load_extension $ext; 686 load_extension $ext;
669 1 687 1
670 } or warn "$ext not loaded: $@"; 688 } or warn "$ext not loaded: $@";
671 } 689 }
672} 690}
673
674sub _perl_reload(&) {
675 my ($msg) = @_;
676
677 $msg->("reloading...");
678
679 eval {
680 # 1. cancel all watchers
681 $_->cancel for Event::all_watchers;
682
683 # 2. unload all extensions
684 for (@exts) {
685 $msg->("unloading <$_>");
686 unload_extension $_;
687 }
688
689 # 3. unload all modules loaded from $LIBDIR
690 while (my ($k, $v) = each %INC) {
691 next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
692
693 $msg->("removing <$k>");
694 delete $INC{$k};
695
696 $k =~ s/\.pm$//;
697 $k =~ s/\//::/g;
698
699 if (my $cb = $k->can ("unload_module")) {
700 $cb->();
701 }
702
703 Symbol::delete_package $k;
704 }
705
706 # 4. get rid of safe::, as good as possible
707 Symbol::delete_package "safe::$_"
708 for qw(cf::object cf::object::player cf::player cf::map cf::party cf::region);
709
710 # 5. remove register_script_function callbacks
711 # TODO
712
713 # 6. unload cf.pm "a bit"
714 delete $INC{"cf.pm"};
715
716 # don't, removes xs symbols, too,
717 # and global variables created in xs
718 #Symbol::delete_package __PACKAGE__;
719
720 # 7. reload cf.pm
721 $msg->("reloading cf.pm");
722 require cf;
723 };
724 $msg->($@) if $@;
725
726 $msg->("reloaded");
727};
728
729sub perl_reload() {
730 _perl_reload {
731 warn $_[0];
732 print "$_[0]\n";
733 };
734}
735
736register_command "perl-reload", 0, sub {
737 my ($who, $arg) = @_;
738
739 if ($who->flag (FLAG_WIZ)) {
740 _perl_reload {
741 warn $_[0];
742 $who->message ($_[0]);
743 };
744 }
745};
746 691
747############################################################################# 692#############################################################################
748# extcmd framework, basically convert ext <msg> 693# extcmd framework, basically convert ext <msg>
749# into pkg::->on_extcmd_arg1 (...) while shortcutting a few 694# into pkg::->on_extcmd_arg1 (...) while shortcutting a few
750 695
803 } 748 }
804 }, 749 },
805; 750;
806 751
807############################################################################# 752#############################################################################
808# core extensions - in perl 753
754=head2 CORE EXTENSIONS
755
756Functions and methods that extend core crossfire objects.
757
758=over 4
809 759
810=item cf::player::exists $login 760=item cf::player::exists $login
811 761
812Returns true when the given account exists. 762Returns true when the given account exists.
813 763
853 $msg{msgid} = $id; 803 $msg{msgid} = $id;
854 804
855 $self->send ("ext " . to_json \%msg); 805 $self->send ("ext " . to_json \%msg);
856} 806}
857 807
808=back
809
810=cut
811
858############################################################################# 812#############################################################################
859# map scripting support 813
814=head2 SAFE SCRIPTING
815
816Functions that provide a safe environment to compile and execute
817snippets of perl code without them endangering the safety of the server
818itself. Looping constructs, I/O operators and other built-in functionality
819is not available in the safe scripting environment, and the number of
820functions and methods that cna be called is greatly reduced.
821
822=cut
860 823
861our $safe = new Safe "safe"; 824our $safe = new Safe "safe";
862our $safe_hole = new Safe::Hole; 825our $safe_hole = new Safe::Hole;
863 826
864$SIG{FPE} = 'IGNORE'; 827$SIG{FPE} = 'IGNORE';
865 828
866$safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time)); 829$safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
867 830
868# here we export the classes and methods available to script code 831# here we export the classes and methods available to script code
832
833=pod
834
835The following fucntions and emthods are available within a safe environment:
836
837 cf::object contr pay_amount pay_player
838 cf::object::player player
839 cf::player peaceful
840
841=cut
869 842
870for ( 843for (
871 ["cf::object" => qw(contr pay_amount pay_player)], 844 ["cf::object" => qw(contr pay_amount pay_player)],
872 ["cf::object::player" => qw(player)], 845 ["cf::object::player" => qw(player)],
873 ["cf::player" => qw(peaceful)], 846 ["cf::player" => qw(peaceful)],
876 my ($pkg, @funs) = @$_; 849 my ($pkg, @funs) = @$_;
877 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"}) 850 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
878 for @funs; 851 for @funs;
879} 852}
880 853
854=over 4
855
856=item @retval = safe_eval $code, [var => value, ...]
857
858Compiled and executes the given perl code snippet. additional var/value
859pairs result in temporary local (my) scalar variables of the given name
860that are available in the code snippet. Example:
861
862 my $five = safe_eval '$first + $second', first => 1, second => 4;
863
864=cut
865
881sub safe_eval($;@) { 866sub safe_eval($;@) {
882 my ($code, %vars) = @_; 867 my ($code, %vars) = @_;
883 868
884 my $qcode = $code; 869 my $qcode = $code;
885 $qcode =~ s/"/‟/g; # not allowed in #line filenames 870 $qcode =~ s/"/‟/g; # not allowed in #line filenames
907 } 892 }
908 893
909 wantarray ? @res : $res[0] 894 wantarray ? @res : $res[0]
910} 895}
911 896
897=item cf::register_script_function $function => $cb
898
899Register a function that can be called from within map/npc scripts. The
900function should be reasonably secure and should be put into a package name
901like the extension.
902
903Example: register a function that gets called whenever a map script calls
904C<rent::overview>, as used by the C<rent> extension.
905
906 cf::register_script_function "rent::overview" => sub {
907 ...
908 };
909
910=cut
911
912sub register_script_function { 912sub register_script_function {
913 my ($fun, $cb) = @_; 913 my ($fun, $cb) = @_;
914 914
915 no strict 'refs'; 915 no strict 'refs';
916 *{"safe::$fun"} = $safe_hole->wrap ($cb); 916 *{"safe::$fun"} = $safe_hole->wrap ($cb);
917} 917}
918 918
919=back
920
921=cut
922
923#############################################################################
924
925=head2 EXTENSION DATABASE SUPPORT
926
927Crossfire maintains a very simple database for extension use. It can
928currently store anything that can be serialised using Storable, which
929excludes objects.
930
931The parameter C<$family> should best start with the name of the extension
932using it, it should be unique.
933
934=over 4
935
936=item $hashref = cf::db_get $family
937
938Return a hashref for use by the extension C<$family>, which can be
939modified. After modifications, you have to call C<cf::db_dirty> or
940C<cf::db_sync>.
941
942=item $value = cf::db_get $family => $key
943
944Returns a single value from the database
945
946=item cf::db_put $family => $hashref
947
948Stores the given family hashref into the database. Updates are delayed, if
949you want the data to be synced to disk immediately, use C<cf::db_sync>.
950
951=item cf::db_put $family => $key => $value
952
953Stores the given C<$value> in the family hash. Updates are delayed, if you
954want the data to be synced to disk immediately, use C<cf::db_sync>.
955
956=item cf::db_dirty
957
958Marks the database as dirty, to be updated at a later time.
959
960=item cf::db_sync
961
962Immediately write the database to disk I<if it is dirty>.
963
964=cut
965
966{
967 my $db;
968 my $path = cf::localdir . "/database.pst";
969
970 sub db_load() {
971 warn "loading database $path\n";#d# remove later
972 $db = stat $path ? Storable::retrieve $path : { };
973 }
974
975 my $pid;
976
977 sub db_save() {
978 warn "saving database $path\n";#d# remove later
979 waitpid $pid, 0 if $pid;
980 if (0 == ($pid = fork)) {
981 $db->{_meta}{version} = 1;
982 Storable::nstore $db, "$path~";
983 rename "$path~", $path;
984 cf::_exit 0 if defined $pid;
985 }
986 }
987
988 my $dirty;
989
990 sub db_sync() {
991 db_save if $dirty;
992 undef $dirty;
993 }
994
995 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, cb => sub {
996 db_sync;
997 });
998
999 sub db_dirty() {
1000 $dirty = 1;
1001 $idle->start;
1002 }
1003
1004 sub db_get($;$) {
1005 @_ >= 2
1006 ? $db->{$_[0]}{$_[1]}
1007 : ($db->{$_[0]} ||= { })
1008 }
1009
1010 sub db_put($$;$) {
1011 if (@_ >= 3) {
1012 $db->{$_[0]}{$_[1]} = $_[2];
1013 } else {
1014 $db->{$_[0]} = $_[1];
1015 }
1016 db_dirty;
1017 }
1018
1019 attach_global
1020 prio => 10000,
1021 on_cleanup => sub {
1022 db_sync;
1023 },
1024 ;
1025}
1026
919############################################################################# 1027#############################################################################
920# the server's main() 1028# the server's main()
921 1029
922sub main { 1030sub main {
1031 db_load;
1032 load_extensions;
923 Event::loop; 1033 Event::loop;
924} 1034}
925 1035
926############################################################################# 1036#############################################################################
927# initialisation 1037# initialisation
928 1038
1039sub _perl_reload(&) {
1040 my ($msg) = @_;
1041
1042 $msg->("reloading...");
1043
1044 eval {
1045 # cancel all watchers
1046 $_->cancel for Event::all_watchers;
1047
1048 # unload all extensions
1049 for (@exts) {
1050 $msg->("unloading <$_>");
1051 unload_extension $_;
1052 }
1053
1054 # unload all modules loaded from $LIBDIR
1055 while (my ($k, $v) = each %INC) {
1056 next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
1057
1058 $msg->("removing <$k>");
1059 delete $INC{$k};
1060
1061 $k =~ s/\.pm$//;
1062 $k =~ s/\//::/g;
1063
1064 if (my $cb = $k->can ("unload_module")) {
1065 $cb->();
1066 }
1067
1068 Symbol::delete_package $k;
1069 }
1070
1071 # sync database to disk
1072 cf::db_sync;
1073
1074 # get rid of safe::, as good as possible
1075 Symbol::delete_package "safe::$_"
1076 for qw(cf::object cf::object::player cf::player cf::map cf::party cf::region);
1077
1078 # remove register_script_function callbacks
1079 # TODO
1080
1081 # unload cf.pm "a bit"
1082 delete $INC{"cf.pm"};
1083
1084 # don't, removes xs symbols, too,
1085 # and global variables created in xs
1086 #Symbol::delete_package __PACKAGE__;
1087
1088 # reload cf.pm
1089 $msg->("reloading cf.pm");
1090 require cf;
1091
1092 # load database again
1093 cf::db_load;
1094
1095 # load extensions
1096 $msg->("load extensions");
1097 cf::load_extensions;
1098
1099 # reattach attachments to objects
1100 $msg->("reattach");
1101 _global_reattach;
1102 };
1103 $msg->($@) if $@;
1104
1105 $msg->("reloaded");
1106};
1107
1108sub perl_reload() {
1109 _perl_reload {
1110 warn $_[0];
1111 print "$_[0]\n";
1112 };
1113}
1114
1115register_command "perl-reload", 0, sub {
1116 my ($who, $arg) = @_;
1117
1118 if ($who->flag (FLAG_WIZ)) {
1119 _perl_reload {
1120 warn $_[0];
1121 $who->message ($_[0]);
1122 };
1123 }
1124};
1125
929register "<global>", __PACKAGE__; 1126register "<global>", __PACKAGE__;
930 1127
931unshift @INC, $LIBDIR; 1128unshift @INC, $LIBDIR;
932
933load_extensions;
934 1129
935$TICK_WATCHER = Event->timer ( 1130$TICK_WATCHER = Event->timer (
936 prio => 1, 1131 prio => 1,
937 at => $NEXT_TICK || 1, 1132 at => $NEXT_TICK || 1,
938 cb => sub { 1133 cb => sub {
947 $TICK_WATCHER->at ($NEXT_TICK); 1142 $TICK_WATCHER->at ($NEXT_TICK);
948 $TICK_WATCHER->start; 1143 $TICK_WATCHER->start;
949 }, 1144 },
950); 1145);
951 1146
952_reload_2;
953
9541 11471
955 1148

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines