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.126 by root, Tue Jan 2 23:12:47 2007 UTC vs.
Revision 1.132 by root, Thu Jan 4 01:35:56 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;
71mkdir cf::localdir . "/" . cf::uniquedir; 71mkdir cf::localdir . "/" . cf::uniquedir;
72mkdir $RANDOM_MAPS; 72mkdir $RANDOM_MAPS;
73 73
74# a special map that is always available 74# a special map that is always available
75our $LINK_MAP; 75our $LINK_MAP;
76 76our $EMERGENCY_POSITION;
77our $EMERGENCY_POSITION = $cf::CFG{emergency_position} || ["/world/world_105_115", 5, 37];
78 77
79############################################################################# 78#############################################################################
80 79
81=head2 GLOBAL VARIABLES 80=head2 GLOBAL VARIABLES
82 81
245 # wake up all waiters, to be on the safe side 244 # wake up all waiters, to be on the safe side
246 $_->ready for @{ delete $LOCK{$key} }; 245 $_->ready for @{ delete $LOCK{$key} };
247 } 246 }
248} 247}
249 248
249=item cf::async { BLOCK }
250
251Like C<Coro::async>, but runs the given BLOCK in an eval and only logs the
252error instead of exiting the server in case of a problem.
253
254=cut
255
256sub async(&) {
257 my ($cb) = @_;
258
259 Coro::async {
260 eval { $cb->() };
261 warn $@ if $@;
262 }
263}
264
250=item cf::sync_job { BLOCK } 265=item cf::sync_job { BLOCK }
251 266
252The design of crossfire+ requires that the main coro ($Coro::main) is 267The design of crossfire+ requires that the main coro ($Coro::main) is
253always able to handle events or runnable, as crossfire+ is only partly 268always able to handle events or runnable, as crossfire+ is only partly
254reentrant. Thus "blocking" it by e.g. waiting for I/O is not acceptable. 269reentrant. Thus "blocking" it by e.g. waiting for I/O is not acceptable.
301=cut 316=cut
302 317
303sub coro(&) { 318sub coro(&) {
304 my $cb = shift; 319 my $cb = shift;
305 320
306 my $coro; $coro = async { 321 my $coro = &cf::async ($cb);
307 eval {
308 $cb->();
309 };
310 warn $@ if $@;
311 };
312 322
313 $coro->on_destroy (sub { 323 $coro->on_destroy (sub {
314 delete $EXT_CORO{$coro+0}; 324 delete $EXT_CORO{$coro+0};
315 }); 325 });
316 $EXT_CORO{$coro+0} = $coro; 326 $EXT_CORO{$coro+0} = $coro;
1193 1203
1194 # do it the slow way 1204 # do it the slow way
1195 my $map = try_load_header $path->save_path; 1205 my $map = try_load_header $path->save_path;
1196 1206
1197 if ($map) { 1207 if ($map) {
1208 $map->last_access ((delete $map->{last_access})
1209 || $cf::RUNTIME); #d#
1198 # safety 1210 # safety
1199 $map->{instantiate_time} = $cf::RUNTIME 1211 $map->{instantiate_time} = $cf::RUNTIME
1200 if $map->{instantiate_time} > $cf::RUNTIME; 1212 if $map->{instantiate_time} > $cf::RUNTIME;
1201 } else { 1213 } else {
1202 if (my $rmp = $path->random_map_params) { 1214 if (my $rmp = $path->random_map_params) {
1207 1219
1208 $map or return; 1220 $map or return;
1209 1221
1210 $map->{load_original} = 1; 1222 $map->{load_original} = 1;
1211 $map->{instantiate_time} = $cf::RUNTIME; 1223 $map->{instantiate_time} = $cf::RUNTIME;
1224 $map->last_access ($cf::RUNTIME);
1212 $map->instantiate; 1225 $map->instantiate;
1213 1226
1214 # per-player maps become, after loading, normal maps 1227 # per-player maps become, after loading, normal maps
1215 $map->per_player (0) if $path->{user_rel}; 1228 $map->per_player (0) if $path->{user_rel};
1216 } 1229 }
1217 1230
1218 $map->path ($key); 1231 $map->path ($key);
1219 $map->{path} = $path; 1232 $map->{path} = $path;
1220 $map->{last_save} = $cf::RUNTIME; 1233 $map->{last_save} = $cf::RUNTIME;
1221 $map->last_access ($cf::RUNTIME);
1222 1234
1223 if ($map->should_reset) { 1235 if ($map->should_reset) {
1224 $map->reset; 1236 $map->reset;
1225 undef $guard; 1237 undef $guard;
1226 $map = find_map $path 1238 $map = find_map $path
1300 1312
1301 $self->{load_path} = $save; 1313 $self->{load_path} = $save;
1302 1314
1303 return if $self->{deny_save}; 1315 return if $self->{deny_save};
1304 1316
1317 local $self->{last_access} = $self->last_access;#d#
1318
1305 if ($uniq) { 1319 if ($uniq) {
1306 $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS); 1320 $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS);
1307 $self->save_objects ($uniq, cf::IO_UNIQUES); 1321 $self->save_objects ($uniq, cf::IO_UNIQUES);
1308 } else { 1322 } else {
1309 $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES); 1323 $self->save_objects ($save, cf::IO_HEADER | cf::IO_OBJECTS | cf::IO_UNIQUES);
1311} 1325}
1312 1326
1313sub swap_out { 1327sub swap_out {
1314 my ($self) = @_; 1328 my ($self) = @_;
1315 1329
1330 # save first because save cedes
1331 $self->save;
1332
1316 return if $self->players; 1333 return if $self->players;
1317 return if $self->in_memory != cf::MAP_IN_MEMORY; 1334 return if $self->in_memory != cf::MAP_IN_MEMORY;
1318 return if $self->{deny_save}; 1335 return if $self->{deny_save};
1319 1336
1320 $self->save;
1321 $self->clear; 1337 $self->clear;
1322 $self->in_memory (cf::MAP_SWAPPED); 1338 $self->in_memory (cf::MAP_SWAPPED);
1323} 1339}
1324 1340
1325sub reset_at { 1341sub reset_at {
1538 1554
1539 # try to abort aborted map switching on player login :) 1555 # try to abort aborted map switching on player login :)
1540 # should happen only on crashes 1556 # should happen only on crashes
1541 if ($pl->ob->{_link_pos}) { 1557 if ($pl->ob->{_link_pos}) {
1542 $pl->ob->enter_link; 1558 $pl->ob->enter_link;
1543 Coro::async { 1559 cf::async {
1544 # we need this sleep as the login has a concurrent enter_exit running 1560 # we need this sleep as the login has a concurrent enter_exit running
1545 # and this sleep increases chances of the player not ending up in scorn 1561 # and this sleep increases chances of the player not ending up in scorn
1546 Coro::Timer::sleep 1; 1562 Coro::Timer::sleep 1;
1547 $pl->ob->leave_link; 1563 $pl->ob->leave_link;
1548 }; 1564 };
1557sub cf::object::player::goto_map { 1573sub cf::object::player::goto_map {
1558 my ($self, $path, $x, $y) = @_; 1574 my ($self, $path, $x, $y) = @_;
1559 1575
1560 $self->enter_link; 1576 $self->enter_link;
1561 1577
1562 (Coro::async { 1578 (cf::async {
1563 $path = new cf::path $path; 1579 $path = new cf::path $path;
1564 1580
1565 my $map = cf::map::find_map $path->as_string; 1581 my $map = cf::map::find_map $path->as_string;
1566 $map = $map->customise_for ($self) if $map; 1582 $map = $map->customise_for ($self) if $map;
1567 1583
1629 1645
1630 return unless $self->type == cf::PLAYER; 1646 return unless $self->type == cf::PLAYER;
1631 1647
1632 $self->enter_link; 1648 $self->enter_link;
1633 1649
1634 (Coro::async { 1650 (cf::async {
1635 unless (eval { 1651 unless (eval {
1636
1637 prepare_random_map $exit 1652 prepare_random_map $exit
1638 if $exit->slaying eq "/!"; 1653 if $exit->slaying eq "/!";
1639 1654
1640 my $path = new cf::path $exit->slaying, $exit->map && $exit->map->path; 1655 my $path = new cf::path $exit->slaying, $exit->map && $exit->map->path;
1641 $self->goto_map ($path, $exit->stats->hp, $exit->stats->sp); 1656 $self->goto_map ($path, $exit->stats->hp, $exit->stats->sp);
1703 on_reply => sub { 1718 on_reply => sub {
1704 my ($ns, $msg) = @_; 1719 my ($ns, $msg) = @_;
1705 1720
1706 # this weird shuffling is so that direct followup queries 1721 # this weird shuffling is so that direct followup queries
1707 # get handled first 1722 # get handled first
1708 my $queue = delete $ns->{query_queue}; 1723 my $queue = delete $ns->{query_queue}
1724 or return; # be conservative, not sure how that can happen, but we saw a crash here
1709 1725
1710 (shift @$queue)->[1]->($msg); 1726 (shift @$queue)->[1]->($msg);
1711 1727
1712 push @{ $ns->{query_queue} }, @$queue; 1728 push @{ $ns->{query_queue} }, @$queue;
1713 1729
1730=cut 1746=cut
1731 1747
1732sub cf::client::coro { 1748sub cf::client::coro {
1733 my ($self, $cb) = @_; 1749 my ($self, $cb) = @_;
1734 1750
1735 my $coro; $coro = async { 1751 my $coro = &cf::async ($cb);
1736 eval {
1737 $cb->();
1738 };
1739 warn $@ if $@;
1740 };
1741 1752
1742 $coro->on_destroy (sub { 1753 $coro->on_destroy (sub {
1743 delete $self->{_coro}{$coro+0}; 1754 delete $self->{_coro}{$coro+0};
1744 }); 1755 });
1745 1756
1980 open my $fh, "<:utf8", cf::confdir . "/config" 1991 open my $fh, "<:utf8", cf::confdir . "/config"
1981 or return; 1992 or return;
1982 1993
1983 local $/; 1994 local $/;
1984 *CFG = YAML::Syck::Load <$fh>; 1995 *CFG = YAML::Syck::Load <$fh>;
1996
1997 $EMERGENCY_POSITION = $CFG{emergency_position} || ["/world/world_105_115", 5, 37];
1998
1999 if (exists $CFG{mlockall}) {
2000 eval {
2001 $CFG{mlockall} ? &mlockall : &munlockall
2002 and die "WARNING: m(un)lockall failed: $!\n";
2003 };
2004 warn $@ if $@;
2005 }
1985} 2006}
1986 2007
1987sub main { 2008sub main {
1988 # we must not ever block the main coroutine 2009 # we must not ever block the main coroutine
1989 local $Coro::idle = sub { 2010 local $Coro::idle = sub {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines