Skip to content

Commit 673928a

Browse files
author
Dave
committed
Basic map file parsing.
1 parent 92563e0 commit 673928a

12 files changed

Lines changed: 736 additions & 0 deletions

File tree

DukeMapGenLib/.classpath

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
<classpathentry kind="src" path="tst"/>
55
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
66
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
7+
<classpathentry kind="lib" path="libs/commons-io-2.4.jar"/>
78
<classpathentry kind="output" path="bin"/>
89
</classpath>
181 KB
Binary file not shown.
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package trn;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
6+
import org.apache.commons.io.EndianUtils;
7+
8+
9+
/**
10+
* So apparently java sucks balls at dealing with byte order. The best libs I've found are:
11+
* - apache endianutils https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/EndianUtils.html
12+
* - guava http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/io/LittleEndianDataInputStream.html
13+
*
14+
* Neither seem to be specific enough for my tastes.
15+
*
16+
*
17+
* See this: http://www.shikadi.net/moddingwiki/MAP_Format_%28Build%29
18+
* and hope its right.
19+
*
20+
* Also in buildhlp.exe its page 40.
21+
*
22+
*
23+
* @author Dave
24+
*
25+
*/
26+
public class ByteUtil {
27+
28+
29+
/**
30+
* reads a little-endian, unsigned integer.
31+
*
32+
* @param bytes
33+
* @param start the index to start reading from
34+
* @return
35+
*/
36+
public static long readUint32LE(byte[] bytes, int start){
37+
38+
//accordding to the apache docs, this is a 32 bit integer.
39+
return EndianUtils.readSwappedUnsignedInteger(bytes, start);
40+
}
41+
42+
public static long readUint32LE(InputStream input) throws IOException{
43+
44+
//accordding to the apache docs, this is a 32 bit integer.
45+
return EndianUtils.readSwappedUnsignedInteger(input);
46+
}
47+
48+
public static int readUint16LE(byte[] bytes, int start){
49+
50+
//according to apache docs, this is a 16 bit integer
51+
return EndianUtils.readSwappedUnsignedShort(bytes, start);
52+
}
53+
54+
public static int readUint16LE(InputStream input) throws IOException{
55+
56+
//according to apache docs, this is a 16 bit integer
57+
return EndianUtils.readSwappedUnsignedShort(input);
58+
}
59+
60+
61+
62+
public static int readInt32LE(InputStream input) throws IOException {
63+
return EndianUtils.readSwappedInteger(input);
64+
}
65+
66+
67+
public static short readInt16LE(InputStream input) throws IOException {
68+
return EndianUtils.readSwappedShort(input);
69+
}
70+
71+
72+
73+
74+
75+
//endian-ness is only for values greater than a single byte...but what about signed vs unsinged?
76+
77+
78+
79+
public static short readUInt8(InputStream input) throws IOException {
80+
81+
//originally wrote this function for sector ceilingshade, which is:
82+
83+
////this is an INT8 ; a.k.a. signed integer
84+
//byte is signed...
85+
//char is two-byte unsigned: http://stackoverflow.com/questions/4458352/purpose-of-char-in-java
86+
//so char is really more of an unsigned short...
87+
88+
89+
int i = input.read(); //returns int [0,255]
90+
91+
//so I have a...signed value, but its stored unsigned in a signed type.
92+
//fuck my head hurts
93+
//can i just subtract 128?
94+
95+
//according to what I've read, we need to do this:
96+
//i = i - 128; //so now its in the range [-128,127]
97+
//however that gives a number that doesnt match what build reports
98+
99+
100+
101+
return (byte)i;
102+
103+
}
104+
105+
}

DukeMapGenLib/src/trn/Main.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,70 @@
11
package trn;
22

3+
import java.io.ByteArrayInputStream;
4+
import java.io.File;
5+
import java.io.FileInputStream;
6+
import java.io.FileNotFoundException;
7+
import java.io.IOException;
8+
9+
import org.apache.commons.io.IOUtils;
10+
311
public class Main {
412

513

14+
//found this, looks like a good resource for the build map format:
15+
// http://www.shikadi.net/moddingwiki/MAP_Format_%28Build%29
16+
17+
/** TODO: remove when I have some real unit tests */
618
public static final String HELLO = "hello world";
19+
20+
public static void main(String[] args){
21+
22+
String fname = "ONEROOM.MAP";
23+
//String fname = "TWOROOMS.MAP";
24+
25+
String filepath = System.getProperty("user.dir") + File.separator + "testdata" + File.separator + fname;
26+
27+
28+
File f = new File(filepath);
29+
if(f.exists() && f.isFile()){
30+
31+
try {
32+
byte[] mapFile = IOUtils.toByteArray(new FileInputStream(f));
33+
parseOnTheFly(mapFile);
34+
35+
36+
} catch (FileNotFoundException e) {
37+
e.printStackTrace();
38+
System.exit(1);
39+
} catch (IOException e) {
40+
e.printStackTrace();
41+
System.exit(1);
42+
}
43+
44+
}else{
45+
System.err.println(String.format("%s is not a valid file", filepath));
46+
System.exit(1);
47+
}
48+
49+
}
50+
51+
/**
52+
* quick and dirty method to print shit while we learn how to read the file
53+
*
54+
* TODO: develop data types, make a nice fancy parser.
55+
* @param mapFile
56+
* @throws IOException
57+
*/
58+
public static void parseOnTheFly(byte[] mapFile) throws IOException{
59+
60+
ByteArrayInputStream bs = new ByteArrayInputStream(mapFile);
61+
62+
Map map = Map.readMap(bs);
63+
64+
map.print();
65+
//ByteArrayInputStream bs = new ByteArrayInputStream(mapFile, 1, mapFile.length - 1);
66+
67+
68+
69+
}
770
}

DukeMapGenLib/src/trn/Map.java

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package trn;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
6+
public class Map {
7+
8+
long mapVersion;
9+
10+
PlayerStart playerStart;
11+
12+
long sectorWithStartPoint;
13+
14+
int sectorCount;
15+
16+
Sector[] sectors;
17+
18+
int wallCount;
19+
20+
Wall walls[];
21+
22+
int spriteCount;
23+
24+
Sprite[] sprites;
25+
26+
public long getMapVersion(){
27+
return mapVersion;
28+
}
29+
30+
public PlayerStart getPlayerStart(){
31+
return this.playerStart;
32+
}
33+
34+
/**
35+
* @return the sector that contains the start point
36+
*/
37+
public long getStartSector(){
38+
return this.sectorWithStartPoint;
39+
}
40+
41+
public int getSectorCount(){
42+
return this.sectorCount;
43+
}
44+
45+
public Sector getSector(int i){
46+
return sectors[i];
47+
}
48+
49+
public int getWallCount(){
50+
return this.wallCount;
51+
}
52+
53+
public Wall getWall(int i){
54+
return this.walls[i];
55+
}
56+
57+
public int getSpriteCount(){
58+
return this.spriteCount;
59+
}
60+
61+
public Sprite getSprite(int i){
62+
return sprites[i];
63+
}
64+
65+
66+
public void print(){
67+
System.out.println("map version: " + mapVersion);
68+
69+
System.out.println("player start: " + playerStart.toString());
70+
71+
System.out.println("sector with start point: " + sectorWithStartPoint);
72+
73+
System.out.println("sector count: " + sectorCount);
74+
75+
System.out.println("wall count: " + wallCount);
76+
77+
System.out.println("sprite count: " + spriteCount);
78+
}
79+
80+
public static Map readMap(InputStream bs) throws IOException {
81+
82+
Map map = new Map();
83+
84+
//long mapVersion = ByteUtil.readUint32LE(mapFile, 0);
85+
map.mapVersion = ByteUtil.readUint32LE(bs);
86+
87+
map.playerStart = PlayerStart.fromBytes(bs);
88+
89+
90+
map.sectorWithStartPoint = ByteUtil.readUint16LE(bs); //NOTE: that wiki page is wrong here!
91+
92+
93+
map.sectorCount = ByteUtil.readUint16LE(bs);
94+
95+
map.sectors = new Sector[map.sectorCount];
96+
for(int i = 0; i < map.sectorCount; ++i){
97+
map.sectors[i] = Sector.readSector(bs);
98+
map.sectors[i].print();
99+
}
100+
101+
map.wallCount = ByteUtil.readUint16LE(bs);
102+
103+
104+
map.walls = new Wall[map.wallCount];
105+
for(int i = 0; i < map.wallCount; ++i){
106+
map.walls[i] = Wall.readWall(bs);
107+
}
108+
109+
map.spriteCount = ByteUtil.readUint16LE(bs);
110+
111+
112+
map.sprites = new Sprite[map.spriteCount];
113+
for(int i = 0; i < map.spriteCount; ++i){
114+
map.sprites[i] = Sprite.readSprite(bs);
115+
116+
System.out.println("sprite texture: " + map.sprites[i].picnum); //oneroom.map should be 22 and 24
117+
}
118+
119+
System.out.println("read method returns: " + bs.read()); //-1 [probably] means EOF, meaning we did it right.
120+
121+
return map;
122+
}
123+
124+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package trn;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
6+
public class PlayerStart {
7+
8+
public static final int BYTE_COUNT = 14;
9+
10+
11+
final long x; //UINT32LE
12+
final long y; //UINT32LE
13+
final long z; //UINT32LE
14+
final int angle; //UINT16LE
15+
16+
public PlayerStart(long x, long y, long z, int angle){
17+
this.x = x;
18+
this.y = y;
19+
this.z = z;
20+
this.angle = angle;
21+
22+
}
23+
24+
public long x(){
25+
return this.x;
26+
}
27+
28+
public long getX(){ return this.x(); }
29+
30+
public long y(){
31+
return this.y;
32+
}
33+
34+
public long getY(){ return this.y(); }
35+
36+
public long z(){
37+
return this.z; //TODO: should we deal with the shift here?
38+
}
39+
40+
public long getZ(){ return this.z(); }
41+
42+
public int getAngle(){
43+
return this.angle;
44+
}
45+
46+
@Override
47+
public String toString(){
48+
49+
return String.format("{ x=%d, y=%d, z=%d angle=%d", x, y, z, angle);
50+
}
51+
52+
public static PlayerStart fromBytes(byte[] bytes, int start){
53+
54+
//note: ByteArrayInputStream does have a constructor that takes an offset...
55+
56+
return new PlayerStart(
57+
ByteUtil.readUint32LE(bytes, start),
58+
ByteUtil.readUint32LE(bytes, (start += 4)),
59+
ByteUtil.readUint32LE(bytes, (start += 4)),
60+
ByteUtil.readUint16LE(bytes, (start += 2))
61+
);
62+
}
63+
64+
public static PlayerStart fromBytes(InputStream input) throws IOException{
65+
66+
return new PlayerStart(
67+
ByteUtil.readUint32LE(input),
68+
ByteUtil.readUint32LE(input),
69+
ByteUtil.readUint32LE(input),
70+
ByteUtil.readUint16LE(input)
71+
);
72+
73+
}
74+
75+
}

0 commit comments

Comments
 (0)