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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines