--- deliantra/server/lib/cf.pm 2006/07/21 00:51:39 1.27 +++ deliantra/server/lib/cf.pm 2006/08/24 13:13:49 1.34 @@ -7,6 +7,7 @@ use Safe; use Safe::Hole; +use Time::HiRes; use Event; $Event::Eval = 1; # no idea why this is required, but it is @@ -72,7 +73,7 @@ # we bless all objects into derived classes to force a method lookup # within the Safe compartment. -for my $pkg (qw(cf::object cf::object::map cf::object::player cf::player cf::map cf::party cf::region)) { +for my $pkg (qw(cf::object cf::object::map cf::object::player cf::player cf::map cf::party cf::region cf::arch)) { no strict 'refs'; @{"ext::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg; } @@ -183,10 +184,6 @@ warn "removing extension $pkg\n"; - if (my $cb = $pkg->can ("on_unload")) { - $cb->($pkg); - } - # remove hooks for my $idx (0 .. $#EVENT) { delete $hook[$idx]{$pkg}; @@ -210,6 +207,13 @@ delete $extcmd{$name}; } + if (my $cb = $pkg->can ("on_unload")) { + eval { + $cb->($pkg); + 1 + } or warn "$pkg unloaded, but with errors: $@"; + } + Symbol::delete_package $pkg; } @@ -287,16 +291,40 @@ }; ############################################################################# -# extcmd framework, basically convert ext arg1 args +# utility functions + +use JSON::Syck (); # TODO# replace by JSON::PC once working + +sub from_json($) { + $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs + JSON::Syck::Load $_[0] +} + +sub to_json($) { + $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs + JSON::Syck::Dump $_[0] +} + +############################################################################# +# extcmd framework, basically convert ext # into pkg::->on_extcmd_arg1 (...) while shortcutting a few sub on_extcmd { my ($pl, $buf) = @_; - my ($type) = $buf =~ s/^(\S+) // ? $1 : ""; + my $msg = eval { from_json $buf }; + + if (ref $msg) { + if (my $cb = $extcmd{$msg->{msgtype}}) { + if (my %reply = $cb->[0]->($pl, $msg)) { + $pl->ext_reply ($msg->{msgid}, %reply); + } + } + } else { + warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n"; + } - $extcmd{$type}[0]->($pl, $buf) - if $extcmd{$type}; + 1 } ############################################################################# @@ -359,10 +387,14 @@ ############################################################################# # load/save perl data associated with player->ob objects +sub all_objects(@) { + @_, map all_objects ($_->inv), @_ +} + *on_player_load = sub { my ($ob, $path) = @_; - for my $o ($ob, $ob->inv) { + for my $o (all_objects $ob) { if (my $value = $o->get_ob_key_value ("_perl_data")) { $o->set_ob_key_value ("_perl_data"); @@ -375,7 +407,7 @@ my ($ob, $path) = @_; $_->set_ob_key_value (_perl_data => unpack "H*", Storable::nfreeze $_) - for grep %$_, $ob, $ob->inv; + for grep %$_, all_objects $ob; }; ############################################################################# @@ -392,6 +424,14 @@ or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2; } +=item $player->reply ($npc, $msg[, $flags]) + +Sends a message to the player, as if the npc C<$npc> replied. C<$npc> +can be C. Does the right thing when the player is currently in a +dialogue with the given NPC character. + +=cut + # rough implementation of a future "reply" method that works # with dialog boxes. sub cf::object::player::reply($$$;$) { @@ -407,6 +447,20 @@ } } +=item $player->ext_reply ($msgid, $msgtype, %msg) + +Sends an ext reply to the player. + +=cut + +sub cf::player::ext_reply($$$%) { + my ($self, $id, %msg) = @_; + + $msg{msgid} = $id; + + $self->send ("ext " . to_json \%msg); +} + ############################################################################# # map scripting support @@ -463,6 +517,28 @@ } ############################################################################# +# the server's main() + +sub run { + my $tick = MAX_TIME * 1e-6; + my $next = Event::time; + my $timer = Event->timer (at => $next, cb => sub { + cf::server_tick; # one server iteration + + $next += $tick; + my $NOW = Event::time; + + # if we are delayd by > 0.25 second, skip ticks + $next = $NOW if $NOW >= $next + .25; + + $_[0]->w->at ($next); + $_[0]->w->start; + }); + + Event::loop; +} + +############################################################################# # initialisation register "", __PACKAGE__;