Skip to content

Instantly share code, notes, and snippets.

@svanellewee
Created May 9, 2016 20:27
Show Gist options
  • Save svanellewee/329733379072195b3288bb596782498f to your computer and use it in GitHub Desktop.
Save svanellewee/329733379072195b3288bb596782498f to your computer and use it in GitHub Desktop.
Rewriting doom into python. Wadfiles.
from __future__ import print_function
import unittest
import collections
import struct
'''
vertex test cases:
(10, FileLump(filepos=94972, size=1868, name='VERTEXES'))
(21, FileLump(filepos=179996, size=3768, name='VERTEXES'))
(32, FileLump(filepos=295644, size=3784, name='VERTEXES'))
(43, FileLump(filepos=394692, size=3120, name='VERTEXES'))
(54, FileLump(filepos=482536, size=2984, name='VERTEXES'))
(65, FileLump(filepos=601156, size=4828, name='VERTEXES'))
(76, FileLump(filepos=731496, size=3584, name='VERTEXES'))
(87, FileLump(filepos=804588, size=1312, name='VERTEXES'))
(98, FileLump(filepos=879156, size=2324, name='VERTEXES'))
'''
class IncorrectByteLength(Exception):
def __init__(self, message="Not correct byte count"):
super(IncorrectByteLength, self).__init__(message=message)
Header = collections.namedtuple("Header", ['identification',
'num_lumps',
'info_table_offset'])
def read_file(file_obj, size, handler, position=None):
if position:
file_obj.seek(position)
datum = file_obj.read(size)
if not datum:
return None
return handler(datum)
def convert_file_header(data):
# type: ([byte]) -> Header
"""
typedef struct
{
// Should be "IWAD" or "PWAD".
char identification[4];
int numlumps;
int infotableofs;
} PACKEDATTR wadinfo_t;
"""
if len(data) != 12:
raise IncorrectByteLength("byte length {} instead of 12".format(len(data)))
values = struct.unpack("<4sII", data)
name, numlumps, info_table_offset = values
return Header(name,
numlumps,
info_table_offset)
FileLump = collections.namedtuple("FileLump", ['filepos',
'size',
'name'])
def convert_filelump(data):
# type: ([byte]) -> FileLump
"""
typedef struct
{
int filepos;
int size;
char name[8];
} PACKEDATTR filelump_t;
"""
try:
filepos, size, name = struct.unpack("<II8s", data)
except Exception:
raise
return FileLump(filepos, size, name)
LumpInfo = collections.namedtuple("LumpInfo", ['position',
'size',
'name',
'wad_file'])
def convert_lumpinfo(wad_file_name, file_lump):
# type: (FileLump) -> LumpInfo
return LumpInfo(file_lump.filepos,
file_lump.size,
file_lump.name,
wad_file_name)
Vertex = collections.namedtuple("Vertex", ["x","y"])
def read_vertex(data):
# type: ([byte]) -> Vertex
"""
typedef struct
{
short x;
short y;
} PACKEDATTR mapvertex_t;
"""
try:
x, y = struct.unpack("<hh", data)
except Exception:
print("DDD", data)
raise
return Vertex(x,y)
def split_file(file_obj, size):
while True:
data = file_obj.read(size)
#print(data)
if not data:
break
yield data
MapLinedef = collections.namedtuple("MapLinedef", [ 'v1',
'v2',
'flags',
'special',
'tag',
'sidenum' ])
def read_maplinedef(data):
# type: ([byte]) -> MapLinedef
"""
typedef struct
{
short v1; //2
short v2; //2
short flags; //2
short special; //2
short tag; //2
// sidenum[1] will be -1 if one sided
short sidenum[2]; //4
# } PACKEDATTR maplinedef_t;
"""
sidenum = [-1, -1]
try:
v1, v2, flags, tag, special, sidenum[0], sidenum[1] = struct.unpack("<hhhhhhh", data)
except Exception:
raise
return MapLinedef(v1, v2, flags, tag, special, [sidenum[0], sidenum[1]])
class TestWad(unittest.TestCase):
def test_add_file(self):
# need to make custom wad for tests...
test_file_name = '/Users/svanellewee/source/doom-stuff/doom1.wad'
with open(test_file_name, 'rb') as file_data:
header = read_file(file_data,
12,
convert_file_header)
file_data.seek(header.info_table_offset)
# LAZY LIZZARD!!!
file_lumps = (convert_filelump(i) for i in split_file(file_data, 16))
lump_info = list(convert_lumpinfo(test_file_name, i) for i in file_lumps)
# map(print, enumerate(lump_info))
def read_lump(lump_self, index, struct_size=1):
current_lump = lump_self[index]
with open(current_lump.wad_file, 'rb') as wad_file_data:
wad_file_data.seek(current_lump.position)
bytes_left = current_lump.size
while True:
datum = wad_file_data.read(struct_size)
if not datum:
break
if bytes_left <= 0:
break
bytes_left -= struct_size
yield datum
#vertexes are 4 bytes big in the file.
for i in read_lump(lump_info, 10, 4):
print(read_vertex(i))
#linedefs are 14 bytes big in the file.
for i in read_lump(lump_info, 8, 14):
print(read_maplinedef(i))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment