ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/ext/highscore.ext
Revision: 1.1
Committed: Sun Jan 31 03:46:20 2010 UTC (14 years, 3 months ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

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     warn "saved highscore file.\n";
48    
49     1
50     }
51    
52     our $HEADER = " |place | name | experience | killer | HP |mana |grace|\n";
53     our $SEP = " +------+-------------|--------------------|----------------------+-----+-----+-----+\n";
54     our $FORMAT = " | %4s | %-11.11s | %18s | %-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, $pos // "-", $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 EV::now,
84     ];
85    
86     cf::async {
87     my $guard = cf::lock_acquire "highscore:check";
88    
89     # load hiscore, patch, save hiscore
90     my $hiscore = load_hiscore;
91    
92     cf::get_slot 0.01, 0, "highscore check";
93    
94     my ($pre, $ins, $save);
95    
96     pop @$hiscore while @$hiscore > $HIGHSCORE_ENTRIES;
97    
98     # find previous entry, and new position
99    
100     for (0 .. $#$hiscore) {
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    
106     my $msg;
107    
108     if (defined $pre) {
109     # we are already in the list
110     if ($hiscore->[$pre][2] < $score->[2]) {
111     $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
136     . $HEADER
137     . $SEP
138     . (fmt $ins, $score)
139     . $SEP;
140    
141     splice @$hiscore, $ins, 0, $score;
142     $save = 1;
143     } else {
144     $msg = "T<You did not enter the highscore list.>\n\n"
145     . $SEP
146     . $HEADER
147     . $SEP
148     . (fmt -1 + (scalar @$hiscore), $hiscore->[-1])
149     . (fmt undef, $score)
150     . $SEP;
151     }
152    
153     warn $msg;#d# remove once working stable
154    
155     $ob->send_msg ($SCORE_CHANNEL => $msg, cf::NDI_CLEAR);
156    
157     if ($save) {
158     save_hiscore $hiscore
159     or die "unable to write highscore file: $!";
160     }
161     };
162     }
163    
164