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

# User Rev Content
1 root 1.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 root 1.5 cf::trace "saved highscore file.\n";
48 root 1.1
49     1
50     }
51    
52 root 1.3 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 root 1.1
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 root 1.2 sprintf $FORMAT, defined $pos ? $pos + 1 : "-", $name, $exp, $killer, $hp, $sp, $grace
68 root 1.1 }
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 root 1.4 int AE::now,
84 root 1.1 ];
85    
86 root 1.7 my $guard = cf::lock_acquire "highscore:check";
87 root 1.1
88 root 1.7 # load hiscore, patch, save hiscore
89     my $hiscore = load_hiscore;
90 root 1.1
91 root 1.7 cf::get_slot 0.01, 0, "highscore check";
92 root 1.1
93 root 1.7 my ($pre, $ins, $save);
94 root 1.1
95 root 1.7 pop @$hiscore while @$hiscore > $HIGHSCORE_ENTRIES;
96 root 1.1
97 root 1.7 # find previous entry, and new position
98 root 1.1
99 root 1.7 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 root 1.1
105 root 1.7 my $msg;
106 root 1.1
107 root 1.7 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 root 1.1 . $SEP
112     . $HEADER
113     . $SEP
114     . (fmt $ins, $score)
115 root 1.7 . (fmt $pre, $hiscore->[$pre])
116 root 1.1 . $SEP;
117    
118 root 1.7 splice @$hiscore, $pre, 1;
119 root 1.1 splice @$hiscore, $ins, 0, $score;
120     $save = 1;
121     } else {
122 root 1.7 $msg = "T<You did not beat your last score.>\n\n"
123 root 1.1 . $SEP
124     . $HEADER
125     . $SEP
126 root 1.7 . (fmt $pre , $hiscore->[$pre])
127 root 1.1 . (fmt undef, $score)
128     . $SEP;
129     }
130 root 1.7 } elsif (defined $ins or @$hiscore < $HIGHSCORE_ENTRIES) {
131     $ins //= @$hiscore;
132 root 1.1
133 root 1.7 $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 root 1.1 }
161