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.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 $LIBDIR = maps_directory "perl"; 20our $LIBDIR = maps_directory "perl";
21 21
22our $TICK = MAX_TIME * 1e-6; 22our $TICK = MAX_TIME * 1e-6;
23our $TICK_WATCHER; 23our $TICK_WATCHER;
24our $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
25 51
26BEGIN { 52BEGIN {
27 *CORE::GLOBAL::warn = sub { 53 *CORE::GLOBAL::warn = sub {
28 my $msg = join "", @_; 54 my $msg = join "", @_;
29 $msg .= "\n" 55 $msg .= "\n"
51my @exts; 77my @exts;
52my @hook; 78my @hook;
53my %command; 79my %command;
54my %extcmd; 80my %extcmd;
55 81
56############################################################################# 82=head2 UTILITY FUNCTIONS
57# utility functions 83
84=over 4
85
86=cut
58 87
59use 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
60 95
61sub from_json($) { 96sub from_json($) {
62 $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs 97 $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs
63 JSON::Syck::Load $_[0] 98 JSON::Syck::Load $_[0]
64} 99}
65 100
101=item $json = cf::to_json $ref
102
103Converts a perl data structure into its JSON representation.
104
105=cut
106
66sub to_json($) { 107sub to_json($) {
67 $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs 108 $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs
68 JSON::Syck::Dump $_[0] 109 JSON::Syck::Dump $_[0]
69} 110}
70 111
71############################################################################# 112=back
72# "new" plug-in system
73 113
114=cut
115
116#############################################################################
117
74=head3 EVENTS AND OBJECT ATTACHMENTS 118=head2 EVENTS AND OBJECT ATTACHMENTS
75 119
76=over 4 120=over 4
77 121
78=item $object->attach ($attachment, key => $value...) 122=item $object->attach ($attachment, key => $value...)
79 123
353 for (@$callbacks) { 397 for (@$callbacks) {
354 eval { &{$_->[1]} }; 398 eval { &{$_->[1]} };
355 399
356 if ($@) { 400 if ($@) {
357 warn "$@"; 401 warn "$@";
358 warn "... while processing $EVENT[$event][0] event, skipping processing altogether.\n"; 402 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
359 override; 403 override;
360 } 404 }
361 405
362 return 1 if $override; 406 return 1 if $override;
363 } 407 }
379removed 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
380results (if you must, access C<@cf::invoke_results> directly). 424results (if you must, access C<@cf::invoke_results> directly).
381 425
382=back 426=back
383 427
384=head2 methods valid for all pointers 428=cut
429
430#############################################################################
431
432=head2 METHODS VALID FOR ALL CORE OBJECTS
385 433
386=over 4 434=over 4
387 435
388=item $object->valid 436=item $object->valid, $player->valid, $map->valid
389
390=item $player->valid
391
392=item $map->valid
393 437
394Just 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
395C-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
396valid C counterpart anymore you get an exception at runtime. This method 440valid 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 441can be used to test for existence of the C object part without causing an
643 1 687 1
644 } or warn "$ext not loaded: $@"; 688 } or warn "$ext not loaded: $@";
645 } 689 }
646} 690}
647 691
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############################################################################# 692#############################################################################
725# extcmd framework, basically convert ext <msg> 693# extcmd framework, basically convert ext <msg>
726# into pkg::->on_extcmd_arg1 (...) while shortcutting a few 694# into pkg::->on_extcmd_arg1 (...) while shortcutting a few
727 695
728attach_to_players 696attach_to_players
780 } 748 }
781 }, 749 },
782; 750;
783 751
784############################################################################# 752#############################################################################
785# core extensions - in perl 753
754=head2 CORE EXTENSIONS
755
756Functions and methods that extend core crossfire objects.
757
758=over 4
786 759
787=item cf::player::exists $login 760=item cf::player::exists $login
788 761
789Returns true when the given account exists. 762Returns true when the given account exists.
790 763
830 $msg{msgid} = $id; 803 $msg{msgid} = $id;
831 804
832 $self->send ("ext " . to_json \%msg); 805 $self->send ("ext " . to_json \%msg);
833} 806}
834 807
808=back
809
810=cut
811
835############################################################################# 812#############################################################################
836# 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
837 823
838our $safe = new Safe "safe"; 824our $safe = new Safe "safe";
839our $safe_hole = new Safe::Hole; 825our $safe_hole = new Safe::Hole;
840 826
841$SIG{FPE} = 'IGNORE'; 827$SIG{FPE} = 'IGNORE';
842 828
843$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));
844 830
845# 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
846 842
847for ( 843for (
848 ["cf::object" => qw(contr pay_amount pay_player)], 844 ["cf::object" => qw(contr pay_amount pay_player)],
849 ["cf::object::player" => qw(player)], 845 ["cf::object::player" => qw(player)],
850 ["cf::player" => qw(peaceful)], 846 ["cf::player" => qw(peaceful)],
853 my ($pkg, @funs) = @$_; 849 my ($pkg, @funs) = @$_;
854 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"}) 850 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
855 for @funs; 851 for @funs;
856} 852}
857 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
858sub safe_eval($;@) { 866sub safe_eval($;@) {
859 my ($code, %vars) = @_; 867 my ($code, %vars) = @_;
860 868
861 my $qcode = $code; 869 my $qcode = $code;
862 $qcode =~ s/"/‟/g; # not allowed in #line filenames 870 $qcode =~ s/"/‟/g; # not allowed in #line filenames
884 } 892 }
885 893
886 wantarray ? @res : $res[0] 894 wantarray ? @res : $res[0]
887} 895}
888 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
889sub register_script_function { 912sub register_script_function {
890 my ($fun, $cb) = @_; 913 my ($fun, $cb) = @_;
891 914
892 no strict 'refs'; 915 no strict 'refs';
893 *{"safe::$fun"} = $safe_hole->wrap ($cb); 916 *{"safe::$fun"} = $safe_hole->wrap ($cb);
894} 917}
895 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
896############################################################################# 1027#############################################################################
897# the server's main() 1028# the server's main()
898 1029
899sub main { 1030sub main {
1031 db_load;
900 load_extensions; 1032 load_extensions;
901 Event::loop; 1033 Event::loop;
902} 1034}
903 1035
904############################################################################# 1036#############################################################################
905# initialisation 1037# initialisation
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};
906 1125
907register "<global>", __PACKAGE__; 1126register "<global>", __PACKAGE__;
908 1127
909unshift @INC, $LIBDIR; 1128unshift @INC, $LIBDIR;
910 1129
923 $TICK_WATCHER->at ($NEXT_TICK); 1142 $TICK_WATCHER->at ($NEXT_TICK);
924 $TICK_WATCHER->start; 1143 $TICK_WATCHER->start;
925 }, 1144 },
926); 1145);
927 1146
928_reload_2;
929
9301 11471
931 1148

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines