--- deliantra/server/ext/highscore.ext 2010/05/04 21:45:42 1.6 +++ deliantra/server/ext/highscore.ext 2012/02/03 03:59:17 1.10 @@ -3,11 +3,14 @@ use Fcntl (); use Coro::AIO; -our $HIGHSCORE_ENTRIES = $cf::CFG{highscore_entries} || 1000; +CONF HIGHSCORE_ENTRIES = 1000 +CONF EXPORT_HIGHSCORE = "www.deliantra.net/highscore.json" + +our $HIGHSCORE; # [name, title, exp, killer, where, hp, sp, gp, uuid] -sub load_hiscore() { +sub load_highscore() { # if (0 <= aio_load "$cf::LOCALDIR/hiscore.json", my $json) { # return JSON::XS::decode_json $json; # } @@ -21,29 +24,24 @@ return []; } -sub save_hiscore($) { - my ($hiscore) = @_; - - my $fh = aio_open "$cf::LOCALDIR/highscore~", Fcntl::O_WRONLY | Fcntl::O_CREAT | Fcntl::O_TRUNC, 0644 - or return; - - $hiscore = join "", map "$_\n", map +(join ":", @$_), @$hiscore; - - length $hiscore == aio_write $fh, 0, (length $hiscore), $hiscore, 0 - or return; +sub reload { + my $lock = cf::lock_acquire "highscore"; - # always fsync - this file is important - aio_fsync $fh - and return; + cf::async_ext { + $lock; - close $fh - or return; + $HIGHSCORE = load_highscore; + }; +} - aio_rename "$cf::LOCALDIR/highscore~", "$cf::LOCALDIR/highscore" - and return; +cf::post_init { + reload; +}; - aio_pathsync "$cf::LOCALDIR"; +sub save_highscore() { + my $highscore = join "", map "$_\n", map +(join ":", @$_), @$HIGHSCORE; + cf::replace_file "$cf::LOCALDIR/highscore", $highscore, 1; cf::trace "saved highscore file.\n"; 1 @@ -83,81 +81,92 @@ int AE::now, ]; - cf::async { - my $guard = cf::lock_acquire "highscore:check"; - - # load hiscore, patch, save hiscore - my $hiscore = load_hiscore; + my $guard = cf::lock_acquire "highscore"; - cf::get_slot 0.01, 0, "highscore check"; + cf::get_slot 0.01, 0, "highscore check"; - my ($pre, $ins, $save); + my ($pre, $ins, $save); - pop @$hiscore while @$hiscore > $HIGHSCORE_ENTRIES; + pop @$HIGHSCORE while @$HIGHSCORE > $HIGHSCORE_ENTRIES; - # find previous entry, and new position + # find previous entry, and new position - for (0 .. $#$hiscore) { - $pre //= $_ if $hiscore->[$_][0] eq $score->[0]; - $ins //= $_ if $hiscore->[$_][2] < $score->[2]; - } - cf::cede_to_tick; # we need an "interruptible" block... - - my $msg; + for (0 .. $#$HIGHSCORE) { + $pre //= $_ if $HIGHSCORE->[$_][0] eq $score->[0]; + $ins //= $_ if $HIGHSCORE->[$_][2] < $score->[2]; + } + cf::cede_to_tick; # we need an "interruptible" block... - if (defined $pre) { - # we are already in the list - if ($hiscore->[$pre][2] < $score->[2]) { - $msg = "T\n\n" - . $SEP - . $HEADER - . $SEP - . (fmt $ins, $score) - . (fmt $pre, $hiscore->[$pre]) - . $SEP; - - splice @$hiscore, $pre, 1; - splice @$hiscore, $ins, 0, $score; - $save = 1; - } else { - $msg = "T\n\n" - . $SEP - . $HEADER - . $SEP - . (fmt $pre , $hiscore->[$pre]) - . (fmt undef, $score) - . $SEP; - } - } elsif (defined $ins or @$hiscore < $HIGHSCORE_ENTRIES) { - $ins //= @$hiscore; + my $msg; - $msg = "T\n\n" + if (defined $pre) { + # we are already in the list + if ($HIGHSCORE->[$pre][2] < $score->[2]) { + $msg = "T\n\n" . $SEP . $HEADER . $SEP . (fmt $ins, $score) + . (fmt $pre, $HIGHSCORE->[$pre]) . $SEP; - splice @$hiscore, $ins, 0, $score; + splice @$HIGHSCORE, $pre, 1; + splice @$HIGHSCORE, $ins, 0, $score; $save = 1; } else { - $msg = "T\n\n" + $msg = "T\n\n" . $SEP . $HEADER . $SEP - . (fmt -1 + (scalar @$hiscore), $hiscore->[-1]) + . (fmt $pre , $HIGHSCORE->[$pre]) . (fmt undef, $score) . $SEP; } + } elsif (defined $ins or @$HIGHSCORE < $HIGHSCORE_ENTRIES) { + $ins //= @$HIGHSCORE; - cf::info $msg;#d# remove once working stable + $msg = "T\n\n" + . $SEP + . $HEADER + . $SEP + . (fmt $ins, $score) + . $SEP; + + splice @$HIGHSCORE, $ins, 0, $score; + $save = 1; + } else { + $msg = "T\n\n" + . $SEP + . $HEADER + . $SEP + . (fmt -1 + (scalar @$HIGHSCORE), $HIGHSCORE->[-1]) + . (fmt undef, $score) + . $SEP; + } - $ob->send_msg ($SCORE_CHANNEL => $msg, cf::NDI_CLEAR); + cf::info $msg;#d# remove once working stable - if ($save) { - save_hiscore $hiscore - or die "unable to write highscore file: $!"; + $ob->send_msg ($SCORE_CHANNEL => $msg, cf::NDI_CLEAR); + + if ($save) { + save_highscore + or die "unable to write highscore file: $!"; + + if (defined $EXPORT_HIGHSCORE) { + cf::get_slot 0.05, 0, "highscore export"; + + my $rank; + my @highscore = map { + my ($name, $title, $exp, $killer, $map, $hp, $sp, $grace) = @$_; + [++$rank, $name, $title, (cf::exp_to_level $exp), $exp, $killer, $map, $hp, $sp, $grace] + } @$HIGHSCORE; + + cf::replace_file $EXPORT_HIGHSCORE, cf::encode_json { + version => 1, + date => $cf::NOW, + data => \@highscore, + }; } - }; + } }