Leaderboard
Popular Content
Showing content with the highest reputation on 12/24/2012 in all areas
-
Bionicle: The Game Game Archive Extracting (Research and Tools)
McJobless and one other reacted to JrMasterModelBuilder for a topic
Bionicle: The Game Game Archive Extracting (Research and Tools) These are more like research tools than actual modding tools, but here we go: BIONICLE: The Game uses a archive format with the header "VOLT", to store all the assets. Within those archives are some additional archives I've been tinkering with. The ones I've had some luck with have the header "BIGB" followed by some command-line build arguments. Thanks to Google, I found a program that was made to decompress and extract the contents of files almost identical to this here: http://wiki.gbatemp.net/wiki/The_Conduit That program is made for a slightly different version of the archive format, so I re-wrote the program in Python below. So, without further ado, my partial file format specs and Python scripts. Main archives: Most of the sub-achives. #BIGB format. 0-3 - ASCII = File Header (BIGB) 4-7 - UINT32 = Offset of data - 16 (probably offset after header) 8-11 - UINT32 = Offset of data after name and before creation arguments - 12 (the amount to skip forward) 12-15 - UINT32 = Version Number? Always 0x01000000 16-79 - ASCII = Null terminated name of some kind. 80-127 - ASCII = Null terminated text of some kind. (normal) 128-131 - UINT32 = Segment 1 Uncompressed Offset? 0 means file contains no data. 132-135 - UINT32 = Segment 1 Uncompressed Offset? 0 means file contains no data. 136-139 - UINT32 = Segment 2 Compressed Offset? 0 means file contains no data. 140-143 - UINT32 = Segment 2 Compressed Offset? 0 means file contains no data. 144-399 - ASCII = Null terminated build command-line arguments. (NOTE: The data contained with is RLE compressed, my Python scripts below decompress these block during extraction.) VOLTExtractor.py , "size", "indexoffset":uint32(fileOffset+8), "unknown":uint32(fileOffset)}) fileOffset += 12 #Remember where the index is. indexOffset = fileOffset for i,v in enumerate(fileList): #Set the file offset to the index start plus the offset in the index. fileOffset = indexOffset + v["indexoffset"] #Set the file offset. fileList[i]["offset"] = uint32(fileOffset) fileOffset += 8#Skip mystery null block as well. #Set the file size. fileList[i]["size"] = uint32(fileOffset) fileOffset += 8#Skip mystery null block as well. #Read in the name until the null byte. if bytesAre == "str": while fileData[fileOffset] != b"\x00": fileList[i]["filename"] += fileData[fileOffset] fileOffset += 1 else: while fileData[fileOffset] != 0x00: fileList[i]["filename"] += chr(fileData[fileOffset]) fileOffset += 1 #And skip the null byte for the new entry. fileOffset += 1 #Create output path from input path. outFolder = path.split(os.sep) endFolder = outFolder[-1].split(".") extension = endFolder[-1] endFolder[0:-1] endFolder = ".".join(endFolder[0:-1]) + "_" + extension outFolder[-1] = endFolder outFolder = os.sep.join(outFolder) #Create the first non-existant folder to extract to. if os.path.exists(outFolder): i = 1 while(os.path.exists(outFolder + "_" + str(i))): i += 1 outFolder = outFolder + "_" + str(i) #Make the output folder. os.makedirs(outFolder) #Create a log file to log extracted files. with open((outFolder + os.sep + "__extract.log"), "w") as log: #Write the header to the log file. log.write(path.split(os.sep).pop() + "\ttotalfiles: " + str(totalFiles) + "\tindexsize: " + str(indexSize) + "\r\nfilename\toffset\tsize\tindexoffset\tunknown\r\n") #Loop through the list of files, saving them. for a in fileList: #Write the file. with open((outFolder + os.sep + a["filename"]), "wb") as f: #Write data to the log. log.write(a["filename"] + "\t" + str(a["offset"]) + "\t" + str(a["size"]) + "\t" + str(a["indexoffset"]) + "\t" + str(a["unknown"]) + "\r\n") f.write(fileData[a["offset"]:a["offset"]+a["size"]]) f.close() #Close the log. log.close() print("\tCOMPLETE: " + str(len(fileList)) + " files extracted.") return True #Detect if executable or not. fileName = sys.argv[0].split(os.sep).pop() if fileName[-3:] == ".py" or fileName[-4:] == ".pyw": runCommand = "python " + fileName else: runCommand = fileName if len(sys.argv) > 1: for i in range(1, len(sys.argv)): extract(sys.argv[i]) else: print("VOLT Extractor 1.0\n\nThis program will extract VOLT archives to an adjacent folder.\n\nCOPYRIGHT:\n\t(C) 2012 JrMasterModelBuilder\n\nLICENSE:\n\tGNU GPLv3\n\tYou accept full responsibility for how you use this program.\n\nUSEAGE:\n\t" + runCommand + " <LIST_OF_FILE_PATHS>") """ VOLT Extractor - VOLT archive extractor. Copyright (C) 2012 JrMasterModelBuilder You accept full responsibility for how you use this program. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. """ import os import sys def extract(path): def uint32(offset): if bytesAre == "str": return ord(fileData[offset]) + (ord(fileData[offset+1]) * 256) + (ord(fileData[offset+2]) * 65536) + (ord(fileData[offset+3]) * 16777216) else: return fileData[offset] + (fileData[offset+1] * 256) + (fileData[offset+2] * 65536) + (fileData[offset+3] * 16777216) #Check if this version of Python treats bytes as int or str bytesAre = type(b'a'[0]).__name__ print("PROCESSING: " + path) #Open the file if valid. try: with open(path, "rb") as f: fileData = f.read() except IOError: print("\tERROR: Failed to read file.") return False if len(fileData) < 4 or fileData[0:4] != b"VOLT": print("\tERROR: Not a VOLT file.") return False print("\tEXTRACTING: Please wait.") fileList = [] fileOffset = 0 #Skip over the header. fileOffset += 8 #Read in info on the file. totalFiles = uint32(fileOffset) fileOffset += 4 indexSize = uint32(fileOffset) fileOffset += 4 #Read the initial index to find index entry offsets in the next index. for i in range(totalFiles): #Add file to the list. fileList.append({"filename":"", "offset" BIGBExtractor.py """ BIGB Extractor - BIGB archive extractor. Copyright (C) 2012 JrMasterModelBuilder You accept full responsibility for how you use this program. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. """ import os import sys def extract(path): def uint32(offset): if bytesAre == "str": return ord(fileData[offset]) + (ord(fileData[offset+1]) * 256) + (ord(fileData[offset+2]) * 65536) + (ord(fileData[offset+3]) * 16777216) else: return fileData[offset] + (fileData[offset+1] * 256) + (fileData[offset+2] * 65536) + (fileData[offset+3] * 16777216) def decompress(offsetStart, length, decompLength): outputData = [] offset = offsetStart endBlock = offset + length outputOffset = 0 while True: commandByte = fileData[offset] if bytesAre == "str": commandByte = ord(commandByte) # print(offset, commandByte) offset += 1 if commandByte & 0x80: #Back reference. # print("Back reference.") byte2 = fileData[offset] if bytesAre == "str": byte2 = ord(byte2) offset += 1 #Make up for taking 2 bytes. dupeBytes = (byte2 & 0xF) + 2 #Bytes to go back. srcRel = commandByte srcRel = (srcRel << 4 | byte2 >> 4) srcRel = (srcRel ^ 0xFFF) + 2 srcOffset = outputOffset - srcRel if srcOffset < 0: print("\tERROR: Back reference before start of file.") return outputData #Append the back reference to the output. outputData.extend(outputData[srcOffset:srcOffset+dupeBytes]) #Skip forward. outputOffset += dupeBytes elif commandByte & 0x40: #RLE. # print("RLE.") #How many bytes, no point if less than 2. byteCount = (commandByte & 0x3F) + 2 repeatedByte = fileData[offset] offset += 1 #Append the byte to the output however many times. for _ in range(byteCount): outputData.append(repeatedByte) #Skip forward. outputOffset += byteCount else: #Literal. # print("Literal.") #How many bytes, at least 1. byteCount = (commandByte & 0x3F) + 1 #Append the bytes to the output. outputData.extend(fileData[offset:offset+byteCount]) #Skip forward. offset += byteCount outputOffset += byteCount if offset >= endBlock or len(outputData) >= decompLength: if offset > endBlock: print("\tERROR: Decompressing ran over.") if len(outputData) > decompLength: print("\tERROR: Too many bytes decompressed.") return outputData #Check if this version of Python treats bytes as int or str bytesAre = type(b'a'[0]).__name__ print("PROCESSING: " + path) #Open the file if valid. try: with open(path, "rb") as f: fileData = f.read() except IOError: print("\tERROR: Failed to read file.") return False if len(fileData) < 4 or fileData[0:4] != b"BIGB": print("\tERROR: Not a BIGB file.") return False print("EXTRACTING: Please wait.") fileOffset = 0 #Skip over the header. fileOffset += 4 #Get the offset of the data including the 16 byte header. dataOffset = uint32(fileOffset) + 16 fileOffset += 4 #Get the dictionary offset jump including the 12 bytes of header already read (ignore 0x01000000 verison number?). fileOffset = uint32(fileOffset) + 12 #Get data about the 2 compressed blocks. fileBlocks = [ { "decomp":uint32(fileOffset), "comp":uint32(fileOffset+8) } , { "decomp":uint32(fileOffset+4), "comp":uint32(fileOffset+12) } ] fileOffset += 16 # print(fileBlocks) buildArguments = "" #Read in the until the null byte. if bytesAre == "str": while fileData[fileOffset] != b"\x00": buildArguments += fileData[fileOffset] fileOffset += 1 else: while fileData[fileOffset] != 0x00: buildArguments += chr(fileData[fileOffset]) fileOffset += 1 #Skip to the data. fileOffset = dataOffset #Create output path from input path. outFolder = path.split(os.sep) endFolder = outFolder[-1].split(".") extension = endFolder[-1] endFolder[0:-1] endFolder = ".".join(endFolder[0:-1]) + "_" + extension outFolder[-1] = endFolder outFolder = os.sep.join(outFolder) #Create the first non-existant folder to extract to. if os.path.exists(outFolder): i = 1 while(os.path.exists(outFolder + "_" + str(i))): i += 1 outFolder = outFolder + "_" + str(i) #Make the output folder. os.makedirs(outFolder) #Create a log file to log extracted files. with open((outFolder + os.sep + "__extract.log"), "w") as log: #Write the header to the log file. p = "BUILD ARGUMENTS:\r\n\t" + buildArguments + "\r\n\r\n" print(p) log.write(p) #Loop through the list of files, saving them. for i,a in enumerate(fileBlocks): #Get the data from each file in local variables for speed. comp = a["comp"] decomp = a["decomp"] p = "BLOCK " + str(i) + ":\r\n\tOFFSET: " + str(fileOffset) + "\r\n\tCOMPRESSED: " + str(comp) + "\r\n\tDECOMPRESSED: " + str(decomp) + "\r\n" if comp == 0: p += "\tNOTE: Block does not exist.\r\n\r\n" print(p) log.write(p) continue #Write the file. with open(outFolder + os.sep + "BLOCK_" + str(i) + ".bin", "wb") as f: #Ckeck if compressed. if comp < decomp: data = decompress(fileOffset, comp, decomp) elif comp == decomp: data = fileData[fileOffset:fileOffset+comp] else: p += "\tERROR: Decompressed size less than compressed size.\r\n\r\n" leng = len(data) p += "\tOUTPUTSIZE: " + str(leng) if leng == decomp: p += " (EQUAL)" if leng < decomp: p += " (LESS)" if leng > decomp: p += " (MORE)" p += "\r\n\r\n" #If bytes are stings, compensate. if bytesAre == "str": #If a list, convert to byte array for writing. if type(data).__name__ == "list": data = bytearray(data) f.write(data) else: f.write(bytes(data)) f.close() #Log data on each file. print(p) log.write(p) #Increment the offset for the next block. fileOffset += comp print("COMPLETE: Files extracted.\r\n\r\n") return True #Detect if executable or not. fileName = sys.argv[0].split(os.sep).pop() if fileName[-3:] == ".py" or fileName[-4:] == ".pyw": runCommand = "python " + fileName else: runCommand = fileName if len(sys.argv) > 1: for i in range(1, len(sys.argv)): extract(sys.argv[i]) else: print("BIGB Extractor 1.0\n\nThis program will extract BIGB archives to an adjacent folder.\n\nCOPYRIGHT:\n\t(C) 2012 JrMasterModelBuilder\n\nLICENSE:\n\tGNU GPLv3\n\tYou accept full responsibility for how you use this program.\n\nUSEAGE:\n\t" + runCommand + " <LIST_OF_FILE_PATHS>") These scripts should work on Python versions 2.7 - 3.3 but will be fastest on 3.0 or higher. Some of the decompressed blocks have what appear to be a list of multiple WAV headers, followed by the audio data. No idea how that all works yet.2 points -
2 points
-
2 points
-
LDD Developer Mode
Fluffy Cupcake reacted to le717 for a topic
Glad tidings I bring, to you and your brick. Good tidings of Christmas and a Happy New Year! I think it is time for me to give out my Chrstmas gift, so on the first (and only) day of Christmas, the Triangle gives to you, LDD Developer Mode! Yes, you are reading correctly: LDD Developer Mode. I found it in the 4.2.5 code a while back, but just got around to figuring out how to enable it. So without futher ado, how to enable LDD Developer Mode! NOTE: This should work in LDD 4.2.5 and 4.3.5. Untested on anything lower than 4.3.5. Extract Assets.lif using 's LEGO Digitial Designer LIF Extractor. Browse to Assets\Scripts\EditMode\MenuLayout.xml, make a copy of the file (so you have an original), and open it in Notepad++ or some other good XML editor. This part is easier to show than explain, so I'll just link to to two images to see how to enable Dev Mode. When you are done, save the file. Image 1 Image 2 Browse to Assets\Scripts\ViewMode\MenuLayout.xml, also make a copy of the file (for the same reason as above), and open it. Again, take a look at these images to view how to enable the mode. Save when done. Image 3 Image 4 Load LDD. Tada! You have now enabled LDD Developer mode! Now for a few notes on the new features enabled. Menu Layout LUA Console Physics Test Best. LDD. Feature. Ever. Normal Physics: "Toggle Physics Test": LDD Web Server If you know what is good for you, you will leave these alone. I clicked LEGO.com, and now LDD says it cannot access the Internet when I run it without a LIF. Play Ball! Unsure what this does, I can't get it to do a thing. Complete Gallery of LDD Developer Mode Images. Merry Christmas, and happy LDD Modding, everybody!1 point -
Tutorial: No JAM Archives
Alcom Isst reacted to le717 for a topic
Flex (AKA LUModder), did you even finish reading the topic before you posted that? The reason that error message came up has already been discovered. In fact, rio and I figured out the fix, and in the process, helped out thr LR modding research... :/1 point -
Tutorial: Skin Texturing
CaptainGolem reacted to lol username for a topic
... You unlock Veronica Voltage's car set and minifigure parts after beating all the time trials... :/1 point -
Not A Surprise
Lair reacted to Redacted for a topic
I never gave attention to starwars... i prefer star-trek :P1 point -
The Walking Dead
Redacted reacted to Kmlkmljkl for a topic
All episodes are released and ready for purchasing! http://store.steampo...com/app/207610/ FAQ: This really is an amazing game. You should try it out, even if you don't like Point&Click games!1 point -
1 point
-
The LEGO Island Cards - Christmas Edition (RRU Special) (UPDATE 3.0!)
Lair reacted to Cirevam for a topic
Neat program. Even neater that you're giving this to us and friends of yours on other forums. Thank you.1 point -
Rock Raiders United Incorporated Research - Help Wanted!
Zephyria reacted to McJobless for a topic
Did you not see the OP where it says that the floors are massive enough to essentially fit anything? I mean, one level is an entire f****ing starship docking station with 4 separate fleets... 775, 776, 780 accepted. Rooms can be soundproofed. Accepted. No-one has wanted Floor 999 yet...1 point -
Rock Raiders United Incorporated Research - Help Wanted!
STUDZ reacted to Zephyria for a topic
I request floor 666 as my own private chambers.1 point -
1 point
-
IT'S COMMING TO REALTIY
STUDZ reacted to Lair for a topic
None of them were ever supposed to be memes. Stop this. You're just being shameful at this point. You can't even do this you haven't been able to do this since before you joined. t('' v)1 point -
Portuguese LEGO Island
Brigs reacted to lol username for a topic
... Oh my goodness, the Infomaniac's voice here makes his English LI2 voice sound good. D81 point
