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.479 by root, Thu Oct 8 05:04:27 2009 UTC vs.
Revision 1.501 by root, Sat Jan 16 23:27:21 2010 UTC

1# 1#
2# This file is part of Deliantra, the Roguelike Realtime MMORPG. 2# This file is part of Deliantra, the Roguelike Realtime MMORPG.
3# 3#
4# Copyright (©) 2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 4# Copyright (©) 2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5# 5#
6# Deliantra is free software: you can redistribute it and/or modify 6# Deliantra is free software: you can redistribute it and/or modify it under
7# it under the terms of the GNU General Public License as published by 7# the terms of the Affero GNU General Public License as published by the
8# the Free Software Foundation, either version 3 of the License, or 8# Free Software Foundation, either version 3 of the License, or (at your
9# (at your option) any later version. 9# option) any later version.
10# 10#
11# This program is distributed in the hope that it will be useful, 11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details. 14# GNU General Public License for more details.
15# 15#
16# You should have received a copy of the GNU General Public License 16# You should have received a copy of the Affero GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>. 17# and the GNU General Public License along with this program. If not, see
18# <http://www.gnu.org/licenses/>.
18# 19#
19# The authors can be reached via e-mail to <support@deliantra.net> 20# The authors can be reached via e-mail to <support@deliantra.net>
20# 21#
21 22
22package cf; 23package cf;
23 24
24use 5.10.0; 25use 5.10.0;
25use utf8; 26use utf8;
31use EV; 32use EV;
32use Opcode; 33use Opcode;
33use Safe; 34use Safe;
34use Safe::Hole; 35use Safe::Hole;
35use Storable (); 36use Storable ();
37use Carp ();
36 38
37use Guard (); 39use Guard ();
38use Coro (); 40use Coro ();
39use Coro::State; 41use Coro::State;
40use Coro::Handle; 42use Coro::Handle;
51use Coro::Util (); 53use Coro::Util ();
52 54
53use JSON::XS 2.01 (); 55use JSON::XS 2.01 ();
54use BDB (); 56use BDB ();
55use Data::Dumper; 57use Data::Dumper;
56use Digest::MD5;
57use Fcntl; 58use Fcntl;
58use YAML (); 59use YAML::XS ();
59use IO::AIO (); 60use IO::AIO ();
60use Time::HiRes; 61use Time::HiRes;
61use Compress::LZF; 62use Compress::LZF;
62use Digest::MD5 (); 63use Digest::MD5 ();
63 64
117our $BDB_DEADLOCK_WATCHER; 118our $BDB_DEADLOCK_WATCHER;
118our $BDB_CHECKPOINT_WATCHER; 119our $BDB_CHECKPOINT_WATCHER;
119our $BDB_TRICKLE_WATCHER; 120our $BDB_TRICKLE_WATCHER;
120our $DB_ENV; 121our $DB_ENV;
121 122
122our @EXTRA_MODULES = qw(pod mapscript); 123our @EXTRA_MODULES = qw(pod match mapscript);
123 124
124our %CFG; 125our %CFG;
125 126
126our $UPTIME; $UPTIME ||= time; 127our $UPTIME; $UPTIME ||= time;
127our $RUNTIME; 128our $RUNTIME;
169for (@REFLECT) { 170for (@REFLECT) {
170 my $reflect = JSON::XS::decode_json $_; 171 my $reflect = JSON::XS::decode_json $_;
171 $REFLECT{$reflect->{class}} = $reflect; 172 $REFLECT{$reflect->{class}} = $reflect;
172} 173}
173 174
175# this is decidedly evil
176$REFLECT{object}{flags} = { map +($_ => undef), grep $_, map /^FLAG_([A-Z0-9_]+)$/ && lc $1, keys %{"cf::"} };
177
174############################################################################# 178#############################################################################
175 179
176=head2 GLOBAL VARIABLES 180=head2 GLOBAL VARIABLES
177 181
178=over 4 182=over 4
224returns directly I<after> the tick processing (and consequently, can only wake one process 228returns directly I<after> the tick processing (and consequently, can only wake one process
225per tick), while cf::wait_for_tick wakes up all waiters after tick processing. 229per tick), while cf::wait_for_tick wakes up all waiters after tick processing.
226 230
227=item @cf::INVOKE_RESULTS 231=item @cf::INVOKE_RESULTS
228 232
229This array contains the results of the last C<invoke ()> call. When 233This array contains the results of the last C<invoke ()> call. When
230C<cf::override> is called C<@cf::INVOKE_RESULTS> is set to the parameters of 234C<cf::override> is called C<@cf::INVOKE_RESULTS> is set to the parameters of
231that call. 235that call.
232 236
233=item %cf::REFLECT 237=item %cf::REFLECT
234 238
235Contains, for each (C++) class name, a hash reference with information 239Contains, for each (C++) class name, a hash reference with information
236about object members (methods, scalars and arrays) and other metadata, 240about object members (methods, scalars, arrays and flags) and other
237which is useful for introspection. 241metadata, which is useful for introspection.
238 242
239=back 243=back
240 244
241=cut 245=cut
242 246
285)) { 289)) {
286 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg; 290 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
287} 291}
288 292
289$EV::DIED = sub { 293$EV::DIED = sub {
290 warn "error in event callback: @_"; 294 Carp::cluck "error in event callback: @_";
291}; 295};
292 296
293############################################################################# 297#############################################################################
294 298
295=head2 UTILITY FUNCTIONS 299=head2 UTILITY FUNCTIONS
2005 2009
2006 $cf::MAP{$path} = $map 2010 $cf::MAP{$path} = $map
2007 } 2011 }
2008} 2012}
2009 2013
2010sub pre_load { } 2014sub pre_load { }
2011sub post_load { } 2015#sub post_load { } # XS
2012 2016
2013sub load { 2017sub load {
2014 my ($self) = @_; 2018 my ($self) = @_;
2015 2019
2016 local $self->{deny_reset} = 1; # loading can take a long time 2020 local $self->{deny_reset} = 1; # loading can take a long time
2337 : normalise $_ 2341 : normalise $_
2338 } @{ aio_readdir $UNIQUEDIR or [] } 2342 } @{ aio_readdir $UNIQUEDIR or [] }
2339 ] 2343 ]
2340} 2344}
2341 2345
2346=item cf::map::static_maps
2347
2348Returns an arrayref if paths of all static maps (all preinstalled F<.map>
2349file in the shared directory excluding F</styles> and F</editor>). May
2350block.
2351
2352=cut
2353
2354sub static_maps() {
2355 my @dirs = "";
2356 my @maps;
2357
2358 while (@dirs) {
2359 my $dir = shift @dirs;
2360
2361 next if $dir eq "/styles" || $dir eq "/editor";
2362
2363 my ($dirs, $files) = Coro::AIO::aio_scandir "$MAPDIR$dir", 2
2364 or return;
2365
2366 for (@$files) {
2367 s/\.map$// or next;
2368 utf8::decode $_;
2369 push @maps, "$dir/$_";
2370 }
2371
2372 push @dirs, map "$dir/$_", @$dirs;
2373 }
2374
2375 \@maps
2376}
2377
2342=back 2378=back
2343 2379
2344=head3 cf::object 2380=head3 cf::object
2345 2381
2346=cut 2382=cut
2541 ($x, $y) = (-1, -1) 2577 ($x, $y) = (-1, -1)
2542 unless (defined $x) && (defined $y); 2578 unless (defined $x) && (defined $y);
2543 2579
2544 # use -1 or undef as default coordinates, not 0, 0 2580 # use -1 or undef as default coordinates, not 0, 0
2545 ($x, $y) = ($map->enter_x, $map->enter_y) 2581 ($x, $y) = ($map->enter_x, $map->enter_y)
2546 if $x <=0 && $y <= 0; 2582 if $x <= 0 && $y <= 0;
2547 2583
2548 $map->load; 2584 $map->load;
2549 $map->load_neighbours; 2585 $map->load_neighbours;
2550 2586
2551 return unless $self->contr->active; 2587 return unless $self->contr->active;
2750 2786
2751 utf8::encode $text; 2787 utf8::encode $text;
2752 $self->send_packet (sprintf "drawinfo %d %s", $flags || cf::NDI_BLACK, $text); 2788 $self->send_packet (sprintf "drawinfo %d %s", $flags || cf::NDI_BLACK, $text);
2753} 2789}
2754 2790
2791=item $client->send_big_packet ($pkt)
2792
2793Like C<send_packet>, but tries to compress large packets, and fragments
2794them as required.
2795
2796=cut
2797
2798our $MAXFRAGSIZE = cf::MAXSOCKBUF - 64;
2799
2800sub cf::client::send_big_packet {
2801 my ($self, $pkt) = @_;
2802
2803 # try lzf for large packets
2804 $pkt = "lzf " . Compress::LZF::compress $pkt
2805 if 1024 <= length $pkt and $self->{can_lzf};
2806
2807 # split very large packets
2808 if ($MAXFRAGSIZE < length $pkt and $self->{can_lzf}) {
2809 $self->send_packet ("frag $_") for unpack "(a$MAXFRAGSIZE)*", $pkt;
2810 $pkt = "frag";
2811 }
2812
2813 $self->send_packet ($pkt);
2814}
2815
2755=item $client->send_msg ($channel, $msg, $color, [extra...]) 2816=item $client->send_msg ($channel, $msg, $color, [extra...])
2756 2817
2757Send a drawinfo or msg packet to the client, formatting the msg for the 2818Send a drawinfo or msg packet to the client, formatting the msg for the
2758client if neccessary. C<$type> should be a string identifying the type of 2819client if neccessary. C<$type> should be a string identifying the type of
2759the message, with C<log> being the default. If C<$color> is negative, suppress 2820the message, with C<log> being the default. If C<$color> is negative, suppress
2761 2822
2762=cut 2823=cut
2763 2824
2764# non-persistent channels (usually the info channel) 2825# non-persistent channels (usually the info channel)
2765our %CHANNEL = ( 2826our %CHANNEL = (
2827 "c/motd" => {
2828 id => "infobox",
2829 title => "MOTD",
2830 reply => undef,
2831 tooltip => "The message of the day",
2832 },
2766 "c/identify" => { 2833 "c/identify" => {
2767 id => "infobox", 2834 id => "infobox",
2768 title => "Identify", 2835 title => "Identify",
2769 reply => undef, 2836 reply => undef,
2770 tooltip => "Items recently identified", 2837 tooltip => "Items recently identified",
2772 "c/examine" => { 2839 "c/examine" => {
2773 id => "infobox", 2840 id => "infobox",
2774 title => "Examine", 2841 title => "Examine",
2775 reply => undef, 2842 reply => undef,
2776 tooltip => "Signs and other items you examined", 2843 tooltip => "Signs and other items you examined",
2844 },
2845 "c/shopinfo" => {
2846 id => "infobox",
2847 title => "Shop Info",
2848 reply => undef,
2849 tooltip => "What your bargaining skill tells you about the shop",
2777 }, 2850 },
2778 "c/book" => { 2851 "c/book" => {
2779 id => "infobox", 2852 id => "infobox",
2780 title => "Book", 2853 title => "Book",
2781 reply => undef, 2854 reply => undef,
2897 my $pkt = "msg " 2970 my $pkt = "msg "
2898 . $self->{json_coder}->encode ( 2971 . $self->{json_coder}->encode (
2899 [$color & cf::NDI_CLIENT_MASK, $channel, $msg, @extra] 2972 [$color & cf::NDI_CLIENT_MASK, $channel, $msg, @extra]
2900 ); 2973 );
2901 2974
2902 # try lzf for large packets
2903 $pkt = "lzf " . Compress::LZF::compress $pkt
2904 if 1024 <= length $pkt and $self->{can_lzf};
2905
2906 # split very large packets
2907 if (8192 < length $pkt and $self->{can_lzf}) {
2908 $self->send_packet ("frag $_") for unpack "(a8192)*", $pkt;
2909 $pkt = "frag";
2910 }
2911
2912 $self->send_packet ($pkt); 2975 $self->send_big_packet ($pkt);
2913} 2976}
2914 2977
2915=item $client->ext_msg ($type, @msg) 2978=item $client->ext_msg ($type, @msg)
2916 2979
2917Sends an ext event to the client. 2980Sends an ext event to the client.
2920 2983
2921sub cf::client::ext_msg($$@) { 2984sub cf::client::ext_msg($$@) {
2922 my ($self, $type, @msg) = @_; 2985 my ($self, $type, @msg) = @_;
2923 2986
2924 if ($self->extcmd == 2) { 2987 if ($self->extcmd == 2) {
2925 $self->send_packet ("ext " . $self->{json_coder}->encode ([$type, @msg])); 2988 $self->send_big_packet ("ext " . $self->{json_coder}->encode ([$type, @msg]));
2926 } elsif ($self->extcmd == 1) { # TODO: remove 2989 } elsif ($self->extcmd == 1) { # TODO: remove
2927 push @msg, msgtype => "event_$type"; 2990 push @msg, msgtype => "event_$type";
2928 $self->send_packet ("ext " . $self->{json_coder}->encode ({@msg})); 2991 $self->send_big_packet ("ext " . $self->{json_coder}->encode ({@msg}));
2929 } 2992 }
2930} 2993}
2931 2994
2932=item $client->ext_reply ($msgid, @msg) 2995=item $client->ext_reply ($msgid, @msg)
2933 2996
2937 3000
2938sub cf::client::ext_reply($$@) { 3001sub cf::client::ext_reply($$@) {
2939 my ($self, $id, @msg) = @_; 3002 my ($self, $id, @msg) = @_;
2940 3003
2941 if ($self->extcmd == 2) { 3004 if ($self->extcmd == 2) {
2942 $self->send_packet ("ext " . $self->{json_coder}->encode (["reply-$id", @msg])); 3005 $self->send_big_packet ("ext " . $self->{json_coder}->encode (["reply-$id", @msg]));
2943 } elsif ($self->extcmd == 1) { 3006 } elsif ($self->extcmd == 1) {
2944 #TODO: version 1, remove 3007 #TODO: version 1, remove
2945 unshift @msg, msgtype => "reply", msgid => $id; 3008 unshift @msg, msgtype => "reply", msgid => $id;
2946 $self->send_packet ("ext " . $self->{json_coder}->encode ({@msg})); 3009 $self->send_big_packet ("ext " . $self->{json_coder}->encode ({@msg}));
2947 } 3010 }
2948} 3011}
2949 3012
2950=item $success = $client->query ($flags, "text", \&cb) 3013=item $success = $client->query ($flags, "text", \&cb)
2951 3014
3078our $safe_hole = new Safe::Hole; 3141our $safe_hole = new Safe::Hole;
3079 3142
3080$SIG{FPE} = 'IGNORE'; 3143$SIG{FPE} = 'IGNORE';
3081 3144
3082$safe->permit_only (Opcode::opset qw( 3145$safe->permit_only (Opcode::opset qw(
3083 :base_core :base_mem :base_orig :base_math 3146 :base_core :base_mem :base_orig :base_math :base_loop
3084 grepstart grepwhile mapstart mapwhile 3147 grepstart grepwhile mapstart mapwhile
3085 sort time 3148 sort time
3086)); 3149));
3087 3150
3088# here we export the classes and methods available to script code 3151# here we export the classes and methods available to script code
3140 $qcode =~ s/"/‟/g; # not allowed in #line filenames 3203 $qcode =~ s/"/‟/g; # not allowed in #line filenames
3141 $qcode =~ s/\n/\\n/g; 3204 $qcode =~ s/\n/\\n/g;
3142 3205
3143 %vars = (_dummy => 0) unless %vars; 3206 %vars = (_dummy => 0) unless %vars;
3144 3207
3208 my @res;
3145 local $_; 3209 local $_;
3146 local @safe::cf::_safe_eval_args = values %vars;
3147 3210
3148 my $eval = 3211 my $eval =
3149 "do {\n" 3212 "do {\n"
3150 . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n" 3213 . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
3151 . "#line 0 \"{$qcode}\"\n" 3214 . "#line 0 \"{$qcode}\"\n"
3152 . $code 3215 . $code
3153 . "\n}" 3216 . "\n}"
3154 ; 3217 ;
3155 3218
3219 if ($CFG{safe_eval}) {
3156 sub_generation_inc; 3220 sub_generation_inc;
3221 local @safe::cf::_safe_eval_args = values %vars;
3157 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval); 3222 @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
3158 sub_generation_inc; 3223 sub_generation_inc;
3224 } else {
3225 local @cf::_safe_eval_args = values %vars;
3226 @res = wantarray ? eval eval : scalar eval $eval;
3227 }
3159 3228
3160 if ($@) { 3229 if ($@) {
3161 warn "$@"; 3230 warn "$@";
3162 warn "while executing safe code '$code'\n"; 3231 warn "while executing safe code '$code'\n";
3163 warn "with arguments " . (join " ", %vars) . "\n"; 3232 warn "with arguments " . (join " ", %vars) . "\n";
3182=cut 3251=cut
3183 3252
3184sub register_script_function { 3253sub register_script_function {
3185 my ($fun, $cb) = @_; 3254 my ($fun, $cb) = @_;
3186 3255
3187 no strict 'refs'; 3256 $fun = "safe::$fun" if $CFG{safe_eval};
3188 *{"safe::$fun"} = $safe_hole->wrap ($cb); 3257 *$fun = $safe_hole->wrap ($cb);
3189} 3258}
3190 3259
3191=back 3260=back
3192 3261
3193=cut 3262=cut
3214 3283
3215 $facedata->{version} == 2 3284 $facedata->{version} == 2
3216 or cf::cleanup "$path: version mismatch, cannot proceed."; 3285 or cf::cleanup "$path: version mismatch, cannot proceed.";
3217 3286
3218 # patch in the exptable 3287 # patch in the exptable
3288 my $exp_table = $enc->encode ([map cf::level_to_min_exp $_, 1 .. cf::settings->max_level]);
3219 $facedata->{resource}{"res/exp_table"} = { 3289 $facedata->{resource}{"res/exp_table"} = {
3220 type => FT_RSRC, 3290 type => FT_RSRC,
3221 data => $enc->encode ([map cf::level_to_min_exp $_, 1 .. cf::settings->max_level]), 3291 data => $exp_table,
3292 hash => (Digest::MD5::md5 $exp_table),
3222 }; 3293 };
3223 cf::cede_to_tick; 3294 cf::cede_to_tick;
3224 3295
3225 { 3296 {
3226 my $faces = $facedata->{faceinfo}; 3297 my $faces = $facedata->{faceinfo};
3228 while (my ($face, $info) = each %$faces) { 3299 while (my ($face, $info) = each %$faces) {
3229 my $idx = (cf::face::find $face) || cf::face::alloc $face; 3300 my $idx = (cf::face::find $face) || cf::face::alloc $face;
3230 3301
3231 cf::face::set_visibility $idx, $info->{visibility}; 3302 cf::face::set_visibility $idx, $info->{visibility};
3232 cf::face::set_magicmap $idx, $info->{magicmap}; 3303 cf::face::set_magicmap $idx, $info->{magicmap};
3233 cf::face::set_data $idx, 0, $info->{data32}, Digest::MD5::md5 $info->{data32}; 3304 cf::face::set_data $idx, 0, $info->{data32}, $info->{hash32};
3234 cf::face::set_data $idx, 1, $info->{data64}, Digest::MD5::md5 $info->{data64}; 3305 cf::face::set_data $idx, 1, $info->{data64}, $info->{hash64};
3235 3306
3236 cf::cede_to_tick; 3307 cf::cede_to_tick;
3237 } 3308 }
3238 3309
3239 while (my ($face, $info) = each %$faces) { 3310 while (my ($face, $info) = each %$faces) {
3263 3334
3264 cf::anim::invalidate_all; # d'oh 3335 cf::anim::invalidate_all; # d'oh
3265 } 3336 }
3266 3337
3267 { 3338 {
3268 # TODO: for gcfclient pleasure, we should give resources
3269 # that gcfclient doesn't grok a >10000 face index.
3270 my $res = $facedata->{resource}; 3339 my $res = $facedata->{resource};
3271 3340
3272 while (my ($name, $info) = each %$res) { 3341 while (my ($name, $info) = each %$res) {
3273 if (defined $info->{type}) { 3342 if (defined $info->{type}) {
3274 my $idx = (cf::face::find $name) || cf::face::alloc $name; 3343 my $idx = (cf::face::find $name) || cf::face::alloc $name;
3275 my $data;
3276 3344
3277 if ($info->{type} & 1) { 3345 cf::face::set_data $idx, 0, $info->{data}, $info->{hash};
3278 # prepend meta info
3279
3280 my $meta = $enc->encode ({
3281 name => $name,
3282 %{ $info->{meta} || {} },
3283 });
3284
3285 $data = pack "(w/a*)*", $meta, $info->{data};
3286 } else {
3287 $data = $info->{data};
3288 }
3289
3290 cf::face::set_data $idx, 0, $data, Digest::MD5::md5 $data;
3291 cf::face::set_type $idx, $info->{type}; 3346 cf::face::set_type $idx, $info->{type};
3292 } else { 3347 } else {
3293 $RESOURCE{$name} = $info; 3348 $RESOURCE{$name} = $info;
3294 } 3349 }
3295 3350
3379 3434
3380 warn "finished reloading resource files\n"; 3435 warn "finished reloading resource files\n";
3381} 3436}
3382 3437
3383sub reload_config { 3438sub reload_config {
3439 warn "reloading config file...\n";
3440
3384 open my $fh, "<:utf8", "$CONFDIR/config" 3441 open my $fh, "<:utf8", "$CONFDIR/config"
3385 or return; 3442 or return;
3386 3443
3387 local $/; 3444 local $/;
3388 *CFG = YAML::Load <$fh>; 3445 *CFG = YAML::XS::Load scalar <$fh>;
3389 3446
3390 $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37]; 3447 $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37];
3391 3448
3392 $cf::map::MAX_RESET = $CFG{map_max_reset} if exists $CFG{map_max_reset}; 3449 $cf::map::MAX_RESET = $CFG{map_max_reset} if exists $CFG{map_max_reset};
3393 $cf::map::DEFAULT_RESET = $CFG{map_default_reset} if exists $CFG{map_default_reset}; 3450 $cf::map::DEFAULT_RESET = $CFG{map_default_reset} if exists $CFG{map_default_reset};
3397 $CFG{mlockall} ? eval "mlockall()" : eval "munlockall()" 3454 $CFG{mlockall} ? eval "mlockall()" : eval "munlockall()"
3398 and die "WARNING: m(un)lockall failed: $!\n"; 3455 and die "WARNING: m(un)lockall failed: $!\n";
3399 }; 3456 };
3400 warn $@ if $@; 3457 warn $@ if $@;
3401 } 3458 }
3459
3460 warn "finished reloading resource files\n";
3402} 3461}
3403 3462
3404sub pidfile() { 3463sub pidfile() {
3405 sysopen my $fh, $PIDFILE, O_RDWR | O_CREAT 3464 sysopen my $fh, $PIDFILE, O_RDWR | O_CREAT
3406 or die "$PIDFILE: $!"; 3465 or die "$PIDFILE: $!";
3454 }; 3513 };
3455 3514
3456 evthread_start IO::AIO::poll_fileno; 3515 evthread_start IO::AIO::poll_fileno;
3457 3516
3458 cf::sync_job { 3517 cf::sync_job {
3518 cf::load_settings;
3519 cf::load_materials;
3520
3459 reload_resources; 3521 reload_resources;
3460 reload_config; 3522 reload_config;
3461 db_init; 3523 db_init;
3462 3524
3463 cf::load_settings;
3464 cf::load_materials;
3465 cf::init_uuid; 3525 cf::init_uuid;
3466 cf::init_signals; 3526 cf::init_signals;
3467 cf::init_commands; 3527 cf::init_commands;
3468 cf::init_skills; 3528 cf::init_skills;
3469 3529
3756 3816
3757 warn "unload completed, starting to reload now"; 3817 warn "unload completed, starting to reload now";
3758 3818
3759 warn "reloading cf.pm"; 3819 warn "reloading cf.pm";
3760 require cf; 3820 require cf;
3761 cf::_connect_to_perl; # nominally unnecessary, but cannot hurt 3821 cf::_connect_to_perl_1;
3762 3822
3763 warn "loading config and database again"; 3823 warn "loading config and database again";
3764 cf::reload_config; 3824 cf::reload_config;
3765 3825
3766 warn "loading extensions"; 3826 warn "loading extensions";
3828 3888
3829our @WAIT_FOR_TICK; 3889our @WAIT_FOR_TICK;
3830our @WAIT_FOR_TICK_BEGIN; 3890our @WAIT_FOR_TICK_BEGIN;
3831 3891
3832sub wait_for_tick { 3892sub wait_for_tick {
3833 return if tick_inhibit || $Coro::current == $Coro::main; 3893 return Coro::cede if tick_inhibit || $Coro::current == $Coro::main;
3834 3894
3835 my $signal = new Coro::Signal; 3895 my $signal = new Coro::Signal;
3836 push @WAIT_FOR_TICK, $signal; 3896 push @WAIT_FOR_TICK, $signal;
3837 $signal->wait; 3897 $signal->wait;
3838} 3898}
3839 3899
3840sub wait_for_tick_begin { 3900sub wait_for_tick_begin {
3841 return if tick_inhibit || $Coro::current == $Coro::main; 3901 return Coro::cede if tick_inhibit || $Coro::current == $Coro::main;
3842 3902
3843 my $signal = new Coro::Signal; 3903 my $signal = new Coro::Signal;
3844 push @WAIT_FOR_TICK_BEGIN, $signal; 3904 push @WAIT_FOR_TICK_BEGIN, $signal;
3845 $signal->wait; 3905 $signal->wait;
3846} 3906}
3974 } 4034 }
3975} 4035}
3976 4036
3977# load additional modules 4037# load additional modules
3978require "cf/$_.pm" for @EXTRA_MODULES; 4038require "cf/$_.pm" for @EXTRA_MODULES;
4039cf::_connect_to_perl_2;
3979 4040
3980END { cf::emergency_save } 4041END { cf::emergency_save }
3981 4042
39821 40431
3983 4044

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines