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.64 by root, Sun Sep 10 00:51:24 2006 UTC vs.
Revision 1.76 by root, Mon Oct 2 15:28:36 2006 UTC

5use Storable; 5use Storable;
6use Opcode; 6use Opcode;
7use Safe; 7use Safe;
8use Safe::Hole; 8use Safe::Hole;
9 9
10use YAML::Syck ();
10use Time::HiRes; 11use Time::HiRes;
11use Event; 12use Event;
12$Event::Eval = 1; # no idea why this is required, but it is 13$Event::Eval = 1; # no idea why this is required, but it is
13 14
15# work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode?
16$YAML::Syck::ImplicitUnicode = 1;
17
14use strict; 18use strict;
15 19
16_init_vars; 20_init_vars;
17 21
18our %COMMAND = (); 22our %COMMAND = ();
20our $LIBDIR = maps_directory "perl"; 24our $LIBDIR = maps_directory "perl";
21 25
22our $TICK = MAX_TIME * 1e-6; 26our $TICK = MAX_TIME * 1e-6;
23our $TICK_WATCHER; 27our $TICK_WATCHER;
24our $NEXT_TICK; 28our $NEXT_TICK;
29
30our %CFG;
31
32our $uptime;
33
34$uptime ||= time;
35
36#############################################################################
37
38=head2 GLOBAL VARIABLES
39
40=over 4
41
42=item $cf::LIBDIR
43
44The perl library directory, where extensions and cf-specific modules can
45be found. It will be added to C<@INC> automatically.
46
47=item $cf::TICK
48
49The interval between server ticks, in seconds.
50
51=item %cf::CFG
52
53Configuration for the server, loaded from C</etc/crossfire/config>, or
54from wherever your confdir points to.
55
56=back
57
58=cut
25 59
26BEGIN { 60BEGIN {
27 *CORE::GLOBAL::warn = sub { 61 *CORE::GLOBAL::warn = sub {
28 my $msg = join "", @_; 62 my $msg = join "", @_;
29 $msg .= "\n" 63 $msg .= "\n"
51my @exts; 85my @exts;
52my @hook; 86my @hook;
53my %command; 87my %command;
54my %extcmd; 88my %extcmd;
55 89
56############################################################################# 90=head2 UTILITY FUNCTIONS
57# utility functions 91
92=over 4
93
94=cut
58 95
59use JSON::Syck (); # TODO# replace by JSON::PC once working 96use JSON::Syck (); # TODO# replace by JSON::PC once working
97
98=item $ref = cf::from_json $json
99
100Converts a JSON string into the corresponding perl data structure.
101
102=cut
60 103
61sub from_json($) { 104sub from_json($) {
62 $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs 105 $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs
63 JSON::Syck::Load $_[0] 106 JSON::Syck::Load $_[0]
64} 107}
65 108
109=item $json = cf::to_json $ref
110
111Converts a perl data structure into its JSON representation.
112
113=cut
114
66sub to_json($) { 115sub to_json($) {
67 $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs 116 $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs
68 JSON::Syck::Dump $_[0] 117 JSON::Syck::Dump $_[0]
69} 118}
70 119
71############################################################################# 120=back
72# "new" plug-in system
73 121
122=cut
123
124#############################################################################
125
74=head3 EVENTS AND OBJECT ATTACHMENTS 126=head2 EVENTS AND OBJECT ATTACHMENTS
75 127
76=over 4 128=over 4
77 129
78=item $object->attach ($attachment, key => $value...) 130=item $object->attach ($attachment, key => $value...)
79 131
379removed in future versions), and there is no public API to access override 431removed in future versions), and there is no public API to access override
380results (if you must, access C<@cf::invoke_results> directly). 432results (if you must, access C<@cf::invoke_results> directly).
381 433
382=back 434=back
383 435
384=head2 methods valid for all pointers 436=cut
437
438#############################################################################
439
440=head2 METHODS VALID FOR ALL CORE OBJECTS
385 441
386=over 4 442=over 4
387 443
388=item $object->valid 444=item $object->valid, $player->valid, $map->valid
389
390=item $player->valid
391
392=item $map->valid
393 445
394Just because you have a perl object does not mean that the corresponding 446Just because you have a perl object does not mean that the corresponding
395C-level object still exists. If you try to access an object that has no 447C-level object still exists. If you try to access an object that has no
396valid C counterpart anymore you get an exception at runtime. This method 448valid C counterpart anymore you get an exception at runtime. This method
397can be used to test for existence of the C object part without causing an 449can be used to test for existence of the C object part without causing an
643 1 695 1
644 } or warn "$ext not loaded: $@"; 696 } or warn "$ext not loaded: $@";
645 } 697 }
646} 698}
647 699
648sub _perl_reload(&) {
649 my ($msg) = @_;
650
651 $msg->("reloading...");
652
653 eval {
654 # 1. cancel all watchers
655 $_->cancel for Event::all_watchers;
656
657 # 2. unload all extensions
658 for (@exts) {
659 $msg->("unloading <$_>");
660 unload_extension $_;
661 }
662
663 # 3. unload all modules loaded from $LIBDIR
664 while (my ($k, $v) = each %INC) {
665 next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
666
667 $msg->("removing <$k>");
668 delete $INC{$k};
669
670 $k =~ s/\.pm$//;
671 $k =~ s/\//::/g;
672
673 if (my $cb = $k->can ("unload_module")) {
674 $cb->();
675 }
676
677 Symbol::delete_package $k;
678 }
679
680 # 4. get rid of safe::, as good as possible
681 Symbol::delete_package "safe::$_"
682 for qw(cf::object cf::object::player cf::player cf::map cf::party cf::region);
683
684 # 5. remove register_script_function callbacks
685 # TODO
686
687 # 6. unload cf.pm "a bit"
688 delete $INC{"cf.pm"};
689
690 # don't, removes xs symbols, too,
691 # and global variables created in xs
692 #Symbol::delete_package __PACKAGE__;
693
694 # 7. reload cf.pm
695 $msg->("reloading cf.pm");
696 require cf;
697
698 $msg->("load extensions");
699 cf::load_extensions;
700
701 $msg->("reattach");
702 _global_reattach;
703 };
704 $msg->($@) if $@;
705
706 $msg->("reloaded");
707};
708
709sub perl_reload() {
710 _perl_reload {
711 warn $_[0];
712 print "$_[0]\n";
713 };
714}
715
716register_command "perl-reload", 0, sub {
717 my ($who, $arg) = @_;
718
719 if ($who->flag (FLAG_WIZ)) {
720 _perl_reload {
721 warn $_[0];
722 $who->message ($_[0]);
723 };
724 }
725};
726
727############################################################################# 700#############################################################################
728# extcmd framework, basically convert ext <msg> 701# extcmd framework, basically convert ext <msg>
729# into pkg::->on_extcmd_arg1 (...) while shortcutting a few 702# into pkg::->on_extcmd_arg1 (...) while shortcutting a few
730 703
731attach_to_players 704attach_to_players
783 } 756 }
784 }, 757 },
785; 758;
786 759
787############################################################################# 760#############################################################################
788# core extensions - in perl 761
762=head2 CORE EXTENSIONS
763
764Functions and methods that extend core crossfire objects.
765
766=over 4
789 767
790=item cf::player::exists $login 768=item cf::player::exists $login
791 769
792Returns true when the given account exists. 770Returns true when the given account exists.
793 771
796sub cf::player::exists($) { 774sub cf::player::exists($) {
797 cf::player::find $_[0] 775 cf::player::find $_[0]
798 or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2; 776 or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2;
799} 777}
800 778
801=item $player->reply ($npc, $msg[, $flags]) 779=item $object->reply ($npc, $msg[, $flags])
802 780
803Sends a message to the player, as if the npc C<$npc> replied. C<$npc> 781Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
804can be C<undef>. Does the right thing when the player is currently in a 782can be C<undef>. Does the right thing when the player is currently in a
805dialogue with the given NPC character. 783dialogue with the given NPC character.
806 784
833 $msg{msgid} = $id; 811 $msg{msgid} = $id;
834 812
835 $self->send ("ext " . to_json \%msg); 813 $self->send ("ext " . to_json \%msg);
836} 814}
837 815
816=back
817
818=cut
819
838############################################################################# 820#############################################################################
839# map scripting support 821
822=head2 SAFE SCRIPTING
823
824Functions that provide a safe environment to compile and execute
825snippets of perl code without them endangering the safety of the server
826itself. Looping constructs, I/O operators and other built-in functionality
827is not available in the safe scripting environment, and the number of
828functions and methods that cna be called is greatly reduced.
829
830=cut
840 831
841our $safe = new Safe "safe"; 832our $safe = new Safe "safe";
842our $safe_hole = new Safe::Hole; 833our $safe_hole = new Safe::Hole;
843 834
844$SIG{FPE} = 'IGNORE'; 835$SIG{FPE} = 'IGNORE';
845 836
846$safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time)); 837$safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
847 838
848# here we export the classes and methods available to script code 839# here we export the classes and methods available to script code
840
841=pod
842
843The following fucntions and emthods are available within a safe environment:
844
845 cf::object contr pay_amount pay_player
846 cf::object::player player
847 cf::player peaceful
848
849=cut
849 850
850for ( 851for (
851 ["cf::object" => qw(contr pay_amount pay_player)], 852 ["cf::object" => qw(contr pay_amount pay_player)],
852 ["cf::object::player" => qw(player)], 853 ["cf::object::player" => qw(player)],
853 ["cf::player" => qw(peaceful)], 854 ["cf::player" => qw(peaceful)],
856 my ($pkg, @funs) = @$_; 857 my ($pkg, @funs) = @$_;
857 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"}) 858 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
858 for @funs; 859 for @funs;
859} 860}
860 861
862=over 4
863
864=item @retval = safe_eval $code, [var => value, ...]
865
866Compiled and executes the given perl code snippet. additional var/value
867pairs result in temporary local (my) scalar variables of the given name
868that are available in the code snippet. Example:
869
870 my $five = safe_eval '$first + $second', first => 1, second => 4;
871
872=cut
873
861sub safe_eval($;@) { 874sub safe_eval($;@) {
862 my ($code, %vars) = @_; 875 my ($code, %vars) = @_;
863 876
864 my $qcode = $code; 877 my $qcode = $code;
865 $qcode =~ s/"/‟/g; # not allowed in #line filenames 878 $qcode =~ s/"/‟/g; # not allowed in #line filenames
887 } 900 }
888 901
889 wantarray ? @res : $res[0] 902 wantarray ? @res : $res[0]
890} 903}
891 904
905=item cf::register_script_function $function => $cb
906
907Register a function that can be called from within map/npc scripts. The
908function should be reasonably secure and should be put into a package name
909like the extension.
910
911Example: register a function that gets called whenever a map script calls
912C<rent::overview>, as used by the C<rent> extension.
913
914 cf::register_script_function "rent::overview" => sub {
915 ...
916 };
917
918=cut
919
892sub register_script_function { 920sub register_script_function {
893 my ($fun, $cb) = @_; 921 my ($fun, $cb) = @_;
894 922
895 no strict 'refs'; 923 no strict 'refs';
896 *{"safe::$fun"} = $safe_hole->wrap ($cb); 924 *{"safe::$fun"} = $safe_hole->wrap ($cb);
897} 925}
898 926
927=back
928
929=cut
930
931#############################################################################
932
933=head2 EXTENSION DATABASE SUPPORT
934
935Crossfire maintains a very simple database for extension use. It can
936currently store anything that can be serialised using Storable, which
937excludes objects.
938
939The parameter C<$family> should best start with the name of the extension
940using it, it should be unique.
941
942=over 4
943
944=item $hashref = cf::db_get $family
945
946Return a hashref for use by the extension C<$family>, which can be
947modified. After modifications, you have to call C<cf::db_dirty> or
948C<cf::db_sync>.
949
950=item $value = cf::db_get $family => $key
951
952Returns a single value from the database
953
954=item cf::db_put $family => $hashref
955
956Stores the given family hashref into the database. Updates are delayed, if
957you want the data to be synced to disk immediately, use C<cf::db_sync>.
958
959=item cf::db_put $family => $key => $value
960
961Stores the given C<$value> in the family hash. Updates are delayed, if you
962want the data to be synced to disk immediately, use C<cf::db_sync>.
963
964=item cf::db_dirty
965
966Marks the database as dirty, to be updated at a later time.
967
968=item cf::db_sync
969
970Immediately write the database to disk I<if it is dirty>.
971
972=cut
973
974{
975 my $db;
976 my $path = cf::localdir . "/database.pst";
977
978 sub db_load() {
979 warn "loading database $path\n";#d# remove later
980 $db = stat $path ? Storable::retrieve $path : { };
981 }
982
983 my $pid;
984
985 sub db_save() {
986 warn "saving database $path\n";#d# remove later
987 waitpid $pid, 0 if $pid;
988 if (0 == ($pid = fork)) {
989 $db->{_meta}{version} = 1;
990 Storable::nstore $db, "$path~";
991 rename "$path~", $path;
992 cf::_exit 0 if defined $pid;
993 }
994 }
995
996 my $dirty;
997
998 sub db_sync() {
999 db_save if $dirty;
1000 undef $dirty;
1001 }
1002
1003 my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, cb => sub {
1004 db_sync;
1005 });
1006
1007 sub db_dirty() {
1008 $dirty = 1;
1009 $idle->start;
1010 }
1011
1012 sub db_get($;$) {
1013 @_ >= 2
1014 ? $db->{$_[0]}{$_[1]}
1015 : ($db->{$_[0]} ||= { })
1016 }
1017
1018 sub db_put($$;$) {
1019 if (@_ >= 3) {
1020 $db->{$_[0]}{$_[1]} = $_[2];
1021 } else {
1022 $db->{$_[0]} = $_[1];
1023 }
1024 db_dirty;
1025 }
1026
1027 attach_global
1028 prio => 10000,
1029 on_cleanup => sub {
1030 db_sync;
1031 },
1032 ;
1033}
1034
899############################################################################# 1035#############################################################################
900# the server's main() 1036# the server's main()
901 1037
1038sub cfg_load {
1039 open my $fh, "<:utf8", cf::confdir . "/config"
1040 or return;
1041
1042 local $/;
1043 *CFG = YAML::Syck::Load <$fh>;
1044}
1045
902sub main { 1046sub main {
1047 cfg_load;
1048 db_load;
903 load_extensions; 1049 load_extensions;
904 Event::loop; 1050 Event::loop;
905} 1051}
906 1052
907############################################################################# 1053#############################################################################
908# initialisation 1054# initialisation
1055
1056sub _perl_reload(&) {
1057 my ($msg) = @_;
1058
1059 $msg->("reloading...");
1060
1061 eval {
1062 # cancel all watchers
1063 $_->cancel for Event::all_watchers;
1064
1065 # unload all extensions
1066 for (@exts) {
1067 $msg->("unloading <$_>");
1068 unload_extension $_;
1069 }
1070
1071 # unload all modules loaded from $LIBDIR
1072 while (my ($k, $v) = each %INC) {
1073 next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
1074
1075 $msg->("removing <$k>");
1076 delete $INC{$k};
1077
1078 $k =~ s/\.pm$//;
1079 $k =~ s/\//::/g;
1080
1081 if (my $cb = $k->can ("unload_module")) {
1082 $cb->();
1083 }
1084
1085 Symbol::delete_package $k;
1086 }
1087
1088 # sync database to disk
1089 cf::db_sync;
1090
1091 # get rid of safe::, as good as possible
1092 Symbol::delete_package "safe::$_"
1093 for qw(cf::object cf::object::player cf::player cf::map cf::party cf::region);
1094
1095 # remove register_script_function callbacks
1096 # TODO
1097
1098 # unload cf.pm "a bit"
1099 delete $INC{"cf.pm"};
1100
1101 # don't, removes xs symbols, too,
1102 # and global variables created in xs
1103 #Symbol::delete_package __PACKAGE__;
1104
1105 # reload cf.pm
1106 $msg->("reloading cf.pm");
1107 require cf;
1108
1109 # load config and database again
1110 cf::cfg_load;
1111 cf::db_load;
1112
1113 # load extensions
1114 $msg->("load extensions");
1115 cf::load_extensions;
1116
1117 # reattach attachments to objects
1118 $msg->("reattach");
1119 _global_reattach;
1120 };
1121 $msg->($@) if $@;
1122
1123 $msg->("reloaded");
1124};
1125
1126sub perl_reload() {
1127 _perl_reload {
1128 warn $_[0];
1129 print "$_[0]\n";
1130 };
1131}
1132
1133register_command "perl-reload", 0, sub {
1134 my ($who, $arg) = @_;
1135
1136 if ($who->flag (FLAG_WIZ)) {
1137 _perl_reload {
1138 warn $_[0];
1139 $who->message ($_[0]);
1140 };
1141 }
1142};
909 1143
910register "<global>", __PACKAGE__; 1144register "<global>", __PACKAGE__;
911 1145
912unshift @INC, $LIBDIR; 1146unshift @INC, $LIBDIR;
913 1147

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines