ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/bin/pclient
(Generate patch)

Comparing deliantra/Deliantra-Client/bin/pclient (file contents):
Revision 1.112 by root, Sat Apr 15 13:56:26 2006 UTC vs.
Revision 1.119 by root, Mon Apr 17 06:50:26 2006 UTC

13use SDL::OpenGL; 13use SDL::OpenGL;
14 14
15use Crossfire; 15use Crossfire;
16use Crossfire::Protocol; 16use Crossfire::Protocol;
17 17
18use Compress::LZF;
19
18use CFClient; 20use CFClient;
19use CFClient::UI; 21use CFClient::UI;
20 22
21our $VERSION = '0.1'; 23our $VERSION = '0.1';
22 24
23my $MAX_FPS = 60; 25my $MAX_FPS = 60;
24my $MIN_FPS = 5; # unused as of yet 26my $MIN_FPS = 5; # unused as of yet
25 27
26our $META_SERVER = "crossfire.real-time.com:13326"; 28our $META_SERVER = "crossfire.real-time.com:13326";
27 29
30our $FACEMAP;
31our $TILECACHE;
28our $FACECACHE; 32our $MAPCACHE;
29 33
30our $LAST_REFRESH; 34our $LAST_REFRESH;
31our $NOW; 35our $NOW;
32 36
33our $CFG; 37our $CFG;
69 73
70sub start_game { 74sub start_game {
71 status "logging in..."; 75 status "logging in...";
72 76
73 my $mapsize = List::Util::min 32, List::Util::max 11, int $WIDTH * $CFG->{mapsize} * 0.01 / 32; 77 my $mapsize = List::Util::min 32, List::Util::max 11, int $WIDTH * $CFG->{mapsize} * 0.01 / 32;
78
79 $MAPCACHE = CFClient::db_table "mapcache_$CFG->{host}";
74 80
75 $MAP = new CFClient::Map $mapsize, $mapsize; 81 $MAP = new CFClient::Map $mapsize, $mapsize;
76 82
77 my ($host, $port) = split /:/, $CFG->{host}; 83 my ($host, $port) = split /:/, $CFG->{host};
78 84
166 172
167 $dialog 173 $dialog
168} 174}
169 175
170sub update_metaserver { 176sub update_metaserver {
177 my ($HOST) = @_;
178
171 status "fetching metaserver list..."; 179 status "fetching metaserver list...";
172 180
173 my $buf; 181 my $buf;
174 182
175 my $fh = new IO::Socket::INET PeerHost => $META_SERVER, Blocking => 0; 183 my $fh = new IO::Socket::INET PeerHost => $META_SERVER, Blocking => 0;
181 $_[0]->w->cancel; 189 $_[0]->w->cancel;
182 status "metaserver: $!"; 190 status "metaserver: $!";
183 } elsif ($res == 0) { 191 } elsif ($res == 0) {
184 $_[0]->w->cancel; 192 $_[0]->w->cancel;
185 status "server list retrieved"; 193 status "server list retrieved";
186 warn $buf; 194
195 my $table = $METASERVER->{table};
196
197 $table->clear;
198
199 my @col = qw(Use #Users Host Uptime Version Description);
200 $table->add ($_, 0, new CFClient::UI::Label align => 0, fg => [1, 1, 0], text => $col[$_])
201 for 0 .. $#col;
202
203 my @align = qw(1 0 1 1 -1);
204
205 my $y = 0;
206 for my $m (sort { $b->[3] <=> $a->[3] } map [split /\|/], split /\015?\012/, $buf) {
207 my ($ip, $last, $host, $users, $version, $desc, $ibytes, $obytes, $uptime) = @$m;
208
209 for ($desc) {
210 s/<br>/\n/gi;
211 s/<li>/\n· /gi;
212 s/<.*?>//sgi;
213 s/&/&amp;/g;
214 s/</&lt;/g;
215 s/>/&gt;/g;
216 }
217
218 $uptime = sprintf "%dd %02d:%02d:%02d",
219 (int $m->[8] / 86400),
220 (int $m->[8] / 3600) % 24,
221 (int $m->[8] / 60) % 60,
222 $m->[8] % 60;
223
224 $m = [$users, $host, $uptime, $version, $desc];
225
226 $y++;
227
228 $table->add (0, $y, new CFClient::UI::VBox children => [
229 (new CFClient::UI::Button text => " ", connect_activate => sub {
230 $HOST->set_text ($CFG->{host} = $host);
231 }),
232 (new CFClient::UI::Empty expand => 1),
233 ]);
234
235 $table->add ($_ + 1, $y, new CFClient::UI::Label align => $align[$_], text => $m->[$_], fontsize => $FONTSIZE * 0.8)
236 for 0 .. $#$m;
237 }
187 } 238 }
188 }); 239 });
189} 240}
190 241
191sub server_setup { 242sub server_setup {
197 $table->add (0, 2, new CFClient::UI::Label align => 1, text => "Host:Port"); 248 $table->add (0, 2, new CFClient::UI::Label align => 1, text => "Host:Port");
198 249
199 { 250 {
200 $table->add (1, 2, my $vbox = new CFClient::UI::VBox); 251 $table->add (1, 2, my $vbox = new CFClient::UI::VBox);
201 252
202 $vbox->add (new CFClient::UI::Entry text => $CFG->{host}, connect_changed => sub { 253 $vbox->add (my $HOST = new CFClient::UI::Entry text => $CFG->{host}, connect_changed => sub {
203 my ($self, $value) = @_; 254 my ($self, $value) = @_;
204 $CFG->{host} = $value; 255 $CFG->{host} = $value;
205 }); 256 });
206 257
207 $METASERVER = metaserver_dialog; 258 $METASERVER = metaserver_dialog;
208 259
209 $vbox->add (new CFClient::UI::Flopper text => "Metaserver", other => $METASERVER, connect_open => sub { 260 $vbox->add (new CFClient::UI::Flopper text => "Metaserver", other => $METASERVER, connect_open => sub {
210 update_metaserver; 261 update_metaserver $HOST;
211 }); 262 });
212 } 263 }
213 264
214 $table->add (0, 4, new CFClient::UI::Label align => 1, text => "Username"); 265 $table->add (0, 4, new CFClient::UI::Label align => 1, text => "Username");
215 $table->add (1, 4, my $user = new CFClient::UI::Entry text => $CFG->{user}, connect_changed => sub { 266 $table->add (1, 4, new CFClient::UI::Entry text => $CFG->{user}, connect_changed => sub {
216 my ($self, $value) = @_; 267 my ($self, $value) = @_;
217 $CFG->{user} = $value; 268 $CFG->{user} = $value;
218 }); 269 });
219 270
220 $table->add (0, 5, new CFClient::UI::Label align => 1, text => "Password"); 271 $table->add (0, 5, new CFClient::UI::Label align => 1, text => "Password");
221 $table->add (1, 5, my $pass = new CFClient::UI::Entry text => $CFG->{password}, hidden => 1, connect_changed => sub { 272 $table->add (1, 5, new CFClient::UI::Entry text => $CFG->{password}, hidden => 1, connect_changed => sub {
222 my ($self, $value) = @_; 273 my ($self, $value) = @_;
223 $CFG->{password} = $value; 274 $CFG->{password} = $value;
224 }); 275 });
225 276
226 $table->add (0, 6, new CFClient::UI::Label align => 1, text => "Def. say cmd"); 277 $table->add (0, 6, new CFClient::UI::Label align => 1, text => "Def. say cmd");
258 $vbox->add ($LOGVIEW = new CFClient::UI::TextView 309 $vbox->add ($LOGVIEW = new CFClient::UI::TextView
259 expand => 1, 310 expand => 1,
260 fontsize => $::CFG->{log_fontsize}, 311 fontsize => $::CFG->{log_fontsize},
261 ); 312 );
262 313
263 $vbox->add (my $input = new CFClient::UI::LineEntry); 314 $vbox->add (my $input = new CFClient::UI::LineEntry
315 connect_focus_in => sub {
316 my ($input, $prev_focus) = @_;
317
318 delete $input->{refocus_map};
319
320 if ($prev_focus == $MAPWIDGET && $input->{auto_activated}) {
321 $input->{refocus_map} = 1;
322 }
323 delete $input->{auto_activated};
324 },
264 $input->connect (activate => sub { 325 connect_activate => sub {
265 my ($input, $text) = @_; 326 my ($input, $text) = @_;
266 $input->set_text (''); 327 $input->set_text ('');
267 328
268 if ($text =~ /^\/(.*)/) { 329 if ($text =~ /^\/(.*)/) {
269 $::CONN->user_send ("command $1"); 330 $::CONN->user_send ("command $1");
270 } else { 331 } else {
271 my $say_cmd = $::CFG->{say_command} || 'say'; 332 my $say_cmd = $::CFG->{say_command} || 'say';
272 $::CONN->user_send ("command $say_cmd $text"); 333 $::CONN->user_send ("command $say_cmd $text");
273 } 334 }
335 if ($input->{refocus_map}) {
336 delete $input->{refocus_map};
337 $MAPWIDGET->focus_in
274 1 338 }
275 }); 339 },
276 $input->connect (escape => sub { 340 connect_escape => sub {
277 $MAPWIDGET->focus_in 341 $MAPWIDGET->focus_in
278 }); 342 },
279 $input->focus_in; 343 );
280 344
281 $CONSOLE = { 345 $CONSOLE = {
282 window => $window, 346 window => $window,
283 input => $input 347 input => $input
284 }; 348 };
300 $FAST = $CFG->{fast}; 364 $FAST = $CFG->{fast};
301 365
302 SDL::GLSetAttribute SDL_GL_RED_SIZE, 5; 366 SDL::GLSetAttribute SDL_GL_RED_SIZE, 5;
303 SDL::GLSetAttribute SDL_GL_GREEN_SIZE, 5; 367 SDL::GLSetAttribute SDL_GL_GREEN_SIZE, 5;
304 SDL::GLSetAttribute SDL_GL_BLUE_SIZE, 5; 368 SDL::GLSetAttribute SDL_GL_BLUE_SIZE, 5;
305 SDL::GLSetAttribute SDL_GL_ALPHA_SIZE, 0; 369 SDL::GLSetAttribute SDL_GL_ALPHA_SIZE, 1;
306 370
307 SDL::GLSetAttribute SDL_GL_ACCUM_RED_SIZE, 0; 371 SDL::GLSetAttribute SDL_GL_ACCUM_RED_SIZE, 0;
308 SDL::GLSetAttribute SDL_GL_ACCUM_GREEN_SIZE, 0; 372 SDL::GLSetAttribute SDL_GL_ACCUM_GREEN_SIZE, 0;
309 SDL::GLSetAttribute SDL_GL_ACCUM_BLUE_SIZE, 0; 373 SDL::GLSetAttribute SDL_GL_ACCUM_BLUE_SIZE, 0;
310 SDL::GLSetAttribute SDL_GL_ACCUM_ALPHA_SIZE, 0; 374 SDL::GLSetAttribute SDL_GL_ACCUM_ALPHA_SIZE, 0;
352 $MAPWIDGET->focus_in; 416 $MAPWIDGET->focus_in;
353 $MAPWIDGET->connect (activate_console => sub { 417 $MAPWIDGET->connect (activate_console => sub {
354 my ($mapwidget, $preset) = @_; 418 my ($mapwidget, $preset) = @_;
355 419
356 if ($CONSOLE) { 420 if ($CONSOLE) {
421 $CONSOLE->{input}->{auto_activated} = 1;
357 $CONSOLE->{input}->focus_in; 422 $CONSOLE->{input}->focus_in;
358 423
359 if ($preset && $CONSOLE->{input}->get_text eq '') { 424 if ($preset && $CONSOLE->{input}->get_text eq '') {
360 $CONSOLE->{input}->set_text ($preset); 425 $CONSOLE->{input}->set_text ($preset);
361 } 426 }
371 $BUTTONBAR->add (new CFClient::UI::Button text => "Save Config", connect_activate => sub { 436 $BUTTONBAR->add (new CFClient::UI::Button text => "Save Config", connect_activate => sub {
372 CFClient::write_cfg "$Crossfire::VARDIR/pclientrc"; 437 CFClient::write_cfg "$Crossfire::VARDIR/pclientrc";
373 status "Configuration Saved"; 438 status "Configuration Saved";
374 }); 439 });
375 440
376 $BUTTONBAR->{children}[0]->emit ("activate"); 441 $BUTTONBAR->{children}[1]->emit ("activate"); # pop up server setup
377} 442}
378 443
379sub destroy_screen { 444sub destroy_screen {
380 $CFClient::UI::ROOT->{children} = []; 445 $CFClient::UI::ROOT->{children} = [];
381 undef $SDL_ACTIVE; 446 undef $SDL_ACTIVE;
444 509
445 $self->send ($command); 510 $self->send ($command);
446 status $command; 511 status $command;
447} 512}
448 513
514sub conn::map_scroll {
515 my ($self, $dx, $dy) = @_;
516
517 $MAP->scroll ($dx, $dy);
518}
519
449sub conn::feed_map1a { 520sub conn::feed_map1a {
450 my ($self, $data) = @_; 521 my ($self, $data) = @_;
451 522
452# $self->Crossfire::Protocol::feed_map1a ($data); 523# $self->Crossfire::Protocol::feed_map1a ($data);
453 524
454 $MAP->scroll (delete $self->{delayed_scroll_x}, delete $self->{delayed_scroll_y});
455 $MAP->map1a_update ($data); 525 $MAP->map1a_update ($data);
456 $MAPWIDGET->update; 526 $MAPWIDGET->update;
457} 527}
458 528
459#sub conn::map_update { 529sub conn::flush_map {
460# my ($self, $dirty) = @_; 530 my ($self) = @_;
461# 531
462# $MAPWIDGET->update; 532 my $map_info = delete $self->{map_info}
463#} 533 or return;
534
535 my ($hash, $x, $y, $w, $h) = @$map_info;
536
537 my $data = $MAP->get_rect ($x, $y, $w, $h);
538 $MAPCACHE->put ($hash => Compress::LZF::compress $data);
539
540 warn sprintf "SAVEmap[%s] length %d\n", $hash, length $data;#d#
541
542}
464 543
465sub conn::map_clear { 544sub conn::map_clear {
466 my ($self) = @_; 545 my ($self) = @_;
467 546
547 $self->flush_map;
548 delete $self->{neigh};
549
468 $MAP->clear; 550 $MAP->clear;
551}
469 552
470# refresh; 553
554sub conn::load_map($$$) {
555 my ($self, $hash, $x, $y) = @_;
556
557 if (defined (my $data = $MAPCACHE->get ($hash))) {
558 $data = Compress::LZF::decompress $data;
559 warn sprintf "LOADmap[%s,%d,%d] length %d\n", $hash, $x, $y, length $data;#d#
560 for my $id ($MAP->set_rect ($x, $y, $data)) {
561 my $data = $TILECACHE->get ($id)
562 or next;
563
564 $self->set_texture ($id => $data);
565 }
566 }
567}
568
569sub conn::flood_fill {
570 my ($self, $path, $hash, $flags, $x0, $y0, $x1, $y1) = @_;
571
572 for my $tile (1..4) {
573 next if $self->{neigh}{$hash}[$tile];
574 next unless $flags & (1 << ($tile - 1));
575
576 my $neigh = $self->{neigh}{$hash} ||= [];
577
578 $self->send_mapinfo ("spatial $path$tile", sub {
579 my ($mode, $flags, $x, $y, $w, $h, $hash) = @_;
580
581 warn "map<$path>_$tile=<$mode,$x,$y,$w,$h,$hash>\n";#d#
582 return if $mode ne "spatial";
583
584 $x += $MAP->ox;
585 $y += $MAP->oy;
586
587 $self->load_map ($hash, $x, $y);
588
589 $neigh->[$tile] = [$x, $y, $w, $h];
590
591 $self->flood_fill ("$path$tile", $hash, $flags, $x0, $y0, $x1, $y1)
592 if $x >= $x0 && $x + $w < $x1 && $y >= $y0 && $y + $h < $y1;
593 });
594 }
595}
596
597sub conn::map_change {
598 my ($self, $mode, $flags, $x, $y, $w, $h, $hash) = @_;
599
600 $self->flush_map;
601
602 my ($ox, $oy) = ($::MAP->ox, $::MAP->oy);
603
604 warn "$ox $oy map_info<$flags, $x, $y, $w, $h, $hash>\n";#d#
605
606 my $mapmapw = 250;
607 my $mapmaph = 250;
608
609 $self->flood_fill ("", $hash, $flags,
610 $ox - $mapmapw * 0.5, $oy - $mapmapw * 0.5,
611 $ox + $mapmapw * 0.5, $oy + $mapmapw * 0.5);
612
613 $x += $ox;
614 $y += $oy;
615
616 $self->{map_info} = [$hash, $x, $y, $w, $h];
617
618 $self->load_map ($hash, $x, $y);
471} 619}
472 620
473sub conn::face_find { 621sub conn::face_find {
474 my ($self, $face) = @_; 622 my ($self, $facenum, $face) = @_;
475 623
476 $FACECACHE->{"$face->{chksum},$face->{name}"} 624 my $hash = "$face->{chksum},$face->{name}";
625
626 my $id = $FACEMAP->get ($hash);
627
628 unless ($id) {
629 # create new id for face
630 # i love transactions
631 for (1..100) {
632 my $txn = $CFClient::DB_ENV->txn_begin;
633 my $status = $FACEMAP->db_get (id => $id, BerkeleyDB::DB_RMW);
634 if ($status == 0 || $status == BerkeleyDB::DB_NOTFOUND) {
635 $id++;
636 if ($FACEMAP->put (id => $id) == 0
637 && $FACEMAP->put ($hash => $id) == 0) {
638 $txn->txn_commit;
639
640 goto gotid;
641 }
642 }
643 $txn->abort;
644 }
645
646 CFClient::fatal "maximum number of transaction retries reached - database problems?";
647 }
648
649gotid:
650 $face->{id} = $id;
651 $MAP->set_face ($facenum => $id);
652 $TILECACHE->get ($id)
477} 653}
478 654
479sub conn::face_update { 655sub conn::face_update {
480 my ($self, $facenum, $face) = @_; 656 my ($self, $facenum, $face) = @_;
481 657
482 $FACECACHE->{"$face->{chksum},$face->{name}"} = $face->{image}; 658 $TILECACHE->put ($face->{id} => $face->{image}); #TODO: try to avoid duplicate writes
483 659
484 my $tex = $face->{texture} = 660 $self->set_texture ($face->{id} => delete $face->{image});
661}
662
663sub conn::set_texture {
664 my ($self, $id, $data) = @_;
665
666 $self->{texture}[$id] ||= do {
667 my $tex =
485 new_from_image CFClient::Texture 668 new_from_image CFClient::Texture
486 delete $face->{image}, minify => 1; 669 $data, minify => 1;
487 670
488 $MAP->set_texture ($facenum, @$tex{qw(name w h s t)}, @{$tex->{minified}}); 671 $MAP->set_texture ($id, @$tex{qw(name w h s t)}, @{$tex->{minified}});
489 $MAPWIDGET->update; 672 $MAPWIDGET->update;
673
674 $tex
675 };
490} 676}
491 677
492sub conn::query { 678sub conn::query {
493 my ($self, $flags, $prompt) = @_; 679 my ($self, $flags, $prompt) = @_;
494 680
500 my ($self, $color, $text) = @_; 686 my ($self, $color, $text) = @_;
501 687
502 my @color = ( 688 my @color = (
503 [1.00, 1.00, 1.00], #[0.00, 0.00, 0.00], 689 [1.00, 1.00, 1.00], #[0.00, 0.00, 0.00],
504 [1.00, 1.00, 1.00], 690 [1.00, 1.00, 1.00],
505 [0.00, 0.00, 0.55], 691 [0.50, 0.50, 1.00], #[0.00, 0.00, 0.55]
506 [1.00, 0.00, 0.00], 692 [1.00, 0.00, 0.00],
507 [1.00, 0.54, 0.00], 693 [1.00, 0.54, 0.00],
508 [0.11, 0.56, 1.00], 694 [0.11, 0.56, 1.00],
509 [0.93, 0.46, 0.00], 695 [0.93, 0.46, 0.00],
510 [0.18, 0.54, 0.34], 696 [0.18, 0.54, 0.34],
553# printf "active %x %x\n", $SDL_EV->active_gain, $SDL_EV->active_state;#d# 739# printf "active %x %x\n", $SDL_EV->active_gain, $SDL_EV->active_state;#d#
554 }, 740 },
555); 741);
556 742
557############################################################################# 743#############################################################################
744
745$TILECACHE = CFClient::db_table "tilecache";
746$FACEMAP = CFClient::db_table "facemap";
558 747
559CFClient::read_cfg "$Crossfire::VARDIR/pclientrc"; 748CFClient::read_cfg "$Crossfire::VARDIR/pclientrc";
560 749
561my %DEF_CFG = ( 750my %DEF_CFG = (
562 sdl_mode => 0, 751 sdl_mode => 0,
595 784
596 CFClient::add_font $_ for @fonts; 785 CFClient::add_font $_ for @fonts;
597 CFClient::set_font $fonts[0]; 786 CFClient::set_font $fonts[0];
598} 787}
599 788
600$FACECACHE = eval { Crossfire::load_ref "$Crossfire::VARDIR/pclient.faces" } || {};
601
602Event::loop; 789Event::loop;
603 790
604Crossfire::save_ref $FACECACHE, "$Crossfire::VARDIR/pclient.faces";
605 791

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines