Skip to content

Instantly share code, notes, and snippets.

@KillerInstinct
Last active October 13, 2016 15:25
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 KillerInstinct/7f5fe35e9beb54d111642ddfb7a0f955 to your computer and use it in GitHub Desktop.
Save KillerInstinct/7f5fe35e9beb54d111642ddfb7a0f955 to your computer and use it in GitHub Desktop.
#!/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