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