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.160 by root, Wed Jan 10 22:54:06 2007 UTC vs.
Revision 1.165 by root, Fri Jan 12 22:09:22 2007 UTC

37our %COMMAND_TIME = (); 37our %COMMAND_TIME = ();
38 38
39our @EXTS = (); # list of extension package names 39our @EXTS = (); # list of extension package names
40our %EXTCMD = (); 40our %EXTCMD = ();
41our %EXT_CORO = (); # coroutines bound to extensions 41our %EXT_CORO = (); # coroutines bound to extensions
42our %EXT_MAP = (); # pluggable maps
42 43
43our @EVENT; 44our @EVENT;
44our $LIBDIR = datadir . "/ext"; 45our $LIBDIR = datadir . "/ext";
45 46
46our $TICK = MAX_TIME * 1e-6; 47our $TICK = MAX_TIME * 1e-6;
371 '""' => \&as_string; 372 '""' => \&as_string;
372 373
373# used to convert map paths into valid unix filenames by repalcing / by ∕ 374# used to convert map paths into valid unix filenames by repalcing / by ∕
374our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons 375our $PATH_SEP = "∕"; # U+2215, chosen purely for visual reasons
375 376
377sub register {
378 my ($pkg, $prefix) = @_;
379
380 $EXT_MAP{$prefix} = $pkg;
381}
382
376sub new { 383sub new {
377 my ($class, $path, $base) = @_; 384 my ($class, $path, $base) = @_;
378 385
379 $path = $path->as_string if ref $path; 386 return $path if ref $path;
380 387
381 my $self = bless { }, $class; 388 my $self = {};
382 389
383 # {... are special paths that are not touched 390 # {... are special paths that are not being touched
384 # ?xxx/... are special absolute paths 391 # ?xxx/... are special absolute paths
385 # ?random/... random maps 392 # ?random/... random maps
386 # /! non-realised random map exit 393 # /! non-realised random map exit
387 # /... normal maps 394 # /... normal maps
388 # ~/... per-player maps without a specific player (DO NOT USE) 395 # ~/... per-player maps without a specific player (DO NOT USE)
390 397
391 $path =~ s/$PATH_SEP/\//go; 398 $path =~ s/$PATH_SEP/\//go;
392 399
393 if ($path =~ /^{/) { 400 if ($path =~ /^{/) {
394 # fine as it is 401 # fine as it is
395 } elsif ($path =~ s{^\?random/}{}) {
396 Coro::AIO::aio_load "$cf::RANDOM_MAPS/$path.meta", my $data;
397 $self->{random} = cf::from_json $data;
398 } else { 402 } else {
399 if ($path =~ s{^~([^/]+)?}{}) { 403 if ($path =~ s{^~([^/]+)?}{}) {
404 # ~user
400 $self->{user_rel} = 1; 405 $self->{user_rel} = 1;
401 406
402 if (defined $1) { 407 if (defined $1) {
403 $self->{user} = $1; 408 $self->{user} = $1;
404 } elsif ($base =~ m{^~([^/]+)/}) { 409 } elsif ($base =~ m{^~([^/]+)/}) {
405 $self->{user} = $1; 410 $self->{user} = $1;
406 } else { 411 } else {
407 warn "cannot resolve user-relative path without user <$path,$base>\n"; 412 warn "cannot resolve user-relative path without user <$path,$base>\n";
408 } 413 }
414 } elsif ($path =~ s{^\?([^/]+)/}{}) {
415 # ?...
416 $self->{ext} = $1;
417 if (my $ext = $EXT_MAP{$1}) {
418 bless $self, $ext;
419 }
409 } elsif ($path =~ /^\//) { 420 } elsif ($path =~ /^\//) {
421 # /...
410 # already absolute 422 # already absolute
411 } else { 423 } else {
424 # relative
412 $base =~ s{[^/]+/?$}{}; 425 $base =~ s{[^/]+/?$}{};
413 return $class->new ("$base/$path"); 426 return $class->new ("$base/$path");
414 } 427 }
415 428
416 for ($path) { 429 for ($path) {
419 } 432 }
420 } 433 }
421 434
422 $self->{path} = $path; 435 $self->{path} = $path;
423 436
437 if ("HASH" eq ref $self) {
438 bless $self, $class;
439 } else {
440 $self->init;
441 }
442
443 for my $ext (values %EXT_MAP) {
444 if (my $subst = $ext->substitute ($self)) {
445 return $subst;
446 }
447 }
448
424 $self 449 $self
450}
451
452sub init {
453 # nop
454}
455
456sub substitute {
457 ()
425} 458}
426 459
427# the name / primary key / in-game path 460# the name / primary key / in-game path
428sub as_string { 461sub as_string {
429 my ($self) = @_; 462 my ($self) = @_;
430 463
431 $self->{user_rel} ? "~$self->{user}$self->{path}" 464 $self->{user_rel} ? "~$self->{user}$self->{path}"
432 : $self->{random} ? "?random/$self->{path}" 465 : $self->{ext} ? "?$self->{ext}/$self->{path}"
433 : $self->{path} 466 : $self->{path}
434} 467}
435 468
436# the displayed name, this is a one way mapping 469# the displayed name, this is a one way mapping
437sub visible_name { 470sub visible_name {
438 my ($self) = @_; 471 &as_string
439
440# if (my $rmp = $self->{random}) {
441# # todo: be more intelligent about this
442# "?random/$rmp->{origin_map}+$rmp->{origin_x}+$rmp->{origin_y}/$rmp->{dungeon_level}"
443# } else {
444 $self->as_string
445# }
446} 472}
447 473
448# escape the /'s in the path 474# escape the /'s in the path
449sub _escaped_path { 475sub _escaped_path {
450 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g; 476 (my $path = $_[0]{path}) =~ s/\//$PATH_SEP/g;
477
451 $path 478 $path
452} 479}
453 480
454# the original (read-only) location 481# the original (read-only) location
455sub load_path { 482sub load_path {
460 487
461# the temporary/swap location 488# the temporary/swap location
462sub save_path { 489sub save_path {
463 my ($self) = @_; 490 my ($self) = @_;
464 491
492 $self->{user_rel}
465 $self->{user_rel} ? sprintf "%s/%s/%s/%s", cf::localdir, cf::playerdir, $self->{user}, $self->_escaped_path 493 ? sprintf "%s/%s/%s/%s", cf::localdir, cf::playerdir, $self->{user}, $self->_escaped_path
466 : $self->{random} ? sprintf "%s/%s", $RANDOM_MAPS, $self->{path}
467 : sprintf "%s/%s/%s", cf::localdir, cf::tmpdir, $self->_escaped_path 494 : sprintf "%s/%s/%s", cf::localdir, cf::tmpdir, $self->_escaped_path
468} 495}
469 496
470# the unique path, might be eq to save_path 497# the unique path, undef == no special unique path
471sub uniq_path { 498sub uniq_path {
472 my ($self) = @_; 499 my ($self) = @_;
473 500
474 $self->{user_rel} || $self->{random} 501 $self->{user_rel} || $self->{ext}
475 ? undef 502 ? undef
476 : sprintf "%s/%s/%s", cf::localdir, cf::uniquedir, $self->_escaped_path 503 : sprintf "%s/%s/%s", cf::localdir, cf::uniquedir, $self->_escaped_path
477} 504}
478 505
479# return random map parameters, or undef 506sub customise_for {
480sub random_map_params {
481 my ($self) = @_; 507 my ($self, $map, $ob) = @_;
482 508
483 $self->{random} 509 if ($map->per_player) {
510 return cf::map::find ("~" . $ob->name . "/" . $map->{path}{path});
511 }
512
513 $map
484} 514}
485 515
486# this is somewhat ugly, but style maps do need special treatment 516# this is somewhat ugly, but style maps do need special treatment
487sub is_style_map { 517sub is_style_map {
488 $_[0]{path} =~ m{^/styles/} 518 $_[0]{path} =~ m{^/styles/}
519}
520
521sub load_orig {
522 my ($self) = @_;
523
524 &cf::map::load_map_header ($self->load_path)
525}
526
527sub load_temp {
528 my ($self) = @_;
529
530 &cf::map::load_map_header ($self->save_path)
531}
532
533sub unlink_save {
534 my ($self) = @_;
535
536 utf8::encode (my $save = $self->save_path);
537 IO::AIO::aioreq_pri 4; IO::AIO::aio_unlink $save;
538 IO::AIO::aioreq_pri 4; IO::AIO::aio_unlink "$save.pst";
489} 539}
490 540
491package cf; 541package cf;
492 542
493############################################################################# 543#############################################################################
1236 1286
1237sub generate_random_map { 1287sub generate_random_map {
1238 my ($path, $rmp) = @_; 1288 my ($path, $rmp) = @_;
1239 1289
1240 # mit "rum" bekleckern, nicht 1290 # mit "rum" bekleckern, nicht
1241 cf::map::_create_random_map 1291 cf::map::_create_random_map (
1242 $path, 1292 $path,
1243 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle}, 1293 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
1244 $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle}, 1294 $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
1245 $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map}, 1295 $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
1246 $rmp->{exit_on_final_map}, 1296 $rmp->{exit_on_final_map},
1248 $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3}, 1298 $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3},
1249 $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase}, 1299 $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase},
1250 $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation}, 1300 $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation},
1251 $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp}, 1301 $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp},
1252 $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used}, 1302 $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used},
1253 (cf::region::find $rmp->{region}) 1303 (cf::region::find $rmp->{region}), $rmp->{custom}
1304 )
1254} 1305}
1255 1306
1256# and all this just because we cannot iterate over 1307# and all this just because we cannot iterate over
1257# all maps in C++... 1308# all maps in C++...
1258sub change_all_map_light { 1309sub change_all_map_light {
1260 1311
1261 $_->change_map_light ($change) 1312 $_->change_map_light ($change)
1262 for grep $_->outdoor, values %cf::MAP; 1313 for grep $_->outdoor, values %cf::MAP;
1263} 1314}
1264 1315
1265sub try_load_header($) { 1316sub load_map_header($) {
1266 my ($path) = @_; 1317 my ($path) = @_;
1267 1318
1268 utf8::encode $path; 1319 utf8::encode $path;
1269 aio_open $path, O_RDONLY, 0 1320 aio_open $path, O_RDONLY, 0
1270 or return; 1321 or return;
1271 1322
1272 my $map = cf::map::new 1323 my $map = cf::map::new
1273 or return; 1324 or return;
1274 1325
1275 # for better error messages only, will be overwritten 1326 # for better error messages only, will be overwritten later
1276 $map->path ($path); 1327 $map->path ($path);
1277 1328
1278 $map->load_header ($path) 1329 $map->load_header ($path)
1279 or return; 1330 or return;
1280 1331
1296 1347
1297 $cf::MAP{$key} || do { 1348 $cf::MAP{$key} || do {
1298 my $guard = cf::lock_acquire "map_find:$key"; 1349 my $guard = cf::lock_acquire "map_find:$key";
1299 1350
1300 # do it the slow way 1351 # do it the slow way
1301 my $map = try_load_header $path->save_path; 1352 my $map = $path->load_temp;
1302 1353
1303 Coro::cede; 1354 Coro::cede;
1304 1355
1305 if ($map) { 1356 if ($map) {
1306 $map->last_access ((delete $map->{last_access}) 1357 $map->last_access ((delete $map->{last_access})
1307 || $cf::RUNTIME); #d# 1358 || $cf::RUNTIME); #d#
1308 # safety 1359 # safety
1309 $map->{instantiate_time} = $cf::RUNTIME 1360 $map->{instantiate_time} = $cf::RUNTIME
1310 if $map->{instantiate_time} > $cf::RUNTIME; 1361 if $map->{instantiate_time} > $cf::RUNTIME;
1311 } else { 1362 } else {
1312 if (my $rmp = $path->random_map_params) { 1363 $map = $path->load_orig
1313 $map = generate_random_map $key, $rmp;
1314 } else {
1315 $map = try_load_header $path->load_path;
1316 }
1317
1318 $map or return; 1364 or return;
1319 1365
1320 $map->{load_original} = 1; 1366 $map->{load_original} = 1;
1321 $map->{instantiate_time} = $cf::RUNTIME; 1367 $map->{instantiate_time} = $cf::RUNTIME;
1322 $map->last_access ($cf::RUNTIME); 1368 $map->last_access ($cf::RUNTIME);
1323 $map->instantiate; 1369 $map->instantiate;
1375 1421
1376 if ($self->{path}->is_style_map) { 1422 if ($self->{path}->is_style_map) {
1377 $self->{deny_save} = 1; 1423 $self->{deny_save} = 1;
1378 $self->{deny_reset} = 1; 1424 $self->{deny_reset} = 1;
1379 } else { 1425 } else {
1426 $self->decay_objects;
1380 $self->fix_auto_apply; 1427 $self->fix_auto_apply;
1381 $self->decay_objects;
1382 $self->update_buttons; 1428 $self->update_buttons;
1383 $self->set_darkness_map; 1429 $self->set_darkness_map;
1384 $self->difficulty ($self->estimate_difficulty) 1430 $self->difficulty ($self->estimate_difficulty)
1385 unless $self->difficulty; 1431 unless $self->difficulty;
1386 $self->activate; 1432 $self->activate;
1522 my ($self) = @_; 1568 my ($self) = @_;
1523 1569
1524 $self->reset_at <= $cf::RUNTIME 1570 $self->reset_at <= $cf::RUNTIME
1525} 1571}
1526 1572
1527sub unlink_save {
1528 my ($self) = @_;
1529
1530 utf8::encode (my $save = $self->{path}->save_path);
1531 aioreq_pri 3; IO::AIO::aio_unlink $save;
1532 aioreq_pri 3; IO::AIO::aio_unlink "$save.pst";
1533}
1534
1535sub rename { 1573sub rename {
1536 my ($self, $new_path) = @_; 1574 my ($self, $new_path) = @_;
1537 1575
1538 $self->unlink_save; 1576 $self->{path}->unlink_save;
1539 1577
1540 delete $cf::MAP{$self->path}; 1578 delete $cf::MAP{$self->path};
1541 $self->{path} = new cf::path $new_path; 1579 $self->{path} = new cf::path $new_path;
1542 $self->path ($self->{path}->as_string); 1580 $self->path ($self->{path}->as_string);
1543 $cf::MAP{$self->path} = $self; 1581 $cf::MAP{$self->path} = $self;
1557 1595
1558 delete $cf::MAP{$self->path}; 1596 delete $cf::MAP{$self->path};
1559 1597
1560 $_->clear_links_to ($self) for values %cf::MAP; 1598 $_->clear_links_to ($self) for values %cf::MAP;
1561 1599
1562 $self->unlink_save; 1600 $self->{path}->unlink_save;
1563 $self->destroy; 1601 $self->destroy;
1564} 1602}
1565 1603
1566my $nuke_counter = "aaaa"; 1604my $nuke_counter = "aaaa";
1567 1605
1570 1608
1571 $self->{deny_save} = 1; 1609 $self->{deny_save} = 1;
1572 $self->reset_timeout (1); 1610 $self->reset_timeout (1);
1573 $self->rename ("{nuke}/" . ($nuke_counter++)); 1611 $self->rename ("{nuke}/" . ($nuke_counter++));
1574 $self->reset; # polite request, might not happen 1612 $self->reset; # polite request, might not happen
1575}
1576
1577sub customise_for {
1578 my ($map, $ob) = @_;
1579
1580 if ($map->per_player) {
1581 return cf::map::find "~" . $ob->name . "/" . $map->{path}{path};
1582 }
1583
1584 $map
1585} 1613}
1586 1614
1587=item cf::map::unique_maps 1615=item cf::map::unique_maps
1588 1616
1589Returns an arrayref of cf::path's of all shared maps that have 1617Returns an arrayref of cf::path's of all shared maps that have
1789 1817
1790 $self->enter_link; 1818 $self->enter_link;
1791 1819
1792 (async { 1820 (async {
1793 my $map = cf::map::find $path->as_string; 1821 my $map = cf::map::find $path->as_string;
1794 $map = $map->customise_for ($self) if $map; 1822 $map = $map->{path}->customise_for ($map, $self) if $map;
1795 1823
1796# warn "entering ", $map->path, " at ($x, $y)\n" 1824# warn "entering ", $map->path, " at ($x, $y)\n"
1797# if $map; 1825# if $map;
1798 1826
1799 $map or $self->message ("The exit to '" . ($path->visible_name) . "' is closed", cf::NDI_UNIQUE | cf::NDI_RED); 1827 $map or $self->message ("The exit to '" . ($path->visible_name) . "' is closed", cf::NDI_UNIQUE | cf::NDI_RED);
2442 reentrant => 0, 2470 reentrant => 0,
2443 prio => 0, 2471 prio => 0,
2444 at => $NEXT_TICK || $TICK, 2472 at => $NEXT_TICK || $TICK,
2445 data => WF_AUTOCANCEL, 2473 data => WF_AUTOCANCEL,
2446 cb => sub { 2474 cb => sub {
2475 $NOW = Event::time;
2476
2447 cf::server_tick; # one server iteration 2477 cf::server_tick; # one server iteration
2448 $RUNTIME += $TICK; 2478 $RUNTIME += $TICK;
2449 $NEXT_TICK += $TICK; 2479 $NEXT_TICK += $TICK;
2450 2480
2451 $WAIT_FOR_TICK->broadcast; 2481 $WAIT_FOR_TICK->broadcast;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines