ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/ext/highscore.ext
Revision: 1.7
Committed: Sun May 9 22:51:13 2010 UTC (14 years ago) by root
Branch: MAIN
CVS Tags: rel-3_0
Changes since 1.6: +50 -52 lines
Log Message:
fix some issues related to fork, highscore calculation and quit_character

File Contents

# Content
1 #! perl
2
3 use Fcntl ();
4 use Coro::AIO;
5
6 our $HIGHSCORE_ENTRIES = $cf::CFG{highscore_entries} || 1000;
7
8 # [name, title, exp, killer, where, hp, sp, gp, uuid]
9
10 sub load_hiscore() {
11 # if (0 <= aio_load "$cf::LOCALDIR/hiscore.json", my $json) {
12 # return JSON::XS::decode_json $json;
13 # }
14
15 # try to convert old highscore file
16 if (0 <= aio_load "$cf::LOCALDIR/highscore", my $data) {
17 # warn "converting from old $cf::LOCALDIR/highscore file\n";
18 return [map [split /:/], split /\n/, $data];
19 }
20
21 return [];
22 }
23
24 sub save_hiscore($) {
25 my ($hiscore) = @_;
26
27 my $fh = aio_open "$cf::LOCALDIR/highscore~", Fcntl::O_WRONLY | Fcntl::O_CREAT | Fcntl::O_TRUNC, 0644
28 or return;
29
30 $hiscore = join "", map "$_\n", map +(join ":", @$_), @$hiscore;
31
32 length $hiscore == aio_write $fh, 0, (length $hiscore), $hiscore, 0
33 or return;
34
35 # always fsync - this file is important
36 aio_fsync $fh
37 and return;
38
39 close $fh
40 or return;
41
42 aio_rename "$cf::LOCALDIR/highscore~", "$cf::LOCALDIR/highscore"
43 and return;
44
45 aio_pathsync "$cf::LOCALDIR";
46
47 cf::trace "saved highscore file.\n";
48
49 1
50 }
51
52 our $HEADER = " | rank | name | experience | reason | HP |mana |grace|\n";
53 our $SEP = " +------+--------------------|--------------|----------------------+-----+-----+-----+\n";
54 our $FORMAT = " | %4s | %-18.18s | %12s | %-20.20s | %3s | %3s | %3s |\n";
55
56 our $SCORE_CHANNEL = {
57 id => "highscore",
58 title => "Highscore",
59 tooltip => "Your highscore ranking.",
60 };
61
62 sub fmt($$) {
63 my ($pos, $score) = @_;
64
65 my ($name, $title, $exp, $killer, $map, $hp, $sp, $grace) = @$score;
66
67 sprintf $FORMAT, defined $pos ? $pos + 1 : "-", $name, $exp, $killer, $hp, $sp, $grace
68 }
69
70 sub check($) {
71 my ($ob) = @_;
72
73 my $score = [
74 $ob->name,
75 length $ob->title ? $ob->title : $ob->contr->title,
76 $ob->stats->exp,
77 $ob->contr->killer_name,
78 $ob->map ? $ob->map->name || $ob->map->path : "",
79 $ob->stats->maxhp,
80 $ob->stats->maxsp,
81 $ob->stats->maxgrace,
82 $ob->uuid,
83 int AE::now,
84 ];
85
86 my $guard = cf::lock_acquire "highscore:check";
87
88 # load hiscore, patch, save hiscore
89 my $hiscore = load_hiscore;
90
91 cf::get_slot 0.01, 0, "highscore check";
92
93 my ($pre, $ins, $save);
94
95 pop @$hiscore while @$hiscore > $HIGHSCORE_ENTRIES;
96
97 # find previous entry, and new position
98
99 for (0 .. $#$hiscore) {
100 $pre //= $_ if $hiscore->[$_][0] eq $score->[0];
101 $ins //= $_ if $hiscore->[$_][2] < $score->[2];
102 }
103 cf::cede_to_tick; # we need an "interruptible" block...
104
105 my $msg;
106
107 if (defined $pre) {
108 # we are already in the list
109 if ($hiscore->[$pre][2] < $score->[2]) {
110 $msg = "T<You beat your last score!>\n\n"
111 . $SEP
112 . $HEADER
113 . $SEP
114 . (fmt $ins, $score)
115 . (fmt $pre, $hiscore->[$pre])
116 . $SEP;
117
118 splice @$hiscore, $pre, 1;
119 splice @$hiscore, $ins, 0, $score;
120 $save = 1;
121 } else {
122 $msg = "T<You did not beat your last score.>\n\n"
123 . $SEP
124 . $HEADER
125 . $SEP
126 . (fmt $pre , $hiscore->[$pre])
127 . (fmt undef, $score)
128 . $SEP;
129 }
130 } elsif (defined $ins or @$hiscore < $HIGHSCORE_ENTRIES) {
131 $ins //= @$hiscore;
132
133 $msg = "T<You entered the highscore list!>\n\n"
134 . $SEP
135 . $HEADER
136 . $SEP
137 . (fmt $ins, $score)
138 . $SEP;
139
140 splice @$hiscore, $ins, 0, $score;
141 $save = 1;
142 } else {
143 $msg = "T<You did not enter the highscore list.>\n\n"
144 . $SEP
145 . $HEADER
146 . $SEP
147 . (fmt -1 + (scalar @$hiscore), $hiscore->[-1])
148 . (fmt undef, $score)
149 . $SEP;
150 }
151
152 cf::info $msg;#d# remove once working stable
153
154 $ob->send_msg ($SCORE_CHANNEL => $msg, cf::NDI_CLEAR);
155
156 if ($save) {
157 save_hiscore $hiscore
158 or die "unable to write highscore file: $!";
159 }
160 }
161