ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/ext/00_map_handling.ext
(Generate patch)

Comparing deliantra/server/ext/00_map_handling.ext (file contents):
Revision 1.10 by root, Sun Dec 31 18:10:40 2006 UTC vs.
Revision 1.11 by root, Sun Dec 31 21:02:04 2006 UTC

1#! perl 1#! perl
2 2
3# why this is an extension is a good question. next question. 3# why this is an extension is a good question. next question.
4 4
5use Digest::MD5;
6use Fcntl; 5use Fcntl;
7 6
8use Coro; 7use Coro;
9use Coro::AIO; 8use Coro::AIO;
10 9
15our $SCHEDULE_INTERVAL = 8; # time the map scheduler sleeps between runs 14our $SCHEDULE_INTERVAL = 8; # time the map scheduler sleeps between runs
16our $SAVE_TIMEOUT = 60; # save maps every n seconds 15our $SAVE_TIMEOUT = 60; # save maps every n seconds
17our $SAVE_INTERVAL = 0.4; # save at max. one map every $SAVE_HOLD 16our $SAVE_INTERVAL = 0.4; # save at max. one map every $SAVE_HOLD
18our $MAX_RESET = 7200; 17our $MAX_RESET = 7200;
19 18
20our $RANDOM_MAPS = cf::localdir . "/random";
21mkdir $RANDOM_MAPS;
22
23$DEACTIVATE_TIMEOUT = 3;#d# 19$DEACTIVATE_TIMEOUT = 3;#d#
24$SWAP_TIMEOUT = 5;#d# 20$SWAP_TIMEOUT = 5;#d#
25$SCHEDULE_INTERVAL = 1; 21$SCHEDULE_INTERVAL = 1;
26
27$cf::LINK_MAP ||= do {
28 my $map = cf::map::new;
29
30 $map->width (41);
31 $map->height (41);
32 $map->alloc;
33 $map->path ("{link}");
34 $map->{path} = bless { path => "{link}" }, "cf::path";
35 $map->in_memory (cf::MAP_IN_MEMORY);
36
37 $map
38};
39
40{
41 package cf::path;
42
43 sub new {
44 my ($class, $path, $base) = @_;
45
46 my $self = bless { }, $class;
47
48 if ($path =~ s{^\?random/}{}) {
49 $self->{random} = cf::from_json $path;
50 } else {
51 if ($path =~ s{^~([^/]+)?}{}) {
52 $self->{user_rel} = 1;
53
54 if (defined $1) {
55 $self->{user} = $1;
56 } elsif ($base =~ m{^~([^/]+)/}) {
57 $self->{user} = $1;
58 } else {
59 warn "cannot resolve user-relative path without user <$path,$base>\n";
60 }
61 } elsif ($path =~ /^\//) {
62 # already absolute
63 } else {
64 $base =~ s{[^/]+/?$}{};
65 return $class->new ("$base/$path");
66 }
67
68 for ($path) {
69 redo if s{/\.?/}{/};
70 redo if s{/[^/]+/\.\./}{/};
71 }
72 }
73
74 $self->{path} = $path;
75
76 $self
77 }
78
79 # the name / primary key / in-game path
80 sub as_string {
81 my ($self) = @_;
82
83 $self->{user_rel} ? "~$self->{user}$self->{path}"
84 : $self->{random} ? "?random/$self->{path}"
85 : $self->{path}
86 }
87
88 # the displayed name, this is a one way mapping
89 sub visible_name {
90 my ($self) = @_;
91
92 $self->{random} ? "?random/$self->{random}{origin_map}+$self->{random}{origin_x}+$self->{random}{origin_y}/$self->{random}{dungeon_level}"
93 : $self->as_string
94 }
95
96 # escape the /'s in the path
97 sub _escaped_path {
98 # ∕ is U+2215
99 (my $path = $_[0]{path}) =~ s/\//∕/g;
100 $path
101 }
102
103 # the original (read-only) location
104 sub load_path {
105 my ($self) = @_;
106
107 sprintf "%s/%s/%s", cf::datadir, cf::mapdir, $self->{path}
108 }
109
110 # the temporary/swap location
111 sub save_path {
112 my ($self) = @_;
113
114 $self->{user_rel} ? sprintf "%s/%s/%s/%s", cf::localdir, cf::playerdir, $self->{user}, $self->_escaped_path
115 : $self->{random} ? sprintf "%s/%s", $RANDOM_MAPS, Digest::MD5::md5_hex $self->{path}
116 : sprintf "%s/%s/%s", cf::localdir, cf::tmpdir, $self->_escaped_path
117 }
118
119 # the unique path, might be eq to save_path
120 sub uniq_path {
121 my ($self) = @_;
122
123 $self->{user_rel} || $self->{random}
124 ? undef
125 : sprintf "%s/%s/%s", cf::localdir, cf::uniquedir, $self->_escaped_path
126 }
127
128 # return random map parameters, or undef
129 sub random_map_params {
130 my ($self) = @_;
131
132 $self->{random}
133 }
134
135 # this is somewhat ugly, but style maps do need special treatment
136 sub is_style_map {
137 $_[0]{path} =~ m{^/styles/}
138 }
139}
140
141sub write_runtime {
142 my $runtime = cf::localdir . "/runtime";
143
144 my $fh = aio_open "$runtime~", O_WRONLY | O_CREAT, 0644
145 or return;
146
147 my $value = $cf::RUNTIME;
148 (aio_write $fh, 0, (length $value), $value, 0) <= 0
149 and return;
150
151 aio_fsync $fh
152 and return;
153
154 close $fh
155 or return;
156
157 aio_rename "$runtime~", $runtime
158 and return;
159
160 1
161}
162
163(Coro::async {
164 unless (write_runtime) {
165 warn "unable to write runtime file: $!";
166 exit 1;
167 }
168})->prio (Coro::PRIO_MAX);
169 22
170our $SCHEDULER = cf::coro { 23our $SCHEDULER = cf::coro {
171 Coro::Timer::sleep 3600;#d#TODO#for debugging only 24 Coro::Timer::sleep 3600;#d#TODO#for debugging only
172 while () { 25 while () {
173 Coro::Timer::sleep $SCHEDULE_INTERVAL; 26 Coro::Timer::sleep $SCHEDULE_INTERVAL;
174
175 write_runtime
176 or warn "unable to write runtime file: $!";
177 27
178 for my $map (values %cf::MAP) { 28 for my $map (values %cf::MAP) {
179 eval { 29 eval {
180 next if $map->in_memory != cf::MAP_IN_MEMORY; 30 next if $map->in_memory != cf::MAP_IN_MEMORY;
181 next if $map->players; 31 next if $map->players;
204$SCHEDULER->prio (-2); 54$SCHEDULER->prio (-2);
205 55
206sub generate_random_map { 56sub generate_random_map {
207 my ($path, $rmp) = @_; 57 my ($path, $rmp) = @_;
208 58
209 # mit "rum" bekleckert, nicht 59 # mit "rum" bekleckern, nicht
210 cf::map::_create_random_map 60 cf::map::_create_random_map
211 $path, 61 $path,
212 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle}, 62 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
213 $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle}, 63 $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
214 $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map}, 64 $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
217 $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3}, 67 $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3},
218 $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase}, 68 $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase},
219 $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation}, 69 $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation},
220 $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp}, 70 $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp},
221 $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used}, 71 $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used},
222 $rmp->{region} 72 (cf::region::find $rmp->{region})
223} 73}
224 74
225sub parse_random_map_params { 75sub parse_random_map_params {
226 my ($spec) = @_; 76 my ($spec) = @_;
227 77
247 # that depends on the exit object 97 # that depends on the exit object
248 98
249 my $rmp = parse_random_map_params $exit->msg; 99 my $rmp = parse_random_map_params $exit->msg;
250 100
251 if ($exit->map) { 101 if ($exit->map) {
252 $rmp->{region} = $exit->map->region ? $exit->map->region->name : undef; 102 $rmp->{region} = $exit->map->region_name;
253 $rmp->{origin_map} = $exit->map->path; 103 $rmp->{origin_map} = $exit->map->path;
254 $rmp->{origin_x} = $exit->x; 104 $rmp->{origin_x} = $exit->x;
255 $rmp->{origin_y} = $exit->y; 105 $rmp->{origin_y} = $exit->y;
256 } 106 }
257 107

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines