--- deliantra/server/ext/help.ext 2007/04/18 17:32:06 1.2 +++ deliantra/server/ext/help.ext 2012/11/20 14:40:01 1.21 @@ -1,9 +1,81 @@ -#! perl +#! perl # mandatory depends=doclet our $TOPIC; +our %DOCLET; -sub load_topics($) { - my ($path) = @_; +our $HELP_CHANNEL = { + id => "help", + title => "Help", + reply => "help ", + tooltip => "Online Help", +}; + +# considerable duplication between load_doclets and load_topics +sub load_doclets { + %DOCLET = (); + + my %command_list; + + for ( + [standard => "command_help"], + [emote => "emote_help"], + [dm => "dmcommand_help"], + ) { + my ($type, $path) = @$_; + + my $paragraphs = cf::pod::load_pod "$PODDIR/$path.pod" + or die "unable to load $path"; + + my $level = 1e9; + my $rpar; + + for my $par (@$paragraphs) { + if ($par->{type} eq "head2") { + # this code taken almost verbatim from DC/Protocol.pm + + if ($par->{markup} =~ /^(\S+) (?:\s+ \( ([^\)]*) \) )?/x) { + my $cmd = $1; + my @args = split /\|/, $2; + @args = (".*") unless @args; + + $_ = $_ eq ".*" ? "" : " $_" + for @args; + + my @variants = map "$cmd$_", sort { (length $a) <=> (length $b) } @args; + + $rpar = \($DOCLET{$cmd} = &cf::pod::as_cfpod ([$par])); + + push @{ $command_list{$type} }, @variants; + $level = $par->{level}; + } else { + cf::error "$par->{markup}: unparsable command heading"; + } + } elsif ($par->{level} > $level) { + $$rpar .= &cf::pod::as_cfpod ([$par]); + } + + cf::cede_to_tick; + } + } + + cf::cede_to_tick; + + while (my ($k, $v) = each %command_list) { + cf::client::set_command_face $k, $v + } +} + +our $DOCLET_HANDLER = ext::doclet::register command => sub { + my ($pl, $category, $command) = @_; + + my $guard = cf::lock_acquire "ext::help::loading"; + + $DOCLET{$command} + || "B" +}; + +sub load_topics($$) { + my ($type, $path) = @_; my $paragraphs = cf::pod::load_pod "$PODDIR/$path.pod" or die "unable to load $path"; @@ -12,10 +84,10 @@ my $level = 1e9; for my $par (@$paragraphs) { - Coro::cede; + cf::cede_to_tick; if ($par->{type} eq "head2") { if ($par->{markup} =~ /^(\S+)/) { - push @topics, $1 => [$par]; + push @topics, $1 => [$type => $par]; $level = $par->{level}; } } elsif ($par->{level} > $level) { @@ -27,27 +99,59 @@ } sub reload() { + my $guard1 = cf::lock_acquire "ext::help::loading"; + my $guard2 = cf::lock_acquire "ext::resource"; + + local $Coro::current->{desc} = "help loader"; + $TOPIC = { - load_topics "dmcommand_help", - load_topics "emote_help", - load_topics "command_help", - load_topics "generic_help", + (load_topics "DM Commands" => "dmcommand_help"), + (load_topics "Emotes" => "emote_help"), + (load_topics "Commands" => "command_help"), + (load_topics "Generic Help Topics" => "generic_help"), }; + + load_doclets; + + () } -cf::sync_job { - my $guard = cf::lock_acquire "ext::help::loading"; - cf::async_ext { - reload; - undef $guard; - }; +cf::post_init { + cf::async_ext { reload }; + Coro::cede; # make sure reload acquires the lock(s) }; -cf::register_command xhelp => sub { +cf::register_command help => sub { my ($pl, $topic) = @_; if (cf::lock_active "ext::help::loading") { - $pl->reply (undef, "help files are being loaded currently, try again in a few seconds"); + $pl->send_msg ($HELP_CHANNEL => "help files are being loaded currently, try again in a few seconds.", cf::NDI_REPLY | cf::NDI_CLEAR); return; } + + $topic = $1 if $topic =~ /(\S+)/; + + if (!length $topic) { + # sort.. + + my %topics; + while (my ($k, $v) = each %$TOPIC) { + push @{$topics{$v->[0]}}, $k; + } + + my $res; + while (my ($k, $v) = each %topics) { + $res .= "T<$k:>\n\n" . (join " ", sort @$v) . "\n\n"; + } + + $pl->send_msg ($HELP_CHANNEL => $res, cf::NDI_REPLY | cf::NDI_CLEAR); + + } elsif (my $item = $TOPIC->{$topic}) { + my ($type, @pars) = @$item; + $pl->send_msg ($HELP_CHANNEL => (cf::pod::as_cfpod \@pars), cf::NDI_REPLY | cf::NDI_CLEAR); + + } else { + $pl->send_msg ($HELP_CHANNEL => "'$topic' no such help topic, try just 'help' to get a list of topics.", cf::NDI_REPLY); + } }; +