-
-
Save KillerInstinct/7f5fe35e9beb54d111642ddfb7a0f955 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# | |
# Structure information based on the work done by Karlovsky120 | |
# The structures were decompiled from his DLL located at | |
# https://github.com/Karlovsky120/7DaysProfileEditor/blob/master/release/0.14.7.2/7DaysSaveManipulator.dll | |
# | |
# This is a Python implementation of the 'Reader' functionality and does not support editing of | |
# save files. This purely supports my needs for reading player files to generate high scores. | |
# | |
# -Tavvy | |
import json | |
import os | |
import struct | |
BuffCategoryFlags = { | |
"0": "None", | |
"1": "Sickness", | |
"2": "Disease", | |
"4": "ArmorUp", | |
"8": "ArmorDown", | |
"12": "Armor", | |
"16": "StaminaUp", | |
"32": "StaminaDown", | |
"48": "Stamina", | |
"64": "HealthUp", | |
"128": "HealthDown", | |
"192": "Health", | |
"256": "SpeedModifier", | |
"512": "Bleeding", | |
"1024": "Drowning", | |
"2048": "Wellness", | |
"4096": "CoreTemp", | |
} | |
def main(): | |
#for filename in getPlayerFiles(): | |
# print filename | |
# readPlayerFile(filename) | |
readPlayerFile("blah") | |
def readPlayerFile(datafile): | |
DATAFILE = "76561198036343538.ttp" # Tavvy | |
#DATAFILE = datafile | |
playerFile = open(DATAFILE, "rb") | |
header = playerFile.read(4) | |
if header != "ttp\x00": | |
print "ERROR: File header does not match 'TTP'. Aborting." | |
exit(0) | |
ret = dict() | |
saveFileVersion = reader("byte", playerFile) | |
ret["saveFileVersion"] = saveFileVersion | |
ecd = dict() | |
ecd["entityCreationDataVersion"] = reader("byte", playerFile) | |
ecd["entityClass"] = reader("int32", playerFile) | |
ecd["id"] = reader("int32", playerFile) | |
ecd["lifetime"] = reader("float", playerFile) | |
ecd["currentPosition"] = { | |
"x": reader("float", playerFile), | |
"y": reader("float", playerFile), | |
"z": reader("float", playerFile), | |
}, | |
ecd["cameraPosition"] = { | |
"x": reader("float", playerFile), | |
"y": reader("float", playerFile), | |
"z": reader("float", playerFile), | |
} | |
ecd["onGround"] = reader("bool", playerFile), | |
ecd["bodyDamage"] = { | |
"bodyDamageVersion": reader("int32", playerFile), | |
"leftUpperLeg": reader("int16", playerFile), | |
"rightUpperLeg": reader("int16", playerFile), | |
"leftUpperArm": reader("int16", playerFile), | |
"rightUpperArm": reader("int16", playerFile), | |
"chest": reader("int16", playerFile), | |
"head": reader("int16", playerFile), | |
"dismemberedLeftUpperArm": reader("bool", playerFile), | |
"dismemberedRightUpperArm": reader("bool", playerFile), | |
"dismemberedHead": reader("bool", playerFile), | |
"dismemberedRightUpperLeg": reader("bool", playerFile), | |
"crippledRightLeg": reader("bool", playerFile), | |
"leftLowerLeg": reader("int16", playerFile), | |
"rightLowerLeg": reader("int16", playerFile), | |
"leftLowerArm": reader("int16", playerFile), | |
"rightLowerArm": reader("int16", playerFile), | |
"dismemberedLeftLowerArm": reader("bool", playerFile), | |
"dismemberedRightLowerArm": reader("bool", playerFile), | |
"dismemberedLeftLowerLeg": reader("bool", playerFile), | |
"dismemberedRightLowerLeg": reader("bool", playerFile), | |
"crippledLeftLeg": reader("bool", playerFile), | |
} | |
ecd["flag1"] = reader("bool", playerFile), | |
ecd["stats"] = { | |
"version": reader("int32", playerFile), | |
"buffCategoryFlags": enumBuffCategoryFlags(reader("int32", playerFile)), | |
} | |
immunity = [0] * 13 | |
# No clue why this is little endian... | |
num1 = struct.unpack(">hh", playerFile.read(4))[0] | |
for i in xrange(0, num1): | |
num2 = struct.unpack("i", playerFile.read(4)) | |
if i < len(immunity): | |
immunity[i] = num2 | |
# Health is the first stat parsed | |
ecd["stats"]["health"] = getStat(playerFile) | |
ecd["stats"]["stamina"] = getStat(playerFile) | |
ecd["stats"]["sickness"] = getStat(playerFile) | |
ecd["stats"]["gassiness"] = getStat(playerFile) | |
ecd["stats"]["speedModifier"] = getStat(playerFile) | |
ecd["stats"]["wellness"] = getStat(playerFile) | |
ecd["stats"]["coreTemp"] = getStat(playerFile) | |
ecd["stats"]["food"] = getStat(playerFile) | |
ecd["stats"]["water"] = getStat(playerFile) | |
ecd["stats"]["waterLevel"] = reader("float", playerFile) | |
buffTotal = playerFile.read(4) #reader("int32", playerFile) | |
ret["entityCreationData"] = ecd | |
print json.dumps(ret, indent=4) | |
print struct.unpack(">i", buffTotal)[0] | |
print struct.unpack("<i", buffTotal)[0] | |
print struct.unpack(">hh", buffTotal)[0] | |
print struct.unpack("<hh", buffTotal)[0] | |
print struct.unpack(">hh", buffTotal)[1] | |
print struct.unpack("<hh", buffTotal)[1] | |
print playerFile.tell() | |
playerFile.close() | |
def getPlayerFiles(): | |
""" | |
Get .ttp files from the CWD | |
""" | |
playerFiles = list() | |
for filename in os.listdir(os.getcwd()): | |
if filename.endswith(".ttp"): | |
playerFiles.append(filename) | |
return playerFiles | |
def enumBuffCategoryFlags(flag): | |
tmp = str(flag) | |
if tmp in BuffCategoryFlags: | |
return BuffCategoryFlags[tmp] | |
else: | |
print "ERROR: EntityCreationData.Stats.BuffCategoryFlags returned a flag which was unknown" | |
return None | |
def getStat(fh=""): | |
ret = { | |
"version": struct.unpack(">hh", fh.read(4))[0], # Defined as 5 | |
"value": reader("float", fh), # this.GA | |
"maxModifier": reader("float", fh), # this.IA | |
"valueModifier": reader("float", fh), # this.RA | |
"baseMax": reader("float", fh), # this.AA | |
"originalMax": reader("float", fh), # this.XA | |
"originalValue": reader("float", fh), # this.HA | |
"changed": reader("bool", fh), # this.CA | |
} | |
bufModifierCount = reader("int32", fh) | |
if bufModifierCount: | |
_ = fh.read(24) | |
return ret | |
def reader(byteType="", fileHandle=""): | |
""" | |
This function short-hands all of the code into the proper structure | |
parsing and byte counts. Mostly so I could type a little less. | |
""" | |
# 4 byte integer (int) | |
if byteType == "int32": | |
return struct.unpack("<i", fileHandle.read(4))[0] | |
# 2 byte integer (short) | |
elif byteType == "int16": | |
return struct.unpack("<h", fileHandle.read(2))[0] | |
# 1 byte represented as integer | |
elif byteType == "byte": | |
return struct.unpack("<b", fileHandle.read(1))[0] | |
# true/false | |
elif byteType == "bool": | |
return struct.unpack("<?", fileHandle.read(1))[0] | |
# 4 byte long | |
elif byteType == "float": | |
return struct.unpack("<f", fileHandle.read(4))[0] | |
# Error out | |
else: | |
print "ERROR: Invalid byteType." | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment