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.287 by root, Mon Jun 25 05:43:45 2007 UTC vs.
Revision 1.298 by root, Sun Jul 8 14:50:07 2007 UTC

20use Coro::Signal; 20use Coro::Signal;
21use Coro::Semaphore; 21use Coro::Semaphore;
22use Coro::AIO; 22use Coro::AIO;
23use Coro::Storable; 23use Coro::Storable;
24 24
25use JSON::XS 1.4 ();
25use BDB (); 26use BDB ();
26use Data::Dumper; 27use Data::Dumper;
27use Digest::MD5; 28use Digest::MD5;
28use Fcntl; 29use Fcntl;
29use YAML::Syck (); 30use YAML::Syck ();
237 $d =~ s/([\x00-\x07\x09\x0b\x0c\x0e-\x1f])/sprintf "\\x%02x", ord($1)/ge; 238 $d =~ s/([\x00-\x07\x09\x0b\x0c\x0e-\x1f])/sprintf "\\x%02x", ord($1)/ge;
238 $d 239 $d
239 } || "[unable to dump $_[0]: '$@']"; 240 } || "[unable to dump $_[0]: '$@']";
240} 241}
241 242
242use JSON::XS ();
243
244=item $ref = cf::from_json $json 243=item $ref = cf::from_json $json
245 244
246Converts a JSON string into the corresponding perl data structure. 245Converts a JSON string into the corresponding perl data structure.
247 246
248=item $json = cf::to_json $ref 247=item $json = cf::to_json $ref
249 248
250Converts a perl data structure into its JSON representation. 249Converts a perl data structure into its JSON representation.
251 250
252=cut 251=cut
253 252
254our $json_coder = JSON::XS->new->convert_blessed->utf8; 253our $json_coder = JSON::XS->new->utf8->max_size (1e6); # accept ~1mb max
255 254
256sub to_json ($) { $json_coder->encode ($_[0]) } 255sub to_json ($) { $json_coder->encode ($_[0]) }
257sub from_json ($) { $json_coder->decode ($_[0]) } 256sub from_json ($) { $json_coder->decode ($_[0]) }
258 257
259=item cf::lock_wait $string 258=item cf::lock_wait $string
422 421
423 if (my $pid = fork) { 422 if (my $pid = fork) {
424 close $fh2; 423 close $fh2;
425 424
426 my $res = (Coro::Handle::unblock $fh1)->readline (undef); 425 my $res = (Coro::Handle::unblock $fh1)->readline (undef);
426 warn "pst<$res>" unless $res =~ /^pst/;
427 $res = Coro::Storable::thaw $res; 427 $res = Coro::Storable::thaw $res;
428 428
429 waitpid $pid, 0; # should not block anymore, we expect the child to simply behave 429 waitpid $pid, 0; # should not block anymore, we expect the child to simply behave
430 430
431 die $$res unless "ARRAY" eq ref $res; 431 Carp::confess $$res unless "ARRAY" eq ref $res;
432 432
433 return wantarray ? @$res : $res->[-1]; 433 return wantarray ? @$res : $res->[-1];
434 } else { 434 } else {
435 reset_signals; 435 reset_signals;
436 local $SIG{__WARN__}; 436 local $SIG{__WARN__};
437 local $SIG{__DIE__}; 437 local $SIG{__DIE__};
438 local $Coro::idle;
439 $Coro::current->prio (Coro::PRIO_MAX);
438 eval { 440 eval {
439 close $fh1; 441 close $fh1;
440 442
441 my @res = eval { $cb->(@args) }; 443 my @res = eval { $cb->(@args) };
442 syswrite $fh2, Coro::Storable::freeze +($@ ? \"$@" : \@res); 444
445 open my $fh, ">", \my $buf
446 or die "fork_call: cannot open fh-to-buf in child : $!";
447 Storable::store_fd +($@ ? \"$@" : \@res), $fh;
448 close $fh;
449
450 warn "writing ", length $buf;
451 my $x;
452 (length $buf) == ($x = syswrite $fh2, $buf)
453 or warn "error writing ".(length $buf)." != $x\n";
454 close $fh2;
443 }; 455 };
444 456
445 warn $@ if $@; 457 warn $@ if $@;
446 _exit 0; 458 _exit 0;
447 } 459 }
1087 cf::override; 1099 cf::override;
1088 }, 1100 },
1089 on_extcmd => sub { 1101 on_extcmd => sub {
1090 my ($pl, $buf) = @_; 1102 my ($pl, $buf) = @_;
1091 1103
1092 my $msg = eval { from_json $buf }; 1104 my $msg = eval { $pl->ns->{json_coder}->decode ($buf) };
1093 1105
1094 if (ref $msg) { 1106 if (ref $msg) {
1095 if (my $cb = $EXTCMD{$msg->{msgtype}}) { 1107 if (my $cb = $EXTCMD{$msg->{msgtype}}) {
1096 if (my %reply = $cb->($pl, $msg)) { 1108 if (my %reply = $cb->($pl, $msg)) {
1097 $pl->ext_reply ($msg->{msgid}, %reply); 1109 $pl->ext_reply ($msg->{msgid}, %reply);
1401 # replace G<male|female> tags 1413 # replace G<male|female> tags
1402 || s{G<([^>|]*)\|([^>]*)>}{ 1414 || s{G<([^>|]*)\|([^>]*)>}{
1403 $self->gender ? $2 : $1 1415 $self->gender ? $2 : $1
1404 }ge 1416 }ge
1405 # replace H<hint text> 1417 # replace H<hint text>
1406 || s/H<([^\>]*)>/<fg name="lightblue">[$1]<\/fg>/g; 1418 || s{H<([^\>]*)>}
1419 {
1420 ("<fg name=\"lightblue\">[$1 (Use hintmode to suppress hints)]</fg>",
1421 "<fg name=\"lightblue\">[Hint suppressed, see hintmode]</fg>",
1422 "")
1423 [$self->{hintmode}]
1424 }ge;
1407 1425
1408 # create single paragraphs (very hackish) 1426 # create single paragraphs (very hackish)
1409 s/(?<=\S)\n(?=\w)/ /g; 1427 s/(?<=\S)\n(?=\w)/ /g;
1410 1428
1429 # compress some whitespace
1430 s/\s+\n/\n/g; # ws line-ends
1431 s/\n\n+/\n/g; # double lines
1432 s/^\n+//; # beginning lines
1433 s/\n+$//; # ending lines
1434
1411 $_ 1435 $_
1436}
1437
1438sub hintmode {
1439 $_[0]{hintmode} = $_[1] if @_ > 1;
1440 $_[0]{hintmode}
1412} 1441}
1413 1442
1414=item $player->ext_reply ($msgid, %msg) 1443=item $player->ext_reply ($msgid, %msg)
1415 1444
1416Sends an ext reply to the player. 1445Sends an ext reply to the player.
1419 1448
1420sub ext_reply($$%) { 1449sub ext_reply($$%) {
1421 my ($self, $id, %msg) = @_; 1450 my ($self, $id, %msg) = @_;
1422 1451
1423 $msg{msgid} = $id; 1452 $msg{msgid} = $id;
1424 $self->send ("ext " . cf::to_json \%msg); 1453 $self->send ("ext " . $self->ns->{json_coder}->encode (\%msg));
1425} 1454}
1426 1455
1427=item $player->ext_event ($type, %msg) 1456=item $player->ext_event ($type, %msg)
1428 1457
1429Sends an ext event to the client. 1458Sends an ext event to the client.
2341 my $hp = $exit->stats->hp; 2370 my $hp = $exit->stats->hp;
2342 my $sp = $exit->stats->sp; 2371 my $sp = $exit->stats->sp;
2343 2372
2344 $self->enter_link; 2373 $self->enter_link;
2345 2374
2375 # if exit is damned, update players death & WoR home-position
2376 $self->contr->savebed ($slaying, $hp, $sp)
2377 if $exit->flag (FLAG_DAMNED);
2378
2346 (async { 2379 (async {
2347 $self->deactivate_recursive; # just to be sure 2380 $self->deactivate_recursive; # just to be sure
2348 unless (eval { 2381 unless (eval {
2349 $self->goto ($slaying, $hp, $sp); 2382 $self->goto ($slaying, $hp, $sp);
2350 2383
2391sub cf::client::send_msg { 2424sub cf::client::send_msg {
2392 my ($self, $color, $type, $msg, @extra) = @_; 2425 my ($self, $color, $type, $msg, @extra) = @_;
2393 2426
2394 $msg = $self->pl->expand_cfpod ($msg); 2427 $msg = $self->pl->expand_cfpod ($msg);
2395 2428
2429 return unless @extra || length $msg;
2430
2396 if ($self->can_msg) { 2431 if ($self->can_msg) {
2397 $self->send_packet ("msg " . cf::to_json [$color, $type, $msg, @extra]); 2432 $self->send_packet ("msg " . $self->{json_coder}->encode ([$color, $type, $msg, @extra]));
2398 } else { 2433 } else {
2399 # replace some tags by gcfclient-compatible ones 2434 # replace some tags by gcfclient-compatible ones
2400 for ($msg) { 2435 for ($msg) {
2401 1 while 2436 1 while
2402 s/<b>([^<]*)<\/b>/[b]${1}[\/b]/ 2437 s/<b>([^<]*)<\/b>/[b]${1}[\/b]/
2425 2460
2426sub cf::client::ext_event($$%) { 2461sub cf::client::ext_event($$%) {
2427 my ($self, $type, %msg) = @_; 2462 my ($self, $type, %msg) = @_;
2428 2463
2429 $msg{msgtype} = "event_$type"; 2464 $msg{msgtype} = "event_$type";
2430 $self->send_packet ("ext " . cf::to_json \%msg); 2465 $self->send_packet ("ext " . $self->{json_coder}->encode (\%msg));
2431} 2466}
2432 2467
2433=item $success = $client->query ($flags, "text", \&cb) 2468=item $success = $client->query ($flags, "text", \&cb)
2434 2469
2435Queues a query to the client, calling the given callback with 2470Queues a query to the client, calling the given callback with
2458 2493
2459 1 2494 1
2460} 2495}
2461 2496
2462cf::client->attach ( 2497cf::client->attach (
2498 on_connect => sub {
2499 my ($ns) = @_;
2500
2501 $ns->{json_coder} = JSON::XS->new->utf8->max_size (1e6)->convert_blessed;
2502 },
2463 on_reply => sub { 2503 on_reply => sub {
2464 my ($ns, $msg) = @_; 2504 my ($ns, $msg) = @_;
2465 2505
2466 # this weird shuffling is so that direct followup queries 2506 # this weird shuffling is so that direct followup queries
2467 # get handled first 2507 # get handled first
2482 } 2522 }
2483 }, 2523 },
2484 on_exticmd => sub { 2524 on_exticmd => sub {
2485 my ($ns, $buf) = @_; 2525 my ($ns, $buf) = @_;
2486 2526
2487 my $msg = eval { from_json $buf }; 2527 my $msg = eval { $ns->{json_coder}->decode ($buf) };
2488 2528
2489 if (ref $msg) { 2529 if (ref $msg) {
2490 if (my $cb = $EXTICMD{$msg->{msgtype}}) { 2530 if (my $cb = $EXTICMD{$msg->{msgtype}}) {
2491 if (my %reply = $cb->($ns, $msg)) { 2531 if (my %reply = $cb->($ns, $msg)) {
2492 $reply{msgid} = $msg->{msgid}; 2532 $reply{msgid} = $msg->{msgid};
2493 $ns->send ("ext " . cf::to_json \%reply); 2533 $ns->send ("ext " . $ns->{json_coder}->encode (\%reply));
2494 } 2534 }
2495 } 2535 }
2496 } else { 2536 } else {
2497 warn "client " . ($ns->pl ? $ns->pl->ob->name : $ns->host) . " sent unparseable exti message: <$buf>\n"; 2537 warn "client " . ($ns->pl ? $ns->pl->ob->name : $ns->host) . " sent unparseable exti message: <$buf>\n";
2498 } 2538 }
2555 2595
2556=pod 2596=pod
2557 2597
2558The following functions and methods are available within a safe environment: 2598The following functions and methods are available within a safe environment:
2559 2599
2560 cf::object contr pay_amount pay_player map 2600 cf::object
2601 contr pay_amount pay_player map x y force_find force_add
2602 insert remove
2603
2561 cf::object::player player 2604 cf::object::player
2562 cf::player peaceful 2605 player
2563 cf::map trigger 2606
2607 cf::player
2608 peaceful
2609
2610 cf::map
2611 trigger
2564 2612
2565=cut 2613=cut
2566 2614
2567for ( 2615for (
2568 ["cf::object" => qw(contr pay_amount pay_player map)], 2616 ["cf::object" => qw(contr pay_amount pay_player map force_find force_add x y
2617 insert remove)],
2569 ["cf::object::player" => qw(player)], 2618 ["cf::object::player" => qw(player)],
2570 ["cf::player" => qw(peaceful)], 2619 ["cf::player" => qw(peaceful)],
2571 ["cf::map" => qw(trigger)], 2620 ["cf::map" => qw(trigger)],
2572) { 2621) {
2573 no strict 'refs'; 2622 no strict 'refs';
2709 load_facedata "$DATADIR/facedata" 2758 load_facedata "$DATADIR/facedata"
2710 or die "unable to load facedata\n"; 2759 or die "unable to load facedata\n";
2711} 2760}
2712 2761
2713sub reload_archetypes { 2762sub reload_archetypes {
2763 load_resource_file "$DATADIR/archetypes"
2764 or die "unable to load archetypes\n";
2765 #d# NEED to laod twice to resolve forward references
2766 # this really needs to be done in an extra post-pass
2767 # (which needs to be synchronous, so solve it differently)
2714 load_resource_file "$DATADIR/archetypes" 2768 load_resource_file "$DATADIR/archetypes"
2715 or die "unable to load archetypes\n"; 2769 or die "unable to load archetypes\n";
2716} 2770}
2717 2771
2718sub reload_treasures { 2772sub reload_treasures {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines