--- deliantra/server/lib/cf.pm 2009/01/08 19:23:44 1.468
+++ deliantra/server/lib/cf.pm 2009/10/12 14:12:54 1.485
@@ -1,23 +1,24 @@
-#
+#
# This file is part of Deliantra, the Roguelike Realtime MMORPG.
#
# Copyright (©) 2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
#
-# Deliantra is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# Deliantra is free software: you can redistribute it and/or modify it under
+# the terms of the Affero GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
+# You should have received a copy of the Affero GNU General Public License
+# and the GNU General Public License along with this program. If not, see
+# .
#
# The authors can be reached via e-mail to
-#
+#
package cf;
@@ -55,7 +56,7 @@
use Data::Dumper;
use Digest::MD5;
use Fcntl;
-use YAML ();
+use YAML::XS ();
use IO::AIO ();
use Time::HiRes;
use Compress::LZF;
@@ -74,6 +75,9 @@
Compress::LZF::set_serializer "Storable", "Storable::net_mstore", "Storable::mretrieve";
Compress::LZF::sfreeze_cr { }; # prime Compress::LZF so it does not use require later
+# strictly for debugging
+$SIG{QUIT} = sub { Carp::cluck "SIGQUIT" };
+
sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload
our %COMMAND = ();
@@ -87,6 +91,8 @@
our $RELOAD; # number of reloads so far, non-zero while in reload
our @EVENT;
+our @REFLECT; # set by XS
+our %REFLECT; # set by us
our $CONFDIR = confdir;
our $DATADIR = datadir;
@@ -107,14 +113,14 @@
our $TICK = MAX_TIME * 1e-6; # this is a CONSTANT(!)
our $NEXT_RUNTIME_WRITE; # when should the runtime file be written
our $NEXT_TICK;
-our $USE_FSYNC = 1; # use fsync to write maps - default off
+our $USE_FSYNC = 1; # use fsync to write maps - default on
our $BDB_DEADLOCK_WATCHER;
our $BDB_CHECKPOINT_WATCHER;
our $BDB_TRICKLE_WATCHER;
our $DB_ENV;
-our @EXTRA_MODULES = qw(pod mapscript);
+our @EXTRA_MODULES = qw(pod match mapscript);
our %CFG;
@@ -136,7 +142,8 @@
our @POST_INIT;
-our $REATTACH_ON_RELOAD; # ste to true to force object reattach on reload (slow)
+our $REATTACH_ON_RELOAD; # set to true to force object reattach on reload (slow)
+our $REALLY_UNLOOP; # never set to true, please :)
binmode STDOUT;
binmode STDERR;
@@ -159,6 +166,17 @@
#############################################################################
+%REFLECT = ();
+for (@REFLECT) {
+ my $reflect = JSON::XS::decode_json $_;
+ $REFLECT{$reflect->{class}} = $reflect;
+}
+
+# this is decidedly evil
+$REFLECT{object}{flags} = { map +($_ => undef), grep $_, map /^FLAG_([A-Z0-9_]+)$/ && lc $1, keys %{"cf::"} };
+
+#############################################################################
+
=head2 GLOBAL VARIABLES
=over 4
@@ -216,38 +234,41 @@
C is called C<@cf::INVOKE_RESULTS> is set to the parameters of
that call.
+=item %cf::REFLECT
+
+Contains, for each (C++) class name, a hash reference with information
+about object members (methods, scalars, arrays and flags) and other
+metadata, which is useful for introspection.
+
=back
=cut
-BEGIN {
- *CORE::GLOBAL::warn = sub {
- my $msg = join "", @_;
+$Coro::State::WARNHOOK = sub {
+ my $msg = join "", @_;
- $msg .= "\n"
- unless $msg =~ /\n$/;
+ $msg .= "\n"
+ unless $msg =~ /\n$/;
- $msg =~ s/([\x00-\x08\x0b-\x1f])/sprintf "\\x%02x", ord $1/ge;
+ $msg =~ s/([\x00-\x08\x0b-\x1f])/sprintf "\\x%02x", ord $1/ge;
- LOG llevError, $msg;
- };
-}
+ LOG llevError, $msg;
+};
$Coro::State::DIEHOOK = sub {
return unless $^S eq 0; # "eq", not "=="
+ warn Carp::longmess $_[0];
+
if ($Coro::current == $Coro::main) {#d#
warn "DIEHOOK called in main context, Coro bug?\n";#d#
return;#d#
}#d#
# kill coroutine otherwise
- warn Carp::longmess $_[0];
Coro::terminate
};
-$SIG{__DIE__} = sub { }; #d#?
-
@safe::cf::global::ISA = @cf::global::ISA = 'cf::attachable';
@safe::cf::object::ISA = @cf::object::ISA = 'cf::attachable';
@safe::cf::player::ISA = @cf::player::ISA = 'cf::attachable';
@@ -1153,7 +1174,10 @@
if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) {
aio_chmod $fh, SAVE_MODE;
aio_write $fh, 0, (length $$rdata), $$rdata, 0;
- aio_fsync $fh if $cf::USE_FSYNC;
+ if ($cf::USE_FSYNC) {
+ aio_sync_file_range $fh, 0, 0, IO::AIO::SYNC_FILE_RANGE_WAIT_BEFORE | IO::AIO::SYNC_FILE_RANGE_WRITE | IO::AIO::SYNC_FILE_RANGE_WAIT_AFTER;
+ aio_fsync $fh;
+ }
aio_close $fh;
if (@$objs) {
@@ -1161,7 +1185,10 @@
aio_chmod $fh, SAVE_MODE;
my $data = Coro::Storable::nfreeze { version => 1, objs => $objs };
aio_write $fh, 0, (length $data), $data, 0;
- aio_fsync $fh if $cf::USE_FSYNC;
+ if ($cf::USE_FSYNC) {
+ aio_sync_file_range $fh, 0, 0, IO::AIO::SYNC_FILE_RANGE_WAIT_BEFORE | IO::AIO::SYNC_FILE_RANGE_WRITE | IO::AIO::SYNC_FILE_RANGE_WAIT_AFTER;
+ aio_fsync $fh;
+ }
aio_close $fh;
aio_rename "$filename.pst~", "$filename.pst";
}
@@ -1322,7 +1349,7 @@
sub cache_extensions {
my $grp = IO::AIO::aio_group;
- add $grp IO::AIO::aio_readdir $LIBDIR, sub {
+ add $grp IO::AIO::aio_readdirx $LIBDIR, IO::AIO::READDIR_STAT_ORDER, sub {
for (grep /\.ext$/, @{$_[0]}) {
add $grp IO::AIO::aio_load "$LIBDIR/$_", my $data;
}
@@ -2215,7 +2242,7 @@
return if $self->players;
- warn "resetting map ", $self->path;
+ warn "resetting map ", $self->path, "\n";
$self->in_memory (cf::MAP_SWAPPED);
@@ -2526,11 +2553,12 @@
$map->load_neighbours;
return unless $self->contr->active;
- $self->flag (cf::FLAG_DEBUG, 0);#d# temp
- $self->activate_recursive;
local $self->{_prev_pos} = $link_pos; # ugly hack for rent.ext
$self->enter_map ($map, $x, $y);
+
+ # only activate afterwards, to support waiting in hooks
+ $self->activate_recursive;
}
=item $player_object->goto ($path, $x, $y[, $check->($map)[, $done->()]])
@@ -2787,6 +2815,12 @@
reply => undef,
tooltip => "Shows your experience per skill and item power",
},
+ "c/shopitems" => {
+ id => "infobox",
+ title => "Shop Items",
+ reply => undef,
+ tooltip => "Shows the items currently for sale in this shop",
+ },
"c/resistances" => {
id => "infobox",
title => "Resistances",
@@ -2799,6 +2833,12 @@
reply => undef,
tooltip => "Shows information abotu your pets/a specific pet",
},
+ "c/perceiveself" => {
+ id => "infobox",
+ title => "Perceive Self",
+ reply => undef,
+ tooltip => "You gained detailed knowledge about yourself",
+ },
"c/uptime" => {
id => "infobox",
title => "Uptime",
@@ -3345,11 +3385,13 @@
}
sub reload_config {
+ warn "reloading config file...\n";
+
open my $fh, "<:utf8", "$CONFDIR/config"
or return;
local $/;
- *CFG = YAML::Load <$fh>;
+ *CFG = YAML::XS::Load scalar <$fh>;
$EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37];
@@ -3363,6 +3405,8 @@
};
warn $@ if $@;
}
+
+ warn "finished reloading resource files\n";
}
sub pidfile() {
@@ -3384,6 +3428,15 @@
print $fh $$;
}
+sub main_loop {
+ warn "EV::loop starting\n";
+ if (1) {
+ EV::loop;
+ }
+ warn "EV::loop returned\n";
+ goto &main_loop unless $REALLY_UNLOOP;
+}
+
sub main {
cf::init_globals; # initialise logging
@@ -3431,12 +3484,13 @@
utime time, time, $RUNTIMEFILE;
# no (long-running) fork's whatsoever before this point(!)
+ use POSIX ();
POSIX::close delete $ENV{LOCKUTIL_LOCK_FD} if exists $ENV{LOCKUTIL_LOCK_FD};
(pop @POST_INIT)->(0) while @POST_INIT;
};
- EV::loop;
+ main_loop;
}
#############################################################################
@@ -3712,7 +3766,7 @@
warn "reloading cf.pm";
require cf;
- cf::_connect_to_perl; # nominally unnecessary, but cannot hurt
+ cf::_connect_to_perl_1;
warn "loading config and database again";
cf::reload_config;
@@ -3930,6 +3984,7 @@
# load additional modules
require "cf/$_.pm" for @EXTRA_MODULES;
+cf::_connect_to_perl_2;
END { cf::emergency_save }