Skip to content

Instantly share code, notes, and snippets.

@fusspawn
Last active November 19, 2019 22:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fusspawn/2f819938b19f12869952eb00fe63345b to your computer and use it in GitHub Desktop.
Save fusspawn/2f819938b19f12869952eb00fe63345b to your computer and use it in GitHub Desktop.
MMTile lua parser. Works inside of wow. requires: https://github.com/iryont/lua-struct
-- fixed invalid mmap_uses_liquid check
local file = GetHackDirectory() .. "\mmaps\\0002239.mmtile"
function pack(...)
return {...}
end
function ToStream(byte_array)
byte_array.index = 0
byte_array.read_bytes = function(self, len)
local ret = {}
for i = 1, len, 1 do
ret[i] = self[self.index + i]
end
self.index = self.index + len
return ret
end
byte_array.read_bytes_str = function(self, len)
local ret = {}
for i = 1, len, 1 do
ret[i] = self[self.index + i]
end
self.index = self.index + len
return bytestostring(ret)
end
return byte_array
end
function bytestostring(bytes)
s = ""
for i = 1, getn(bytes) do
s = s .. string.char(bytes[i]) -- Fixme: '..' creates new string. Expensive and shit!
end
return s
end
dtAlign4 = function(x)
return bit.band((x+3), bit.bnot(3))
end
function DumpNavMeshFile(filename)
if #GetDirectoryFiles(filename) == 0 then
DEBUG("No file found..: " .. filename)
return
end
print("reading file: " .. filename)
local bytes = ReadFile(filename, true)
print("loaded " .. #bytes .. " of navmesh")
local byte_stream = ToStream(bytes)
local magic_header = byte_stream:read_bytes_str(4)
if magic_header ~= "PAMM" then
print("Found invalid magic header. stopping")
return
end
print("magic header was... ok!")
local dt_version_num = struct.unpack("<I", byte_stream:read_bytes_str(4))
if dt_version_num ~= 7 then
print("invalid dt version num. expected 7 got: " .. dt_version_num)
end
print("detour version was... ok!")
local mmap_version_num = struct.unpack("<I", byte_stream:read_bytes_str(4))
print("mmap version was... " .. mmap_version_num)
local mmap_data_size = struct.unpack("<I", byte_stream:read_bytes_str(4))
print("mmap data size was... " .. mmap_data_size)
local mmap_uses_liquid = struct.unpack("<i", byte_stream:read_bytes_str(4)) == 1 or false
print("mmap uses liquid: " .. tostring(mmap_uses_liquid))
local data_start_index = byte_stream.index
local t_magic = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_version = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_x = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_y = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_layer = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_userId = struct.unpack("<I", byte_stream:read_bytes_str(4))
local t_polyCount = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_vertCount = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_maxLinkCount = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_detailMeshCount = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_detailVertCount = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_detailTriCount = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_bvNodeCount = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_offMeshConCount = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_offMeshBase = struct.unpack("<i", byte_stream:read_bytes_str(4))
local t_walkableHeight = struct.unpack("<f", byte_stream:read_bytes_str(4))
local t_walkableRadius = struct.unpack("<f", byte_stream:read_bytes_str(4))
local t_walkableClimb = struct.unpack("<f", byte_stream:read_bytes_str(4))
local t_bMinX = struct.unpack("<f", byte_stream:read_bytes_str(4))
local t_bMinY = struct.unpack("<f", byte_stream:read_bytes_str(4))
local t_bMinZ = struct.unpack("<f", byte_stream:read_bytes_str(4))
local t_bMaxX = struct.unpack("<f", byte_stream:read_bytes_str(4))
local t_bMaxY = struct.unpack("<f", byte_stream:read_bytes_str(4))
local t_bMaxZ = struct.unpack("<f", byte_stream:read_bytes_str(4))
local t_bvQuantFactor = struct.unpack("<f", byte_stream:read_bytes_str(4))
print("found nav tile: Pos: (".. t_x .. "/" .. t_y.. " - layer: ".. t_layer ..") WalkableHeight: " .. t_walkableHeight .. " WalkableRadius: " .. t_walkableRadius .. " WalkableClimb: " .. t_walkableClimb)
print("Tile BoundingBox: ")
print("Min: ")
print("X: " .. t_bMinX)
print("Y: " .. t_bMinY)
print("Z: " .. t_bMinZ)
print("Max: ")
print("X: " .. t_bMaxX)
print("Y: " .. t_bMaxY)
print("Z: " .. t_bMaxZ)
local headerSize = dtAlign4(100);
local vertsSize = dtAlign4(4 * 3 * t_vertCount);
local polysSize = dtAlign4(34 * t_polyCount);
local linksSize = dtAlign4(16 * t_maxLinkCount);
local detailMeshesSize = dtAlign4(10 * t_detailMeshCount);
local detailVertsSize = dtAlign4(4*3*t_detailVertCount);
local detailTrisSize = dtAlign4(4*t_detailTriCount);
local bvtreeSize = dtAlign4(8*t_bvNodeCount);
local offMeshLinksSize = dtAlign4(36*t_offMeshConCount);
local data_index = data_start_index + headerSize
byte_stream.index = data_index
local vertex_data = pack(struct.unpack("<" .. string.rep("f", t_vertCount), byte_stream:read_bytes_str(4 * t_vertCount)))
print("Read " .. #vertex_data .. " vertices")
data_index = data_start_index + headerSize + vertsSize;
byte_stream.index = data_index
local poly_data = {}
for poly_index = 1, t_polyCount, 1 do
local poly = pack(struct.unpack("<IHHHHHHHHHHHHHBB", byte_stream:read_bytes_str(34)))
poly_data[poly_index] = poly
end
print("read: " .. #poly_data .. " polygons expected: " .. t_polyCount)
data_index = data_start_index + headerSize + vertsSize + polysSize;
byte_stream.index = data_index
local link_data = {}
for link_index = 1, t_maxLinkCount, 1 do
local link = pack(struct.unpack("<LIBBBB", byte_stream:read_bytes_str(16)))
--print("link_index: " .. link_index .. " / " .. link[1])
link_data[link_index] = link
end
print("read: " .. #link_data .. " links expected: " .. t_maxLinkCount)
data_index = data_start_index + headerSize + vertsSize + polysSize + linksSize;
byte_stream.index = data_index
local detail_mesh_data = {}
for link_index = 1, t_detailMeshCount, 1 do
local link = pack(struct.unpack("<IIBB", byte_stream:read_bytes_str(10)))
detail_mesh_data[link_index] = link
end
print("read: " .. #detail_mesh_data .. " detail meshes expected: " .. t_detailMeshCount)
data_index = data_start_index + headerSize + vertsSize + polysSize + linksSize + detailMeshesSize;
byte_stream.index = data_index
local detail_mesh_verts = {}
for link_index = 1, t_detailVertCount, 1 do
local link = pack(struct.unpack("<FFF", byte_stream:read_bytes_str(12)))
detail_mesh_verts[link_index] = link
end
print("read: " .. #detail_mesh_verts .. " detail mesh vert expected: " .. t_detailVertCount)
data_index = data_start_index + headerSize + vertsSize + polysSize + linksSize + detailMeshesSize + detailVertsSize;
byte_stream.index = data_index
local detail_mesh_tris = {}
for link_index = 1, t_detailTriCount, 1 do
local link = pack(struct.unpack("<B", byte_stream:read_bytes_str(1)))
detail_mesh_tris[link_index] = link
end
print("read: " .. #detail_mesh_tris .. " detail mesh tri expected: " .. t_detailTriCount)
local mmtile = {
header = {
magic = t_magic,
version = t_version,
x = t_x,
y = t_y,
layer = t_layer,
userId = t_userId,
polyCount = t_polyCount,
vertCount = t_vertCount,
maxLinkCount = t_maxLinkCount,
detailMeshCount = t_detailMeshCount,
detailVertCount = t_detailVertCount,
detailTriCount = t_detailTriCount,
bvNodeCount = t_bvNodeCount,
offMeshConCount = t_offMeshConCount,
offMeshBase = t_offMeshBase,
walkableHeight = t_walkableHeight,
walkableRadius = t_walkableRadius,
walkableClimb = t_walkableClimb,
BBox= {
Min = {
X = t_bMinX,
Y = t_bMinY,
Z = t_bMinZ
},
Max = {
X = t_bMaxX,
Y = t_bMaxY,
Z = t_bMaxZ
}
},
bvQuantFactor = t_bvQuantFactor
},
verticies = vertex_data,
polys =poly_data,
links =link_data,
detailMeshs =detail_mesh_data,
detailMeshVerts = detail_mesh_verts,
detailMeshTris = detail_mesh_tris
}
return mmtile;
end
DumpNavMeshFile(file)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment