ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
(Generate patch)

Comparing deliantra/server/lib/cf.pm (file contents):
Revision 1.115 by root, Mon Jan 1 16:50:10 2007 UTC vs.
Revision 1.137 by root, Fri Jan 5 10:23:05 2007 UTC

8use Storable; 8use Storable;
9use Opcode; 9use Opcode;
10use Safe; 10use Safe;
11use Safe::Hole; 11use Safe::Hole;
12 12
13use Coro 3.3; 13use Coro 3.3 ();
14use Coro::Event; 14use Coro::Event;
15use Coro::Timer; 15use Coro::Timer;
16use Coro::Signal; 16use Coro::Signal;
17use Coro::Semaphore; 17use Coro::Semaphore;
18use Coro::AIO; 18use Coro::AIO;
49our $UPTIME; $UPTIME ||= time; 49our $UPTIME; $UPTIME ||= time;
50our $RUNTIME; 50our $RUNTIME;
51 51
52our %MAP; # all maps 52our %MAP; # all maps
53our $LINK_MAP; # the special {link} map 53our $LINK_MAP; # the special {link} map
54our $FREEZE;
55our $RANDOM_MAPS = cf::localdir . "/random"; 54our $RANDOM_MAPS = cf::localdir . "/random";
56our %EXT_CORO; 55our %EXT_CORO;
57 56
58binmode STDOUT; 57binmode STDOUT;
59binmode STDERR; 58binmode STDERR;
71mkdir cf::localdir . "/" . cf::uniquedir; 70mkdir cf::localdir . "/" . cf::uniquedir;
72mkdir $RANDOM_MAPS; 71mkdir $RANDOM_MAPS;
73 72
74# a special map that is always available 73# a special map that is always available
75our $LINK_MAP; 74our $LINK_MAP;
76 75our $EMERGENCY_POSITION;
77our $EMERGENCY_POSITION = $cf::CFG{emergency_position} || ["/world/world_105_115", 5, 37];
78 76
79############################################################################# 77#############################################################################
80 78
81=head2 GLOBAL VARIABLES 79=head2 GLOBAL VARIABLES
82 80
181sub to_json($) { 179sub to_json($) {
182 $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs 180 $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs
183 JSON::Syck::Dump $_[0] 181 JSON::Syck::Dump $_[0]
184} 182}
185 183
184=item cf::lock_wait $string
185
186Wait until the given lock is available. See cf::lock_acquire.
187
188=item my $lock = cf::lock_acquire $string
189
190Wait until the given lock is available and then acquires it and returns
191a Coro::guard object. If the guard object gets destroyed (goes out of scope,
192for example when the coroutine gets canceled), the lock is automatically
193returned.
194
195Lock names should begin with a unique identifier (for example, cf::map::find
196uses map_find and cf::map::load uses map_load).
197
198=cut
199
200our %LOCK;
201
202sub lock_wait($) {
203 my ($key) = @_;
204
205 # wait for lock, if any
206 while ($LOCK{$key}) {
207 push @{ $LOCK{$key} }, $Coro::current;
208 Coro::schedule;
209 }
210}
211
212sub lock_acquire($) {
213 my ($key) = @_;
214
215 # wait, to be sure we are not locked
216 lock_wait $key;
217
218 $LOCK{$key} = [];
219
220 Coro::guard {
221 # wake up all waiters, to be on the safe side
222 $_->ready for @{ delete $LOCK{$key} };
223 }
224}
225
226=item cf::async { BLOCK }
227
228Like C<Coro::async>, but runs the given BLOCK in an eval and only logs the
229error instead of exiting the server in case of a problem.
230
231=cut
232
233sub async(&) {
234 my ($cb) = @_;
235
236 Coro::async {
237 eval { $cb->() };
238 warn $@ if $@;
239 }
240}
241
242sub freeze_mainloop {
243 return unless $TICK_WATCHER->is_active;
244
245 my $guard = Coro::guard { $TICK_WATCHER->start };
246 $TICK_WATCHER->stop;
247 $guard
248}
249
186=item cf::sync_job { BLOCK } 250=item cf::sync_job { BLOCK }
187 251
188The design of crossfire+ requires that the main coro ($Coro::main) is 252The design of crossfire+ requires that the main coro ($Coro::main) is
189always able to handle events or runnable, as crossfire+ is only partly 253always able to handle events or runnable, as crossfire+ is only partly
190reentrant. Thus "blocking" it by e.g. waiting for I/O is not acceptable. 254reentrant. Thus "blocking" it by e.g. waiting for I/O is not acceptable.
203 # this is the main coro, too bad, we have to block 267 # this is the main coro, too bad, we have to block
204 # till the operation succeeds, freezing the server :/ 268 # till the operation succeeds, freezing the server :/
205 269
206 # TODO: use suspend/resume instead 270 # TODO: use suspend/resume instead
207 # (but this is cancel-safe) 271 # (but this is cancel-safe)
208 local $FREEZE = 1; 272 my $freeze_guard = freeze_mainloop;
209 273
210 my $busy = 1; 274 my $busy = 1;
211 my @res; 275 my @res;
212 276
213 (Coro::async { 277 (Coro::async {
237=cut 301=cut
238 302
239sub coro(&) { 303sub coro(&) {
240 my $cb = shift; 304 my $cb = shift;
241 305
242 my $coro; $coro = async { 306 my $coro = &cf::async ($cb);
243 eval {
244 $cb->();
245 };
246 warn $@ if $@;
247 };
248 307
249 $coro->on_destroy (sub { 308 $coro->on_destroy (sub {
250 delete $EXT_CORO{$coro+0}; 309 delete $EXT_CORO{$coro+0};
251 }); 310 });
252 $EXT_CORO{$coro+0} = $coro; 311 $EXT_CORO{$coro+0} = $coro;
817 (aio_load "$filename.pst", $av) >= 0 876 (aio_load "$filename.pst", $av) >= 0
818 or return; 877 or return;
819 $av = eval { (Storable::thaw $av)->{objs} }; 878 $av = eval { (Storable::thaw $av)->{objs} };
820 } 879 }
821 880
881 warn sprintf "loading %s (%d)\n",
882 $filename, length $data, scalar @{$av || []};#d#
822 return ($data, $av); 883 return ($data, $av);
823} 884}
824 885
825############################################################################# 886#############################################################################
826# command handling &c 887# command handling &c
1060package cf::map; 1121package cf::map;
1061 1122
1062use Fcntl; 1123use Fcntl;
1063use Coro::AIO; 1124use Coro::AIO;
1064 1125
1065our $MAX_RESET = 7200; 1126our $MAX_RESET = 3600;
1066our $DEFAULT_RESET = 3600; 1127our $DEFAULT_RESET = 3000;
1067 1128
1068sub generate_random_map { 1129sub generate_random_map {
1069 my ($path, $rmp) = @_; 1130 my ($path, $rmp) = @_;
1070 1131
1071 # mit "rum" bekleckern, nicht 1132 # mit "rum" bekleckern, nicht
1087# and all this just because we cannot iterate over 1148# and all this just because we cannot iterate over
1088# all maps in C++... 1149# all maps in C++...
1089sub change_all_map_light { 1150sub change_all_map_light {
1090 my ($change) = @_; 1151 my ($change) = @_;
1091 1152
1092 $_->change_map_light ($change) for values %cf::MAP; 1153 $_->change_map_light ($change)
1154 for grep $_->outdoor, values %cf::MAP;
1093} 1155}
1094 1156
1095sub try_load_header($) { 1157sub try_load_header($) {
1096 my ($path) = @_; 1158 my ($path) = @_;
1097 1159
1100 or return; 1162 or return;
1101 1163
1102 my $map = cf::map::new 1164 my $map = cf::map::new
1103 or return; 1165 or return;
1104 1166
1167 # for better error messages only, will be overwritten
1168 $map->path ($path);
1169
1105 $map->load_header ($path) 1170 $map->load_header ($path)
1106 or return; 1171 or return;
1107 1172
1108 $map->{load_path} = $path; 1173 $map->{load_path} = $path;
1109 1174
1110 $map 1175 $map
1111} 1176}
1112 1177
1178sub find;
1113sub find_map { 1179sub find {
1114 my ($path, $origin) = @_; 1180 my ($path, $origin) = @_;
1115 1181
1116 #warn "find_map<$path,$origin>\n";#d# 1182 #warn "find<$path,$origin>\n";#d#
1117 1183
1118 $path = new cf::path $path, $origin && $origin->path; 1184 $path = new cf::path $path, $origin && $origin->path;
1119 my $key = $path->as_string; 1185 my $key = $path->as_string;
1120 1186
1187 cf::lock_wait "map_find:$key";
1188
1121 $cf::MAP{$key} || do { 1189 $cf::MAP{$key} || do {
1190 my $guard = cf::lock_acquire "map_find:$key";
1191
1122 # do it the slow way 1192 # do it the slow way
1123 my $map = try_load_header $path->save_path; 1193 my $map = try_load_header $path->save_path;
1124 1194
1195 Coro::cede;
1196
1125 if ($map) { 1197 if ($map) {
1198 $map->last_access ((delete $map->{last_access})
1199 || $cf::RUNTIME); #d#
1126 # safety 1200 # safety
1127 $map->{instantiate_time} = $cf::RUNTIME 1201 $map->{instantiate_time} = $cf::RUNTIME
1128 if $map->{instantiate_time} > $cf::RUNTIME; 1202 if $map->{instantiate_time} > $cf::RUNTIME;
1129 } else { 1203 } else {
1130 if (my $rmp = $path->random_map_params) { 1204 if (my $rmp = $path->random_map_params) {
1135 1209
1136 $map or return; 1210 $map or return;
1137 1211
1138 $map->{load_original} = 1; 1212 $map->{load_original} = 1;
1139 $map->{instantiate_time} = $cf::RUNTIME; 1213 $map->{instantiate_time} = $cf::RUNTIME;
1214 $map->last_access ($cf::RUNTIME);
1140 $map->instantiate; 1215 $map->instantiate;
1141 1216
1142 # per-player maps become, after loading, normal maps 1217 # per-player maps become, after loading, normal maps
1143 $map->per_player (0) if $path->{user_rel}; 1218 $map->per_player (0) if $path->{user_rel};
1144 } 1219 }
1145 1220
1146 $map->path ($key); 1221 $map->path ($key);
1147 $map->{path} = $path; 1222 $map->{path} = $path;
1148 $map->last_access ($cf::RUNTIME); 1223 $map->{last_save} = $cf::RUNTIME;
1224
1225 Coro::cede;
1149 1226
1150 if ($map->should_reset) { 1227 if ($map->should_reset) {
1151 $map->reset; 1228 $map->reset;
1229 undef $guard;
1152 $map = find_map $path; 1230 $map = find $path
1231 or return;
1153 } 1232 }
1154 1233
1155 $cf::MAP{$key} = $map 1234 $cf::MAP{$key} = $map
1156 } 1235 }
1157} 1236}
1158 1237
1159sub load { 1238sub load {
1160 my ($self) = @_; 1239 my ($self) = @_;
1161 1240
1241 my $path = $self->{path};
1242 my $guard = cf::lock_acquire "map_load:" . $path->as_string;
1243
1162 return if $self->in_memory != cf::MAP_SWAPPED; 1244 return if $self->in_memory != cf::MAP_SWAPPED;
1163 1245
1164 $self->in_memory (cf::MAP_LOADING); 1246 $self->in_memory (cf::MAP_LOADING);
1165
1166 my $path = $self->{path};
1167 1247
1168 $self->alloc; 1248 $self->alloc;
1169 $self->load_objects ($self->{load_path}, 1) 1249 $self->load_objects ($self->{load_path}, 1)
1170 or return; 1250 or return;
1171 1251
1177 if (aio_open $uniq, O_RDONLY, 0) { 1257 if (aio_open $uniq, O_RDONLY, 0) {
1178 $self->clear_unique_items; 1258 $self->clear_unique_items;
1179 $self->load_objects ($uniq, 0); 1259 $self->load_objects ($uniq, 0);
1180 } 1260 }
1181 } 1261 }
1262
1263 Coro::cede;
1182 1264
1183 # now do the right thing for maps 1265 # now do the right thing for maps
1184 $self->link_multipart_objects; 1266 $self->link_multipart_objects;
1185 1267
1186 if ($self->{path}->is_style_map) { 1268 if ($self->{path}->is_style_map) {
1194 $self->difficulty ($self->estimate_difficulty) 1276 $self->difficulty ($self->estimate_difficulty)
1195 unless $self->difficulty; 1277 unless $self->difficulty;
1196 $self->activate; 1278 $self->activate;
1197 } 1279 }
1198 1280
1281 Coro::cede;
1282
1199 $self->in_memory (cf::MAP_IN_MEMORY); 1283 $self->in_memory (cf::MAP_IN_MEMORY);
1200} 1284}
1201 1285
1202sub load_map_sync { 1286sub find_sync {
1203 my ($path, $origin) = @_; 1287 my ($path, $origin) = @_;
1204 1288
1205 #warn "load_map_sync<$path, $origin>\n";#d# 1289 cf::sync_job { cf::map::find $path, $origin }
1290}
1206 1291
1207 cf::sync_job { 1292sub do_load_sync {
1208 my $map = cf::map::find_map $path, $origin 1293 my ($map) = @_;
1209 or return; 1294
1210 $map->load; 1295 cf::sync_job { $map->load };
1211 $map
1212 }
1213} 1296}
1214 1297
1215sub save { 1298sub save {
1216 my ($self) = @_; 1299 my ($self) = @_;
1217 1300
1301 my $lock = cf::lock_acquire "map_data:" . $self->path;
1302
1303 $self->{last_save} = $cf::RUNTIME;
1304
1305 return unless $self->dirty;
1306
1218 my $save = $self->{path}->save_path; utf8::encode $save; 1307 my $save = $self->{path}->save_path; utf8::encode $save;
1219 my $uniq = $self->{path}->uniq_path; utf8::encode $uniq; 1308 my $uniq = $self->{path}->uniq_path; utf8::encode $uniq;
1220 1309
1221 $self->{last_save} = $cf::RUNTIME;
1222
1223 return unless $self->dirty;
1224
1225 $self->{load_path} = $save; 1310 $self->{load_path} = $save;
1226 1311
1227 return if $self->{deny_save}; 1312 return if $self->{deny_save};
1313
1314 local $self->{last_access} = $self->last_access;#d#
1228 1315
1229 if ($uniq) { 1316 if ($uniq) {
1230 $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS); 1317 $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
1231 $self->save_objects ($uniq, cf::IO_UNIQUES); 1318 $self->save_objects ($uniq, cf::IO_UNIQUES);
1232 } else { 1319 } else {
1235} 1322}
1236 1323
1237sub swap_out { 1324sub swap_out {
1238 my ($self) = @_; 1325 my ($self) = @_;
1239 1326
1327 # save first because save cedes
1328 $self->save;
1329
1330 my $lock = cf::lock_acquire "map_data:" . $self->path;
1331
1240 return if $self->players; 1332 return if $self->players;
1241 return if $self->in_memory != cf::MAP_IN_MEMORY; 1333 return if $self->in_memory != cf::MAP_IN_MEMORY;
1242 return if $self->{deny_save}; 1334 return if $self->{deny_save};
1243 1335
1244 $self->save;
1245 $self->clear; 1336 $self->clear;
1246 $self->in_memory (cf::MAP_SWAPPED); 1337 $self->in_memory (cf::MAP_SWAPPED);
1247} 1338}
1248 1339
1249sub reset_at { 1340sub reset_at {
1287} 1378}
1288 1379
1289sub reset { 1380sub reset {
1290 my ($self) = @_; 1381 my ($self) = @_;
1291 1382
1383 my $lock = cf::lock_acquire "map_data:" . $self->path;
1384
1292 return if $self->players; 1385 return if $self->players;
1293 return if $self->{path}{user_rel};#d# 1386 return if $self->{path}{user_rel};#d#
1294 1387
1295 warn "resetting map ", $self->path;#d# 1388 warn "resetting map ", $self->path;#d#
1296 1389
1315 1408
1316sub customise_for { 1409sub customise_for {
1317 my ($map, $ob) = @_; 1410 my ($map, $ob) = @_;
1318 1411
1319 if ($map->per_player) { 1412 if ($map->per_player) {
1320 return cf::map::find_map "~" . $ob->name . "/" . $map->{path}{path}; 1413 return cf::map::find "~" . $ob->name . "/" . $map->{path}{path};
1321 } 1414 }
1322 1415
1323 $map 1416 $map
1324} 1417}
1325 1418
1326sub emergency_save { 1419sub emergency_save {
1327 local $cf::FREEZE = 1; 1420 my $freeze_guard = cf::freeze_mainloop;
1328 1421
1329 warn "enter emergency map save\n"; 1422 warn "enter emergency map save\n";
1330 1423
1331 cf::sync_job { 1424 cf::sync_job {
1332 warn "begin emergency map save\n"; 1425 warn "begin emergency map save\n";
1404=cut 1497=cut
1405 1498
1406sub cf::object::player::enter_link { 1499sub cf::object::player::enter_link {
1407 my ($self) = @_; 1500 my ($self) = @_;
1408 1501
1502 $self->deactivate_recursive;
1503
1409 return if $self->map == $LINK_MAP; 1504 return if $self->map == $LINK_MAP;
1410 1505
1411 $self->{_link_pos} = [$self->map->{path}, $self->x, $self->y] 1506 $self->{_link_pos} ||= [$self->map->{path}, $self->x, $self->y]
1412 if $self->map; 1507 if $self->map;
1413 1508
1414 $self->enter_map ($LINK_MAP, 20, 20); 1509 $self->enter_map ($LINK_MAP, 20, 20);
1415 $self->deactivate_recursive;
1416} 1510}
1417 1511
1418sub cf::object::player::leave_link { 1512sub cf::object::player::leave_link {
1419 my ($self, $map, $x, $y) = @_; 1513 my ($self, $map, $x, $y) = @_;
1420 1514
1421 my $link_pos = delete $self->{_link_pos}; 1515 my $link_pos = delete $self->{_link_pos};
1422 1516
1423 unless ($map) { 1517 unless ($map) {
1424 # restore original map position 1518 # restore original map position
1425 ($map, $x, $y) = @{ $link_pos || [] }; 1519 ($map, $x, $y) = @{ $link_pos || [] };
1426 $map = cf::map::find_map $map; 1520 $map = cf::map::find $map;
1427 1521
1428 unless ($map) { 1522 unless ($map) {
1429 ($map, $x, $y) = @$EMERGENCY_POSITION; 1523 ($map, $x, $y) = @$EMERGENCY_POSITION;
1430 $map = cf::map::find_map $map 1524 $map = cf::map::find $map
1431 or die "FATAL: cannot load emergency map\n"; 1525 or die "FATAL: cannot load emergency map\n";
1432 } 1526 }
1433 } 1527 }
1434 1528
1435 ($x, $y) = (-1, -1) 1529 ($x, $y) = (-1, -1)
1443 1537
1444 $self->activate_recursive; 1538 $self->activate_recursive;
1445 $self->enter_map ($map, $x, $y); 1539 $self->enter_map ($map, $x, $y);
1446} 1540}
1447 1541
1542cf::player->attach (
1543 on_logout => sub {
1544 my ($pl) = @_;
1545
1546 # abort map switching before logout
1547 if ($pl->ob->{_link_pos}) {
1548 cf::sync_job {
1549 $pl->ob->leave_link
1550 };
1551 }
1552 },
1553 on_login => sub {
1554 my ($pl) = @_;
1555
1556 # try to abort aborted map switching on player login :)
1557 # should happen only on crashes
1558 if ($pl->ob->{_link_pos}) {
1559 $pl->ob->enter_link;
1560 cf::async {
1561 # we need this sleep as the login has a concurrent enter_exit running
1562 # and this sleep increases chances of the player not ending up in scorn
1563 Coro::Timer::sleep 1;
1564 $pl->ob->leave_link;
1565 };
1566 }
1567 },
1568);
1569
1448=item $player_object->goto_map ($map, $x, $y) 1570=item $player_object->goto ($path, $x, $y)
1449 1571
1450=cut 1572=cut
1451 1573
1452sub cf::object::player::goto_map { 1574sub cf::object::player::goto {
1453 my ($self, $path, $x, $y) = @_; 1575 my ($self, $path, $x, $y) = @_;
1454 1576
1455 $self->enter_link; 1577 $self->enter_link;
1456 1578
1457 (Coro::async { 1579 (cf::async {
1458 $path = new cf::path $path; 1580 $path = new cf::path $path;
1459 1581
1460 my $map = cf::map::find_map $path->as_string; 1582 my $map = cf::map::find $path->as_string;
1461 $map = $map->customise_for ($self) if $map; 1583 $map = $map->customise_for ($self) if $map;
1462 1584
1463 warn "entering ", $map->path, " at ($x, $y)\n" 1585# warn "entering ", $map->path, " at ($x, $y)\n"
1464 if $map; 1586# if $map;
1465 1587
1466 $map or $self->message ("The exit is closed", cf::NDI_UNIQUE | cf::NDI_RED); 1588 $map or $self->message ("The exit is closed", cf::NDI_UNIQUE | cf::NDI_RED);
1467 1589
1468 $self->leave_link ($map, $x, $y); 1590 $self->leave_link ($map, $x, $y);
1469 })->prio (1); 1591 })->prio (1);
1524 1646
1525 return unless $self->type == cf::PLAYER; 1647 return unless $self->type == cf::PLAYER;
1526 1648
1527 $self->enter_link; 1649 $self->enter_link;
1528 1650
1529 (Coro::async { 1651 (cf::async {
1652 $self->deactivate_recursive; # just to be sure
1530 unless (eval { 1653 unless (eval {
1531
1532 prepare_random_map $exit 1654 prepare_random_map $exit
1533 if $exit->slaying eq "/!"; 1655 if $exit->slaying eq "/!";
1534 1656
1535 my $path = new cf::path $exit->slaying, $exit->map && $exit->map->path; 1657 my $path = new cf::path $exit->slaying, $exit->map && $exit->map->path;
1536 $self->goto_map ($path, $exit->stats->hp, $exit->stats->sp); 1658 $self->goto ($path, $exit->stats->hp, $exit->stats->sp);
1537 1659
1538 1; 1660 1;
1539 }) { 1661 }) {
1540 $self->message ("Something went wrong deep within the crossfire server. " 1662 $self->message ("Something went wrong deep within the crossfire server. "
1541 . "I'll try to bring you back to the map you were before. " 1663 . "I'll try to bring you back to the map you were before. "
1598 on_reply => sub { 1720 on_reply => sub {
1599 my ($ns, $msg) = @_; 1721 my ($ns, $msg) = @_;
1600 1722
1601 # this weird shuffling is so that direct followup queries 1723 # this weird shuffling is so that direct followup queries
1602 # get handled first 1724 # get handled first
1603 my $queue = delete $ns->{query_queue}; 1725 my $queue = delete $ns->{query_queue}
1726 or return; # be conservative, not sure how that can happen, but we saw a crash here
1604 1727
1605 (shift @$queue)->[1]->($msg); 1728 (shift @$queue)->[1]->($msg);
1606 1729
1607 push @{ $ns->{query_queue} }, @$queue; 1730 push @{ $ns->{query_queue} }, @$queue;
1608 1731
1625=cut 1748=cut
1626 1749
1627sub cf::client::coro { 1750sub cf::client::coro {
1628 my ($self, $cb) = @_; 1751 my ($self, $cb) = @_;
1629 1752
1630 my $coro; $coro = async { 1753 my $coro = &cf::async ($cb);
1631 eval {
1632 $cb->();
1633 };
1634 warn $@ if $@;
1635 };
1636 1754
1637 $coro->on_destroy (sub { 1755 $coro->on_destroy (sub {
1638 delete $self->{_coro}{$coro+0}; 1756 delete $self->{_coro}{$coro+0};
1639 }); 1757 });
1640 1758
1812 1930
1813{ 1931{
1814 my $path = cf::localdir . "/database.pst"; 1932 my $path = cf::localdir . "/database.pst";
1815 1933
1816 sub db_load() { 1934 sub db_load() {
1817 warn "loading database $path\n";#d# remove later
1818 $DB = stat $path ? Storable::retrieve $path : { }; 1935 $DB = stat $path ? Storable::retrieve $path : { };
1819 } 1936 }
1820 1937
1821 my $pid; 1938 my $pid;
1822 1939
1823 sub db_save() { 1940 sub db_save() {
1824 warn "saving database $path\n";#d# remove later
1825 waitpid $pid, 0 if $pid; 1941 waitpid $pid, 0 if $pid;
1826 if (0 == ($pid = fork)) { 1942 if (0 == ($pid = fork)) {
1827 $DB->{_meta}{version} = 1; 1943 $DB->{_meta}{version} = 1;
1828 Storable::nstore $DB, "$path~"; 1944 Storable::nstore $DB, "$path~";
1829 rename "$path~", $path; 1945 rename "$path~", $path;
1877 open my $fh, "<:utf8", cf::confdir . "/config" 1993 open my $fh, "<:utf8", cf::confdir . "/config"
1878 or return; 1994 or return;
1879 1995
1880 local $/; 1996 local $/;
1881 *CFG = YAML::Syck::Load <$fh>; 1997 *CFG = YAML::Syck::Load <$fh>;
1998
1999 $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37];
2000
2001 if (exists $CFG{mlockall}) {
2002 eval {
2003 $CFG{mlockall} ? &mlockall : &munlockall
2004 and die "WARNING: m(un)lockall failed: $!\n";
2005 };
2006 warn $@ if $@;
2007 }
1882} 2008}
1883 2009
1884sub main { 2010sub main {
1885 # we must not ever block the main coroutine 2011 # we must not ever block the main coroutine
1886 local $Coro::idle = sub { 2012 local $Coro::idle = sub {
1906 return; 2032 return;
1907 } 2033 }
1908 2034
1909 warn "reloading..."; 2035 warn "reloading...";
1910 2036
1911 local $FREEZE = 1; 2037 my $guard = freeze_mainloop;
1912 cf::emergency_save; 2038 cf::emergency_save;
1913 2039
1914 eval { 2040 eval {
1915 # if anything goes wrong in here, we should simply crash as we already saved 2041 # if anything goes wrong in here, we should simply crash as we already saved
1916 2042
2052 reentrant => 0, 2178 reentrant => 0,
2053 prio => 0, 2179 prio => 0,
2054 at => $NEXT_TICK || $TICK, 2180 at => $NEXT_TICK || $TICK,
2055 data => WF_AUTOCANCEL, 2181 data => WF_AUTOCANCEL,
2056 cb => sub { 2182 cb => sub {
2057 unless ($FREEZE) {
2058 cf::server_tick; # one server iteration 2183 cf::server_tick; # one server iteration
2059 $RUNTIME += $TICK; 2184 $RUNTIME += $TICK;
2060 }
2061
2062 $NEXT_TICK += $TICK; 2185 $NEXT_TICK += $TICK;
2063 2186
2064 # if we are delayed by four ticks or more, skip them all 2187 # if we are delayed by four ticks or more, skip them all
2065 $NEXT_TICK = Event::time if Event::time >= $NEXT_TICK + $TICK * 4; 2188 $NEXT_TICK = Event::time if Event::time >= $NEXT_TICK + $TICK * 4;
2066 2189
2089 or warn "ERROR: unable to write runtime file: $!"; 2212 or warn "ERROR: unable to write runtime file: $!";
2090 })->(); 2213 })->();
2091 }, 2214 },
2092); 2215);
2093 2216
2217END { cf::emergency_save }
2218
20941 22191
2095 2220

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines