… | |
… | |
367 | |
367 | |
368 | ############################################################################# |
368 | ############################################################################# |
369 | |
369 | |
370 | package cf::path; |
370 | package cf::path; |
371 | |
371 | |
|
|
372 | use overload |
|
|
373 | '""' => \&as_string; |
|
|
374 | |
372 | # used to convert map paths into valid unix filenames by repalcing / by ∕ |
375 | # used to convert map paths into valid unix filenames by repalcing / by ∕ |
373 | our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons |
376 | our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons |
374 | |
377 | |
375 | sub new { |
378 | sub new { |
376 | my ($class, $path, $base) = @_; |
379 | my ($class, $path, $base) = @_; |
… | |
… | |
384 | # ?random/... random maps |
387 | # ?random/... random maps |
385 | # /! non-realised random map exit |
388 | # /! non-realised random map exit |
386 | # /... normal maps |
389 | # /... normal maps |
387 | # ~/... per-player maps without a specific player (DO NOT USE) |
390 | # ~/... per-player maps without a specific player (DO NOT USE) |
388 | # ~user/... per-player map of a specific user |
391 | # ~user/... per-player map of a specific user |
|
|
392 | |
|
|
393 | $path =~ s/$PATH_SEP/\//go; |
389 | |
394 | |
390 | if ($path =~ /^{/) { |
395 | if ($path =~ /^{/) { |
391 | # fine as it is |
396 | # fine as it is |
392 | } elsif ($path =~ s{^\?random/}{}) { |
397 | } elsif ($path =~ s{^\?random/}{}) { |
393 | Coro::AIO::aio_load "$cf::RANDOM_MAPS/$path.meta", my $data; |
398 | Coro::AIO::aio_load "$cf::RANDOM_MAPS/$path.meta", my $data; |
… | |
… | |
1240 | my @paths; |
1245 | my @paths; |
1241 | |
1246 | |
1242 | for (@$files) { |
1247 | for (@$files) { |
1243 | utf8::decode $_; |
1248 | utf8::decode $_; |
1244 | next if /\.(?:pl|pst)$/; |
1249 | next if /\.(?:pl|pst)$/; |
1245 | next unless /^$PATH_SEP/; |
1250 | next unless /^$PATH_SEP/o; |
1246 | |
1251 | |
1247 | s/$PATH_SEP/\//g; |
|
|
1248 | push @paths, new cf::path "~" . $pl->ob->name . "/" . $_; |
1252 | push @paths, new cf::path "~" . $pl->ob->name . "/" . $_; |
1249 | } |
1253 | } |
1250 | |
1254 | |
1251 | \@paths |
1255 | \@paths |
1252 | } |
1256 | } |
… | |
… | |
1439 | Coro::cede; |
1443 | Coro::cede; |
1440 | |
1444 | |
1441 | $self->in_memory (cf::MAP_IN_MEMORY); |
1445 | $self->in_memory (cf::MAP_IN_MEMORY); |
1442 | } |
1446 | } |
1443 | |
1447 | |
|
|
1448 | # find and load all maps in the 3x3 area around a map |
|
|
1449 | sub load_diag { |
|
|
1450 | my ($map) = @_; |
|
|
1451 | |
|
|
1452 | my @diag; # diagonal neighbours |
|
|
1453 | |
|
|
1454 | for (0 .. 3) { |
|
|
1455 | my $neigh = $map->tile_path ($_) |
|
|
1456 | or next; |
|
|
1457 | $neigh = find $neigh, $map |
|
|
1458 | or next; |
|
|
1459 | $neigh->load; |
|
|
1460 | |
|
|
1461 | push @diag, [$neigh->tile_path (($_ + 3) % 4), $neigh], |
|
|
1462 | [$neigh->tile_path (($_ + 1) % 4), $neigh]; |
|
|
1463 | } |
|
|
1464 | |
|
|
1465 | for (@diag) { |
|
|
1466 | my $neigh = find @$_ |
|
|
1467 | or next; |
|
|
1468 | $neigh->load; |
|
|
1469 | } |
|
|
1470 | } |
|
|
1471 | |
1444 | sub find_sync { |
1472 | sub find_sync { |
1445 | my ($path, $origin) = @_; |
1473 | my ($path, $origin) = @_; |
1446 | |
1474 | |
1447 | cf::sync_job { cf::map::find $path, $origin } |
1475 | cf::sync_job { find $path, $origin } |
1448 | } |
1476 | } |
1449 | |
1477 | |
1450 | sub do_load_sync { |
1478 | sub do_load_sync { |
1451 | my ($map) = @_; |
1479 | my ($map) = @_; |
1452 | |
1480 | |
1453 | cf::sync_job { $map->load }; |
1481 | cf::sync_job { $map->load }; |
|
|
1482 | } |
|
|
1483 | |
|
|
1484 | our %MAP_PREFETCH; |
|
|
1485 | our $MAP_PREFETCHER = Coro::async { |
|
|
1486 | while () { |
|
|
1487 | while (%MAP_PREFETCH) { |
|
|
1488 | my $key = each %MAP_PREFETCH |
|
|
1489 | or next; |
|
|
1490 | my $path = delete $MAP_PREFETCH{$key}; |
|
|
1491 | |
|
|
1492 | my $map = find $path |
|
|
1493 | or next; |
|
|
1494 | $map->load; |
|
|
1495 | } |
|
|
1496 | Coro::schedule; |
|
|
1497 | } |
|
|
1498 | }; |
|
|
1499 | |
|
|
1500 | sub find_async { |
|
|
1501 | my ($path, $origin) = @_; |
|
|
1502 | |
|
|
1503 | $path = new cf::path $path, $origin && $origin->path; |
|
|
1504 | my $key = $path->as_string; |
|
|
1505 | |
|
|
1506 | if (my $map = $cf::MAP{$key}) { |
|
|
1507 | return $map if $map->in_memory == cf::MAP_IN_MEMORY; |
|
|
1508 | } |
|
|
1509 | |
|
|
1510 | $MAP_PREFETCH{$key} = $path; |
|
|
1511 | $MAP_PREFETCHER->ready; |
|
|
1512 | |
|
|
1513 | () |
1454 | } |
1514 | } |
1455 | |
1515 | |
1456 | sub save { |
1516 | sub save { |
1457 | my ($self) = @_; |
1517 | my ($self) = @_; |
1458 | |
1518 | |
… | |
… | |
1576 | } |
1636 | } |
1577 | |
1637 | |
1578 | $map |
1638 | $map |
1579 | } |
1639 | } |
1580 | |
1640 | |
|
|
1641 | =item cf::map::unique_maps |
|
|
1642 | |
|
|
1643 | Returns an arrayref of cf::path's of all shared maps that have |
|
|
1644 | instantiated unique items. May block. |
|
|
1645 | |
|
|
1646 | =cut |
|
|
1647 | |
|
|
1648 | sub unique_maps() { |
|
|
1649 | my $files = aio_readdir cf::localdir . "/" . cf::uniquedir |
|
|
1650 | or return; |
|
|
1651 | |
|
|
1652 | my @paths; |
|
|
1653 | |
|
|
1654 | for (@$files) { |
|
|
1655 | utf8::decode $_; |
|
|
1656 | next if /\.pst$/; |
|
|
1657 | next unless /^$PATH_SEP/o; |
|
|
1658 | |
|
|
1659 | push @paths, new cf::path $_; |
|
|
1660 | } |
|
|
1661 | |
|
|
1662 | \@paths |
|
|
1663 | } |
|
|
1664 | |
1581 | package cf; |
1665 | package cf; |
1582 | |
1666 | |
1583 | =back |
1667 | =back |
1584 | |
1668 | |
1585 | =head3 cf::object |
1669 | =head3 cf::object |
… | |
… | |
1707 | # use -1 or undef as default coordinates, not 0, 0 |
1791 | # use -1 or undef as default coordinates, not 0, 0 |
1708 | ($x, $y) = ($map->enter_x, $map->enter_y) |
1792 | ($x, $y) = ($map->enter_x, $map->enter_y) |
1709 | if $x <=0 && $y <= 0; |
1793 | if $x <=0 && $y <= 0; |
1710 | |
1794 | |
1711 | $map->load; |
1795 | $map->load; |
|
|
1796 | $map->load_diag; |
1712 | |
1797 | |
1713 | return unless $self->contr->active; |
1798 | return unless $self->contr->active; |
1714 | $self->activate_recursive; |
1799 | $self->activate_recursive; |
1715 | $self->enter_map ($map, $x, $y); |
1800 | $self->enter_map ($map, $x, $y); |
1716 | } |
1801 | } |
… | |
… | |
1753 | |
1838 | |
1754 | sub cf::object::player::goto { |
1839 | sub cf::object::player::goto { |
1755 | my ($self, $path, $x, $y) = @_; |
1840 | my ($self, $path, $x, $y) = @_; |
1756 | |
1841 | |
1757 | $path = new cf::path $path; |
1842 | $path = new cf::path $path; |
1758 | $path ne "/" or Carp::cluck ("oy");#d# |
|
|
1759 | |
1843 | |
1760 | $self->enter_link; |
1844 | $self->enter_link; |
1761 | |
1845 | |
1762 | (async { |
1846 | (async { |
1763 | my $map = cf::map::find $path->as_string; |
1847 | my $map = cf::map::find $path->as_string; |
… | |
… | |
1840 | |
1924 | |
1841 | 1; |
1925 | 1; |
1842 | }) { |
1926 | }) { |
1843 | $self->message ("Something went wrong deep within the crossfire server. " |
1927 | $self->message ("Something went wrong deep within the crossfire server. " |
1844 | . "I'll try to bring you back to the map you were before. " |
1928 | . "I'll try to bring you back to the map you were before. " |
1845 | . "Please report this to the dungeon master", |
1929 | . "Please report this to the dungeon master!", |
1846 | cf::NDI_UNIQUE | cf::NDI_RED); |
1930 | cf::NDI_UNIQUE | cf::NDI_RED); |
1847 | |
1931 | |
1848 | warn "ERROR in enter_exit: $@"; |
1932 | warn "ERROR in enter_exit: $@"; |
1849 | $self->leave_link; |
1933 | $self->leave_link; |
1850 | } |
1934 | } |