… | |
… | |
162 | |
162 | |
163 | The raw value load value from the last tick. |
163 | The raw value load value from the last tick. |
164 | |
164 | |
165 | =item %cf::CFG |
165 | =item %cf::CFG |
166 | |
166 | |
167 | Configuration for the server, loaded from C</etc/crossfire/config>, or |
167 | Configuration for the server, loaded from C</etc/deliantra-server/config>, or |
168 | from wherever your confdir points to. |
168 | from wherever your confdir points to. |
169 | |
169 | |
170 | =item cf::wait_for_tick, cf::wait_for_tick_begin |
170 | =item cf::wait_for_tick, cf::wait_for_tick_begin |
171 | |
171 | |
172 | These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only |
172 | These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only |
… | |
… | |
406 | |
406 | |
407 | BEGIN { *async = \&Coro::async_pool } |
407 | BEGIN { *async = \&Coro::async_pool } |
408 | |
408 | |
409 | =item cf::sync_job { BLOCK } |
409 | =item cf::sync_job { BLOCK } |
410 | |
410 | |
411 | The design of Crossfire TRT requires that the main coroutine ($Coro::main) |
411 | The design of Deliantra requires that the main coroutine ($Coro::main) |
412 | is always able to handle events or runnable, as Crossfire TRT is only |
412 | is always able to handle events or runnable, as Deliantra is only |
413 | partly reentrant. Thus "blocking" it by e.g. waiting for I/O is not |
413 | partly reentrant. Thus "blocking" it by e.g. waiting for I/O is not |
414 | acceptable. |
414 | acceptable. |
415 | |
415 | |
416 | If it must be done, put the blocking parts into C<sync_job>. This will run |
416 | If it must be done, put the blocking parts into C<sync_job>. This will run |
417 | the given BLOCK in another coroutine while waiting for the result. The |
417 | the given BLOCK in another coroutine while waiting for the result. The |
… | |
… | |
662 | attach callbacks/event handlers (a collection of which is called an "attachment") |
662 | attach callbacks/event handlers (a collection of which is called an "attachment") |
663 | to it. All such attachable objects support the following methods. |
663 | to it. All such attachable objects support the following methods. |
664 | |
664 | |
665 | In the following description, CLASS can be any of C<global>, C<object> |
665 | In the following description, CLASS can be any of C<global>, C<object> |
666 | C<player>, C<client> or C<map> (i.e. the attachable objects in |
666 | C<player>, C<client> or C<map> (i.e. the attachable objects in |
667 | Crossfire TRT). |
667 | Deliantra). |
668 | |
668 | |
669 | =over 4 |
669 | =over 4 |
670 | |
670 | |
671 | =item $attachable->attach ($attachment, key => $value...) |
671 | =item $attachable->attach ($attachment, key => $value...) |
672 | |
672 | |
… | |
… | |
1081 | close $fh; |
1081 | close $fh; |
1082 | |
1082 | |
1083 | if (@$objs) { |
1083 | if (@$objs) { |
1084 | if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) { |
1084 | if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) { |
1085 | chmod SAVE_MODE, $fh; |
1085 | chmod SAVE_MODE, $fh; |
1086 | my $data = Coro::Storable::blocking_nfreeze { version => 1, objs => $objs }; |
1086 | my $data = Coro::Storable::nfreeze { version => 1, objs => $objs }; |
1087 | aio_write $fh, 0, (length $data), $data, 0; |
1087 | aio_write $fh, 0, (length $data), $data, 0; |
1088 | aio_fsync $fh if $cf::USE_FSYNC; |
1088 | aio_fsync $fh if $cf::USE_FSYNC; |
1089 | close $fh; |
1089 | close $fh; |
1090 | aio_rename "$filename.pst~", "$filename.pst"; |
1090 | aio_rename "$filename.pst~", "$filename.pst"; |
1091 | } |
1091 | } |
… | |
… | |
1122 | |
1122 | |
1123 | unless (aio_stat "$filename.pst") { |
1123 | unless (aio_stat "$filename.pst") { |
1124 | (aio_load "$filename.pst", $av) >= 0 |
1124 | (aio_load "$filename.pst", $av) >= 0 |
1125 | or return; |
1125 | or return; |
1126 | |
1126 | |
1127 | my $st = eval { Coro::Storable::thaw $av } |
1127 | my $st = eval { Coro::Storable::thaw $av }; |
1128 | || eval { my $guard = Coro::Storable::guard; Storable::thaw $av }; #d# compatibility, remove |
|
|
1129 | $av = $st->{objs}; |
1128 | $av = $st->{objs}; |
1130 | } |
1129 | } |
1131 | |
1130 | |
1132 | utf8::decode (my $decname = $filename); |
1131 | utf8::decode (my $decname = $filename); |
1133 | warn sprintf "loading %s (%d,%d)\n", |
1132 | warn sprintf "loading %s (%d,%d)\n", |
… | |
… | |
1549 | |
1548 | |
1550 | Expand crossfire pod fragments into protocol xml. |
1549 | Expand crossfire pod fragments into protocol xml. |
1551 | |
1550 | |
1552 | =cut |
1551 | =cut |
1553 | |
1552 | |
|
|
1553 | use re 'eval'; |
|
|
1554 | |
|
|
1555 | my $group; |
|
|
1556 | my $interior; $interior = qr{ |
|
|
1557 | # match a pod interior sequence sans C<< >> |
|
|
1558 | (?: |
|
|
1559 | \ (.*?)\ (?{ $group = $^N }) |
|
|
1560 | | < (??{$interior}) > |
|
|
1561 | ) |
|
|
1562 | }x; |
|
|
1563 | |
1554 | sub expand_cfpod { |
1564 | sub expand_cfpod { |
1555 | ((my $self), (local $_)) = @_; |
1565 | my ($self, $pod) = @_; |
1556 | |
1566 | |
1557 | # escape & and < |
1567 | my $xml; |
1558 | s/&/&/g; |
|
|
1559 | s/(?<![BIUGHT])</</g; |
|
|
1560 | |
1568 | |
1561 | # this is buggy, it needs to properly take care of nested <'s |
1569 | while () { |
|
|
1570 | if ($pod =~ /\G( (?: [^BCGHITU]+ | .(?!<) )+ )/xgcs) { |
|
|
1571 | $group = $1; |
1562 | |
1572 | |
1563 | 1 while |
1573 | $group =~ s/&/&/g; |
1564 | # replace B<>, I<>, U<> etc. |
1574 | $group =~ s/</</g; |
1565 | s/B<([^\>]*)>/<b>$1<\/b>/ |
1575 | |
1566 | || s/I<([^\>]*)>/<i>$1<\/i>/ |
1576 | $xml .= $group; |
1567 | || s/U<([^\>]*)>/<u>$1<\/u>/ |
1577 | } elsif ($pod =~ m%\G |
1568 | || s/T<([^\>]*)>/<big><b>$1<\/b><\/big>/ |
1578 | ([BCGHITU]) |
1569 | # replace G<male|female> tags |
1579 | < |
1570 | || s{G<([^>|]*)\|([^>]*)>}{ |
1580 | (?: |
1571 | $self->gender ? $2 : $1 |
1581 | ([^<>]*) (?{ $group = $^N }) |
1572 | }ge |
1582 | | < $interior > |
1573 | # replace H<hint text> |
1583 | ) |
1574 | || s{H<([^\>]*)>} |
1584 | > |
|
|
1585 | %gcsx |
1575 | { |
1586 | ) { |
|
|
1587 | my ($code, $data) = ($1, $group); |
|
|
1588 | |
|
|
1589 | if ($code eq "B") { |
|
|
1590 | $xml .= "<b>" . expand_cfpod ($self, $data) . "</b>"; |
|
|
1591 | } elsif ($code eq "I") { |
|
|
1592 | $xml .= "<i>" . expand_cfpod ($self, $data) . "</i>"; |
|
|
1593 | } elsif ($code eq "U") { |
|
|
1594 | $xml .= "<u>" . expand_cfpod ($self, $data) . "</u>"; |
|
|
1595 | } elsif ($code eq "C") { |
|
|
1596 | $xml .= "<tt>" . expand_cfpod ($self, $data) . "</tt>"; |
|
|
1597 | } elsif ($code eq "T") { |
|
|
1598 | $xml .= "<big><b>" . expand_cfpod ($self, $data) . "</b></big>"; |
|
|
1599 | } elsif ($code eq "G") { |
|
|
1600 | my ($male, $female) = split /\|/, $data; |
|
|
1601 | $data = $self->gender ? $female : $male; |
|
|
1602 | $xml .= expand_cfpod ($self, $data); |
|
|
1603 | } elsif ($code eq "H") { |
1576 | ("<fg name=\"lightblue\">[$1 (Use hintmode to suppress hints)]</fg>", |
1604 | $xml .= ("<fg name=\"lightblue\">[" . expand_cfpod ($self, $data) . " (Use hintmode to suppress hints)]</fg>", |
1577 | "<fg name=\"lightblue\">[Hint suppressed, see hintmode]</fg>", |
1605 | "<fg name=\"lightblue\">[Hint suppressed, see hintmode]</fg>", |
1578 | "") |
1606 | "") |
1579 | [$self->{hintmode}] |
1607 | [$self->{hintmode}]; |
|
|
1608 | } else { |
|
|
1609 | $xml .= "error processing '$code($data)' directive"; |
1580 | }ge; |
1610 | } |
|
|
1611 | } else { |
|
|
1612 | if ($pod =~ /\G(.+)/) { |
|
|
1613 | warn "parse error while expanding $pod (at $1)"; |
|
|
1614 | } |
|
|
1615 | last; |
|
|
1616 | } |
|
|
1617 | } |
1581 | |
1618 | |
|
|
1619 | for ($xml) { |
1582 | # create single paragraphs (very hackish) |
1620 | # create single paragraphs (very hackish) |
1583 | s/(?<=\S)\n(?=\w)/ /g; |
1621 | s/(?<=\S)\n(?=\w)/ /g; |
1584 | |
1622 | |
1585 | # compress some whitespace |
1623 | # compress some whitespace |
1586 | s/\s+\n/\n/g; # ws line-ends |
1624 | s/\s+\n/\n/g; # ws line-ends |
1587 | s/\n\n+/\n/g; # double lines |
1625 | s/\n\n+/\n/g; # double lines |
1588 | s/^\n+//; # beginning lines |
1626 | s/^\n+//; # beginning lines |
1589 | s/\n+$//; # ending lines |
1627 | s/\n+$//; # ending lines |
|
|
1628 | } |
1590 | |
1629 | |
1591 | $_ |
1630 | $xml |
1592 | } |
1631 | } |
|
|
1632 | |
|
|
1633 | no re 'eval'; |
1593 | |
1634 | |
1594 | sub hintmode { |
1635 | sub hintmode { |
1595 | $_[0]{hintmode} = $_[1] if @_ > 1; |
1636 | $_[0]{hintmode} = $_[1] if @_ > 1; |
1596 | $_[0]{hintmode} |
1637 | $_[0]{hintmode} |
1597 | } |
1638 | } |
… | |
… | |
2667 | the message, with C<log> being the default. If C<$color> is negative, suppress |
2708 | the message, with C<log> being the default. If C<$color> is negative, suppress |
2668 | the message unless the client supports the msg packet. |
2709 | the message unless the client supports the msg packet. |
2669 | |
2710 | |
2670 | =cut |
2711 | =cut |
2671 | |
2712 | |
|
|
2713 | # non-persistent channels (usually the info channel) |
2672 | our %CHANNEL = ( |
2714 | our %CHANNEL = ( |
2673 | "c/identify" => { |
2715 | "c/identify" => { |
2674 | id => "infobox", |
2716 | id => "infobox", |
2675 | title => "Identify", |
2717 | title => "Identify", |
2676 | reply => undef, |
2718 | reply => undef, |
… | |
… | |
2680 | id => "infobox", |
2722 | id => "infobox", |
2681 | title => "Examine", |
2723 | title => "Examine", |
2682 | reply => undef, |
2724 | reply => undef, |
2683 | tooltip => "Signs and other items you examined", |
2725 | tooltip => "Signs and other items you examined", |
2684 | }, |
2726 | }, |
|
|
2727 | "c/book" => { |
|
|
2728 | id => "infobox", |
|
|
2729 | title => "Book", |
|
|
2730 | reply => undef, |
|
|
2731 | tooltip => "The contents of a note or book", |
|
|
2732 | }, |
2685 | "c/lookat" => { |
2733 | "c/lookat" => { |
2686 | id => "infobox", |
2734 | id => "infobox", |
2687 | title => "Look", |
2735 | title => "Look", |
2688 | reply => undef, |
2736 | reply => undef, |
2689 | tooltip => "What you saw there", |
2737 | tooltip => "What you saw there", |
|
|
2738 | }, |
|
|
2739 | "c/who" => { |
|
|
2740 | id => "infobox", |
|
|
2741 | title => "Players", |
|
|
2742 | reply => undef, |
|
|
2743 | tooltip => "Shows players who are currently online", |
|
|
2744 | }, |
|
|
2745 | "c/body" => { |
|
|
2746 | id => "infobox", |
|
|
2747 | title => "Body Parts", |
|
|
2748 | reply => undef, |
|
|
2749 | tooltip => "Shows which body parts you posess and are available", |
|
|
2750 | }, |
|
|
2751 | "c/uptime" => { |
|
|
2752 | id => "infobox", |
|
|
2753 | title => "Uptime", |
|
|
2754 | reply => undef, |
|
|
2755 | tooltip => "How long the server has been running since last restart", |
|
|
2756 | }, |
|
|
2757 | "c/mapinfo" => { |
|
|
2758 | id => "infobox", |
|
|
2759 | title => "Map Info", |
|
|
2760 | reply => undef, |
|
|
2761 | tooltip => "Information related to the maps", |
2690 | }, |
2762 | }, |
2691 | ); |
2763 | ); |
2692 | |
2764 | |
2693 | sub cf::client::send_msg { |
2765 | sub cf::client::send_msg { |
2694 | my ($self, $channel, $msg, $color, @extra) = @_; |
2766 | my ($self, $channel, $msg, $color, @extra) = @_; |