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.293 by root, Tue Jul 3 05:14:15 2007 UTC vs.
Revision 1.305 by root, Thu Jul 12 08:40:14 2007 UTC

29use Fcntl; 29use Fcntl;
30use YAML::Syck (); 30use YAML::Syck ();
31use IO::AIO 2.32 (); 31use IO::AIO 2.32 ();
32use Time::HiRes; 32use Time::HiRes;
33use Compress::LZF; 33use Compress::LZF;
34use Digest::MD5 ();
34 35
35# configure various modules to our taste 36# configure various modules to our taste
36# 37#
37$Storable::canonical = 1; # reduce rsync transfers 38$Storable::canonical = 1; # reduce rsync transfers
38Coro::State::cctx_stacksize 256000; # 1-2MB stack, for deep recursions in maze generator 39Coro::State::cctx_stacksize 256000; # 1-2MB stack, for deep recursions in maze generator
409Coro::Storable. May, of course, block. Note that the executed sub may 410Coro::Storable. May, of course, block. Note that the executed sub may
410never block itself or use any form of Event handling. 411never block itself or use any form of Event handling.
411 412
412=cut 413=cut
413 414
415sub _store_scalar {
416 open my $fh, ">", \my $buf
417 or die "fork_call: cannot open fh-to-buf in child : $!";
418 Storable::store_fd $_[0], $fh;
419 close $fh;
420
421 $buf
422}
423
414sub fork_call(&@) { 424sub fork_call(&@) {
415 my ($cb, @args) = @_; 425 my ($cb, @args) = @_;
416 426
417# socketpair my $fh1, my $fh2, Socket::AF_UNIX, Socket::SOCK_STREAM, Socket::PF_UNSPEC 427# socketpair my $fh1, my $fh2, Socket::AF_UNIX, Socket::SOCK_STREAM, Socket::PF_UNSPEC
418# or die "socketpair: $!"; 428# or die "socketpair: $!";
421 431
422 if (my $pid = fork) { 432 if (my $pid = fork) {
423 close $fh2; 433 close $fh2;
424 434
425 my $res = (Coro::Handle::unblock $fh1)->readline (undef); 435 my $res = (Coro::Handle::unblock $fh1)->readline (undef);
436 warn "pst<$res>" unless $res =~ /^pst/;
426 $res = Coro::Storable::thaw $res; 437 $res = Coro::Storable::thaw $res;
427 438
428 waitpid $pid, 0; # should not block anymore, we expect the child to simply behave 439 waitpid $pid, 0; # should not block anymore, we expect the child to simply behave
429 440
430 die $$res unless "ARRAY" eq ref $res; 441 Carp::confess $$res unless "ARRAY" eq ref $res;
431 442
432 return wantarray ? @$res : $res->[-1]; 443 return wantarray ? @$res : $res->[-1];
433 } else { 444 } else {
434 reset_signals; 445 reset_signals;
435 local $SIG{__WARN__}; 446 local $SIG{__WARN__};
436 local $SIG{__DIE__}; 447 local $SIG{__DIE__};
448 # just in case, this hack effectively disables event
449 # in the child. cleaner and slower would be canceling all watchers,
450 # but this works for the time being.
451 local $Coro::idle;
452 $Coro::current->prio (Coro::PRIO_MAX);
453
437 eval { 454 eval {
438 close $fh1; 455 close $fh1;
439 456
440 my @res = eval { $cb->(@args) }; 457 my @res = eval { $cb->(@args) };
458
441 syswrite $fh2, Coro::Storable::freeze +($@ ? \"$@" : \@res); 459 syswrite $fh2, _store_scalar $@ ? \"$@" : \@res;
460 close $fh2;
442 }; 461 };
443 462
444 warn $@ if $@; 463 warn $@ if $@;
445 _exit 0; 464 _exit 0;
446 } 465 }
1412 1431
1413 # create single paragraphs (very hackish) 1432 # create single paragraphs (very hackish)
1414 s/(?<=\S)\n(?=\w)/ /g; 1433 s/(?<=\S)\n(?=\w)/ /g;
1415 1434
1416 # compress some whitespace 1435 # compress some whitespace
1417 1 while s/\s*\n\s*\n\s*/\n/; 1436 s/\s+\n/\n/g; # ws line-ends
1418 1437 s/\n\n+/\n/g; # double lines
1419 s/^\s+//; 1438 s/^\n+//; # beginning lines
1420 s/\s+$//; 1439 s/\n+$//; # ending lines
1421 1440
1422 $_ 1441 $_
1423} 1442}
1424 1443
1425sub hintmode { 1444sub hintmode {
1470 my ($path) = @_; 1489 my ($path) = @_;
1471 1490
1472 my ($match, $specificity); 1491 my ($match, $specificity);
1473 1492
1474 for my $region (list) { 1493 for my $region (list) {
1475 if ($region->match && $path =~ $region->match) { 1494 if ($region->{match} && $path =~ $region->{match}) {
1476 ($match, $specificity) = ($region, $region->specificity) 1495 ($match, $specificity) = ($region, $region->specificity)
1477 if $region->specificity > $specificity; 1496 if $region->specificity > $specificity;
1478 } 1497 }
1479 } 1498 }
1480 1499
2357 my $hp = $exit->stats->hp; 2376 my $hp = $exit->stats->hp;
2358 my $sp = $exit->stats->sp; 2377 my $sp = $exit->stats->sp;
2359 2378
2360 $self->enter_link; 2379 $self->enter_link;
2361 2380
2381 # if exit is damned, update players death & WoR home-position
2382 $self->contr->savebed ($slaying, $hp, $sp)
2383 if $exit->flag (FLAG_DAMNED);
2384
2362 (async { 2385 (async {
2363 $self->deactivate_recursive; # just to be sure 2386 $self->deactivate_recursive; # just to be sure
2364 unless (eval { 2387 unless (eval {
2365 $self->goto ($slaying, $hp, $sp); 2388 $self->goto ($slaying, $hp, $sp);
2366 2389
2406 2429
2407sub cf::client::send_msg { 2430sub cf::client::send_msg {
2408 my ($self, $color, $type, $msg, @extra) = @_; 2431 my ($self, $color, $type, $msg, @extra) = @_;
2409 2432
2410 $msg = $self->pl->expand_cfpod ($msg); 2433 $msg = $self->pl->expand_cfpod ($msg);
2434
2435 return unless @extra || length $msg;
2411 2436
2412 if ($self->can_msg) { 2437 if ($self->can_msg) {
2413 $self->send_packet ("msg " . $self->{json_coder}->encode ([$color, $type, $msg, @extra])); 2438 $self->send_packet ("msg " . $self->{json_coder}->encode ([$color, $type, $msg, @extra]));
2414 } else { 2439 } else {
2415 # replace some tags by gcfclient-compatible ones 2440 # replace some tags by gcfclient-compatible ones
2440=cut 2465=cut
2441 2466
2442sub cf::client::ext_event($$%) { 2467sub cf::client::ext_event($$%) {
2443 my ($self, $type, %msg) = @_; 2468 my ($self, $type, %msg) = @_;
2444 2469
2470 return unless $self->extcmd;
2471
2445 $msg{msgtype} = "event_$type"; 2472 $msg{msgtype} = "event_$type";
2446 $self->send_packet ("ext " . $self->{json_coder}->encode (\%msg)); 2473 $self->send_packet ("ext " . $self->{json_coder}->encode (\%msg));
2447} 2474}
2448 2475
2449=item $success = $client->query ($flags, "text", \&cb) 2476=item $success = $client->query ($flags, "text", \&cb)
2576 2603
2577=pod 2604=pod
2578 2605
2579The following functions and methods are available within a safe environment: 2606The following functions and methods are available within a safe environment:
2580 2607
2581 cf::object contr pay_amount pay_player map 2608 cf::object
2609 contr pay_amount pay_player map x y force_find force_add
2610 insert remove
2611
2582 cf::object::player player 2612 cf::object::player
2583 cf::player peaceful 2613 player
2584 cf::map trigger 2614
2615 cf::player
2616 peaceful
2617
2618 cf::map
2619 trigger
2585 2620
2586=cut 2621=cut
2587 2622
2588for ( 2623for (
2589 ["cf::object" => qw(contr pay_amount pay_player map)], 2624 ["cf::object" => qw(contr pay_amount pay_player map force_find force_add x y
2625 insert remove)],
2590 ["cf::object::player" => qw(player)], 2626 ["cf::object::player" => qw(player)],
2591 ["cf::player" => qw(peaceful)], 2627 ["cf::player" => qw(peaceful)],
2592 ["cf::map" => qw(trigger)], 2628 ["cf::map" => qw(trigger)],
2593) { 2629) {
2594 no strict 'refs'; 2630 no strict 'refs';
2686 { 2722 {
2687 my $faces = $facedata->{faceinfo}; 2723 my $faces = $facedata->{faceinfo};
2688 2724
2689 while (my ($face, $info) = each %$faces) { 2725 while (my ($face, $info) = each %$faces) {
2690 my $idx = (cf::face::find $face) || cf::face::alloc $face; 2726 my $idx = (cf::face::find $face) || cf::face::alloc $face;
2691 cf::face::set $idx, $info->{visibility}, $info->{magicmap}; 2727 cf::face::set_visibility $idx, $info->{visibility};
2728 cf::face::set_magicmap $idx, $info->{magicmap};
2692 cf::face::set_data $idx, 0, $info->{data32}, $info->{chksum32}; 2729 cf::face::set_data $idx, 0, $info->{data32}, $info->{chksum32};
2693 cf::face::set_data $idx, 1, $info->{data64}, $info->{chksum64}; 2730 cf::face::set_data $idx, 1, $info->{data64}, $info->{chksum64};
2694 Coro::cede; 2731
2732 cf::cede_to_tick;
2695 } 2733 }
2696 2734
2697 while (my ($face, $info) = each %$faces) { 2735 while (my ($face, $info) = each %$faces) {
2698 next unless $info->{smooth}; 2736 next unless $info->{smooth};
2699 my $idx = cf::face::find $face 2737 my $idx = cf::face::find $face
2700 or next; 2738 or next;
2701 if (my $smooth = cf::face::find $info->{smooth}) { 2739 if (my $smooth = cf::face::find $info->{smooth}) {
2740 cf::face::set_smooth $idx, $smooth;
2702 cf::face::set_smooth $idx, $smooth, $info->{smoothlevel}; 2741 cf::face::set_smoothlevel $idx, $info->{smoothlevel};
2703 } else { 2742 } else {
2704 warn "smooth face '$info->{smooth}' not found for face '$face'"; 2743 warn "smooth face '$info->{smooth}' not found for face '$face'";
2705 } 2744 }
2706 Coro::cede; 2745
2746 cf::cede_to_tick;
2707 } 2747 }
2708 } 2748 }
2709 2749
2710 { 2750 {
2711 my $anims = $facedata->{animinfo}; 2751 my $anims = $facedata->{animinfo};
2712 2752
2713 while (my ($anim, $info) = each %$anims) { 2753 while (my ($anim, $info) = each %$anims) {
2714 cf::anim::set $anim, $info->{frames}, $info->{facings}; 2754 cf::anim::set $anim, $info->{frames}, $info->{facings};
2715 Coro::cede; 2755 cf::cede_to_tick;
2716 } 2756 }
2717 2757
2718 cf::anim::invalidate_all; # d'oh 2758 cf::anim::invalidate_all; # d'oh
2759 }
2760
2761 {
2762 # TODO: for gcfclient pleasure, we should give resources
2763 # that gcfclient doesn't grok a >10000 face index.
2764 my $res = $facedata->{resource};
2765 my $enc = JSON::XS->new->utf8->canonical;
2766
2767 while (my ($name, $info) = each %$res) {
2768 my $meta = $enc->encode ({
2769 name => $name,
2770 type => $info->{type},
2771 copyright => $info->{copyright}, #TODO#
2772 });
2773 my $data = pack "(w/a*)*", $meta, $info->{data};
2774 my $chk = Digest::MD5::md5 "$info->{chksum},$meta"; # mangle data checksum and metadata
2775
2776 my $idx = (cf::face::find $name) || cf::face::alloc $name;
2777 cf::face::set_type $idx, 1;
2778 cf::face::set_data $idx, 0, $data, $chk;
2779
2780 cf::cede_to_tick;
2781 }
2719 } 2782 }
2720 2783
2721 1 2784 1
2722} 2785}
2723 2786
2724sub reload_regions { 2787sub reload_regions {
2725 load_resource_file "$MAPDIR/regions" 2788 load_resource_file "$MAPDIR/regions"
2726 or die "unable to load regions file\n"; 2789 or die "unable to load regions file\n";
2790
2791 for (cf::region::list) {
2792 $_->{match} = qr/$_->{match}/
2793 if exists $_->{match};
2794 }
2727} 2795}
2728 2796
2729sub reload_facedata { 2797sub reload_facedata {
2730 load_facedata "$DATADIR/facedata" 2798 load_facedata "$DATADIR/facedata"
2731 or die "unable to load facedata\n"; 2799 or die "unable to load facedata\n";

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines