Skip to content

Instantly share code, notes, and snippets.

@warmist
Created February 13, 2022 16:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save warmist/f06b553621dd2d516b0f8d91f6da1e53 to your computer and use it in GitHub Desktop.
Save warmist/f06b553621dd2d516b0f8d91f6da1e53 to your computer and use it in GitHub Desktop.
local fname="mp_forwardbase_kodai.ain"
local print_stuff=true
local save_nodes=true
local save_links=true
--[[ current struct layouts ]]
local MAX_HULLS=5
local ain_file={
{"u32","magic"},
{"u32","mapver"},
{"u32","crc"},
{"u32","nodecount"},
{"CAI_NodeDisk","nodes","nodecount"},
{"u32","linkcount"},
{"AINLink","links","linkcount"},
{"u32","unk0","nodecount"},
{"u16","unk1"},
{"UnkStruct0","unk2","unk1"},
{"UnkStruct1","unk3",MAX_HULLS},
--[[
{"u32","unk4"},
{"UnkStruct3","unk5","unk4"},
{"u32","unk6"},
{"UnkStruct4","unk7","unk6"},
{"u32","unk8"},
{"u32","scriptnodecount"},
{"AINScriptNode","scriptnodes","scriptnodecount"},
{"u32","hintcount"},
{"AINHint","hints","hintcount"},
--]]
}
local ain_node={
{"float","x"},
{"float","y"},
{"float","z"},
{"float","yaw"},
{"float","hulls",MAX_HULLS},
{"s8","unk0"},
{"u32","unk1"},
{"u16","unk2",MAX_HULLS},
{"s8","unk3",MAX_HULLS},
{"u16","unk4"},
{"u16","unk5"},
{"s8","unk6",8},
}
local ain_link={
{"u16","srcID"};
{"u16","destID"};
{"u8","unk0",6};
}
local unk0={
{"u8","unk0",20}
}
local unk1={
{"u32","unk0"},
{"u16","unk1"},
{"u16","unk2"},
{"u32","unk3","unk2"},--originally u8 of unk2*4
}
local typenames={
CAI_NodeDisk=ain_node,
AINLink=ain_link,
UnkStruct0=unk0,
UnkStruct1=unk1,
}
local type_transforms={
u32="I4",
u16="I2",
u8="I1",
s32="i4",
s16="i2",
s8="i1",
float="f",
double="d",
}
function opt_print( ... )
if print_stuff then
print(...)
end
end
function byte_array_tohex( barr )
local ret=""
for i=1,#barr do
ret=ret..string.format("%02x",barr[i])
end
return ret
end
--prints typename
function print_tname( struct,tname,fname )
if type(tname)=="string" then
opt_print(string.format("\t%20s\t%s",fname or "",tostring(struct)))
return
end
for i,v in ipairs(tname) do
opt_print(string.format("\t%20s\t%s",v[2],tostring(struct[v[2]])))
end
end
--loads typename from a string
function load_typename(s,cp,tname)
--print("D:",cp/#s)
local ret={}
if type(tname)=="string" then
local tformat=type_transforms[tname]
if tformat~=nil then
ret,cp=string.unpack(tformat,s,cp)
return ret,cp
else
tformat=typenames[tname]
return load_typename(s,cp,tformat)
end
end
for i,v in ipairs(tname) do
--print(i,v,v[1],v[2],v[3])
local tformat=type_transforms[v[1]]
local count=v[3]
if type(count)=="string" then
count=ret[count]
end
if count~=nil then
--if tformat==nil then tformat=typenames[v[1]] end
ret[v[2]],cp=load_array(s,cp,v[1],count)
else
if tformat~=nil then
ret[v[2]],cp=string.unpack(tformat,s,cp)
else
tformat=typenames[tname]
ret[v[2]],cp=load_typename(s,cp,tformat)
end
end
end
return ret,cp
end
--loads array of typename from a string
function load_array( s,cp,tname,count )
--print(tname,count)
local ret={}
for i=1,count do
ret[i],cp=load_typename(s,cp,tname)
end
return ret,cp
end
function load_file( fname,typename )
print(string.format("Loading:\t%20s\t=========================================",fname))
local f=io.open(fname,"rb")
local s=f:read("a")
f:close()
local cp=1
local loaded_file
loaded_file,cp=load_typename(s,cp,typename)
--assert(cp==#s)
return loaded_file
end
function cross_prod(a,b)
local ret={
a[2]*b[3]-a[3]*b[2],
a[3]*b[1]-a[1]*b[3],
a[1]*b[2]-a[2]*b[1]
}
return ret
end
function length( v )
return math.sqrt(v[1]*v[1]+v[2]*v[2]+v[3]*v[3])
end
function normalize( v )
local l=length(v)
return {v[1]/l,v[2]/l,v[3]/l}
end
function add_pt(a,b)
return {a[1]+b[1],a[2]+b[2],a[3]+b[3]}
end
function mult_pt( a,scalar)
return {a[1]*scalar,a[2]*scalar,a[3]*scalar}
end
function add_tube( out_verts,out_tris,pt_start,pt_end,radius )
local dx={-1,-1,1,1}
local dz={1,-1,-1,1}
local s_pt={pt_start.x,pt_start.y,pt_start.z}
local e_pt={pt_end.x,pt_end.y,pt_end.z}
local con_d=add_pt(s_pt,mult_pt(e_pt,-1))
local cd=normalize(con_d)
local ovec1=cross_prod(cd,{0,0,1})
local ovec2=cross_prod(cd,ovec1)
local rad=radius
local vert_count_start=#out_verts
for i=1,4 do
local v=add_pt(s_pt,add_pt(mult_pt(ovec1,dx[i]*rad),mult_pt(ovec2,dz[i]*rad)))
table.insert(out_verts,string.format("%g %g %g\n",v[1],v[2],v[3]))
end
for i=1,4 do
local v=add_pt(e_pt,add_pt(mult_pt(ovec1,dx[i]*rad),mult_pt(ovec2,dz[i]*rad)))
table.insert(out_verts,string.format("%g %g %g\n",v[1],v[2],v[3]))
end
local tris={
{0,1,5},
{0,5,4},
{1,2,5},
{2,6,5},
{3,2,6},
{3,6,7},
{0,3,4},
{3,7,4}
}
for i,v in ipairs(tris) do
table.insert(out_tris,string.format("3 %d %d %d\n",v[1]+vert_count_start,v[2]+vert_count_start,v[3]+vert_count_start))
end
end
function add_box( out_verts,out_tris,pt,radius )
local dx={-1, 1, 1,-1,-1, 1, 1,-1}
local dy={-1,-1, 1, 1,-1,-1, 1, 1}
local dz={-1,-1,-1,-1, 1, 1, 1, 1}
local s_pt={pt.x,pt.y,pt.z}
local rad=radius
local vert_count_start=#out_verts
for i=1,8 do
local v=add_pt(s_pt,mult_pt({dx[i],dy[i],dz[i]},rad))
table.insert(out_verts,string.format("%g %g %g\n",v[1],v[2],v[3]))
end
local tris={
{0,1,5},
{0,5,4},
{1,2,5},
{2,6,5},
{3,6,2},
{3,7,6},
{0,4,3},
{3,4,7},
{2,1,0},
{3,2,0},
{6,4,5},
{7,4,6},
}
for i,v in ipairs(tris) do
table.insert(out_tris,string.format("3 %d %d %d\n",v[1]+vert_count_start,v[2]+vert_count_start,v[3]+vert_count_start))
end
end
function print_recurse( t,tabs )
tabs=tabs or 0
if type(t)=="table" then
for k,v in pairs(t) do
print(string.rep("\t",tabs)..k)
print_recurse(v,tabs+1)
end
else
print(string.rep("\t",tabs)..t)
end
end
function save_ply(verts,tris,fname )
print(string.format("Writing:\t%20s\t=========================================",fname))
local ply_header=
[[
ply
format ascii 1.0
element vertex %d
property float x
property float y
property float z
element face %d
property list uchar int vertex_index
end_header
]]
local ply_data=ply_header:format(#verts,#tris)..table.concat(verts)..table.concat(tris)
local f_out=io.open (fname,"w")
f_out:write(ply_data)
f_out:close()
end
local lf=load_file(fname,ain_file)
--print_recurse(lf.unk3)
local verts={}
local tris={}
function add_nodes(node_file,verts,tris )
for i,v in ipairs(node_file.nodes) do
add_box(verts,tris,v,16)
end
end
function fingerprint(tbl )
local ret=0
for i=1,6 do
ret=bit32.bor(ret,bit32.lshift(tbl[i],(i-1)*4))
end
return ret
end
local fprints={}
local fprints_idx={
"000404000404",
"000404040400",
"000000010001",
"000101000100",
"000100000000",
"000000000101",
"000101010101",
"000404040404",
"000100000100",
"000000010000",
"000100000101",
"000404000400",
"000000000100",
"000100010101",
"000101000101",
"000000000001",
"000100010100",
"000400000400",
}
function add_links(node_file,verts,tris,l)
local count_added=0
for j,v in ipairs(node_file.links) do
local need_add=true
local s=node_file.nodes[v.srcID+1]
local e=node_file.nodes[v.destID+1]
--[[for i=1,6 do
if v.unk0[i]~=0 and v.unk0[i]~=1 then
need_add=false
end
end--]]
--print(fingerprint(v.unk0))
--local ff=fingerprint(v.unk0)
local ff=byte_array_tohex(v.unk0)
if fprints[ff]==nil then
fprints[ff]=1
else
fprints[ff]=fprints[ff]+1
end
if l~=nil then
need_add=(ff==l)
end
if need_add then
add_tube(verts,tris,s,e,1)
count_added=count_added+1
end
end
print("Added",count_added,"links")
for k,v in pairs(fprints) do
print("0x"..k,v)
end
end
if save_links then
add_nodes(lf,verts,tris)
end
-- [[
--for i,v in ipairs(fprints_idx) do
--local verts={}
--local tris={}
if save_links then
add_links(lf,verts,tris,v)
end
if save_links or save_nodes then
save_ply(verts,tris,fname..".ply")
end
--end
--]]
--[[
local new_nodes={
}
for i,v in ipairs(new_nodes) do
add_box(verts,tris,{x=v[1],y=v[2],z=v[3]},16)
end
save_ply(verts,tris,"mp_wargames_loged.ply")
--]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment