--- deliantra/server/lib/cf.pm 2008/09/10 18:18:10 1.445 +++ deliantra/server/lib/cf.pm 2008/09/27 08:17:40 1.455 @@ -65,10 +65,13 @@ # $Storable::canonical = 1; # reduce rsync transfers Coro::State::cctx_stacksize 256000; # 1-2MB stack, for deep recursions in maze generator -Compress::LZF::sfreeze_cr { }; # prime Compress::LZF so it does not use require later $Coro::main->prio (Coro::PRIO_MAX); # run main coroutine ("the server") with very high priority +# make sure c-lzf reinitialises itself +Compress::LZF::set_serializer "Storable", "Storable::net_mstore", "Storable::mretrieve"; +Compress::LZF::sfreeze_cr { }; # prime Compress::LZF so it does not use require later + sub WF_AUTOCANCEL () { 1 } # automatically cancel this watcher on reload our %COMMAND = (); @@ -80,7 +83,7 @@ our %EXT_CORO = (); # coroutines bound to extensions our %EXT_MAP = (); # pluggable maps -our $RELOAD; # number of reloads so far +our $RELOAD; # number of reloads so far, non-zero while in reload our @EVENT; our $CONFDIR = confdir; @@ -127,6 +130,8 @@ our $JITTER; # average jitter our $TICK_START; # for load detecting purposes +our @POST_INIT; + binmode STDOUT; binmode STDERR; @@ -304,6 +309,20 @@ sub encode_json($) { $json_coder->encode ($_[0]) } sub decode_json($) { $json_coder->decode ($_[0]) } +=item cf::post_init { BLOCK } + +Execute the given codeblock, I all extensions have been (re-)loaded, +but I the server starts ticking again. + +The cdoeblock will have a single boolean argument to indicate whether this +is a reload or not. + +=cut + +sub post_init(&) { + push @POST_INIT, shift; +} + =item cf::lock_wait $string Wait until the given lock is available. See cf::lock_acquire. @@ -340,6 +359,7 @@ # wait for lock, if any while ($LOCK{$key}) { + #local $Coro::current->{desc} = "$Coro::current->{desc} "; push @{ $LOCK{$key} }, $Coro::current; Coro::schedule; } @@ -732,7 +752,7 @@ =head2 ATTACHABLE OBJECTS -Many objects in crossfire are so-called attachable objects. That means you can +Many objects in deliantra are so-called attachable objects. That means you can attach callbacks/event handlers (a collection of which is called an "attachment") to it. All such attachable objects support the following methods. @@ -792,7 +812,7 @@ Register an attachment by C<$name> through which attachable objects of the given CLASS can refer to this attachment. -Some classes such as crossfire maps and objects can specify attachments +Some classes such as deliantra maps and objects can specify attachments that are attached at load/instantiate time, thus the need for a name. These calls expect any number of the following handler/hook descriptions: @@ -1390,7 +1410,7 @@ =head2 CORE EXTENSIONS -Functions and methods that extend core crossfire objects. +Functions and methods that extend core deliantra objects. =cut @@ -1443,7 +1463,7 @@ my ($login) = @_; $cf::PLAYER{$login} - or cf::sync_job { !aio_stat path $login } + or !aio_stat path $login } sub find($) { @@ -1624,9 +1644,9 @@ \@paths } -=item $protocol_xml = $player->expand_cfpod ($crossfire_pod) +=item $protocol_xml = $player->expand_cfpod ($cfpod) -Expand crossfire pod fragments into protocol xml. +Expand deliantra pod fragments into protocol xml. =item $player->ext_reply ($msgid, @msg) @@ -2450,8 +2470,10 @@ Freezes the player and moves him/her to a special map (C<{link}>). -The player should be reasonably safe there for short amounts of time. You -I call C as soon as possible, though. +The player should be reasonably safe there for short amounts of time (e.g. +for loading a map). You I call C as soon as possible, +though, as the palyer cannot control the character while it is on the link +map. Will never block. @@ -2519,6 +2541,7 @@ $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 @@ -2691,7 +2714,7 @@ 1 }) { - $self->message ("Something went wrong deep within the crossfire server. " + $self->message ("Something went wrong deep within the deliantra server. " . "I'll try to bring you back to the map you were before. " . "Please report this to the dungeon master!", cf::NDI_UNIQUE | cf::NDI_RED); @@ -2767,6 +2790,12 @@ reply => undef, tooltip => "Shows which body parts you posess and are available", }, + "c/skills" => { + id => "infobox", + title => "Skills", + reply => undef, + tooltip => "Shows your experience per skill and item power", + }, "c/uptime" => { id => "infobox", title => "Uptime", @@ -2790,7 +2819,8 @@ sub cf::client::send_msg { my ($self, $channel, $msg, $color, @extra) = @_; - $msg = $self->pl->expand_cfpod ($msg); + $msg = $self->pl->expand_cfpod ($msg) + unless $color & cf::NDI_VERBATIM; $color &= cf::NDI_CLIENT_MASK; # just in case... @@ -3329,14 +3359,6 @@ warn "finished reloading resource files\n"; } -sub init { - my $guard = freeze_mainloop; - - evthread_start IO::AIO::poll_fileno; - - reload_resources; -} - sub reload_config { open my $fh, "<:utf8", "$CONFDIR/config" or return; @@ -3378,7 +3400,20 @@ } sub main { - atomic; + cf::init_globals; # initialise logging + + LOG llevInfo, "Welcome to Deliantra, v" . VERSION; + LOG llevInfo, "Copyright (C) 2005-2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team."; + LOG llevInfo, "Copyright (C) 1994 Mark Wedel."; + LOG llevInfo, "Copyright (C) 1992 Frank Tore Johansen."; + + cf::init_experience; + cf::init_anim; + cf::init_attackmess; + cf::init_dynamic; + cf::init_block; + + $Coro::current->prio (Coro::PRIO_MAX); # give the main loop max. priority # we must not ever block the main coroutine local $Coro::idle = sub { @@ -3389,19 +3424,33 @@ })->prio (Coro::PRIO_MAX); }; - { - my $guard = freeze_mainloop; + evthread_start IO::AIO::poll_fileno; + + cf::sync_job { + reload_resources; reload_config; db_init; + + cf::load_settings; + cf::load_materials; + cf::init_uuid; + cf::init_signals; + cf::init_commands; + cf::init_skills; + + cf::init_beforeplay; + + atomic; + load_extensions; - $Coro::current->prio (Coro::PRIO_MAX); # give the main loop max. priority - } + utime time, time, $RUNTIMEFILE; - utime time, time, $RUNTIMEFILE; + # no (long-running) fork's whatsoever before this point(!) + POSIX::close delete $ENV{LOCKUTIL_LOCK_FD} if exists $ENV{LOCKUTIL_LOCK_FD}; - # no (long-running) fork's whatsoever before this point(!) - POSIX::close delete $ENV{LOCKUTIL_LOCK_FD} if exists $ENV{LOCKUTIL_LOCK_FD}; + (pop @POST_INIT)->(0) while @POST_INIT; + }; EV::loop; } @@ -3469,7 +3518,14 @@ my $fh = aio_open "$uuid~", O_WRONLY | O_CREAT, 0644 or return; - my $value = uuid_str $uuid_skip + uuid_seq uuid_cur; + my $value = uuid_seq uuid_cur; + + unless ($value) { + warn "cowardly refusing to write zero uuid value!\n"; + return; + } + + my $value = uuid_str $value + $uuid_skip; $uuid_skip = 0; (aio_write $fh, 0, (length $value), $value, 0) <= 0 @@ -3569,11 +3625,9 @@ _gv_clear *{"$pkg$name"}; # use PApp::Util; PApp::Util::sv_dump *{"$pkg$name"}; } - warn "cleared package #$pkg\n";#d# + warn "cleared package $pkg\n";#d# } -our $RELOAD; # how many times to reload - sub do_reload_perl() { # can/must only be called in main if ($Coro::current != $Coro::main) { @@ -3677,6 +3731,9 @@ warn "reattaching attachments to players"; reattach $_ for values %PLAYER; + warn "running post_load"; + (pop @POST_INIT)->(1) while @POST_INIT; + warn "leaving sync_job"; 1 @@ -3696,7 +3753,7 @@ # doing reload synchronously and two reloads happen back-to-back, # coro crashes during coro_state_free->destroy here. - $RELOAD_WATCHER ||= EV::timer 0, 0, sub { + $RELOAD_WATCHER ||= EV::timer $TICK * 1.5, 0, sub { do_reload_perl; undef $RELOAD_WATCHER; }; @@ -3834,6 +3891,7 @@ # limit the # of concurrent backtraces if ($_log_backtrace < 2) { ++$_log_backtrace; + my $perl_bt = Carp::longmess $msg; async { $Coro::current->{desc} = "abt $msg"; @@ -3854,7 +3912,8 @@ @funcs }; - LOG llevInfo, "[ABT] $msg\n"; + LOG llevInfo, "[ABT] $perl_bt\n"; + LOG llevInfo, "[ABT] --- C backtrace follows ---\n"; LOG llevInfo, "[ABT] $_\n" for @bt; --$_log_backtrace; };