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.598 by root, Sun Nov 11 02:38:10 2012 UTC vs.
Revision 1.607 by root, Sun Nov 18 09:29:25 2012 UTC

251Configuration for the server, loaded from C</etc/deliantra-server/config>, or 251Configuration for the server, loaded from C</etc/deliantra-server/config>, or
252from wherever your confdir points to. 252from wherever your confdir points to.
253 253
254=item cf::wait_for_tick, cf::wait_for_tick_begin 254=item cf::wait_for_tick, cf::wait_for_tick_begin
255 255
256These are functions that inhibit the current coroutine one tick. cf::wait_for_tick_begin only 256These are functions that inhibit the current coroutine one tick.
257returns directly I<after> the tick processing (and consequently, can only wake one thread 257cf::wait_for_tick_begin only returns directly I<after> the tick
258processing (and consequently, can only wake one thread per tick), while
258per tick), while cf::wait_for_tick wakes up all waiters after tick processing. 259cf::wait_for_tick wakes up all waiters after tick processing.
259 260
260Note that cf::Wait_for_tick will immediately return when the server is not 261Note that cf::wait_for_tick will immediately return when the server is not
261ticking, making it suitable for small pauses in threads that need to run 262ticking, making it suitable for small pauses in threads that need to run
262when the server is paused. If that is not applicable (i.e. you I<really> 263when the server is paused. If that is not applicable (i.e. you I<really>
263want to wait, use C<$cf::WAIT_FOR_TICK>). 264want to wait, use C<$cf::WAIT_FOR_TICK>).
264 265
265=item $cf::WAIT_FOR_TICK 266=item $cf::WAIT_FOR_TICK
572Allocate $time seconds of blocking CPU time at priority C<$priority> 573Allocate $time seconds of blocking CPU time at priority C<$priority>
573(default: 0): This call blocks and returns only when you have at least 574(default: 0): This call blocks and returns only when you have at least
574C<$time> seconds of cpu time till the next tick. The slot is only valid 575C<$time> seconds of cpu time till the next tick. The slot is only valid
575till the next cede. 576till the next cede.
576 577
577Background jobs should use a priority les than zero, interactive jobs 578Background jobs should use a priority less than zero, interactive jobs
578should use 100 or more. 579should use 100 or more.
579 580
580The optional C<$name> can be used to identify the job to run. It might be 581The optional C<$name> can be used to identify the job to run. It might be
581used for statistical purposes and should identify the same time-class. 582used for statistical purposes and should identify the same time-class.
582 583
737 reset_signals; 738 reset_signals;
738} 739}
739 740
740sub fork_call(&@) { 741sub fork_call(&@) {
741 my ($cb, @args) = @_; 742 my ($cb, @args) = @_;
742
743 # we seemingly have to make a local copy of the whole thing,
744 # otherwise perl prematurely frees the stuff :/
745 # TODO: investigate and fix (likely this will be rather laborious)
746 743
747 my @res = Coro::Util::fork_eval { 744 my @res = Coro::Util::fork_eval {
748 cf::post_fork; 745 cf::post_fork;
749 &$cb 746 &$cb
750 } @args; 747 } @args;
2653 2650
2654Creates and returns a persistent reference to an object that can be stored as a string. 2651Creates and returns a persistent reference to an object that can be stored as a string.
2655 2652
2656=item $ob = cf::object::deref ($refstring) 2653=item $ob = cf::object::deref ($refstring)
2657 2654
2658returns the objetc referenced by refstring. may return undef when it cnanot find the object, 2655returns the objetc referenced by refstring. may return undef when it cannot find the object,
2659even if the object actually exists. May block. 2656even if the object actually exists. May block.
2660 2657
2661=cut 2658=cut
2662 2659
2663sub deref { 2660sub deref {
3056 3053
3057sub cf::client::send_drawinfo { 3054sub cf::client::send_drawinfo {
3058 my ($self, $text, $flags) = @_; 3055 my ($self, $text, $flags) = @_;
3059 3056
3060 utf8::encode $text; 3057 utf8::encode $text;
3061 $self->send_packet (sprintf "drawinfo %d %s", $flags || cf::NDI_BLACK, $text); 3058 $self->send_packet (sprintf "msg %d log %s", $flags || cf::NDI_BLACK, $text);
3062} 3059}
3063 3060
3064=item $client->send_big_packet ($pkt) 3061=item $client->send_big_packet ($pkt)
3065 3062
3066Like C<send_packet>, but tries to compress large packets, and fragments 3063Like C<send_packet>, but tries to compress large packets, and fragments
3086 $self->send_packet ($pkt); 3083 $self->send_packet ($pkt);
3087} 3084}
3088 3085
3089=item $client->send_msg ($channel, $msg, $color, [extra...]) 3086=item $client->send_msg ($channel, $msg, $color, [extra...])
3090 3087
3091Send a drawinfo or msg packet to the client, formatting the msg for the 3088Send a msg packet to the client, formatting the msg for the client if
3092client if neccessary. C<$type> should be a string identifying the type of 3089necessary. C<$type> should be a string identifying the type of the
3093the message, with C<log> being the default. If C<$color> is negative, suppress 3090message, with C<log> being the default. If C<$color> is negative, suppress
3094the message unless the client supports the msg packet. 3091the message unless the client supports the msg packet.
3095 3092
3096=cut 3093=cut
3097 3094
3098# non-persistent channels (usually the info channel) 3095# non-persistent channels (usually the info channel)
3203 id => "death", 3200 id => "death",
3204 title => "Death", 3201 title => "Death",
3205 reply => undef, 3202 reply => undef,
3206 tooltip => "Reason for and more info about your most recent death", 3203 tooltip => "Reason for and more info about your most recent death",
3207 }, 3204 },
3205 "c/fatal" => {
3206 id => "fatal",
3207 title => "Fatal Error",
3208 reply => undef,
3209 tooltip => "Reason for the server disconnect",
3210 },
3208 "c/say" => $SAY_CHANNEL, 3211 "c/say" => $SAY_CHANNEL,
3209 "c/chat" => $CHAT_CHANNEL, 3212 "c/chat" => $CHAT_CHANNEL,
3210); 3213);
3211 3214
3212sub cf::client::send_msg { 3215sub cf::client::send_msg {
3518=cut 3521=cut
3519 3522
3520############################################################################# 3523#############################################################################
3521# the server's init and main functions 3524# the server's init and main functions
3522 3525
3523our %FACEHASH; # hash => idx, #d# HACK for http server 3526{
3527 package cf::face;
3524 3528
3529 our %HASH; # hash => idx
3530 our @DATA; # dynamically-created facedata, only faceste 0 used
3531 our @FOFS; # file offset, if > 0
3532 our @SIZE; # size of face, in octets
3533 our @META; # meta hash of face, if any
3534 our $DATAFH; # facedata filehandle
3535
3525# internal api, not fianlised 3536 # internal api, not finalised
3526sub set_face { 3537 sub set {
3527 my ($name, $type, $data) = @_; 3538 my ($name, $type, $data) = @_;
3528 3539
3529 my $idx = cf::face::find $name; 3540 my $idx = cf::face::find $name;
3530 3541
3531 if ($idx) { 3542 if ($idx) {
3532 delete $FACEHASH{cf::face::get_chksum $idx}; 3543 delete $HASH{cf::face::get_csum $idx};
3533 } else { 3544 } else {
3534 $idx = cf::face::alloc $name; 3545 $idx = cf::face::alloc $name;
3535 } 3546 }
3536 3547
3537 my $hash = cf::face::mangle_chksum Digest::MD5::md5 $data; 3548 my $hash = cf::face::mangle_csum Digest::MD5::md5 $data;
3538 3549
3539 cf::face::set_type $idx, $type; 3550 cf::face::set_type $idx, $type;
3540 cf::face::set_data $idx, 0, $data, $hash; 3551 cf::face::set_csum $idx, 0, $hash;
3541 cf::face::set_meta $idx, $type & 1 ? undef : undef; 3552
3553 # we need to destroy the SV itself, not just modify it, as a running ix
3554 # might hold a reference to it: "delete" achieves that.
3555 delete $FOFS[0][$idx];
3556 delete $DATA[0][$idx];
3557 $DATA[0][$idx] = $data;
3558 $SIZE[0][$idx] = length $data;
3559 delete $META[$idx];
3542 $FACEHASH{$hash} = $idx;#d# 3560 $HASH{$hash} = $idx;#d#
3543 3561
3544 $idx 3562 $idx
3563 }
3564
3565 sub _get_data($$$) {
3566 my ($idx, $set, $cb) = @_;
3567
3568 if (defined $DATA[$set][$idx]) {
3569 $cb->($DATA[$set][$idx]);
3570 } elsif (my $fofs = $FOFS[$set][$idx]) {
3571 my $size = $SIZE[$set][$idx];
3572 my $buf;
3573 IO::AIO::aio_read $DATAFH, $fofs, $size, $buf, 0, sub {
3574 if ($_[0] == $size) {
3575 #cf::debug "read face $idx, $size from $fofs as ", length $buf;#d#
3576 $cb->($buf);
3577 } else {
3578 cf::error "INTERNAL ERROR: unable to read facedata for face $idx#$set ($size, $fofs), ignoring request.";
3579 }
3580 };
3581 } else {
3582 cf::error "requested facedata for unknown face $idx#$set, ignoring.";
3583 }
3584 }
3585
3586 # rather ineffient
3587 sub cf::face::get_data($;$) {
3588 my ($idx, $set) = @_;
3589
3590 _get_data $idx, $set, Coro::rouse_cb;
3591 Coro::rouse_wait
3592 }
3593
3594 sub cf::face::ix {
3595 my ($ns, $set, $idx, $pri) = @_;
3596
3597 _get_data $idx, $set, sub {
3598 $ns->ix_send ($idx, $pri, $_[0]);
3599 };
3600 }
3545} 3601}
3546 3602
3547sub load_facedata($) { 3603sub load_facedata($) {
3548 my ($path) = @_; 3604 my ($path) = @_;
3549 3605
3550 # HACK to clear player env face cache, we need some signal framework
3551 # for this (global event?)
3552 %ext::player_env::MUSIC_FACE_CACHE = ();
3553
3554 my $enc = JSON::XS->new->utf8->canonical->relaxed; 3606 my $enc = JSON::XS->new->utf8->canonical->relaxed;
3555 3607
3556 trace "loading facedata from $path\n"; 3608 trace "loading facedata from $path\n";
3557 3609
3558 my $facedata = decode_storable load_file $path; 3610 my $facedata = decode_storable load_file "$path/faceinfo";
3559 3611
3560 $facedata->{version} == 2 3612 $facedata->{version} == 2
3561 or cf::cleanup "$path: version mismatch, cannot proceed."; 3613 or cf::cleanup "$path/faceinfo: version mismatch, cannot proceed.";
3562 3614
3563 cf::cede_to_tick; 3615 my $fh = aio_open "$DATADIR/facedata", IO::AIO::O_RDONLY, 0
3616 or cf::cleanup "$path/facedata: $!, cannot proceed.";
3617
3618 get_slot 1, -100, "load_facedata"; # make sure we get a very big slot
3619
3620 # BEGIN ATOMIC
3621 # from here on, everything must be atomic - no thread switch allowed
3622 my $t1 = EV::time;
3564 3623
3565 { 3624 {
3566 my $faces = delete $facedata->{faceinfo}; 3625 my $faces = $facedata->{faceinfo};
3567 3626
3568 for my $face (sort keys %$faces) { 3627 for my $face (sort keys %$faces) {
3569 my $info = $faces->{$face}; 3628 my $info = $faces->{$face};
3570 my $idx = (cf::face::find $face) || cf::face::alloc $face; 3629 my $idx = (cf::face::find $face) || cf::face::alloc $face;
3571 3630
3572 cf::face::set_visibility $idx, $info->{visibility}; 3631 cf::face::set_visibility $idx, $info->{visibility};
3573 cf::face::set_magicmap $idx, $info->{magicmap}; 3632 cf::face::set_magicmap $idx, $info->{magicmap};
3574 cf::face::set_data $idx, 0, $info->{data32}, $info->{hash32}; 3633 cf::face::set_csum $idx, 0, $info->{hash64}; $cf::face::SIZE[0][$idx] = $info->{size64}; $cf::face::FOFS[0][$idx] = $info->{fofs64};
3575 cf::face::set_data $idx, 1, $info->{data64}, $info->{hash64}; 3634 cf::face::set_csum $idx, 1, $info->{hash32}; $cf::face::SIZE[1][$idx] = $info->{size32}; $cf::face::FOFS[1][$idx] = $info->{fofs32};
3576 cf::face::set_data $idx, 2, $info->{glyph} , $info->{glyph} ; 3635 cf::face::set_csum $idx, 2, $info->{glyph}; $cf::face::DATA[2][$idx] = $info->{glyph};
3577 $FACEHASH{$info->{hash64}} = $idx;#d# 3636 $cf::face::HASH{$info->{hash64}} = $idx;
3578 3637 delete $cf::face::META[$idx];
3579 cf::cede_to_tick;
3580 } 3638 }
3581 3639
3582 while (my ($face, $info) = each %$faces) { 3640 while (my ($face, $info) = each %$faces) {
3583 next unless $info->{smooth}; 3641 next unless $info->{smooth};
3584 3642
3589 cf::face::set_smooth $idx, $smooth; 3647 cf::face::set_smooth $idx, $smooth;
3590 cf::face::set_smoothlevel $idx, $info->{smoothlevel}; 3648 cf::face::set_smoothlevel $idx, $info->{smoothlevel};
3591 } else { 3649 } else {
3592 error "smooth face '$info->{smooth}' not found for face '$face'"; 3650 error "smooth face '$info->{smooth}' not found for face '$face'";
3593 } 3651 }
3594
3595 cf::cede_to_tick;
3596 } 3652 }
3597 } 3653 }
3598 3654
3599 { 3655 {
3600 my $anims = delete $facedata->{animinfo}; 3656 my $anims = $facedata->{animinfo};
3601 3657
3602 while (my ($anim, $info) = each %$anims) { 3658 while (my ($anim, $info) = each %$anims) {
3603 cf::anim::set $anim, $info->{frames}, $info->{facings}; 3659 cf::anim::set $anim, $info->{frames}, $info->{facings};
3604 cf::cede_to_tick;
3605 } 3660 }
3606 3661
3607 cf::anim::invalidate_all; # d'oh 3662 cf::anim::invalidate_all; # d'oh
3608 } 3663 }
3609 3664
3610 { 3665 {
3611 my $res = delete $facedata->{resource}; 3666 my $res = $facedata->{resource};
3612 3667
3613 while (my ($name, $info) = each %$res) { 3668 while (my ($name, $info) = each %$res) {
3614 if (defined (my $type = $info->{type})) { 3669 if (defined (my $type = $info->{type})) {
3615 # TODO: different hash - must free and use new index, or cache ixface data queue 3670 # TODO: different hash - must free and use new index, or cache ixface data queue
3616 my $idx = (cf::face::find $name) || cf::face::alloc $name; 3671 my $idx = (cf::face::find $name) || cf::face::alloc $name;
3617 3672
3618 cf::face::set_type $idx, $type; 3673 cf::face::set_type $idx, $type;
3619 cf::face::set_data $idx, 0, $info->{data}, $info->{hash}; 3674 cf::face::set_csum $idx, 0, $info->{hash};
3675 $cf::face::SIZE[0][$idx] = $info->{size};
3676 $cf::face::FOFS[0][$idx] = $info->{fofs};
3620 cf::face::set_meta $idx, $type & 1 ? undef : $info->{meta}; # preserve meta unless prepended already 3677 $cf::face::META[$idx] = $type & 1 ? undef : $info->{meta}; # preserve meta unless prepended already
3621 $FACEHASH{$info->{hash}} = $idx;#d# 3678 $cf::face::HASH{$info->{hash}} = $idx;
3622 } else { 3679 } else {
3623# $RESOURCE{$name} = $info; # unused 3680# $RESOURCE{$name} = $info; # unused
3624 } 3681 }
3625
3626 cf::cede_to_tick;
3627 } 3682 }
3628 } 3683 }
3684
3685 ($fh, $cf::face::DATAFH) = ($cf::face::DATAFH, $fh);
3686
3687 # HACK to clear player env face cache, we need some signal framework
3688 # for this (global event?)
3689 %ext::player_env::MUSIC_FACE_CACHE = ();
3690
3691 # END ATOMIC
3692
3693 cf::debug "facedata atomic update time ", EV::time - $t1;
3629 3694
3630 cf::global->invoke (EVENT_GLOBAL_RESOURCE_UPDATE); 3695 cf::global->invoke (EVENT_GLOBAL_RESOURCE_UPDATE);
3696
3697 aio_close $fh if $fh; # close old facedata
3631 3698
3632 1 3699 1
3633} 3700}
3634 3701
3635register_exticmd fx_want => sub { 3702register_exticmd fx_want => sub {
3651} 3718}
3652 3719
3653sub reload_exp_table { 3720sub reload_exp_table {
3654 _reload_exp_table; 3721 _reload_exp_table;
3655 3722
3723 cf::face::set
3656 set_face "res/exp_table" => FT_RSRC, 3724 "res/exp_table" => FT_RSRC,
3657 JSON::XS->new->utf8->canonical->encode ( 3725 JSON::XS->new->utf8->canonical->encode (
3658 [map cf::level_to_min_exp $_, 1 .. cf::settings->max_level] 3726 [map cf::level_to_min_exp $_, 1 .. cf::settings->max_level]
3659 ); 3727 );
3660} 3728}
3661 3729
3662sub reload_materials { 3730sub reload_materials {
3663 _reload_materials; 3731 _reload_materials;
3664} 3732}
3676 if exists $_->{match}; 3744 if exists $_->{match};
3677 } 3745 }
3678} 3746}
3679 3747
3680sub reload_facedata { 3748sub reload_facedata {
3681 load_facedata "$DATADIR/facedata" 3749 load_facedata $DATADIR
3682 or die "unable to load facedata\n"; 3750 or die "unable to load facedata\n";
3683} 3751}
3684 3752
3685sub reload_archetypes { 3753sub reload_archetypes {
3686 load_resource_file "$DATADIR/archetypes" 3754 load_resource_file "$DATADIR/archetypes"
3687 or die "unable to load archetypes\n"; 3755 or die "unable to load archetypes\n";
3688 3756
3757 cf::face::set
3689 set_face "res/skill_info" => FT_RSRC, 3758 "res/skill_info" => FT_RSRC,
3690 JSON::XS->new->utf8->canonical->encode ( 3759 JSON::XS->new->utf8->canonical->encode (
3691 [map [cf::arch::skillvec ($_)->name], 0 .. cf::arch::skillvec_size - 1] 3760 [map [cf::arch::skillvec ($_)->name], 0 .. cf::arch::skillvec_size - 1]
3692 ); 3761 );
3762
3763 cf::face::set
3693 set_face "res/spell_paths" => FT_RSRC, 3764 "res/spell_paths" => FT_RSRC,
3694 JSON::XS->new->utf8->canonical->encode ( 3765 JSON::XS->new->utf8->canonical->encode (
3695 [map [cf::spellpathnames ($_)], 0 .. NRSPELLPATHS - 1] 3766 [map [cf::spellpathnames ($_)], 0 .. NRSPELLPATHS - 1]
3696 ); 3767 );
3697} 3768}
3698 3769
3699sub reload_treasures { 3770sub reload_treasures {
3700 load_resource_file "$DATADIR/treasures" 3771 load_resource_file "$DATADIR/treasures"
3701 or die "unable to load treasurelists\n"; 3772 or die "unable to load treasurelists\n";

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines