--- deliantra/Deliantra-Client/bin/deliantra 2008/07/07 12:56:07 1.49 +++ deliantra/Deliantra-Client/bin/deliantra 2008/09/01 09:12:08 1.66 @@ -51,7 +51,7 @@ if ($^O eq "MSWin32") { # pango is relocatable on win32 - } else { + } elsif (-e "$root/pangoversion") { open my $fh, "<:perlio", "$root/pangoversion" or die "pangoversion: $!"; my $PANGO = <$fh>; @@ -71,6 +71,13 @@ open my $fh, ">:perlio", $ENV{PANGO_RC_FILE} or die "$ENV{PANGO_RC_FILE}: $!"; print $fh "[Pango]\nModuleFiles = $root/pango-modules\n"; + } else { + # OS X + $ENV{FC_CONFIG_FILE} = "$root/fonts.conf"; # no effect??!?! + $ENV{FC_CONFIG_DIR} = $root; # no effect??!?! + $ENV{PANGO_RC_FILE} = "$root/pango.rc"; + $ENV{DYLD_LIBRARY_PATH} = $root; + chdir $root; # for pango modules, maybe other things } unshift @INC, $root; @@ -99,12 +106,55 @@ use Deliantra; use Deliantra::Protocol::Constants; +use AnyEvent::Util (); use AnyEvent::DNS; +use AnyEvent::Socket (); use Compress::LZF; +use JSON::XS; use DC; -BEGIN { $SIG{__DIE__} = sub { DC::fatal Carp::longmess "$@" unless $^S } } + +############################################################################# + +our $CONN; + +# write a crash message blockingly to the socket, if possible +# this is a bit too complicated for my tastes, but it was easy. +sub crash($;$) { + my ($msg, $backtrace) = @_; + + return unless $CONN; + + my $fh = $CONN->{fh} + or return; + + my $buf = delete $CONN->{wbuf}; + + $buf .= pack "n/a*", "exti " . JSON::XS::encode_json [clientlog => undef, substr $msg, 0, 8000]; + + AnyEvent::Util::fh_nonblocking $fh, 0; + + syswrite $fh, $buf; + AnyEvent::Util::fh_nonblocking $fh, 1; + + $msg =~ s/\s+$//; + + # backtrace as second step, in case it crashes, too + crash (Carp::longmess "$msg\nbacktrace, for client version $DC::VERSION, generated") + if $backtrace; +} + +############################################################################# + +BEGIN { + $SIG{__DIE__} = sub { + return if $^S; + crash ("CRASH/DIE: $_[0]" => 1); + DC::fatal Carp::longmess "$_[0]"; + } +} + use DC::OpenGL (); use DC::Protocol; use DC::DB; @@ -114,7 +164,6 @@ use DC::UI::SpellList; use DC::UI::Dockable; use DC::UI::Dockbar; -use DC::UI::MessageWindow; use DC::UI::ChatView; use DC::MessageDistributor; use DC::Pod; @@ -125,6 +174,7 @@ $SIG{PIPE} = 'IGNORE'; $EV::DIED = sub { + crash ("CRASH/EV::DIED: $@" => 1); DC::fatal Carp::longmess $@; }; @@ -136,13 +186,16 @@ our $NOW; our $CFG; -our $CONN; our $PROFILE; # current profile our $FAST; # fast, low-quality mode, possibly useful for software-rendering our $WANT_REFRESH; +our $MODE_SLIDER; +our $CAVEAT_LABEL; + our @SDL_MODES; +our $SDL_REINIT = 1; our $WIDTH; our $HEIGHT; our $FULLSCREEN; @@ -738,7 +791,7 @@ $CONN = new DC::Protocol host => $host, - port => $port || 13327, + port => $port, user => $PROFILE->{user}, pass => $PROFILE->{password}, mapw => $mapsize, @@ -776,7 +829,7 @@ $LOGIN_BUTTON->set_text ("Logout"); $SETUP_DIALOG->hide; - my ($host, $port) = split /:/, $PROFILE->{host}; + my ($host, $port) = AnyEvent::Socket::parse_hostport $PROFILE->{host}, "deliantra=13327"; $MAP = new DC::Map; @@ -797,6 +850,8 @@ } sub stop_game { + crash "stop_game"; + $LOGIN_BUTTON->set_text ("Login / Register"); $SETUP_NOTEBOOK->set_current_page ($SETUP_LOGIN); $SETUP_DIALOG->show; @@ -826,8 +881,16 @@ $table->add_at (0, $row, new DC::UI::Label align => 1, text => "OpenGL Info"); $table->add_at (1, $row++, new DC::UI::Label fontsize => 0.8, text => DC::OpenGL::gl_vendor . ", " . DC::OpenGL::gl_version, - can_events => 1, - tooltip => "" . (DC::OpenGL::gl_extensions) . ""); + can_events => 1, + tooltip => "" . (DC::OpenGL::gl_extensions) . ""); + + $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Caveats"); + $table->add_at (1, $row++, $CAVEAT_LABEL = new DC::UI::Label fontsize => 0.8, + can_events => 1, + tooltip => "This field shows any known issues with your config or driver, such as " + . "a non-accelerated display format. You can try to work around these issues " + . "by selecting a different video mode, changing the settings below or " + . "by installing the right driver for your graphics card."); my $vidmode_tooltip = "Video Mode. The video mode to use for fullscreen (and the window size for windowed operation). " @@ -836,20 +899,21 @@ $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Video Mode"); $table->add_at (1, $row++, my $hbox = new DC::UI::HBox); - $hbox->add (my $mode_slider = new DC::UI::Slider - force_w => $WIDTH * 0.1, expand => 1, range => [$CFG->{sdl_mode}, 0, $#SDL_MODES, 0, 1], + $hbox->add ($MODE_SLIDER = new DC::UI::Slider + force_w => $WIDTH * 0.1, expand => 1, + range => [ ($CFG->{sdl_mode}) x 3 ], tooltip => $vidmode_tooltip); $hbox->add (my $mode_label = new DC::UI::Label height => 0.8, template => "9999x9999@9+9", can_events => 1, tooltip => $vidmode_tooltip); - $mode_slider->connect (changed => sub { + $MODE_SLIDER->connect (changed => sub { my ($self, $value) = @_; $CFG->{sdl_mode} = $self->{range}[0] = $value = int $value; $mode_label->set_text (sprintf '%dx%d@%d+%d', @{$SDL_MODES[$value]}); }); - $mode_slider->emit (changed => $mode_slider->{range}[0]); + $MODE_SLIDER->emit (changed => $MODE_SLIDER->{range}[0]); $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Fullscreen"); $table->add_at (1, $row++, $FULLSCREEN_ENABLE = new DC::UI::CheckBox @@ -865,18 +929,35 @@ . "higher memory usage and slower performance. It will, however, help tremendously on " . "cards that claim to support a feature but fall back to software rendering. " . "Nvidia Geforce FX cards are known to claim features the hardware doesn't support, " - . "but cards and drivers from other vendors (ATI) are often just as bad. If you " - . "experience extremely low framerates and your card should do better, try this option.", + . "but cards and drivers from other vendors (ATI) are often just as bad. " + . "If you experience extremely low framerates and your card should do better, try this option.", on_changed => sub { my ($self, $value) = @_; $CFG->{force_opengl11} = $value; 0 } ); + $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Forbid Alpha"); + $table->add_at (1, $row++, new DC::UI::CheckBox + state => $CFG->{disable_alpha}, + tooltip => "Forbid off the use of the alpha channel. This makes Deliantra look a lot worse " + . "by disabling a number of textures and transparency effects. Normally, these " + . "effects do not cost a lot of resources, but some graphics cards might fall " + . "back to etxremely slow rendering if this is enabled. If disabling this option " + . "noticably improves the framerate of the client please report this! " + . "If you experience extremely low framerates and your card should do better, try this option.", + on_changed => sub { + my ($self, $value) = @_; + $CFG->{disable_alpha} = $value; + $SDL_REINIT = 1; # SDL_SetVideoMode ignores GL attr changes + 0 + } + ); + $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Compress Textures"); $table->add_at (1, $row++, new DC::UI::CheckBox state => $CFG->{texture_compression}, tooltip => "Use texture compression. Normally this will not reduce visual quality noticable but " - . "will save a lot of memory and increase performance. The compression algorithm " - . "can differ form card to card, so your mileage may vary. This setting is ignored in " - . "forced OpenGL 1.1 mode.", + . "will save a lot of memory and increase performance (and also fall prey to the ever-buggy Mac OS X software renderer). " + . "The compression algorithm can differ form card to card, so your mileage may vary. This setting is ignored in " + . "forced OpenGL 1.1 mode and when using the Apple renderer.", on_changed => sub { my ($self, $value) = @_; $CFG->{texture_compression} = $value; 0 } ); @@ -904,6 +985,15 @@ } ); + $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Smooth Movement"); + $table->add_at (1, $row++, new DC::UI::CheckBox + state => $CFG->{smooth_movement}, + tooltip => "Smooth Movement tries to make movement, well, smoother, but also increases the framerate. " + . "If you have a very slow system, non-accelerated drivers or plain dislike smooth scrolling, " + . "then disable this option. Changes take effect immdiately.", + on_changed => sub { my ($self, $value) = @_; $CFG->{smooth_movement} = $value; 0 } + ); + $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Map Scale"); $table->add_at (1, $row++, new DC::UI::Slider range => [(log $CFG->{map_scale}) / (log 2), -3, 1, 0, 1], @@ -1551,11 +1641,13 @@ ); $vbox->add (new DC::UI::FancyFrame - label => "Registering", - min_h => 200, + label => "How to Play", + min_h => 240, child => (new DC::UI::Label valign => 0, ellipsise => 0, markup => - "To register a new account, choose a username that hasn't been taken yet and " + "First select a suitable video resolution in the Graphics tab, above.\n\n" + . "Then register a new account (or use an existing one if you have one). " + . "To register an account, choose a username that hasn't been taken yet (just guess) and " . "try to log-in. Follow the instructions in the Log tab in the message window.", ), ); @@ -1711,7 +1803,7 @@ ["Jewelery" => PICKUP_JEWELS], ["Flesh" => PICKUP_FLESH], ], - ["Weight/Value ratio", 2, 17] + ["Value/Weight ratio", 2, 17] ) { my ($title, $x, $y, @bits) = @$_; @@ -1746,6 +1838,7 @@ $table->add_at (2, 18, new DC::UI::ValSlider range => [$::CFG->{pickup} & 0xF, 0, 16, 1, 1], template => ">= 99", + tooltip => "Pick up items whose value/weight (silver/kg) ratio is equal or higher than this setting (which is specified in gold coins).", to_value => sub { ">= " . 5 * $_[0] }, on_changed => sub { my ($slider, $value) = @_; @@ -1811,7 +1904,7 @@ }, ); $hb1->add (new DC::UI::Label text => "Weight: ", align => 1, expand => 1); - #TODO# update to weigh/maxweight + #TODO# update to weight/maxweight $hb1->add ($STATWIDS->{i_weight} = new DC::UI::Label align => 0); $vb1->add (my $sw1 = new DC::UI::ScrolledWindow expand => 1, scroll_y => 1); @@ -2085,7 +2178,10 @@ $hb->add (new DC::UI::Button text => "Quit anyway", expand => 1, - on_activate => sub { EV::unloop EV::UNLOOP_ALL }, + on_activate => sub { + crash "Quit anyway"; + EV::unloop EV::UNLOOP_ALL; + }, ); } @@ -2148,12 +2244,31 @@ } sub sdl_init { - DC::SDL_Init + DC::SDL_Init DC::SDL_INIT_AUDIO #| DC::SDL_NOPARACHUTE and die "SDL::Init failed!\n"; } sub video_init { - $CFG->{sdl_mode} = 0 if $CFG->{sdl_mode} >= @SDL_MODES; + DC::SDL_InitSubSystem DC::SDL_INIT_VIDEO if $SDL_REINIT; + $SDL_REINIT = 0; + + @SDL_MODES = DC::SDL_ListModes 8, $CFG->{disable_alpha} ? 0 : 8; + @SDL_MODES = DC::SDL_ListModes 8, 8 unless @SDL_MODES; + @SDL_MODES = DC::SDL_ListModes 5, 0 unless @SDL_MODES; + @SDL_MODES or DC::fatal "Unable to find a usable video mode\n(hardware accelerated opengl fullscreen)"; + + @SDL_MODES = sort { $a->[0] * $a->[1] <=> $b->[0] * $b->[1] } @SDL_MODES; + + if (!defined $CFG->{sdl_mode} or $CFG->{sdl_mode} > $#SDL_MODES) { + $CFG->{sdl_mode} = 0; # lowest resolution by default + + # now choose biggets mode <= 1024x768 + for (0 .. $#SDL_MODES) { + if ($SDL_MODES[$_][0] * $SDL_MODES[$_][1] <= 1024 * 768) { + $CFG->{sdl_mode} = $_; + } + } + } my ($old_w, $old_h) = ($WIDTH, $HEIGHT); @@ -2161,7 +2276,9 @@ $FULLSCREEN = $CFG->{fullscreen}; $FAST = $CFG->{fast}; + # due to mac os x braindamage, we simply retry with !fullscreen in case of an error DC::SDL_SetVideoMode $WIDTH, $HEIGHT, $rgb, $alpha, $FULLSCREEN + or DC::SDL_SetVideoMode $WIDTH, $HEIGHT, $rgb, $alpha, !$FULLSCREEN or die "SDL_SetVideoMode failed: " . (DC::SDL_GetError) . "\n"; $SDL_ACTIVE = 1; @@ -2347,11 +2464,19 @@ $MESSAGE_WINDOW->show; } + $MODE_SLIDER->set_range ([$CFG->{sdl_mode}, 0, $#SDL_MODES, 1, 1]); + $MODE_SLIDER->emit (changed => $CFG->{sdl_mode}); + + $CAVEAT_LABEL->set_text ("None :)"); + $CAVEAT_LABEL->set_text ("Software Rendering (very slow)") + unless DC::SDL_GL_GetAttribute DC::SDL_GL_ACCELERATED_VISUAL; + $STATUSBOX->add ("Set video mode $WIDTH×$HEIGHT", timeout => 10, fg => [1, 1, 1, 0.5]); } sub video_shutdown { DC::OpenGL::shutdown; + DC::SDL_QuitSubSystem DC::SDL_INIT_VIDEO if $SDL_REINIT; undef $SDL_ACTIVE; } @@ -2404,6 +2529,7 @@ %SDL_CB = ( DC::SDL_QUIT => sub { + crash "SDL_QUIT"; EV::unloop EV::UNLOOP_ALL; }, DC::SDL_VIDEORESIZE => sub { @@ -2422,8 +2548,8 @@ DC::SDL_KEYDOWN => sub { if ($_[0]{mod} & DC::KMOD_ALT && $_[0]{sym} == 13) { # alt-enter - $FULLSCREEN_ENABLE->toggle; video_shutdown; + $FULLSCREEN_ENABLE->toggle; video_init; } else { &DC::UI::feed_sdl_key_down_event; @@ -2453,114 +2579,110 @@ #d# TODO calling exit here hangs the process in some futex }; -{ - DC::Pod::load_docwiki DC::find_rcfile "docwiki.pst"; +# due to mac os x + sdl combined briandamage, we need this contortion +sub main { + { + DC::Pod::load_docwiki DC::find_rcfile "docwiki.pst"; - if (-e "$Deliantra::VARDIR/client.cf") { - DC::read_cfg "$Deliantra::VARDIR/client.cf"; - } else { - #TODO: compatibility cruft - DC::read_cfg "$Deliantra::OLDDIR/cfplusrc"; - print STDERR "INFO: used old configuration file\n"; - } - - DC::DB::Server::run; - - if ($CFG->{db_schema} < 1) { - warn "INFO: upgrading database schema from 0 to 1, mapcache and tilecache will be lost\n"; - DC::DB::nuke_db; - $CFG->{db_schema} = 1; - DC::write_cfg; - } - - DC::DB::open_db; - - DC::UI::set_layout ($::CFG->{layout}); - - my %DEF_CFG = ( - sdl_mode => 0, - fullscreen => 1, - fast => 0, - force_opengl11 => undef, - texture_compression => 1, - map_scale => 1, - fow_enable => 1, - fow_intensity => 0, - map_smoothing => 1, - gui_fontsize => 1, - log_fontsize => 0.7, - gauge_fontsize => 1, - gauge_size => 0.35, - stat_fontsize => 0.7, - mapsize => 100, - audio_enable => 1, - audio_hw_channels => 0, - audio_hw_frequency => 0, - audio_hw_chunksize => 0, - audio_mix_channels => 8, - effects_enable => 1, - effects_volume => 1, - bgm_enable => 1, - bgm_volume => 0.5, - output_rate => "", - pickup => 0, - inv_sort => "mtime", - default => "profile", # default profile - show_tips => 1, - logview_max_par => 1000, - shift_fire_stop => 0, - ); - - while (my ($k, $v) = each %DEF_CFG) { - $CFG->{$k} = $v unless exists $CFG->{$k}; - } + if (-e "$Deliantra::VARDIR/client.cf") { + DC::read_cfg "$Deliantra::VARDIR/client.cf"; + } else { + #TODO: compatibility cruft + DC::read_cfg "$Deliantra::OLDDIR/cfplusrc"; + print STDERR "INFO: used old configuration file\n"; + } + + DC::DB::Server::run; + + if ($CFG->{db_schema} < 1) { + warn "INFO: upgrading database schema from 0 to 1, mapcache and tilecache will be lost\n"; + DC::DB::nuke_db; + $CFG->{db_schema} = 1; + DC::write_cfg; + } + + DC::DB::open_db; + + DC::UI::set_layout ($::CFG->{layout}); + + my %DEF_CFG = ( + sdl_mode => undef, + fullscreen => 1, + fast => 0, + force_opengl11 => undef, + disable_alpha => 0, + smooth_movement => 1, + texture_compression => 1, + map_scale => 1, + fow_enable => 1, + fow_intensity => 0, + map_smoothing => 1, + gui_fontsize => 1, + log_fontsize => 0.7, + gauge_fontsize => 1, + gauge_size => 0.35, + stat_fontsize => 0.7, + mapsize => 100, + audio_enable => 1, + audio_hw_channels => 0, + audio_hw_frequency => 0, + audio_hw_chunksize => 0, + audio_mix_channels => 8, + effects_enable => 1, + effects_volume => 1, + bgm_enable => 1, + bgm_volume => 0.5, + output_rate => "", + pickup => 0, + inv_sort => "mtime", + default => "profile", # default profile + show_tips => 1, + logview_max_par => 1000, + shift_fire_stop => 0, + ); + + while (my ($k, $v) = each %DEF_CFG) { + $CFG->{$k} = $v unless exists $CFG->{$k}; + } - $CFG->{profile}{default}{host} ||= "gameserver.deliantra.net"; - $PROFILE = $CFG->{profile}{default}; + $CFG->{profile}{default}{host} ||= "gameserver.deliantra.net"; + $PROFILE = $CFG->{profile}{default}; - # convert old bindings (only default profile matters) - if (my $bindings = delete $PROFILE->{bindings}) { - while (my ($mod, $syms) = each %$bindings) { - while (my ($sym, $cmds) = each %$syms) { - push @{ $PROFILE->{macro} }, { - accelkey => [$mod*1, $sym*1], - action => $cmds, - }; + # convert old bindings (only default profile matters) + if (my $bindings = delete $PROFILE->{bindings}) { + while (my ($mod, $syms) = each %$bindings) { + while (my ($sym, $cmds) = each %$syms) { + push @{ $PROFILE->{macro} }, { + accelkey => [$mod*1, $sym*1], + action => $cmds, + }; + } } } - } - sdl_init; - - @SDL_MODES = DC::SDL_ListModes 8, 8; - @SDL_MODES = DC::SDL_ListModes 5, 0 unless @SDL_MODES; - @SDL_MODES or DC::fatal "Unable to find a usable video mode\n(hardware accelerated opengl fullscreen)"; + sdl_init; - @SDL_MODES = sort { $a->[0] * $a->[1] <=> $b->[0] * $b->[1] } @SDL_MODES; - - $CFG->{sdl_mode} = 0 if $CFG->{sdl_mode} > @SDL_MODES; - - { - my @fonts = map DC::find_rcfile "fonts/$_", qw( - DejaVuSans.ttf - DejaVuSansMono.ttf - DejaVuSans-Bold.ttf - DejaVuSansMono-Bold.ttf - DejaVuSans-Oblique.ttf - DejaVuSansMono-Oblique.ttf - DejaVuSans-BoldOblique.ttf - DejaVuSansMono-BoldOblique.ttf - ); + { + my @fonts = map DC::find_rcfile "fonts/$_", qw( + DejaVuSans.ttf + DejaVuSansMono.ttf + DejaVuSans-Bold.ttf + DejaVuSansMono-Bold.ttf + DejaVuSans-Oblique.ttf + DejaVuSansMono-Oblique.ttf + DejaVuSans-BoldOblique.ttf + DejaVuSansMono-BoldOblique.ttf + ); - DC::add_font $_ for @fonts; - - $FONT_PROP = new_from_file DC::Font $fonts[0]; - $FONT_FIXED = new_from_file DC::Font $fonts[1]; + DC::add_font $_ for @fonts; + + $FONT_PROP = new_from_file DC::Font $fonts[0]; + $FONT_FIXED = new_from_file DC::Font $fonts[1]; - $FONT_PROP->make_default; + $FONT_PROP->make_default; - DC::pango_init; - } + DC::pango_init; + } # compare mono (ft) vs. rgba (cairo) # ft - 1.8s, cairo 3s, even in alpha-only mode @@ -2575,25 +2697,28 @@ # warn $t2-$t1; # } - video_init; - audio_init; -} + video_init; + audio_init; + } -show_tip_of_the_day if $CFG->{show_tips}; + show_tip_of_the_day if $CFG->{show_tips}; -our $STARTUP_CANCEL = EV::idle sub { - undef $::STARTUP_CANCEL; - $startup_done->(); -}; + our $STARTUP_CANCEL = EV::idle sub { + undef $::STARTUP_CANCEL; + $startup_done->(); + }; -delete $SIG{__DIE__}; -EV::loop; + delete $SIG{__DIE__}; + EV::loop; #video_shutdown; #audio_shutdown; -DC::OpenGL::quit; -DC::SDL_Quit; -DC::DB::Server::stop; + DC::OpenGL::quit; + DC::SDL_Quit; + DC::DB::Server::stop; +} + +DC::SDL_braino; # see sub above =head1 NAME @@ -2620,7 +2745,7 @@ =head1 AUTHOR -Marc Lehmann , Robin Redeker +Marc Lehmann , Robin Redeker