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.348 by root, Thu Aug 30 08:34:40 2007 UTC vs.
Revision 1.358 by root, Fri Sep 7 18:10:52 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
1304 aio_link +(playerdir $login) . "/$login.pl.pst", (playerdir $login) . "/playerdata.pst"; 1321 aio_link +(playerdir $login) . "/$login.pl.pst", (playerdir $login) . "/playerdata.pst";
1305 aio_link +(playerdir $login) . "/$login.pl" , (playerdir $login) . "/playerdata"; 1322 aio_link +(playerdir $login) . "/$login.pl" , (playerdir $login) . "/playerdata";
1306 aio_unlink +(playerdir $login) . "/$login.pl.pst"; 1323 aio_unlink +(playerdir $login) . "/$login.pl.pst";
1307 aio_unlink +(playerdir $login) . "/$login.pl"; 1324 aio_unlink +(playerdir $login) . "/$login.pl";
1308 1325
1309 my $pl = load_pl path $login 1326 my $f = new_from_file cf::object::thawer path $login
1310 or return; 1327 or return;
1328
1329 $f->next;
1330 my $pl = cf::player::load_pl $f
1331 or return;
1332 local $cf::PLAYER_LOADING{$login} = $pl;
1333 $f->resolve_delayed_derefs;
1311 $cf::PLAYER{$login} = $pl 1334 $cf::PLAYER{$login} = $pl
1312 } 1335 }
1313 } 1336 }
1314} 1337}
1315 1338
1413 or return []; 1436 or return [];
1414 1437
1415 my @logins; 1438 my @logins;
1416 1439
1417 for my $login (@$dirs) { 1440 for my $login (@$dirs) {
1441 my $path = path $login;
1442
1443 # a .pst is a dead give-away for a valid player
1444 unless (-e "$path.pst") {
1418 my $fh = aio_open path $login, Fcntl::O_RDONLY, 0 or next; 1445 my $fh = aio_open $path, Fcntl::O_RDONLY, 0 or next;
1419 aio_read $fh, 0, 512, my $buf, 0 or next; 1446 aio_read $fh, 0, 512, my $buf, 0 or next;
1420 $buf !~ /^password -------------$/m or next; # official not-valid tag 1447 $buf !~ /^password -------------$/m or next; # official not-valid tag
1448 }
1421 1449
1422 utf8::decode $login; 1450 utf8::decode $login;
1423 push @logins, $login; 1451 push @logins, $login;
1424 } 1452 }
1425 1453
1463sub expand_cfpod { 1491sub expand_cfpod {
1464 ((my $self), (local $_)) = @_; 1492 ((my $self), (local $_)) = @_;
1465 1493
1466 # escape & and < 1494 # escape & and <
1467 s/&/&amp;/g; 1495 s/&/&amp;/g;
1468 s/(?<![BIUGH])</&lt;/g; 1496 s/(?<![BIUGHT])</&lt;/g;
1469 1497
1470 # this is buggy, it needs to properly take care of nested <'s 1498 # this is buggy, it needs to properly take care of nested <'s
1471 1499
1472 1 while 1500 1 while
1473 # replace B<>, I<>, U<> etc. 1501 # replace B<>, I<>, U<> etc.
1474 s/B<([^\>]*)>/<b>$1<\/b>/ 1502 s/B<([^\>]*)>/<b>$1<\/b>/
1475 || s/I<([^\>]*)>/<i>$1<\/i>/ 1503 || s/I<([^\>]*)>/<i>$1<\/i>/
1476 || s/U<([^\>]*)>/<u>$1<\/u>/ 1504 || s/U<([^\>]*)>/<u>$1<\/u>/
1505 || s/T<([^\>]*)>/<big><b>$1<\/b><\/big>/
1477 # replace G<male|female> tags 1506 # replace G<male|female> tags
1478 || s{G<([^>|]*)\|([^>]*)>}{ 1507 || s{G<([^>|]*)\|([^>]*)>}{
1479 $self->gender ? $2 : $1 1508 $self->gender ? $2 : $1
1480 }ge 1509 }ge
1481 # replace H<hint text> 1510 # replace H<hint text>
1749 1778
1750sub load_header_from($) { 1779sub load_header_from($) {
1751 my ($self, $path) = @_; 1780 my ($self, $path) = @_;
1752 1781
1753 utf8::encode $path; 1782 utf8::encode $path;
1754 #aio_open $path, O_RDONLY, 0 1783 my $f = new_from_file cf::object::thawer $path
1755 # or return;
1756
1757 $self->_load_header ($path)
1758 or return; 1784 or return;
1785
1786 $self->_load_header ($f)
1787 or return;
1788
1789 local $MAP_LOADING{$self->{path}} = $self;
1790 $f->resolve_delayed_derefs;
1759 1791
1760 $self->{load_path} = $path; 1792 $self->{load_path} = $path;
1761 1793
1762 1 1794 1
1763} 1795}
1817sub find { 1849sub find {
1818 my ($path, $origin) = @_; 1850 my ($path, $origin) = @_;
1819 1851
1820 $path = normalise $path, $origin && $origin->path; 1852 $path = normalise $path, $origin && $origin->path;
1821 1853
1854 cf::lock_wait "map_data:$path";#d#remove
1822 cf::lock_wait "map_find:$path"; 1855 cf::lock_wait "map_find:$path";
1823 1856
1824 $cf::MAP{$path} || do { 1857 $cf::MAP{$path} || do {
1825 my $guard = cf::lock_acquire "map_find:$path"; 1858 my $guard1 = cf::lock_acquire "map_find:$path";
1859 my $guard2 = cf::lock_acquire "map_data:$path"; # just for the fun of it
1860
1826 my $map = new_from_path cf::map $path 1861 my $map = new_from_path cf::map $path
1827 or return; 1862 or return;
1828 1863
1829 $map->{last_save} = $cf::RUNTIME; 1864 $map->{last_save} = $cf::RUNTIME;
1830 1865
1832 or return; 1867 or return;
1833 1868
1834 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?) 1869 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?)
1835 # doing this can freeze the server in a sync job, obviously 1870 # doing this can freeze the server in a sync job, obviously
1836 #$cf::WAIT_FOR_TICK->wait; 1871 #$cf::WAIT_FOR_TICK->wait;
1872 undef $guard1;
1873 undef $guard2;
1837 $map->reset; 1874 $map->reset;
1838 undef $guard;
1839 return find $path; 1875 return find $path;
1840 } 1876 }
1841 1877
1842 $cf::MAP{$path} = $map 1878 $cf::MAP{$path} = $map
1843 } 1879 }
1852 local $self->{deny_reset} = 1; # loading can take a long time 1888 local $self->{deny_reset} = 1; # loading can take a long time
1853 1889
1854 my $path = $self->{path}; 1890 my $path = $self->{path};
1855 1891
1856 { 1892 {
1857 my $guard1 = cf::lock_acquire "map_data:$path"; 1893 my $guard = cf::lock_acquire "map_data:$path";
1858 my $guard2 = cf::lock_acquire "map_load:$path";
1859 1894
1895 return unless $self->valid;
1860 return if $self->in_memory != cf::MAP_SWAPPED; 1896 return if $self->in_memory != cf::MAP_SWAPPED;
1861 1897
1862 $self->in_memory (cf::MAP_LOADING); 1898 $self->in_memory (cf::MAP_LOADING);
1863 1899
1864 $self->alloc; 1900 $self->alloc;
1865 1901
1866 $self->pre_load; 1902 $self->pre_load;
1867 cf::cede_to_tick; 1903 cf::cede_to_tick;
1868 1904
1905 my $f = new_from_file cf::object::thawer $self->{load_path};
1906 $f->skip_block;
1869 $self->_load_objects ($self->{load_path}, 1) 1907 $self->_load_objects ($f)
1870 or return; 1908 or return;
1871 1909
1872 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1) 1910 $self->set_object_flag (cf::FLAG_OBJ_ORIGINAL, 1)
1873 if delete $self->{load_original}; 1911 if delete $self->{load_original};
1874 1912
1875 if (my $uniq = $self->uniq_path) { 1913 if (my $uniq = $self->uniq_path) {
1876 utf8::encode $uniq; 1914 utf8::encode $uniq;
1877 if (aio_open $uniq, O_RDONLY, 0) { 1915 unless (aio_stat $uniq) {
1916 if (my $f = new_from_file cf::object::thawer $uniq) {
1878 $self->clear_unique_items; 1917 $self->clear_unique_items;
1879 $self->_load_objects ($uniq, 0); 1918 $self->_load_objects ($f);
1919 $f->resolve_delayed_derefs;
1920 }
1880 } 1921 }
1881 } 1922 }
1923
1924 $f->resolve_delayed_derefs;
1882 1925
1883 cf::cede_to_tick; 1926 cf::cede_to_tick;
1884 # now do the right thing for maps 1927 # now do the right thing for maps
1885 $self->link_multipart_objects; 1928 $self->link_multipart_objects;
1886 $self->difficulty ($self->estimate_difficulty) 1929 $self->difficulty ($self->estimate_difficulty)
2030 2073
2031 return if $self->players; 2074 return if $self->players;
2032 return if $self->in_memory != cf::MAP_IN_MEMORY; 2075 return if $self->in_memory != cf::MAP_IN_MEMORY;
2033 return if $self->{deny_save}; 2076 return if $self->{deny_save};
2034 2077
2078 $self->deactivate;
2035 $self->clear; 2079 $self->clear;
2036 $self->in_memory (cf::MAP_SWAPPED); 2080 $self->in_memory (cf::MAP_SWAPPED);
2037} 2081}
2038 2082
2039sub reset_at { 2083sub reset_at {
2073 if $uniq; 2117 if $uniq;
2074 } 2118 }
2075 2119
2076 delete $cf::MAP{$self->path}; 2120 delete $cf::MAP{$self->path};
2077 2121
2122 $self->deactivate;
2078 $self->clear; 2123 $self->clear;
2079 2124
2080 $_->clear_links_to ($self) for values %cf::MAP; 2125 $_->clear_links_to ($self) for values %cf::MAP;
2081 2126
2082 $self->unlink_save; 2127 $self->unlink_save;
2086my $nuke_counter = "aaaa"; 2131my $nuke_counter = "aaaa";
2087 2132
2088sub nuke { 2133sub nuke {
2089 my ($self) = @_; 2134 my ($self) = @_;
2090 2135
2136 {
2137 my $lock = cf::lock_acquire "map_data:$self->{path}";
2138
2091 delete $cf::MAP{$self->path}; 2139 delete $cf::MAP{$self->path};
2092 2140
2093 $self->unlink_save; 2141 $self->unlink_save;
2094 2142
2095 bless $self, "cf::map"; 2143 bless $self, "cf::map";
2096 delete $self->{deny_reset}; 2144 delete $self->{deny_reset};
2097 $self->{deny_save} = 1; 2145 $self->{deny_save} = 1;
2098 $self->reset_timeout (1); 2146 $self->reset_timeout (1);
2099 $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++)); 2147 $self->path ($self->{path} = "{nuke}/" . ($nuke_counter++));
2100 2148
2101 $cf::MAP{$self->path} = $self; 2149 $cf::MAP{$self->path} = $self;
2150 }
2102 2151
2103 $self->reset; # polite request, might not happen 2152 $self->reset; # polite request, might not happen
2104} 2153}
2105 2154
2106=item $maps = cf::map::tmp_maps 2155=item $maps = cf::map::tmp_maps
2182 2231
2183sub inv_recursive { 2232sub inv_recursive {
2184 inv_recursive_ inv $_[0] 2233 inv_recursive_ inv $_[0]
2185} 2234}
2186 2235
2236=item $ref = $ob->ref
2237
2238creates and returns a persistent reference to an objetc that can be stored as a string.
2239
2240=item $ob = cf::object::deref ($refstring)
2241
2242returns the objetc referenced by refstring. may return undef when it cnanot find the object,
2243even if the object actually exists. May block.
2244
2245=cut
2246
2247sub deref {
2248 my ($ref) = @_;
2249
2250 # temporary compatibility#TODO#remove
2251 $ref =~ s{^<}{player/<};
2252
2253 if ($ref =~ m{^player\/(<1\.\d+>)/(.*)$}) {
2254 my ($uuid, $name) = ($1, $2);
2255 my $pl = $cf::PLAYER_LOADING{$name} || cf::player::find $name
2256 or return;
2257 $pl->ob->uuid eq $uuid
2258 or return;
2259
2260 $pl->ob
2261 } else {
2262 warn "$ref: cannot resolve object reference\n";
2263 undef
2264 }
2265}
2266
2187package cf; 2267package cf;
2188 2268
2189=back 2269=back
2190 2270
2191=head3 cf::object::player 2271=head3 cf::object::player
2500the message, with C<log> being the default. If C<$color> is negative, suppress 2580the message, with C<log> being the default. If C<$color> is negative, suppress
2501the message unless the client supports the msg packet. 2581the message unless the client supports the msg packet.
2502 2582
2503=cut 2583=cut
2504 2584
2585our %CHANNEL = (
2586 "c/identify" => {
2587 id => "identify",
2588 title => "Identify",
2589 reply => undef,
2590 tooltip => "Items recently identified",
2591 },
2592 "c/examine" => {
2593 id => "examine",
2594 title => "Examine",
2595 reply => undef,
2596 tooltip => "Signs and other items you examined",
2597 },
2598);
2599
2505sub cf::client::send_msg { 2600sub cf::client::send_msg {
2506 my ($self, $channel, $msg, $color, @extra) = @_; 2601 my ($self, $channel, $msg, $color, @extra) = @_;
2507 2602
2508 $msg = $self->pl->expand_cfpod ($msg); 2603 $msg = $self->pl->expand_cfpod ($msg);
2509 2604
2510 $color &= cf::NDI_CLIENT_MASK; # just in case... 2605 $color &= cf::NDI_CLIENT_MASK; # just in case...
2606
2607 # check predefined channels, for the benefit of C
2608 $channel = $CHANNEL{$channel} if $CHANNEL{$channel};
2511 2609
2512 if (ref $channel) { 2610 if (ref $channel) {
2513 # send meta info to client, if not yet sent 2611 # send meta info to client, if not yet sent
2514 unless (exists $self->{channel}{$channel->{id}}) { 2612 unless (exists $self->{channel}{$channel->{id}}) {
2515 $self->{channel}{$channel->{id}} = $channel; 2613 $self->{channel}{$channel->{id}} = $channel;
2516 $self->ext_msg (channel_info => $channel); 2614 $self->ext_msg (channel_info => $channel)
2615 if $self->can_msg;
2517 } 2616 }
2518 2617
2519 $channel = $channel->{id}; 2618 $channel = $channel->{id};
2520 } 2619 }
2521 2620
3345 or die; 3444 or die;
3346 3445
3347 $map->width (50); 3446 $map->width (50);
3348 $map->height (50); 3447 $map->height (50);
3349 $map->alloc; 3448 $map->alloc;
3350 $map->_load_objects ("/tmp/x.map", 1); 3449 $map->_load_objects ("/tmp/x.map", 1); #TODO: does not work
3351 my $t = Event::time - $t; 3450 my $t = Event::time - $t;
3352 3451
3353 #next unless $t < 0.0013;#d# 3452 #next unless $t < 0.0013;#d#
3354 if ($t < $min) { 3453 if ($t < $min) {
3355 $min = $t; 3454 $min = $t;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines