Skip to content

Instantly share code, notes, and snippets.

@maludwig
Created March 20, 2022 19:45
Show Gist options
  • Save maludwig/87ab60893330004bddddcec3d2f6a9d5 to your computer and use it in GitHub Desktop.
Save maludwig/87ab60893330004bddddcec3d2f6a9d5 to your computer and use it in GitHub Desktop.
Timberborn World Lifter
#!/usr/bin/env python3
"""
Requires python 3 or higher
Usage:
This would lift a custom map, saved as "my_custom_map" by 8 blocks up vertically.
I doubt this will work with save files, but it should produce a new .timber file you can create a new game on
python --timber-path C:\Users\mitchell.ludwig\Documents\Timberborn\Maps\my_custom_map.timber --lift-by 8
"""
from os import mkdir, path, makedirs
import json
import zipfile
import argparse
def extract_timber_file(timber_path: str):
dir_path = timber_path.replace('.timber', '')
with zipfile.ZipFile(timber_path, 'r') as zip_ref:
zip_ref.extractall(dir_path)
return dir_path
def compress_timber_file(dest_dir_path: str):
dest_timber_path = f"{dest_dir_path}.timber"
print(f"Writing new timber file here: {dest_timber_path}")
with zipfile.ZipFile(dest_timber_path, 'w', compression=zipfile.ZIP_DEFLATED) as zip_ref:
zip_ref.write(path.join(dest_dir_path, 'world.json'), 'world.json')
def lift_heights(height_str: str, lift_by: int):
new_heights = []
for h in height_str.split(' '):
hn = int(h)
# print(f"{h} + 1 = {hn+1}")
new_heights.append(f"{int(h) + lift_by}")
return " ".join(new_heights)
def parse_args():
parser = argparse.ArgumentParser(description='Lifts timberborn maps.')
parser.add_argument('--timber-path', type=str, default='HundredIslands.timber', help='the path to a .timber map file')
parser.add_argument('--lift-by', type=int, default=16, help='the number of blocks to lift the map by')
args = parser.parse_args()
return args
def lift_terrain(world_data, lift_by: int):
new_height_array_str = lift_heights(world_data['Singletons']['TerrainMap']['Heights']['Array'], lift_by)
world_data['Singletons']['TerrainMap']['Heights']['Array'] = new_height_array_str
def lift_entities(data, lift_by: int):
if isinstance(data, dict):
if "Coordinates" in data:
if "Z" in data["Coordinates"]:
data["Coordinates"]["Z"] = data["Coordinates"]["Z"] + lift_by
else:
for val in data.values():
lift_entities(val, lift_by)
elif isinstance(data, list):
for val in data:
lift_entities(val, lift_by)
def main():
args = parse_args()
dir_path = extract_timber_file(args.timber_path)
world_path = path.join(dir_path, 'world.json')
with open(world_path) as world_file:
data = json.load(world_file)
print(data['Singletons']['TerrainMap']['Heights']['Array'])
lift_terrain(data, args.lift_by)
lift_entities(data, args.lift_by)
dest_dir_path = f"{dir_path}_lift_{args.lift_by}"
makedirs(dest_dir_path, exist_ok=True)
dest_world_path = path.join(dest_dir_path, 'world.json')
with open(dest_world_path,'w') as lifted_file:
json.dump(data, lifted_file)
compress_timber_file(dest_dir_path)
print("Done!")
if __name__ == '__main__':
main()
else:
print(__name__)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment