ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/adm/map_check
Revision: 1.1
Committed: Fri Feb 3 07:14:15 2006 UTC (18 years, 5 months ago) by root
Branch point for: UPSTREAM, MAIN
Log Message:
Initial revision

File Contents

# User Rev Content
1 root 1.1 #!/usr/bin/perl
2     #
3     # (C) Copyright Markus Weber, 1994. All rights reserved.
4     # Permission is granted to use, copy, and modify for non-commercial use.
5     #
6    
7     # usage: check-consistency.pl [options]...
8     # Options:
9     # archdb=pathname-of-archetype-database *** not used ***
10     # default ./ARCHDB .{dir,pag}
11     # archetypes=pathname-of-archetypes-file
12     # default $cfdir/share/crossfire/archetypes
13     # cfdir=pathname-to-crossfire-installation
14     # default /opt/cf0901 (hardcoded)
15     # mapdir=pathname-of-map-directory
16     # default $cfdir/share/crossfire/maps
17     # start-map=map-path-of-starting map
18     # default (init in archetypes)
19    
20     # %% make it a command line option
21     $debug = 1;
22    
23     #
24     # ARGUMENT PROCESSING
25     #
26     # preset options
27     $cfdir = "/export/home/crossfire/cf-installroot";
28    
29     # loop thru arg vector
30     while (@ARGV) {
31     $_ = @ARGV[0];
32     if (/^archdb=/) {
33     ($junk,$archdb) = split(/=/,$ARGV[0]);
34     shift;
35     }
36     elsif (/^archetypes=/) {
37     ($junk,$archetypes) = split(/=/,$ARGV[0]);
38     shift;
39     }
40     elsif (/^cfdir=/) {
41     ($junk,$cfdir) = split(/=/,$ARGV[0]);
42     shift;
43     }
44     elsif (/^mapdir=/) {
45     ($junk,$mapdir) = split(/=/,$ARGV[0]);
46     shift;
47     }
48     elsif (/^start-map=/) {
49     ($junk,$start_map) = split(/=/,$ARGV[0]);
50     shift;
51     }
52     else {
53     print "Unknown option $ARGV[0]\n";
54     exit;
55     }
56     }
57    
58     # post-process
59     $mapdir = "$cfdir/share/crossfire/maps" unless defined($mapdir);
60     $archetypes = "$cfdir/share/crossfire/archetypes" unless defined($archetypes);
61     print STDERR "DBG: archetypes=$archetypes\n" if $debug > 5;
62     print STDERR "DBG: archdb=$archdb\n" if $debug > 5;
63     print STDERR "DBG: mapdir=$mapdir\n" if $debug > 5;
64    
65    
66     #
67     # INIT ARCHETYPES DATABASE
68     #
69     print STDERR "DBG: initializing archetype database...\n" if $debug;
70     &init_archetypes_database; # unless $skip_db_init;
71     print STDERR "DBG: ...done\n" if $debug;
72    
73     defined($start_map) || die "FATAL: no starting map";
74     print STDERR "DBG: start_map=$start_map\n" if $debug;
75    
76    
77     print STDERR "DBG: scanning for archetypes of special interest...\n" if $debug;
78    
79     while ( ($arch,$type) = each(%ARCHDB) ) {
80    
81     next if !defined($type); # skip if not special
82    
83     $_ = $type; # see below
84    
85     if ($type == 41 || $type == 66 || $type == 94) {
86     # EXITS: archetypes with exits to other maps
87     $EXITS{$arch} = 1;
88     }
89     # Bad Programming Style Alert. Don't try this at home!
90     elsif (/^1[78]$/ || /^2[679]$/ || /^3[012]$/ || /^9[123]$/) {
91     # CONNECT: "connected" archetypes,
92     # e.g. buttons, handles, gates, ...
93     $CONNECT{$arch} = 1;
94     }
95     if ($type == 85) {
96     $SB{$arch} = 1;
97     }
98    
99     }
100    
101     print STDERR "DBG: ...done.\n" if $debug;
102    
103     #
104     # MAIN LOOP
105     #
106    
107     # pathname of start_map is assumed to be absolute (e.g. /village/village
108     push(@MAPS,$start_map);
109    
110     while ($map = pop(@MAPS)) {
111    
112     # print STDERR "array stack size is $#MAPS\n";
113     next if $visited{$map}; # skip if been here before
114     $visited{$map} = 1; # flag it if not
115    
116     # skip random maps
117     next if ($map =~ m#/!#);
118    
119     print STDERR "DBG: visiting $map\n" if $debug;
120     #print "visiting $map\n" if $debug;
121    
122     #
123     # side effect: check_map pushes any (legal) exits found on stack
124     #
125     &check_map($map);
126     }
127    
128     print "Unused archetypes:\n";
129     foreach $key (sort(keys %ARCHDB)) {
130     print "$key\n" if (!defined($USED{$key}))
131     }
132    
133    
134    
135     exit;
136    
137     #
138     # ++++++++++++++++++++ END OF MAIN ++++++++++++++++++
139     #
140    
141     #
142     # INIT ARCHETYPES DATABASE
143     #
144     # store (archname,type) pairs
145     #
146     sub init_archetypes_database {
147     local($arch_lines,$arches); # counters
148     local($arch,$type,$slaying); # values
149     local($junk);
150    
151     print STDERR "DBG: opening archetypes: $archetypes\n" if $debug > 5;
152     open(ARCHETYPES,$archetypes) || die "can't open $archetypes";
153    
154     $arch_lines = 0;
155     $arches = 0;
156     $type = 0;
157    
158     while ( <ARCHETYPES> ) {
159     $arch_lines++;
160     if (/^Object\s/) {
161     ($junk,$arch) = split;
162     if (!defined($arch)) {
163     print STDERR "$archetypes: bad Object, line $arch_lines\n";
164     }
165     }
166     elsif (/^type\s/) {
167     ($junk,$type) = split;
168     if (!defined($type)) {
169     print STDERR "$archetypes: bad type, line $arch_lines\n";
170     }
171     }
172     elsif (/^slaying\s/ && $arch eq "map") {
173     ($junk,$slaying) = split;
174     # don't care if defined or not (yet)
175     }
176     elsif (/^end$/) {
177     print STDERR "DBG: entered arch=$arch, optional type=$type\n" if $debug > 10;
178     next if (!defined($arch));
179     # don't care whether $type defined or not
180     $ARCHDB{$arch} = $type;
181     $arches++;
182     $type = 0;
183     }
184     elsif (/^end\s*$/) {
185     print STDERR "DBG: arch $arch is using end with space before newline\n";
186     next if (!defined($arch));
187     # don't care whether $type defined or not
188     $ARCHDB{$arch} = $type;
189     $arches++;
190     $type = 0;
191     }
192     }
193    
194     #
195     # find start map
196     # print error message iff "map" arch not found or missing path
197     # assign start map (unless pre-defined on cmd line)
198     #
199     if (!defined($slaying)) {
200     print STDERR "***ERROR*** no map object or map path missing\n";
201     }
202     elsif (!defined($start_map)) {
203     $start_map = $slaying;
204     }
205     #print STDERR "DBG: start_map=$start_map\n";
206    
207     close(ARCHETYPES);
208     print STDERR "DBG: closed $archetypes, $arch_lines lines, $arches arches\n"
209     if $debug > 5;
210     }
211    
212     #
213     # CHECK MAP FOR ELEMENTARY CONSISTENCY
214     #
215    
216     sub check_map {
217     local($map) = @_;
218     local($arch,$connected,$slaying,$exit,$x,$y, $rx, $ry);
219     local($lines,$fullmap);
220     local($junk);
221     $depth=0;
222    
223     # build full pathname (nb: map path starts with /) and open map file
224     $fullmap = "$mapdir$map";
225     open(MAP,$fullmap) || die "can't open $fullmap";
226     print STDERR "DBG: opened $map\n" if $debug > 5;
227    
228     $lines = 0;
229    
230     while ( <MAP> ) {
231     if (/^tile_path_/) {
232     ($junk,$slaying) = split;
233     $_ = "$map $slaying"; # easy matching :-)
234     s@^(/.*/)([^/]*)\s([^\./].*)$@\1\2 \1\3@;
235     s@^(/.*/)([^/]*)\s(\.\./.*)$@\1\2 \1\3@;
236     s@/[^/]*/\.\./@/@g;
237     ($junk,$exit) = split;
238     next if $visited{$exit};
239    
240     if ( (! -r "$mapdir$exit") && ( $exit ne "/!") ) {
241     print "ERROR: map $map, arch $arch, line $lines, no such exit $exit ($rx, $ry, to $x, $y)\n";
242     next;
243     }
244     push(@MAPS,$exit);
245     }
246    
247    
248     $lines++;
249     if (/^arch\s/) {
250     # Note we have to do some checks here - that is because
251     # if an object is inside an object, the value of $arch
252     # is clobbered.
253     ($junk,$arch) = split;
254     # if ($SB{$arch}) {
255     # print "WARNING: spellbook found at map $map, line $lines, arch $arch\n";
256     # }
257     if (!defined($ARCHDB{$arch})) {
258     print "FATAL: map $map, line $lines, bad archetype: $arch ($rx, $ry)\n";
259     }
260     $USED{$arch}=1;
261     undef($slaying);
262     undef($x);
263     undef($y);
264     undef($rx);
265     undef($ry);
266     undef($connected);
267     $depth++;
268     }
269     elsif (/^connected\s/) {
270     ($junk,$connected) = split;
271     }
272     elsif (/^slaying\s/) {
273     ($junk,$slaying) = split;
274     }
275     elsif (/^hp\s/) {
276     ($junk,$x) = split;
277     }
278     elsif (/^sp\s/) {
279     ($junk,$y) = split;
280     }
281     elsif (/^x\s/) {
282     ($junk, $rx) = split;
283     }
284     elsif (/^y\s/) {
285     ($junk, $ry) = split;
286     }
287     elsif (/^anim$/) {
288     print "Map $fullmap has an anim command in it\n";
289     }
290    
291     next if !/^end$/; # continue iff not end of arch
292     $depth--;
293    
294     #
295     # CHECK 2: connect-arch actually connected?
296     # NB: if not, that's perfectly legal, but suspicious
297     #
298     # if ($CONNECT{$arch}) {
299     # if (!$connected) {
300     #print STDERR "WARNING: map $map, line $lines, arch $arch, not connected\n";
301     #print "WARNING: map $map, line $lines, arch $arch, not connected\n";
302     # }
303     # next;
304     # }
305    
306     next if !$EXITS{$arch}; # continue if not an exit
307    
308    
309     #
310     # CHECK 3: exit-type arch, but no path given
311     # Presumably the path defaults to the local map,
312     # but in all probability this is an error
313     #
314     if (!defined($slaying)) {
315     if ($x || $y) {
316     #print STDERR "ERROR: map $map, line $lines, arch $arch, exit defaults\n";
317     #print "ERROR: map $map, line $lines, arch $arch, exit defaults\n";
318     }
319     else {
320     #print STDERR "INFO: map $map, line $lines, arch $arch, no exit defined\n";
321     #print "INFO: map $map, line $lines, arch $arch, no exit defined\n";
322     }
323     next;
324     }
325    
326     #
327     # CHECK 4: verify that exit map exists
328     # if not, the game (hopefully!) won't crash, but
329     # chances are this _is_ an error
330     #
331    
332     #
333     # normalize exit path (FullyQualifiedPathName :-)))
334     # (i.e. construct absolute pathname, rooted in CLibDir/maps)
335     # E.g.:
336     # current map: /village/somewhere
337     # EXIT PATH YIELDS
338     # /village/building /village/building
339     # townhouse /village/townhouse
340     # ../island /island
341     #
342     $_ = "$map $slaying"; # easy matching :-)
343     # /path/map exit --> /path/map /path/exit
344     s@^(/.*/)([^/]*)\s([^\./].*)$@\1\2 \1\3@;
345     # /path/map ../exit --> /path/map /path/../exit
346     s@^(/.*/)([^/]*)\s(\.\./.*)$@\1\2 \1\3@;
347     # /dir/../ --> / (all occurances)
348     s@/[^/]*/\.\./@/@g;
349    
350     ($junk,$exit) = split;
351     #print STDERR "DBG: exit $map $exit\n" if $debug > 5;
352     #print "exit $map $exit\n";
353    
354     #
355     # shortcut: if the exit map was already checked, don't bother
356     # stacking it again.
357     # %% if a map is never pushed twice in the first place,
358     # the corresponding test in the main loop is probably
359     # in vain.
360     #
361     next if $visited{$exit};
362    
363     #
364     # this is check 4, finally.
365     # if exit map can't be opened, complain and continue
366     #
367     if ( (! -r "$mapdir$exit") && ( $exit ne "/!") ) {
368     #print STDERR "ERROR: map $map, arch $arch, line $lines, no such exit $exit\n";
369     print "ERROR: map $map, arch $arch, line $lines, no such exit $exit ($rx, $ry, to $x, $y)\n";
370     next;
371     }
372    
373     #
374     # the exit map looks good; push it and continue
375     push(@MAPS,$exit);
376     }
377    
378     close(MAP);
379     if ($depth != 0) {
380     print "ERROR: map $map, mismatched arch/end, $depth\n";
381     }
382     }