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.162 by root, Thu Jan 11 00:41:08 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}
475 ? undef
476 : sprintf "%s/%s/%s", cf::localdir, cf::uniquedir, $self->_escaped_path 501 sprintf "%s/%s/%s", cf::localdir, cf::uniquedir, $self->_escaped_path
477}
478
479# return random map parameters, or undef
480sub random_map_params {
481 my ($self) = @_;
482
483 $self->{random}
484} 502}
485 503
486# this is somewhat ugly, but style maps do need special treatment 504# this is somewhat ugly, but style maps do need special treatment
487sub is_style_map { 505sub is_style_map {
488 $_[0]{path} =~ m{^/styles/} 506 $_[0]{path} =~ m{^/styles/}
507}
508
509sub load_orig {
510 my ($self) = @_;
511
512 &cf::map::load_map_header ($self->load_path)
513}
514
515sub load_temp {
516 my ($self) = @_;
517
518 &cf::map::load_map_header ($self->save_path)
489} 519}
490 520
491package cf; 521package cf;
492 522
493############################################################################# 523#############################################################################
1236 1266
1237sub generate_random_map { 1267sub generate_random_map {
1238 my ($path, $rmp) = @_; 1268 my ($path, $rmp) = @_;
1239 1269
1240 # mit "rum" bekleckern, nicht 1270 # mit "rum" bekleckern, nicht
1241 cf::map::_create_random_map 1271 cf::map::_create_random_map (
1242 $path, 1272 $path,
1243 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle}, 1273 $rmp->{wallstyle}, $rmp->{wall_name}, $rmp->{floorstyle}, $rmp->{monsterstyle},
1244 $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle}, 1274 $rmp->{treasurestyle}, $rmp->{layoutstyle}, $rmp->{doorstyle}, $rmp->{decorstyle},
1245 $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map}, 1275 $rmp->{origin_map}, $rmp->{final_map}, $rmp->{exitstyle}, $rmp->{this_map},
1246 $rmp->{exit_on_final_map}, 1276 $rmp->{exit_on_final_map},
1248 $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3}, 1278 $rmp->{expand2x}, $rmp->{layoutoptions1}, $rmp->{layoutoptions2}, $rmp->{layoutoptions3},
1249 $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase}, 1279 $rmp->{symmetry}, $rmp->{difficulty}, $rmp->{difficulty_given}, $rmp->{difficulty_increase},
1250 $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation}, 1280 $rmp->{dungeon_level}, $rmp->{dungeon_depth}, $rmp->{decoroptions}, $rmp->{orientation},
1251 $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp}, 1281 $rmp->{origin_y}, $rmp->{origin_x}, $rmp->{random_seed}, $rmp->{total_map_hp},
1252 $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used}, 1282 $rmp->{map_layout_style}, $rmp->{treasureoptions}, $rmp->{symmetry_used},
1253 (cf::region::find $rmp->{region}) 1283 (cf::region::find $rmp->{region}), $rmp->{custom}
1284 )
1254} 1285}
1255 1286
1256# and all this just because we cannot iterate over 1287# and all this just because we cannot iterate over
1257# all maps in C++... 1288# all maps in C++...
1258sub change_all_map_light { 1289sub change_all_map_light {
1260 1291
1261 $_->change_map_light ($change) 1292 $_->change_map_light ($change)
1262 for grep $_->outdoor, values %cf::MAP; 1293 for grep $_->outdoor, values %cf::MAP;
1263} 1294}
1264 1295
1265sub try_load_header($) { 1296sub load_map_header($) {
1266 my ($path) = @_; 1297 my ($path) = @_;
1267 1298
1268 utf8::encode $path; 1299 utf8::encode $path;
1269 aio_open $path, O_RDONLY, 0 1300 aio_open $path, O_RDONLY, 0
1270 or return; 1301 or return;
1271 1302
1272 my $map = cf::map::new 1303 my $map = cf::map::new
1273 or return; 1304 or return;
1274 1305
1275 # for better error messages only, will be overwritten 1306 # for better error messages only, will be overwritten later
1276 $map->path ($path); 1307 $map->path ($path);
1277 1308
1278 $map->load_header ($path) 1309 $map->load_header ($path)
1279 or return; 1310 or return;
1280 1311
1296 1327
1297 $cf::MAP{$key} || do { 1328 $cf::MAP{$key} || do {
1298 my $guard = cf::lock_acquire "map_find:$key"; 1329 my $guard = cf::lock_acquire "map_find:$key";
1299 1330
1300 # do it the slow way 1331 # do it the slow way
1301 my $map = try_load_header $path->save_path; 1332 my $map = $path->load_temp;
1302 1333
1303 Coro::cede; 1334 Coro::cede;
1304 1335
1305 if ($map) { 1336 if ($map) {
1306 $map->last_access ((delete $map->{last_access}) 1337 $map->last_access ((delete $map->{last_access})
1307 || $cf::RUNTIME); #d# 1338 || $cf::RUNTIME); #d#
1308 # safety 1339 # safety
1309 $map->{instantiate_time} = $cf::RUNTIME 1340 $map->{instantiate_time} = $cf::RUNTIME
1310 if $map->{instantiate_time} > $cf::RUNTIME; 1341 if $map->{instantiate_time} > $cf::RUNTIME;
1311 } else { 1342 } else {
1312 if (my $rmp = $path->random_map_params) { 1343 $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; 1344 or return;
1319 1345
1320 $map->{load_original} = 1; 1346 $map->{load_original} = 1;
1321 $map->{instantiate_time} = $cf::RUNTIME; 1347 $map->{instantiate_time} = $cf::RUNTIME;
1322 $map->last_access ($cf::RUNTIME); 1348 $map->last_access ($cf::RUNTIME);
1323 $map->instantiate; 1349 $map->instantiate;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines