Skip to content

Instantly share code, notes, and snippets.

@blewert
Last active October 8, 2017 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save blewert/839de8228f3dd7a21603 to your computer and use it in GitHub Desktop.
Save blewert/839de8228f3dd7a21603 to your computer and use it in GitHub Desktop.
An IPL decompiler for binary IPL data files for gta:sa.
## Benjamin Williams
## <eeu222@bangor.ac.uk>
## --
## bipltool.py/pyc
import os
import sys
import struct
#Base path to read from
basePath = "T:\\gtasa\\data\\maps\\exported\\";
outputPath = basePath + "output\\";
#File to read from
file = "vegasn_stream6.ipl";
for file in [x for x in os.listdir(basePath) if x.endswith(".ipl")]:
print("[opening " + basePath + file + "...]");
#Open up the file
f = open(basePath + file, "rb");
#INST and CARS block output
instLines = [];
carLines = [];
try:
header = f.read(4);
if header != b"bnry":
print("\t[!] Target file is not a binary ipl file. (Failed file signature)\n");
f.close();
continue;
else:
print("\t[!] Target file is a binary ipl file. Reading header..");
numberOfInsts = struct.unpack('i', f.read(4))[0];
print("\t[head] INST block has " + str(numberOfInsts) + " items.");
#Skip unknown bytes (4 * 3)
f.seek(f.tell() + 4 * 3);
numberOfCars = struct.unpack('i', f.read(4))[0];
print("\t[head] CARS block has " + str(numberOfCars) + " items.");
#Skip unknown bytes (4 * 1)
f.seek(f.tell() + 4);
offset = struct.unpack('i', f.read(4))[0];
print(str(offset) + " is the offset for the INST block.\n");
#Skip junk data (11 * 4)
f.seek(f.tell() + (11 * 4));
print("\t[!] Read header values. Reading INST block:");
#INST
for i in range(0, numberOfInsts):
posX = struct.unpack('f', f.read(4))[0];
posY = struct.unpack('f', f.read(4))[0];
posZ = struct.unpack('f', f.read(4))[0];
rotX = struct.unpack('f', f.read(4))[0];
rotY = struct.unpack('f', f.read(4))[0];
rotZ = struct.unpack('f', f.read(4))[0];
rotW = struct.unpack('f', f.read(4))[0];
objID = struct.unpack('i', f.read(4))[0];
unk = struct.unpack('i', f.read(4))[0];
flags = struct.unpack('i', f.read(4))[0];
#ID, ModelName, Interior, PosX, PosY, PosZ, RotX, RotY, RotZ, RotW, LOD
instLines.append("%d, dummy, %d, %.5f, %.5f, %.5f, %.5f, %.5f, %.5f, %.5f, %d" % (objID, unk, posX, posY, posZ, rotX, rotY, rotZ, rotW, flags));
#print("\t\t[INST] Read and appended entry " + str(i + 1) + "/" + str(numberOfInsts) + ".");
print("\n\t[!] Processed INST block. Reading CARS block:");
#CARS
for i in range(0, numberOfCars):
posX = struct.unpack('f', f.read(4))[0];
posY = struct.unpack('f', f.read(4))[0];
posZ = struct.unpack('f', f.read(4))[0];
#For some reason this needs negating and multiplying by 100...
posA = -struct.unpack('f', f.read(4))[0] * 100;
vID = struct.unpack('i', f.read(4))[0];
#PosX, PosY, PosZ, Angle, CarID, PrimCol, SecCol, ForceSpawn, Alarm, DoorLock, Unknown1, Unknown2
carLines.append("%.5f, %.5f, %.5f, %.2f, %d, -1, -1, 0, 0, -1, -1" % (posX, posY, posZ, posA, vID));
#Skip junk flags at end of CARS block (28 bytes)
f.seek(f.tell() + 28);
#print("\t\t[CARS] Read and appended entry " + str(i + 1) + "/" + str(numberOfCars) + ".");
print("\n\t[!] Processed CARS block.");
finally:
f.close();
#Append output
lines = "inst\n" + "\n".join(instLines) + "\nend\n";
lines += "cars\n" + "\n".join(carLines) + "\nend";
outputFile = outputPath + file;
print("\n\t[!] Saving data to " + outputFile + "...");
fp = open(outputFile, "w+");
fp.write(lines);
fp.close();
## Benjamin Williams
## <eeu222@bangor.ac.uk>
## --
## bipltool.py/pyc
import os
import sys
import struct
#Base path to read from
basePath = "T:\\gtasa\\data\\maps\\exported\\";
#File to read from
file = "vegasn_stream6.ipl";
#Open up the file
f = open(basePath + file, "rb");
#INST and CARS block output
instLines = [];
carLines = [];
try:
header = f.read(4);
if header != b"bnry":
print("target file is not a binary ipl file.");
f.close();
exit(1);
else:
print("target file is a binary ipl file.");
numberOfInsts = struct.unpack('i', f.read(4))[0];
print("[header] INST block has " + str(numberOfInsts) + " items.");
#Skip unknown bytes (4 * 3)
f.seek(f.tell() + 4 * 3);
numberOfCars = struct.unpack('i', f.read(4))[0];
print("[header] CARS block has " + str(numberOfCars) + " items.");
#Skip unknown bytes (4 * 1)
f.seek(f.tell() + 4);
offset = struct.unpack('i', f.read(4))[0];
print(str(offset) + " is the offset for the INST block.");
#Skip junk data (11 * 4)
f.seek(f.tell() + (11 * 4));
print("Read header values. Reading instance data.");
#INST
for i in range(0, numberOfInsts):
posX = struct.unpack('f', f.read(4))[0];
posY = struct.unpack('f', f.read(4))[0];
posZ = struct.unpack('f', f.read(4))[0];
rotX = struct.unpack('f', f.read(4))[0];
rotY = struct.unpack('f', f.read(4))[0];
rotZ = struct.unpack('f', f.read(4))[0];
rotW = struct.unpack('f', f.read(4))[0];
objID = struct.unpack('i', f.read(4))[0];
unk = struct.unpack('i', f.read(4))[0];
flags = struct.unpack('i', f.read(4))[0];
#ID, ModelName, Interior, PosX, PosY, PosZ, RotX, RotY, RotZ, RotW, LOD
instLines.append("%d, dummy, %d, %.5f, %.5f, %.5f, %.5f, %.5f, %.5f, %.5f, %d" % (objID, unk, posX, posY, posZ, rotX, rotY, rotZ, rotW, flags));
#CARS
for i in range(0, numberOfCars):
posX = struct.unpack('f', f.read(4))[0];
posY = struct.unpack('f', f.read(4))[0];
posZ = struct.unpack('f', f.read(4))[0];
#For some reason this needs negating and multiplying by 100...
posA = -struct.unpack('f', f.read(4))[0] * 100;
vID = struct.unpack('i', f.read(4))[0];
#PosX, PosY, PosZ, Angle, CarID, PrimCol, SecCol, ForceSpawn, Alarm, DoorLock, Unknown1, Unknown2
carLines.append("%.5f, %.5f, %.5f, %.2f, %d, -1, -1, 0, 0, -1, -1" % (posX, posY, posZ, posA, vID));
#Skip junk flags at end of CARS block (28 bytes)
f.seek(f.tell() + 28);
finally:
f.close();
#Append output
lines = "inst\n" + "\n".join(instLines) + "\nend\n";
lines += "cars\n" + "\n".join(carLines) + "\nend";
print(lines);
import sys
import os
basePath = "T:\gtasa\data\maps\\";
folders = [ ".", "country", "generic", "interior", "LA", "leveldes", "SF", "vegas", "veh_mods", "exported2" ];
targetTag = "inst";
outputLines = "";
for folder in folders:
files = os.listdir(basePath + folder);
filteredFiles = [file for file in files if file.endswith(".ipl")];
for file in filteredFiles:
fp = open(basePath + folder + "\\" + file, "r");
print("[" + basePath + folder + "\\" + file + "]");
tagActive = False;
for line in fp:
if line.startswith(targetTag) and tagActive == False:
tagActive = True;
continue;
if tagActive == True:
if line.startswith("end"):
tagActive = False;
continue;
else:
outputLines += line;
fp.close();
fp = open(basePath + "output-" + targetTag + ".txt", "w+");
fp.write(outputLines);
fp.close();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment