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.423 by root, Sun Apr 20 00:44:13 2008 UTC vs.
Revision 1.432 by root, Mon May 5 22:38:47 2008 UTC

1141 utf8::decode (my $decname = $filename); 1141 utf8::decode (my $decname = $filename);
1142 warn sprintf "saving %s (%d,%d)\n", 1142 warn sprintf "saving %s (%d,%d)\n",
1143 $decname, length $$rdata, scalar @$objs; 1143 $decname, length $$rdata, scalar @$objs;
1144 1144
1145 if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) { 1145 if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) {
1146 chmod SAVE_MODE, $fh; 1146 aio_chmod $fh, SAVE_MODE;
1147 aio_write $fh, 0, (length $$rdata), $$rdata, 0; 1147 aio_write $fh, 0, (length $$rdata), $$rdata, 0;
1148 aio_fsync $fh if $cf::USE_FSYNC; 1148 aio_fsync $fh if $cf::USE_FSYNC;
1149 close $fh; 1149 aio_close $fh;
1150 1150
1151 if (@$objs) { 1151 if (@$objs) {
1152 if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) { 1152 if (my $fh = aio_open "$filename.pst~", O_WRONLY | O_CREAT, 0600) {
1153 chmod SAVE_MODE, $fh; 1153 aio_chmod $fh, SAVE_MODE;
1154 my $data = Coro::Storable::nfreeze { version => 1, objs => $objs }; 1154 my $data = Coro::Storable::nfreeze { version => 1, objs => $objs };
1155 aio_write $fh, 0, (length $data), $data, 0; 1155 aio_write $fh, 0, (length $data), $data, 0;
1156 aio_fsync $fh if $cf::USE_FSYNC; 1156 aio_fsync $fh if $cf::USE_FSYNC;
1157 close $fh; 1157 aio_close $fh;
1158 aio_rename "$filename.pst~", "$filename.pst"; 1158 aio_rename "$filename.pst~", "$filename.pst";
1159 } 1159 }
1160 } else { 1160 } else {
1161 aio_unlink "$filename.pst"; 1161 aio_unlink "$filename.pst";
1162 } 1162 }
1456 my $f = new_from_file cf::object::thawer path $login 1456 my $f = new_from_file cf::object::thawer path $login
1457 or return; 1457 or return;
1458 1458
1459 my $pl = cf::player::load_pl $f 1459 my $pl = cf::player::load_pl $f
1460 or return; 1460 or return;
1461
1461 local $cf::PLAYER_LOADING{$login} = $pl; 1462 local $cf::PLAYER_LOADING{$login} = $pl;
1462 $f->resolve_delayed_derefs; 1463 $f->resolve_delayed_derefs;
1463 $cf::PLAYER{$login} = $pl 1464 $cf::PLAYER{$login} = $pl
1464 } 1465 }
1465 } 1466 }
1522 $pl->{deny_save} = 1; 1523 $pl->{deny_save} = 1;
1523 $pl->password ("*"); # this should lock out the player until we nuked the dir 1524 $pl->password ("*"); # this should lock out the player until we nuked the dir
1524 1525
1525 $pl->invoke (cf::EVENT_PLAYER_LOGOUT, 1) if $pl->active; 1526 $pl->invoke (cf::EVENT_PLAYER_LOGOUT, 1) if $pl->active;
1526 $pl->deactivate; 1527 $pl->deactivate;
1528 my $killer = cf::arch::get "killer_quit"; $pl->killer ($killer); $killer->destroy;
1529 $pl->ob->check_score;
1527 $pl->invoke (cf::EVENT_PLAYER_QUIT); 1530 $pl->invoke (cf::EVENT_PLAYER_QUIT);
1528 $pl->ns->destroy if $pl->ns; 1531 $pl->ns->destroy if $pl->ns;
1529 1532
1530 my $path = playerdir $pl; 1533 my $path = playerdir $pl;
1531 my $temp = "$path~$cf::RUNTIME~deleting~"; 1534 my $temp = "$path~$cf::RUNTIME~deleting~";
1570 1573
1571 for my $login (@$dirs) { 1574 for my $login (@$dirs) {
1572 my $path = path $login; 1575 my $path = path $login;
1573 1576
1574 # a .pst is a dead give-away for a valid player 1577 # a .pst is a dead give-away for a valid player
1575 unless (-e "$path.pst") { 1578 # if no pst file found, open and chekc for blocked users
1579 if (aio_stat "$path.pst") {
1576 my $fh = aio_open $path, Fcntl::O_RDONLY, 0 or next; 1580 my $fh = aio_open $path, Fcntl::O_RDONLY, 0 or next;
1577 aio_read $fh, 0, 512, my $buf, 0 or next; 1581 aio_read $fh, 0, 512, my $buf, 0 or next;
1578 $buf !~ /^password -------------$/m or next; # official not-valid tag 1582 $buf !~ /^password -------------$/m or next; # official not-valid tag
1579 } 1583 }
1580 1584
2029 2033
2030 cf::lock_wait "map_data:$path";#d#remove 2034 cf::lock_wait "map_data:$path";#d#remove
2031 cf::lock_wait "map_find:$path"; 2035 cf::lock_wait "map_find:$path";
2032 2036
2033 $cf::MAP{$path} || do { 2037 $cf::MAP{$path} || do {
2034 my $guard1 = cf::lock_acquire "map_find:$path";
2035 my $guard2 = cf::lock_acquire "map_data:$path"; # just for the fun of it 2038 my $guard1 = cf::lock_acquire "map_data:$path"; # just for the fun of it
2039 my $guard2 = cf::lock_acquire "map_find:$path";
2036 2040
2037 my $map = new_from_path cf::map $path 2041 my $map = new_from_path cf::map $path
2038 or return; 2042 or return;
2039 2043
2040 $map->{last_save} = $cf::RUNTIME; 2044 $map->{last_save} = $cf::RUNTIME;
2043 or return; 2047 or return;
2044 2048
2045 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?) 2049 if ($map->should_reset) {#d#TODO# disabled, crashy (locking issue?)
2046 # doing this can freeze the server in a sync job, obviously 2050 # doing this can freeze the server in a sync job, obviously
2047 #$cf::WAIT_FOR_TICK->wait; 2051 #$cf::WAIT_FOR_TICK->wait;
2052 undef $guard2;
2048 undef $guard1; 2053 undef $guard1;
2049 undef $guard2;
2050 $map->reset; 2054 $map->reset;
2051 return find $path; 2055 return find $path;
2052 } 2056 }
2053 2057
2054 $cf::MAP{$path} = $map 2058 $cf::MAP{$path} = $map
2457can be C<undef>. Does the right thing when the player is currently in a 2461can be C<undef>. Does the right thing when the player is currently in a
2458dialogue with the given NPC character. 2462dialogue with the given NPC character.
2459 2463
2460=cut 2464=cut
2461 2465
2466our $SAY_CHANNEL = {
2467 id => "say",
2468 title => "Map",
2469 reply => "say ",
2470 tooltip => "Things said to and replied from npcs near you and other players on the same map only.",
2471};
2472
2473our $CHAT_CHANNEL = {
2474 id => "chat",
2475 title => "Chat",
2476 reply => "chat ",
2477 tooltip => "Player chat and shouts, global to the server.",
2478};
2479
2462# rough implementation of a future "reply" method that works 2480# rough implementation of a future "reply" method that works
2463# with dialog boxes. 2481# with dialog boxes.
2464#TODO: the first argument must go, split into a $npc->reply_to ( method 2482#TODO: the first argument must go, split into a $npc->reply_to ( method
2465sub cf::object::player::reply($$$;$) { 2483sub cf::object::player::reply($$$;$) {
2466 my ($self, $npc, $msg, $flags) = @_; 2484 my ($self, $npc, $msg, $flags) = @_;
2477 my $dialog = $pl->{npc_dialog}; 2495 my $dialog = $pl->{npc_dialog};
2478 $dialog->{pl}->ext_msg ($dialog->{id}, update => msg => $dialog->{pl}->expand_cfpod ($msg)); 2496 $dialog->{pl}->ext_msg ($dialog->{id}, update => msg => $dialog->{pl}->expand_cfpod ($msg));
2479 2497
2480 } else { 2498 } else {
2481 $msg = $npc->name . " says: $msg" if $npc; 2499 $msg = $npc->name . " says: $msg" if $npc;
2482 $self->message ($msg, $flags); 2500 $self->send_msg ($SAY_CHANNEL => $msg, $flags);
2483 } 2501 }
2484 } 2502 }
2485} 2503}
2486 2504
2487=item $object->send_msg ($channel, $msg, $color, [extra...]) 2505=item $object->send_msg ($channel, $msg, $color, [extra...])
2682} 2700}
2683 2701
2684sub prepare_random_map { 2702sub prepare_random_map {
2685 my ($exit) = @_; 2703 my ($exit) = @_;
2686 2704
2687 my $guard = cf::lock_acquire "exit_prepare:$exit";
2688
2689 # all this does is basically replace the /! path by 2705 # all this does is basically replace the /! path by
2690 # a new random map path (?random/...) with a seed 2706 # a new random map path (?random/...) with a seed
2691 # that depends on the exit object 2707 # that depends on the exit object
2692 2708
2693 my $rmp = parse_random_map_params $exit->msg; 2709 my $rmp = parse_random_map_params $exit->msg;
2695 if ($exit->map) { 2711 if ($exit->map) {
2696 $rmp->{region} = $exit->region->name; 2712 $rmp->{region} = $exit->region->name;
2697 $rmp->{origin_map} = $exit->map->path; 2713 $rmp->{origin_map} = $exit->map->path;
2698 $rmp->{origin_x} = $exit->x; 2714 $rmp->{origin_x} = $exit->x;
2699 $rmp->{origin_y} = $exit->y; 2715 $rmp->{origin_y} = $exit->y;
2716
2717 $exit->map->touch;
2700 } 2718 }
2701 2719
2702 $rmp->{random_seed} ||= $exit->random_seed; 2720 $rmp->{random_seed} ||= $exit->random_seed;
2703 2721
2704 my $data = JSON::XS->new->utf8->pretty->canonical->encode ($rmp); 2722 my $data = JSON::XS->new->utf8->pretty->canonical->encode ($rmp);
2708 if (my $fh = aio_open "$meta~", O_WRONLY | O_CREAT, 0666) { 2726 if (my $fh = aio_open "$meta~", O_WRONLY | O_CREAT, 0666) {
2709 aio_write $fh, 0, (length $data), $data, 0; 2727 aio_write $fh, 0, (length $data), $data, 0;
2710 undef $fh; 2728 undef $fh;
2711 aio_rename "$meta~", $meta; 2729 aio_rename "$meta~", $meta;
2712 2730
2731 my $slaying = "?random/$md5";
2732
2733 if ($exit->valid) {
2713 $exit->slaying ("?random/$md5"); 2734 $exit->slaying ("?random/$md5");
2714 $exit->msg (undef); 2735 $exit->msg (undef);
2736 }
2715 } 2737 }
2716} 2738}
2717 2739
2718sub cf::object::player::enter_exit { 2740sub cf::object::player::enter_exit {
2719 my ($self, $exit) = @_; 2741 my ($self, $exit) = @_;
2720 2742
2721 return unless $self->type == cf::PLAYER; 2743 return unless $self->type == cf::PLAYER;
2722 2744
2723 if ($exit->slaying eq "/!") {
2724 #TODO: this should de-fi-ni-te-ly not be a sync-job
2725 # the problem is that $exit might not survive long enough
2726 # so it needs to be done right now, right here
2727 cf::sync_job { prepare_random_map $exit };
2728 }
2729
2730 my $slaying = cf::map::normalise $exit->slaying, $exit->map && $exit->map->path;
2731 my $hp = $exit->stats->hp;
2732 my $sp = $exit->stats->sp;
2733
2734 $self->enter_link; 2745 $self->enter_link;
2735 2746
2736 # if exit is damned, update players death & WoR home-position
2737 $self->contr->savebed ($slaying, $hp, $sp)
2738 if $exit->flag (FLAG_DAMNED);
2739
2740 (async { 2747 (async {
2741 $Coro::current->{desc} = "enter_exit $slaying $hp $sp"; 2748 $Coro::current->{desc} = "enter_exit";
2742 2749
2743 $self->deactivate_recursive; # just to be sure
2744 unless (eval { 2750 unless (eval {
2751 $self->deactivate_recursive; # just to be sure
2752
2753 # random map handling
2754 {
2755 my $guard = cf::lock_acquire "exit_prepare:$exit";
2756
2757 prepare_random_map $exit
2758 if $exit->slaying eq "/!";
2759 }
2760
2761 my $map = cf::map::normalise $exit->slaying, $exit->map && $exit->map->path;
2762 my $x = $exit->stats->hp;
2763 my $y = $exit->stats->sp;
2764
2745 $self->goto ($slaying, $hp, $sp); 2765 $self->goto ($map, $x, $y);
2746 2766
2767 # if exit is damned, update players death & WoR home-position
2768 $self->contr->savebed ($map, $x, $y)
2769 if $exit->flag (cf::FLAG_DAMNED);
2770
2747 1; 2771 1
2748 }) { 2772 }) {
2749 $self->message ("Something went wrong deep within the crossfire server. " 2773 $self->message ("Something went wrong deep within the crossfire server. "
2750 . "I'll try to bring you back to the map you were before. " 2774 . "I'll try to bring you back to the map you were before. "
2751 . "Please report this to the dungeon master!", 2775 . "Please report this to the dungeon master!",
2752 cf::NDI_UNIQUE | cf::NDI_RED); 2776 cf::NDI_UNIQUE | cf::NDI_RED);
2832 id => "infobox", 2856 id => "infobox",
2833 title => "Map Info", 2857 title => "Map Info",
2834 reply => undef, 2858 reply => undef,
2835 tooltip => "Information related to the maps", 2859 tooltip => "Information related to the maps",
2836 }, 2860 },
2861 "c/party" => {
2862 id => "party",
2863 title => "Party",
2864 reply => "gsay ",
2865 tooltip => "Messages and chat related to your party",
2866 },
2837); 2867);
2838 2868
2839sub cf::client::send_msg { 2869sub cf::client::send_msg {
2840 my ($self, $channel, $msg, $color, @extra) = @_; 2870 my ($self, $channel, $msg, $color, @extra) = @_;
2841 2871
3078 3108
3079The following functions and methods are available within a safe environment: 3109The following functions and methods are available within a safe environment:
3080 3110
3081 cf::object 3111 cf::object
3082 contr pay_amount pay_player map x y force_find force_add destroy 3112 contr pay_amount pay_player map x y force_find force_add destroy
3083 insert remove name archname title slaying race decrease_ob_nr 3113 insert remove name archname title slaying race decrease split
3084 3114
3085 cf::object::player 3115 cf::object::player
3086 player 3116 player
3087 3117
3088 cf::player 3118 cf::player
3093 3123
3094=cut 3124=cut
3095 3125
3096for ( 3126for (
3097 ["cf::object" => qw(contr pay_amount pay_player map force_find force_add x y 3127 ["cf::object" => qw(contr pay_amount pay_player map force_find force_add x y
3098 insert remove inv name archname title slaying race 3128 insert remove inv nrof name archname title slaying race
3099 decrease_ob_nr destroy)], 3129 decrease split destroy)],
3100 ["cf::object::player" => qw(player)], 3130 ["cf::object::player" => qw(player)],
3101 ["cf::player" => qw(peaceful)], 3131 ["cf::player" => qw(peaceful)],
3102 ["cf::map" => qw(trigger)], 3132 ["cf::map" => qw(trigger)],
3103) { 3133) {
3104 no strict 'refs'; 3134 no strict 'refs';
3313 $ns->fx_want ($k, $v); 3343 $ns->fx_want ($k, $v);
3314 } 3344 }
3315}; 3345};
3316 3346
3317sub load_resource_file($) { 3347sub load_resource_file($) {
3348 my $guard = lock_acquire "load_resource_file";
3349
3318 my $status = load_resource_file_ $_[0]; 3350 my $status = load_resource_file_ $_[0];
3319 get_slot 0.1, 100; 3351 get_slot 0.1, 100;
3320 cf::arch::commit_load; 3352 cf::arch::commit_load;
3353
3321 $status 3354 $status
3322} 3355}
3323 3356
3324sub reload_regions { 3357sub reload_regions {
3325 # HACK to clear player env face cache, we need some signal framework 3358 # HACK to clear player env face cache, we need some signal framework

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines