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.350 by root, Sat Sep 1 08:03:45 2007 UTC vs.
Revision 1.361 by root, Sun Sep 9 12:52:48 2007 UTC

87our %CFG; 87our %CFG;
88 88
89our $UPTIME; $UPTIME ||= time; 89our $UPTIME; $UPTIME ||= time;
90our $RUNTIME; 90our $RUNTIME;
91 91
92our %PLAYER; # all users 92our (%PLAYER, %PLAYER_LOADING); # all users
93our %MAP; # all maps 93our (%MAP, %MAP_LOADING ); # all maps
94our $LINK_MAP; # the special {link} map, which is always available 94our $LINK_MAP; # the special {link} map, which is always available
95 95
96# used to convert map paths into valid unix filenames by replacing / by ∕ 96# used to convert map paths into valid unix filenames by replacing / by ∕
97our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons 97our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons
98 98
285Return true if the lock is currently active, i.e. somebody has locked it. 285Return true if the lock is currently active, i.e. somebody has locked it.
286 286
287=cut 287=cut
288 288
289our %LOCK; 289our %LOCK;
290our %LOCKER;#d#
290 291
291sub lock_wait($) { 292sub lock_wait($) {
292 my ($key) = @_; 293 my ($key) = @_;
294
295 if ($LOCKER{$key} == $Coro::current) {#d#
296 Carp::cluck "lock_wait($key) for already-acquired lock";#d#
297 return;#d#
298 }#d#
293 299
294 # wait for lock, if any 300 # wait for lock, if any
295 while ($LOCK{$key}) { 301 while ($LOCK{$key}) {
296 push @{ $LOCK{$key} }, $Coro::current; 302 push @{ $LOCK{$key} }, $Coro::current;
297 Coro::schedule; 303 Coro::schedule;
303 309
304 # wait, to be sure we are not locked 310 # wait, to be sure we are not locked
305 lock_wait $key; 311 lock_wait $key;
306 312
307 $LOCK{$key} = []; 313 $LOCK{$key} = [];
314 $LOCKER{$key} = $Coro::current;#d#
308 315
309 Coro::guard { 316 Coro::guard {
317 delete $LOCKER{$key};#d#
310 # wake up all waiters, to be on the safe side 318 # wake up all waiters, to be on the safe side
311 $_->ready for @{ delete $LOCK{$key} }; 319 $_->ready for @{ delete $LOCK{$key} };
312 } 320 }
313} 321}
314 322
481sub fork_call(&@) { 489sub fork_call(&@) {
482 my ($cb, @args) = @_; 490 my ($cb, @args) = @_;
483 491
484 # we seemingly have to make a local copy of the whole thing, 492 # we seemingly have to make a local copy of the whole thing,
485 # otherwise perl prematurely frees the stuff :/ 493 # otherwise perl prematurely frees the stuff :/
486 # TODO: investigate and fix (liekly this will be rather laborious) 494 # TODO: investigate and fix (likely this will be rather laborious)
487 495
488 my @res = Coro::Util::fork_eval { 496 my @res = Coro::Util::fork_eval {
489 reset_signals; 497 reset_signals;
490 &$cb 498 &$cb
491 }, @args; 499 }, @args;
1004 }, 1012 },
1005); 1013);
1006 1014
1007sub object_freezer_save { 1015sub object_freezer_save {
1008 my ($filename, $rdata, $objs) = @_; 1016 my ($filename, $rdata, $objs) = @_;
1017
1018 my $guard = cf::lock_acquire "io";
1009 1019
1010 sync_job { 1020 sync_job {
1011 if (length $$rdata) { 1021 if (length $$rdata) {
1012 warn sprintf "saving %s (%d,%d)\n", 1022 warn sprintf "saving %s (%d,%d)\n",
1013 $filename, length $$rdata, scalar @$objs; 1023 $filename, length $$rdata, scalar @$objs;
1037 } 1047 }
1038 } else { 1048 } else {
1039 aio_unlink $filename; 1049 aio_unlink $filename;
1040 aio_unlink "$filename.pst"; 1050 aio_unlink "$filename.pst";
1041 } 1051 }
1042 } 1052 };
1053
1054 undef $guard;
1043} 1055}
1044 1056
1045sub object_freezer_as_string { 1057sub object_freezer_as_string {
1046 my ($rdata, $objs) = @_; 1058 my ($rdata, $objs) = @_;
1047 1059
1052 1064
1053sub object_thawer_load { 1065sub object_thawer_load {
1054 my ($filename) = @_; 1066 my ($filename) = @_;
1055 1067
1056 my ($data, $av); 1068 my ($data, $av);
1069
1070 my $guard = cf::lock_acquire "io";
1057 1071
1058 (aio_load $filename, $data) >= 0 1072 (aio_load $filename, $data) >= 0
1059 or return; 1073 or return;
1060 1074
1061 unless (aio_stat "$filename.pst") { 1075 unless (aio_stat "$filename.pst") {
1062 (aio_load "$filename.pst", $av) >= 0 1076 (aio_load "$filename.pst", $av) >= 0
1063 or return; 1077 or return;
1078
1079 undef $guard;
1064 $av = eval { (Storable::thaw $av)->{objs} }; 1080 $av = eval { (Storable::thaw $av)->{objs} };
1065 } 1081 }
1066 1082
1067 warn sprintf "loading %s (%d)\n", 1083 warn sprintf "loading %s (%d)\n",
1068 $filename, length $data, scalar @{$av || []}; 1084 $filename, length $data, scalar @{$av || []};
1085
1069 return ($data, $av); 1086 ($data, $av)
1070} 1087}
1071 1088
1072=head2 COMMAND CALLBACKS 1089=head2 COMMAND CALLBACKS
1073 1090
1074=over 4 1091=over 4
1260 1277
1261=head3 cf::player 1278=head3 cf::player
1262 1279
1263=over 4 1280=over 4
1264 1281
1282=item cf::player::num_playing
1283
1284Returns the official number of playing players, as per the Crossfire metaserver rules.
1285
1286=cut
1287
1288sub num_playing {
1289 scalar grep
1290 $_->ob->map
1291 && !$_->hidden
1292 && !$_->ob->flag (cf::FLAG_WIZ),
1293 cf::player::list
1294}
1295
1265=item cf::player::find $login 1296=item cf::player::find $login
1266 1297
1267Returns the given player object, loading it if necessary (might block). 1298Returns the given player object, loading it if necessary (might block).
1268 1299
1269=cut 1300=cut
1304 aio_link +(playerdir $login) . "/$login.pl.pst", (playerdir $login) . "/playerdata.pst"; 1335 aio_link +(playerdir $login) . "/$login.pl.pst", (playerdir $login) . "/playerdata.pst";
1305 aio_link +(playerdir $login) . "/$login.pl" , (playerdir $login) . "/playerdata"; 1336 aio_link +(playerdir $login) . "/$login.pl" , (playerdir $login) . "/playerdata";
1306 aio_unlink +(playerdir $login) . "/$login.pl.pst"; 1337 aio_unlink +(playerdir $login) . "/$login.pl.pst";
1307 aio_unlink +(playerdir $login) . "/$login.pl"; 1338 aio_unlink +(playerdir $login) . "/$login.pl";
1308 1339
1309 my $pl = load_pl path $login 1340 my $f = new_from_file cf::object::thawer path $login
1310 or return; 1341 or return;
1342
1343 $f->next;
1344 my $pl = cf::player::load_pl $f
1345 or return;
1346 local $cf::PLAYER_LOADING{$login} = $pl;
1347 $f->resolve_delayed_derefs;
1311 $cf::PLAYER{$login} = $pl 1348 $cf::PLAYER{$login} = $pl
1312 } 1349 }
1313 } 1350 }
1314} 1351}
1315 1352
1413 or return []; 1450 or return [];
1414 1451
1415 my @logins; 1452 my @logins;
1416 1453
1417 for my $login (@$dirs) { 1454 for my $login (@$dirs) {
1455 my $path = path $login;
1456
1457 # a .pst is a dead give-away for a valid player
1458 unless (-e "$path.pst") {
1418 my $fh = aio_open path $login, Fcntl::O_RDONLY, 0 or next; 1459 my $fh = aio_open $path, Fcntl::O_RDONLY, 0 or next;
1419 aio_read $fh, 0, 512, my $buf, 0 or next; 1460 aio_read $fh, 0, 512, my $buf, 0 or next;
1420 $buf !~ /^password -------------$/m or next; # official not-valid tag 1461 $buf !~ /^password -------------$/m or next; # official not-valid tag
1462 }
1421 1463
1422 utf8::decode $login; 1464 utf8::decode $login;
1423 push @logins, $login; 1465 push @logins, $login;
1424 } 1466 }
1425 1467
1463sub expand_cfpod { 1505sub expand_cfpod {
1464 ((my $self), (local $_)) = @_; 1506 ((my $self), (local $_)) = @_;
1465 1507
1466 # escape & and < 1508 # escape & and <
1467 s/&/&amp;/g; 1509 s/&/&amp;/g;
1468 s/(?<![BIUGH])</&lt;/g; 1510 s/(?<![BIUGHT])</&lt;/g;
1469 1511
1470 # this is buggy, it needs to properly take care of nested <'s 1512 # this is buggy, it needs to properly take care of nested <'s
1471 1513
1472 1 while 1514 1 while
1473 # replace B<>, I<>, U<> etc. 1515 # replace B<>, I<>, U<> etc.
1474 s/B<([^\>]*)>/<b>$1<\/b>/ 1516 s/B<([^\>]*)>/<b>$1<\/b>/
1475 || s/I<([^\>]*)>/<i>$1<\/i>/ 1517 || s/I<([^\>]*)>/<i>$1<\/i>/
1476 || s/U<([^\>]*)>/<u>$1<\/u>/ 1518 || s/U<([^\>]*)>/<u>$1<\/u>/
1519 || s/T<([^\>]*)>/<big><b>$1<\/b><\/big>/
1477 # replace G<male|female> tags 1520 # replace G<male|female> tags
1478 || s{G<([^>|]*)\|([^>]*)>}{ 1521 || s{G<([^>|]*)\|([^>]*)>}{
1479 $self->gender ? $2 : $1 1522 $self->gender ? $2 : $1
1480 }ge 1523 }ge
1481 # replace H<hint text> 1524 # replace H<hint text>
1749 1792
1750sub load_header_from($) { 1793sub load_header_from($) {
1751 my ($self, $path) = @_; 1794 my ($self, $path) = @_;
1752 1795
1753 utf8::encode $path; 1796 utf8::encode $path;
1754 #aio_open $path, O_RDONLY, 0 1797 my $f = new_from_file cf::object::thawer $path
1755 # or return;
1756
1757 $self->_load_header ($path)
1758 or return; 1798 or return;
1799
1800 $self->_load_header ($f)
1801 or return;
1802
1803 local $MAP_LOADING{$self->{path}} = $self;
1804 $f->resolve_delayed_derefs;
1759 1805
1760 $self->{load_path} = $path; 1806 $self->{load_path} = $path;
1761 1807
1762 1 1808 1
1763} 1809}
1817sub find { 1863sub find {
1818 my ($path, $origin) = @_; 1864 my ($path, $origin) = @_;
1819 1865
1820 $path = normalise $path, $origin && $origin->path; 1866 $path = normalise $path, $origin && $origin->path;
1821 1867
1868 cf::lock_wait "map_data:$path";#d#remove
1822 cf::lock_wait "map_find:$path"; 1869 cf::lock_wait "map_find:$path";
1823 1870
1824 $cf::MAP{$path} || do { 1871 $cf::MAP{$path} || do {
1825 my $guard = cf::lock_acquire "map_find:$path"; 1872 my $guard1 = cf::lock_acquire "map_find:$path";
1873 my $guard2 = cf::lock_acquire "map_data:$path"; # just for the fun of it
1874
1826 my $map = new_from_path cf::map $path 1875 my $map = new_from_path cf::map $path
1827 or return; 1876 or return;
1828 1877
1829 $map->{last_save} = $cf::RUNTIME; 1878 $map->{last_save} = $cf::RUNTIME;
1830 1879
1832 or return; 1881 or return;
1833 1882
1834 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?) 1883 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?)
1835 # doing this can freeze the server in a sync job, obviously 1884 # doing this can freeze the server in a sync job, obviously
1836 #$cf::WAIT_FOR_TICK->wait; 1885 #$cf::WAIT_FOR_TICK->wait;
1886 undef $guard1;
1887 undef $guard2;
1837 $map->reset; 1888 $map->reset;
1838 undef $guard;
1839 return find $path; 1889 return find $path;
1840 } 1890 }
1841 1891
1842 $cf::MAP{$path} = $map 1892 $cf::MAP{$path} = $map
1843 } 1893 }
1852 local $self->{deny_reset} = 1; # loading can take a long time 1902 local $self->{deny_reset} = 1; # loading can take a long time
1853 1903
1854 my $path = $self->{path}; 1904 my $path = $self->{path};
1855 1905
1856 { 1906 {
1857 my $guard1 = cf::lock_acquire "map_data:$path"; 1907 my $guard = cf::lock_acquire "map_data:$path";
1858 my $guard2 = cf::lock_acquire "map_load:$path";
1859 1908
1909 return unless $self->valid;
1860 return if $self->in_memory != cf::MAP_SWAPPED; 1910 return unless $self->in_memory == cf::MAP_SWAPPED;
1861 1911
1862 $self->in_memory (cf::MAP_LOADING); 1912 $self->in_memory (cf::MAP_LOADING);
1863 1913
1864 $self->alloc; 1914 $self->alloc;
1865 1915
1866 $self->pre_load; 1916 $self->pre_load;
1867 cf::cede_to_tick; 1917 cf::cede_to_tick;
1868 1918
1919 my $f = new_from_file cf::object::thawer $self->{load_path};
1920 $f->skip_block;
1869 $self->_load_objects ($self->{load_path}, 1) 1921 $self->_load_objects ($f)
1870 or return; 1922 or return;
1871 1923
1872 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1) 1924 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1)
1873 if delete $self->{load_original}; 1925 if delete $self->{load_original};
1874 1926
1875 if (my $uniq = $self->uniq_path) { 1927 if (my $uniq = $self->uniq_path) {
1876 utf8::encode $uniq; 1928 utf8::encode $uniq;
1877 if (aio_open $uniq, O_RDONLY, 0) { 1929 unless (aio_stat $uniq) {
1930 if (my $f = new_from_file cf::object::thawer $uniq) {
1878 $self->clear_unique_items; 1931 $self->clear_unique_items;
1879 $self->_load_objects ($uniq, 0); 1932 $self->_load_objects ($f);
1933 $f->resolve_delayed_derefs;
1934 }
1880 } 1935 }
1881 } 1936 }
1937
1938 $f->resolve_delayed_derefs;
1882 1939
1883 cf::cede_to_tick; 1940 cf::cede_to_tick;
1884 # now do the right thing for maps 1941 # now do the right thing for maps
1885 $self->link_multipart_objects; 1942 $self->link_multipart_objects;
1886 $self->difficulty ($self->estimate_difficulty) 1943 $self->difficulty ($self->estimate_difficulty)
2030 2087
2031 return if $self->players; 2088 return if $self->players;
2032 return if $self->in_memory != cf::MAP_IN_MEMORY; 2089 return if $self->in_memory != cf::MAP_IN_MEMORY;
2033 return if $self->{deny_save}; 2090 return if $self->{deny_save};
2034 2091
2092 $self->in_memory (cf::MAP_SWAPPED);
2093
2094 $self->deactivate;
2095 $_->clear_links_to ($self) for values %cf::MAP;
2035 $self->clear; 2096 $self->clear;
2036 $self->in_memory (cf::MAP_SWAPPED);
2037} 2097}
2038 2098
2039sub reset_at { 2099sub reset_at {
2040 my ($self) = @_; 2100 my ($self) = @_;
2041 2101
2073 if $uniq; 2133 if $uniq;
2074 } 2134 }
2075 2135
2076 delete $cf::MAP{$self->path}; 2136 delete $cf::MAP{$self->path};
2077 2137
2138 $self->deactivate;
2139 $_->clear_links_to ($self) for values %cf::MAP;
2078 $self->clear; 2140 $self->clear;
2079
2080 $_->clear_links_to ($self) for values %cf::MAP;
2081 2141
2082 $self->unlink_save; 2142 $self->unlink_save;
2083 $self->destroy; 2143 $self->destroy;
2084} 2144}
2085 2145
2090 2150
2091 { 2151 {
2092 my $lock = cf::lock_acquire "map_data:$self->{path}"; 2152 my $lock = cf::lock_acquire "map_data:$self->{path}";
2093 2153
2094 delete $cf::MAP{$self->path}; 2154 delete $cf::MAP{$self->path};
2155
2156 $self->unlink_save;
2095 2157
2096 bless $self, "cf::map"; 2158 bless $self, "cf::map";
2097 delete $self->{deny_reset}; 2159 delete $self->{deny_reset};
2098 $self->{deny_save} = 1; 2160 $self->{deny_save} = 1;
2099 $self->reset_timeout (1); 2161 $self->reset_timeout (1);
2100 $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++)); 2162 $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++));
2101
2102 $self->unlink_save;
2103 2163
2104 $cf::MAP{$self->path} = $self; 2164 $cf::MAP{$self->path} = $self;
2105 } 2165 }
2106 2166
2107 $self->reset; # polite request, might not happen 2167 $self->reset; # polite request, might not happen
2186 2246
2187sub inv_recursive { 2247sub inv_recursive {
2188 inv_recursive_ inv $_[0] 2248 inv_recursive_ inv $_[0]
2189} 2249}
2190 2250
2251=item $ref = $ob->ref
2252
2253creates and returns a persistent reference to an objetc that can be stored as a string.
2254
2255=item $ob = cf::object::deref ($refstring)
2256
2257returns the objetc referenced by refstring. may return undef when it cnanot find the object,
2258even if the object actually exists. May block.
2259
2260=cut
2261
2262sub deref {
2263 my ($ref) = @_;
2264
2265 # temporary compatibility#TODO#remove
2266 $ref =~ s{^<}{player/<};
2267
2268 if ($ref =~ m{^player\/(<1\.\d+>)/(.*)$}) {
2269 my ($uuid, $name) = ($1, $2);
2270 my $pl = $cf::PLAYER_LOADING{$name} || cf::player::find $name
2271 or return;
2272 $pl->ob->uuid eq $uuid
2273 or return;
2274
2275 $pl->ob
2276 } else {
2277 warn "$ref: cannot resolve object reference\n";
2278 undef
2279 }
2280}
2281
2191package cf; 2282package cf;
2192 2283
2193=back 2284=back
2194 2285
2195=head3 cf::object::player 2286=head3 cf::object::player
2511 id => "identify", 2602 id => "identify",
2512 title => "Identify", 2603 title => "Identify",
2513 reply => undef, 2604 reply => undef,
2514 tooltip => "Items recently identified", 2605 tooltip => "Items recently identified",
2515 }, 2606 },
2607 "c/examine" => {
2608 id => "examine",
2609 title => "Examine",
2610 reply => undef,
2611 tooltip => "Signs and other items you examined",
2612 },
2516); 2613);
2517 2614
2518sub cf::client::send_msg { 2615sub cf::client::send_msg {
2519 my ($self, $channel, $msg, $color, @extra) = @_; 2616 my ($self, $channel, $msg, $color, @extra) = @_;
2520 2617
2527 2624
2528 if (ref $channel) { 2625 if (ref $channel) {
2529 # send meta info to client, if not yet sent 2626 # send meta info to client, if not yet sent
2530 unless (exists $self->{channel}{$channel->{id}}) { 2627 unless (exists $self->{channel}{$channel->{id}}) {
2531 $self->{channel}{$channel->{id}} = $channel; 2628 $self->{channel}{$channel->{id}} = $channel;
2532 $self->ext_msg (channel_info => $channel); 2629 $self->ext_msg (channel_info => $channel)
2630 if $self->can_msg;
2533 } 2631 }
2534 2632
2535 $channel = $channel->{id}; 2633 $channel = $channel->{id};
2536 } 2634 }
2537 2635
3361 or die; 3459 or die;
3362 3460
3363 $map->width (50); 3461 $map->width (50);
3364 $map->height (50); 3462 $map->height (50);
3365 $map->alloc; 3463 $map->alloc;
3366 $map->_load_objects ("/tmp/x.map", 1); 3464 $map->_load_objects ("/tmp/x.map", 1); #TODO: does not work
3367 my $t = Event::time - $t; 3465 my $t = Event::time - $t;
3368 3466
3369 #next unless $t < 0.0013;#d# 3467 #next unless $t < 0.0013;#d#
3370 if ($t < $min) { 3468 if ($t < $min) {
3371 $min = $t; 3469 $min = $t;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines