1 | #!/opt/bin/perl |
1 | #!/opt/bin/perl |
|
|
2 | |
|
|
3 | if ($ENV{DELIANTRA_CORO_DEBUG}) { |
|
|
4 | eval ' |
|
|
5 | use Coro; |
|
|
6 | use Coro::EV; |
|
|
7 | use Coro::Debug; |
|
|
8 | our $debug = new_unix_server Coro::Debug "/tmp/dc"; |
|
|
9 | '; |
|
|
10 | } |
2 | |
11 | |
3 | # do splash-screen thingy on win32 |
12 | # do splash-screen thingy on win32 |
4 | my $startup_done = sub { }; |
13 | my $startup_done = sub { }; |
5 | BEGIN { |
14 | BEGIN { |
6 | if (%PAR::LibCache && $^O eq "MSWin32") { |
15 | if (%PAR::LibCache && $^O eq "MSWin32") { |
… | |
… | |
71 | # need to do it again because that pile of garbage called PAR nukes it before main |
80 | # need to do it again because that pile of garbage called PAR nukes it before main |
72 | unshift @INC, $ENV{PAR_TEMP} |
81 | unshift @INC, $ENV{PAR_TEMP} |
73 | if %PAR::LibCache; |
82 | if %PAR::LibCache; |
74 | |
83 | |
75 | use Time::HiRes 'time'; |
84 | use Time::HiRes 'time'; |
76 | use Event; |
85 | use EV; |
77 | use List::Util qw(max min); |
86 | use List::Util qw(max min); |
78 | |
87 | |
79 | use Crossfire; |
88 | use Deliantra; |
80 | use Crossfire::Protocol::Constants; |
89 | use Deliantra::Protocol::Constants; |
81 | |
90 | |
82 | use Compress::LZF; |
91 | use Compress::LZF; |
83 | |
92 | |
84 | use CFPlus; |
93 | use CFPlus; |
85 | use CFPlus::OpenGL (); |
94 | use CFPlus::OpenGL (); |
… | |
… | |
97 | use CFPlus::Macro; |
106 | use CFPlus::Macro; |
98 | |
107 | |
99 | $SIG{QUIT} = sub { Carp::cluck "QUIT" }; |
108 | $SIG{QUIT} = sub { Carp::cluck "QUIT" }; |
100 | $SIG{PIPE} = 'IGNORE'; |
109 | $SIG{PIPE} = 'IGNORE'; |
101 | |
110 | |
102 | $Event::Eval = 1; |
|
|
103 | $Event::DIED = sub { |
111 | $EV::DIED = sub { |
104 | CFPlus::fatal Carp::longmess $_[1] |
112 | CFPlus::fatal Carp::longmess $@; |
105 | }; |
113 | }; |
106 | |
114 | |
107 | my $MAX_FPS = 60; |
115 | my $MAX_FPS = 60; |
108 | my $MIN_FPS = 5; # unused as of yet |
116 | my $MIN_FPS = 5; # unused as of yet |
109 | |
117 | |
… | |
… | |
223 | |
231 | |
224 | $AUDIO_PLAY{$face} |
232 | $AUDIO_PLAY{$face} |
225 | or return; |
233 | or return; |
226 | |
234 | |
227 | if (my $chunk = $AUDIO_CHUNK{$face}) { |
235 | if (my $chunk = $AUDIO_CHUNK{$face}) { |
228 | for (grep $_->[0] >= Event::time, @{(delete $AUDIO_PLAY{$face}) || []}) { |
236 | for (grep $_->[0] >= EV::now, @{(delete $AUDIO_PLAY{$face}) || []}) { |
229 | my (undef, $dx, $dy, $vol) = @$_; |
237 | my (undef, $dx, $dy, $vol) = @$_; |
230 | |
238 | |
231 | my $channel = CFPlus::Channel::find; |
239 | my $channel = CFPlus::Channel::find; |
232 | $channel->volume ($vol * $CFG->{effects_volume} * 128 / 255); |
240 | $channel->volume ($vol * $CFG->{effects_volume} * 128 / 255); |
233 | $channel->set_position_r ($dx, $dy, 20); |
241 | $channel->set_position_r ($dx, $dy, 20); |
… | |
… | |
250 | } else { |
258 | } else { |
251 | # fetch from database |
259 | # fetch from database |
252 | CFPlus::DB::get res_data => $meta->{name}, sub { |
260 | CFPlus::DB::get res_data => $meta->{name}, sub { |
253 | my $rwops = new CFPlus::RW $_[0]; |
261 | my $rwops = new CFPlus::RW $_[0]; |
254 | my $chunk = new CFPlus::MixChunk $rwops |
262 | my $chunk = new CFPlus::MixChunk $rwops |
255 | or Carp::confess "sound face " . (JSON::XS::to_json $meta) . " unloadable: " . CFPlus::Mix_GetError; |
263 | or Carp::confess "sound face " . (JSON::XS::encode_json $meta) . " unloadable: " . CFPlus::Mix_GetError; |
256 | $chunk->volume (($meta->{data}{volume} || 1) * 128); |
264 | $chunk->volume (($meta->{data}{volume} || 1) * 128); |
257 | $AUDIO_CHUNK{$face} = $chunk; |
265 | $AUDIO_CHUNK{$face} = $chunk; |
258 | |
266 | |
259 | audio_sound_push ($face); |
267 | audio_sound_push ($face); |
260 | }; |
268 | }; |
… | |
… | |
269 | or return; |
277 | or return; |
270 | $CFG->{effects_enable} |
278 | $CFG->{effects_enable} |
271 | or return; |
279 | or return; |
272 | |
280 | |
273 | my $queue = $AUDIO_PLAY{$face} ||= []; |
281 | my $queue = $AUDIO_PLAY{$face} ||= []; |
274 | push @$queue, [Event::time + 0.6, $dx, $dy, $vol]; # do not play sound for outdated events |
282 | push @$queue, [EV::now + 0.6, $dx, $dy, $vol]; # do not play sound for outdated events |
275 | audio_sound_push $face |
283 | audio_sound_push $face |
276 | unless @$queue > 1; |
284 | unless @$queue > 1; |
277 | } |
285 | } |
278 | |
286 | |
279 | sub audio_music_set_meta { |
287 | sub audio_music_set_meta { |
… | |
… | |
336 | return unless $SDL_MIXER; |
344 | return unless $SDL_MIXER; |
337 | |
345 | |
338 | my $fade_out; |
346 | my $fade_out; |
339 | |
347 | |
340 | if (@MUSIC_JINGLE) { |
348 | if (@MUSIC_JINGLE) { |
|
|
349 | $fade_out = 333; |
341 | @MUSIC_HAVE = $MUSIC_JINGLE[0]; |
350 | @MUSIC_HAVE = $MUSIC_JINGLE[0]; |
342 | $fade_out = 333; |
351 | |
343 | } else { |
352 | } else { |
344 | return unless $CFG->{bgm_enable}; |
353 | return unless $CFG->{bgm_enable}; |
345 | |
354 | |
346 | my @have = |
355 | $fade_out = 700; |
|
|
356 | |
|
|
357 | @MUSIC_HAVE = |
347 | grep $_ && $_->{data}, |
358 | grep $_ && $_->{data}, |
348 | map $CONN->{face}[$_], |
359 | map $CONN->{face}[$_], |
349 | @$MUSIC_WANT; |
360 | @$MUSIC_WANT; |
350 | |
361 | |
351 | # randomize music a bit so that the order is not always the same |
362 | # randomize music a bit so that the order is not always the same |
352 | $_->{stop_time} ||= rand for @have; |
363 | $_->{stop_time} ||= rand for @MUSIC_HAVE; |
353 | |
|
|
354 | @MUSIC_HAVE = @have |
|
|
355 | if @have; |
|
|
356 | |
364 | |
357 | # default MUSIC_HAVE == MUSIC_DEFAULT |
365 | # default MUSIC_HAVE == MUSIC_DEFAULT |
358 | @MUSIC_HAVE = { path => CFPlus::find_rcfile "music/$MUSIC_DEFAULT" } unless @MUSIC_HAVE; |
366 | @MUSIC_HAVE = { path => CFPlus::find_rcfile "music/$MUSIC_DEFAULT" } |
359 | $fade_out = 700; |
367 | unless @MUSIC_HAVE; |
360 | } |
368 | } |
361 | |
369 | |
362 | # if the currently playing song is acceptable, let it continue |
370 | # if the currently playing song is acceptable, let it continue |
363 | return if grep $MUSIC_PLAYING_META == $_, @MUSIC_HAVE; |
371 | return if grep $MUSIC_PLAYING_META == $_, @MUSIC_HAVE; |
364 | |
372 | |
… | |
… | |
461 | my ($conn, $flags, $prompt) = @_; |
469 | my ($conn, $flags, $prompt) = @_; |
462 | |
470 | |
463 | # FIXME: a very ugly hack to wait for stat update #d# |
471 | # FIXME: a very ugly hack to wait for stat update #d# |
464 | if ($prompt =~ /roll new stats/ and not $conn->{stat_change_with}) { |
472 | if ($prompt =~ /roll new stats/ and not $conn->{stat_change_with}) { |
465 | unless ($QUERY_TIMER) { |
473 | unless ($QUERY_TIMER) { |
466 | $QUERY_TIMER = |
474 | $QUERY_TIMER = EV::timer 1, 0, sub { |
467 | Event->timer ( |
|
|
468 | after => 1, |
|
|
469 | cb => sub { |
|
|
470 | server_query ($conn, $flags, $prompt, 1); |
475 | server_query ($conn, $flags, $prompt, 1); |
471 | $QUERY_TIMER = undef |
476 | $QUERY_TIMER = undef |
472 | } |
|
|
473 | ); |
477 | }; |
|
|
478 | |
474 | return; |
479 | return; |
475 | } |
480 | } |
476 | } |
481 | } |
477 | |
482 | |
478 | $conn->{query_dialog} = my $dialog = new CFPlus::UI::Toplevel |
483 | $conn->{query_dialog} = my $dialog = new CFPlus::UI::Toplevel |
… | |
… | |
994 | c_colspan => 2, expand => 1, |
999 | c_colspan => 2, expand => 1, |
995 | value => $CFG->{audio_hw_channels}, |
1000 | value => $CFG->{audio_hw_channels}, |
996 | options => [ |
1001 | options => [ |
997 | [0, "default" , "Use System Default"], |
1002 | [0, "default" , "Use System Default"], |
998 | [1, "Mono" , "Mono (single channel, low quality)"], |
1003 | [1, "Mono" , "Mono (single channel, low quality)"], |
999 | [2, "Stereo" , "Stereo (dual channe, standard quality)"], |
1004 | [2, "Stereo" , "Stereo (dual channel, standard quality)"], |
1000 | [4, "4 Ch Surround", "4 Channel Surround Sound (3d sound, high quality)"], |
1005 | [4, "4 Ch Surround", "4 Channel Surround Sound (3d sound, high quality)"], |
1001 | [6, "6 Ch Surround", "6 Channel Surround Sound (3d sound + center + lfe)"], |
1006 | [6, "6 Ch Surround", "6 Channel Surround Sound (3d sound + center + lfe)"], |
1002 | ], |
1007 | ], |
1003 | tooltip => "The number of independent sound channels to use. Higher sounds better, but also more cpu-intensive and might cause stuttering.", |
1008 | tooltip => "The number of independent sound channels to use. Higher sounds better, but also more cpu-intensive and might cause stuttering.", |
1004 | on_changed => sub { |
1009 | on_changed => sub { |
… | |
… | |
1345 | my $ok = 0; |
1350 | my $ok = 0; |
1346 | |
1351 | |
1347 | CFPlus::background { |
1352 | CFPlus::background { |
1348 | my $ua = CFPlus::lwp_useragent; |
1353 | my $ua = CFPlus::lwp_useragent; |
1349 | |
1354 | |
1350 | CFPlus::background_msg CFPlus::from_json +(CFPlus::lwp_check $ua->get ($META_SERVER))->decoded_content; |
1355 | CFPlus::background_msg CFPlus::decode_json +(CFPlus::lwp_check $ua->get ($META_SERVER))->decoded_content; |
1351 | } sub { |
1356 | } sub { |
1352 | my ($msg) = @_; |
1357 | my ($msg) = @_; |
1353 | if ($msg) { |
1358 | if ($msg) { |
1354 | $table->clear; |
1359 | $table->clear; |
1355 | |
1360 | |
… | |
… | |
1521 | $CFG->{profile}{default}{host} = $value; |
1526 | $CFG->{profile}{default}{host} = $value; |
1522 | 1 |
1527 | 1 |
1523 | } |
1528 | } |
1524 | ); |
1529 | ); |
1525 | |
1530 | |
|
|
1531 | if (0) { #d# disabled |
1526 | $vbox->add (new CFPlus::UI::Button |
1532 | $vbox->add (new CFPlus::UI::Button |
1527 | expand => 1, |
1533 | expand => 1, |
1528 | text => "Server List", |
1534 | text => "Server List", |
1529 | other => $METASERVER, |
1535 | other => $METASERVER, |
1530 | tooltip => "Show a list of available crossfire servers", |
1536 | tooltip => "Show a list of available crossfire servers", |
1531 | on_activate => sub { $METASERVER->toggle_visibility; 0 }, |
1537 | on_activate => sub { $METASERVER->toggle_visibility; 0 }, |
1532 | on_visibility_change => sub { $METASERVER->hide unless $_[1]; 1 }, |
1538 | on_visibility_change => sub { $METASERVER->hide unless $_[1]; 1 }, |
1533 | ); |
1539 | ); |
|
|
1540 | }#d# |
1534 | } |
1541 | } |
1535 | |
1542 | |
1536 | $table->add_at (0, ++$row, new CFPlus::UI::Label valign => 0, align => 1, text => "Map Size"); |
1543 | $table->add_at (0, ++$row, new CFPlus::UI::Label valign => 0, align => 1, text => "Map Size"); |
1537 | $table->add_at (1, $row, new CFPlus::UI::Slider |
1544 | $table->add_at (1, $row, new CFPlus::UI::Slider |
1538 | force_w => 100, |
1545 | force_w => 100, |
… | |
… | |
2013 | on_activate => sub { $QUIT_DIALOG->hide; 0 }, |
2020 | on_activate => sub { $QUIT_DIALOG->hide; 0 }, |
2014 | ); |
2021 | ); |
2015 | $hb->add (new CFPlus::UI::Button |
2022 | $hb->add (new CFPlus::UI::Button |
2016 | text => "Quit anyway", |
2023 | text => "Quit anyway", |
2017 | expand => 1, |
2024 | expand => 1, |
2018 | on_activate => sub { Event::unloop_all }, |
2025 | on_activate => sub { EV::unloop EV::UNLOOP_ALL }, |
2019 | ); |
2026 | ); |
2020 | } |
2027 | } |
2021 | |
2028 | |
2022 | $QUIT_DIALOG->show; |
2029 | $QUIT_DIALOG->show; |
2023 | $QUIT_DIALOG->grab_focus; |
2030 | $QUIT_DIALOG->grab_focus; |
… | |
… | |
2139 | force_y => "max", |
2146 | force_y => "max", |
2140 | child => $STATUSBOX, |
2147 | child => $STATUSBOX, |
2141 | )->show; |
2148 | )->show; |
2142 | |
2149 | |
2143 | CFPlus::UI::Toplevel->new ( |
2150 | CFPlus::UI::Toplevel->new ( |
2144 | title => "Map", |
2151 | title => "Minimap", |
2145 | name => "mapmap", |
2152 | name => "mapmap", |
2146 | x => 0, |
2153 | x => 0, |
2147 | y => $FONTSIZE + 8, |
2154 | y => $FONTSIZE + 8, |
2148 | border_bg => [1, 1, 1, 192/255], |
2155 | border_bg => [1, 1, 1, 192/255], |
2149 | bg => [1, 1, 1, 0], |
2156 | bg => [1, 1, 1, 0], |
… | |
… | |
2220 | $BUTTONBAR->add (new CFPlus::UI::Button |
2227 | $BUTTONBAR->add (new CFPlus::UI::Button |
2221 | text => "Save Config", |
2228 | text => "Save Config", |
2222 | tooltip => "Saves the options chosen in the client setting, server settings and the window layout to be restored on later runs.", |
2229 | tooltip => "Saves the options chosen in the client setting, server settings and the window layout to be restored on later runs.", |
2223 | on_activate => sub { |
2230 | on_activate => sub { |
2224 | $::CFG->{layout} = CFPlus::UI::get_layout; |
2231 | $::CFG->{layout} = CFPlus::UI::get_layout; |
2225 | CFPlus::write_cfg "$Crossfire::VARDIR/cfplusrc"; |
2232 | CFPlus::write_cfg "$Deliantra::VARDIR/cfplusrc"; |
2226 | status "Configuration Saved"; |
2233 | status "Configuration Saved"; |
2227 | 0 |
2234 | 0 |
2228 | }, |
2235 | }, |
2229 | ); |
2236 | ); |
2230 | |
2237 | |
… | |
… | |
2237 | tooltip => "Terminates the program", |
2244 | tooltip => "Terminates the program", |
2238 | on_activate => sub { |
2245 | on_activate => sub { |
2239 | if ($CONN) { |
2246 | if ($CONN) { |
2240 | open_quit_dialog; |
2247 | open_quit_dialog; |
2241 | } else { |
2248 | } else { |
2242 | Event::unloop_all; |
2249 | EV::unloop EV::UNLOOP_ALL; |
2243 | } |
2250 | } |
2244 | 0 |
2251 | 0 |
2245 | }, |
2252 | }, |
2246 | ); |
2253 | ); |
2247 | |
2254 | |
… | |
… | |
2268 | if ($ENV{CFPLUS_DEBUG} & 4) { |
2275 | if ($ENV{CFPLUS_DEBUG} & 4) { |
2269 | $fps = $fps * 0.98 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.02; |
2276 | $fps = $fps * 0.98 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.02; |
2270 | debug sprintf "%3.2f", $fps; |
2277 | debug sprintf "%3.2f", $fps; |
2271 | } |
2278 | } |
2272 | |
2279 | |
|
|
2280 | $WANT_REFRESH->stop; |
|
|
2281 | |
2273 | $CFPlus::UI::ROOT->draw; |
2282 | $CFPlus::UI::ROOT->draw; |
2274 | CFPlus::SDL_GL_SwapBuffers; |
2283 | CFPlus::SDL_GL_SwapBuffers; |
2275 | $LAST_REFRESH = $NOW; |
2284 | $LAST_REFRESH = $NOW; |
2276 | $WANT_REFRESH->stop; |
|
|
2277 | } |
2285 | } |
2278 | |
2286 | |
2279 | $WANT_REFRESH = Event->idle (min => 0.001, max => 0.06, parked => 1, cb => \&force_refresh); |
2287 | $WANT_REFRESH = EV::idle_ns \&force_refresh; |
2280 | |
2288 | |
2281 | my $input = Event->timer (after => 0, hard => 0, interval => 1 / 50, cb => sub { |
2289 | # 0.015 is server tick time / 8 ~~ 66.6...hz |
|
|
2290 | my $input = EV::periodic 0, 0.015, undef, sub { |
2282 | $NOW = time; |
2291 | $NOW = time; |
2283 | |
2292 | |
2284 | ($SDL_CB{$_->{type}} || sub { warn "unhandled event $_->{type}" })->($_) |
2293 | ($SDL_CB{$_->{type}} || sub { warn "unhandled event $_->{type}" })->($_) |
2285 | for CFPlus::poll_events; |
2294 | for CFPlus::poll_events; |
2286 | |
2295 | |
2287 | if (%animate_object) { |
2296 | if (%animate_object) { |
2288 | $_->animate ($LAST_REFRESH - $NOW) for values %animate_object; |
2297 | $_->animate ($LAST_REFRESH - $NOW) for values %animate_object; |
2289 | $WANT_REFRESH->start; |
2298 | $WANT_REFRESH->start; |
2290 | } |
2299 | } |
2291 | }); |
2300 | }; |
2292 | |
2301 | |
2293 | sub animation_start { |
2302 | sub animation_start { |
2294 | my ($widget) = @_; |
2303 | my ($widget) = @_; |
2295 | $animate_object{$widget} = $widget; |
2304 | $animate_object{$widget} = $widget; |
2296 | } |
2305 | } |
… | |
… | |
2300 | delete $animate_object{$widget}; |
2309 | delete $animate_object{$widget}; |
2301 | } |
2310 | } |
2302 | |
2311 | |
2303 | %SDL_CB = ( |
2312 | %SDL_CB = ( |
2304 | CFPlus::SDL_QUIT => sub { |
2313 | CFPlus::SDL_QUIT => sub { |
2305 | Event::unloop_all; |
2314 | EV::unloop EV::UNLOOP_ALL; |
2306 | }, |
2315 | }, |
2307 | CFPlus::SDL_VIDEORESIZE => sub { |
2316 | CFPlus::SDL_VIDEORESIZE => sub { |
2308 | }, |
2317 | }, |
2309 | CFPlus::SDL_VIDEOEXPOSE => sub { |
2318 | CFPlus::SDL_VIDEOEXPOSE => sub { |
2310 | CFPlus::UI::full_refresh; |
2319 | CFPlus::UI::full_refresh; |
2311 | }, |
2320 | }, |
2312 | CFPlus::SDL_ACTIVEEVENT => sub { |
2321 | CFPlus::SDL_ACTIVEEVENT => sub { |
2313 | # not useful, as APPACTIVE include sonly iconified state, not unmapped |
2322 | # not useful, as APPACTIVE includes only iconified state, not unmapped |
2314 | # printf "active %x %x %x\n", $_[0]{gain}, $_[0]{state}, CFPlus::SDL_GetAppState;#d# |
2323 | # printf "active %x %x %x\n", $_[0]{gain}, $_[0]{state}, CFPlus::SDL_GetAppState;#d# |
2315 | # printf "a %x\n", CFPlus::SDL_GetAppState & CFPlus::SDL_APPACTIVE;#d# |
2324 | # printf "a %x\n", CFPlus::SDL_GetAppState & CFPlus::SDL_APPACTIVE;#d# |
2316 | # printf "A\n" if $_[0]{state} & CFPlus::SDL_APPACTIVE; |
2325 | # printf "A\n" if $_[0]{state} & CFPlus::SDL_APPACTIVE; |
2317 | # printf "K\n" if $_[0]{state} & CFPlus::SDL_APPINPUTFOCUS; |
2326 | # printf "K\n" if $_[0]{state} & CFPlus::SDL_APPINPUTFOCUS; |
2318 | # printf "M\n" if $_[0]{state} & CFPlus::SDL_APPMOUSEFOCUS; |
2327 | # printf "M\n" if $_[0]{state} & CFPlus::SDL_APPMOUSEFOCUS; |
… | |
… | |
2340 | }, |
2349 | }, |
2341 | ); |
2350 | ); |
2342 | |
2351 | |
2343 | ############################################################################# |
2352 | ############################################################################# |
2344 | |
2353 | |
2345 | $SIG{INT} = $SIG{TERM} = sub { exit }; |
2354 | $SIG{INT} = $SIG{TERM} = sub { |
|
|
2355 | EV::unloop; |
|
|
2356 | #d# TODO calling exit here hangs the process in some futex |
|
|
2357 | }; |
2346 | |
2358 | |
2347 | { |
2359 | { |
2348 | CFPlus::read_cfg "$Crossfire::VARDIR/cfplusrc"; |
2360 | CFPlus::read_cfg "$Deliantra::VARDIR/cfplusrc"; |
2349 | CFPlus::DB::Server::run; |
2361 | CFPlus::DB::Server::run; |
2350 | |
2362 | |
2351 | CFPlus::UI::set_layout ($::CFG->{layout}); |
2363 | CFPlus::UI::set_layout ($::CFG->{layout}); |
2352 | |
2364 | |
2353 | my %DEF_CFG = ( |
2365 | my %DEF_CFG = ( |
2354 | sdl_mode => 0, |
2366 | sdl_mode => 0, |
2355 | fullscreen => 0, |
2367 | fullscreen => 1, |
2356 | fast => 0, |
2368 | fast => 0, |
2357 | force_opengl11 => undef, |
2369 | force_opengl11 => undef, |
2358 | texture_compression => 1, |
2370 | texture_compression => 1, |
2359 | map_scale => 1, |
2371 | map_scale => 1, |
2360 | fow_enable => 1, |
2372 | fow_enable => 1, |
… | |
… | |
2451 | audio_init; |
2463 | audio_init; |
2452 | } |
2464 | } |
2453 | |
2465 | |
2454 | show_tip_of_the_day if $CFG->{show_tips}; |
2466 | show_tip_of_the_day if $CFG->{show_tips}; |
2455 | |
2467 | |
2456 | Event->idle (cb => sub { |
2468 | our $STARTUP_CANCEL = EV::idle sub { |
2457 | $_[0]->w->cancel; |
2469 | undef $::STARTUP_CANCEL; |
2458 | $startup_done->(); |
2470 | $startup_done->(); |
2459 | }); |
2471 | }; |
2460 | |
2472 | |
2461 | Event::loop; |
2473 | EV::loop; |
2462 | |
2474 | |
2463 | #video_shutdown; |
2475 | #video_shutdown; |
2464 | #audio_shutdown; |
2476 | #audio_shutdown; |
2465 | CFPlus::SDL_Quit; |
2477 | CFPlus::SDL_Quit; |
2466 | CFPlus::DB::Server::stop; |
2478 | CFPlus::DB::Server::stop; |