From 50c3e40a228e0cf20f03aff5869da1099cc9b096 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 26 May 2017 20:05:38 -0700 Subject: [PATCH] Adds mapmergePY More or less because I CBA to install java right now. --- html/changelogs/chaoko99-mapmergepy.yml | 37 ++ tools/mapmergepy/1 Prepare Maps.bat | 12 + tools/mapmergepy/2 Clean Maps.bat | 4 + .../__pycache__/map_helpers.cpython-36.pyc | Bin 0 -> 7998 bytes tools/mapmergepy/map_helpers.py | 524 ++++++++++++++++++ tools/mapmergepy/mapmerger.py | 81 +++ tools/mapmergepy/prepare_maps.sh | 2 + 7 files changed, 660 insertions(+) create mode 100644 html/changelogs/chaoko99-mapmergepy.yml create mode 100644 tools/mapmergepy/1 Prepare Maps.bat create mode 100644 tools/mapmergepy/2 Clean Maps.bat create mode 100644 tools/mapmergepy/__pycache__/map_helpers.cpython-36.pyc create mode 100644 tools/mapmergepy/map_helpers.py create mode 100644 tools/mapmergepy/mapmerger.py create mode 100644 tools/mapmergepy/prepare_maps.sh diff --git a/html/changelogs/chaoko99-mapmergepy.yml b/html/changelogs/chaoko99-mapmergepy.yml new file mode 100644 index 0000000000..32e38564aa --- /dev/null +++ b/html/changelogs/chaoko99-mapmergepy.yml @@ -0,0 +1,37 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: chaoko99 + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Added mapmerge PY to the \tools directory of the Vorestation repository." + diff --git a/tools/mapmergepy/1 Prepare Maps.bat b/tools/mapmergepy/1 Prepare Maps.bat new file mode 100644 index 0000000000..d878510e3b --- /dev/null +++ b/tools/mapmergepy/1 Prepare Maps.bat @@ -0,0 +1,12 @@ +@echo off +cd ../../maps/ + +for /R %%f in (*.dmm) do copy "%%f" "%%f.backup" + +cls +echo All dmm files in maps directories have been backed up +echo Now you can make your changes... +echo --- +echo Remember to run Run_Map_Merge.bat just before you commit your changes! +echo --- +pause diff --git a/tools/mapmergepy/2 Clean Maps.bat b/tools/mapmergepy/2 Clean Maps.bat new file mode 100644 index 0000000000..b651f5da71 --- /dev/null +++ b/tools/mapmergepy/2 Clean Maps.bat @@ -0,0 +1,4 @@ +@echo off +set MAPROOT="../../maps/" +python mapmerger.py %1 %MAPROOT% +pause \ No newline at end of file diff --git a/tools/mapmergepy/__pycache__/map_helpers.cpython-36.pyc b/tools/mapmergepy/__pycache__/map_helpers.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bee5f17afa8c4d4a7ea784c168c99d81e428209 GIT binary patch literal 7998 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 1: + i = 1 + nextnew = key + while i < difference: + nextnew = get_next_key(nextnew) + unused_keys.append(nextnew) + i += 1 + sort = 1 + + + #Recycle outdated keys with any new tile data, starting from the bottom of the dictionary + i = 0 + for key, value in reversed(tempDict.items()): + recycled_key = key + if len(unused_keys) > 0: + recycled_key = unused_keys.pop() + + for coord, gridkey in tempGrid.items(): + if gridkey == None: + continue + if gridkey == key: + mergeGrid[coord] = recycled_key + tempGrid[coord] = None + + originalDict[recycled_key] = value + + #if gaps in the key sequence were found, sort the dictionary for cleanliness + if sort == 1: + sorted_dict = collections.OrderedDict() + next_key = get_next_key("") + while len(sorted_dict) < len(originalDict): + try: + sorted_dict[next_key] = originalDict[next_key] + except KeyError: + pass + next_key = get_next_key(next_key) + originalDict = sorted_dict + + if tgm: + with open(newfile, "w") as output: + write_dictionary_tgm(output, originalDict) + write_grid_coord_small(output, mergeGrid) + else: + with open(newfile, "wt", encoding='cp1252', newline='\n') as output: + write_dictionary_dmm(output, originalDict) + write_grid_dmm(output, mergeGrid) + return 1 + +#write dictionary in tgm format +def write_dictionary_tgm(output, dictionary): + output.write("//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE \n") + for key, list_ in dictionary.items(): + output.write("\"{}\" = (\n".format(key)) + + for thing in list_: + buffer = "" + in_quote_block = False + in_varedit_block = False + for char in thing: + + if in_quote_block: + if char == "\"": + in_quote_block = False + buffer = buffer + char + continue + elif char == "\"": + in_quote_block = True + buffer = buffer + char + continue + + if not in_varedit_block: + if char == "{": + in_varedit_block = True + buffer = buffer + "{\n\t" + continue + else: + if char == ";": + buffer = buffer + ";\n\t" + continue + elif char == "}": + buffer = buffer + "\n\t}" + in_varedit_block = False + continue + + buffer = buffer + char + + if list_.index(thing) != len(list_) - 1: + buffer = buffer + ",\n" + output.write(buffer) + + output.write(")\n") + +#thanks to YotaXP for finding out about this one +def write_grid_coord_small(output, grid): + output.write("\n") + + for x in range(1, maxx+1): + output.write("({},{},1) = {{\"\n".format(x, 1, 1)) + for y in range(1, maxy): + output.write("{}\n".format(grid[x,y])) + output.write("{}\n\"}}\n".format(grid[x,maxy])) + +def search_key(dictionary, data): + for key, value in dictionary.items(): + if value == data: + return key + return None + +def generate_new_key(dictionary): + last_key = next(reversed(dictionary)) + return get_next_key(last_key) + +def get_next_key(key): + if key == "": + return "".join("a" for _ in range(key_length)) + + length = len(key) + new_key = "" + carry = 1 + for char in key[::-1]: + if carry <= 0: + new_key = new_key + char + continue + if char == 'Z': + new_key = new_key + 'a' + carry += 1 + length -= 1 + if length <= 0: + return "OVERFLOW" + elif char == 'z': + new_key = new_key + 'A' + else: + new_key = new_key + chr(ord(char) + 1) + if carry > 0: + carry -= 1 + return new_key[::-1] + +#still does not support more than one z level per file, but should parse any format +def parse_map(map_file): + with open(map_file, "r") as map_input: + characters = map_input.read() + + in_quote_block = False + in_key_block = False + in_data_block = False + in_varedit_block = False + after_data_block = False + escaping = False + skip_whitespace = False + + dictionary = collections.OrderedDict() + curr_key = "" + curr_datum = "" + curr_data = list() + + in_map_block = False + in_coord_block = False + in_map_string = False + iter_x = 0 + adjust_y = True + + curr_num = "" + reading_coord = "x" + + global key_length + global maxx + global maxy + curr_x = 0 + curr_y = 0 + curr_z = 1 + grid = dict() + + for char in characters: + + if not in_map_block: + + if char == "\n" or char == "\t": + continue + + if in_data_block: + + if in_varedit_block: + + if in_quote_block: + if char == "\\": + curr_datum = curr_datum + char + escaping = True + continue + + if escaping: + curr_datum = curr_datum + char + escaping = False + continue + + if char == "\"": + curr_datum = curr_datum + char + in_quote_block = False + continue + + curr_datum = curr_datum + char + continue + + if skip_whitespace and char == " ": + skip_whitespace = False + continue + skip_whitespace = False + + if char == "\"": + curr_datum = curr_datum + char + in_quote_block = True + continue + + if char == ";": + skip_whitespace = False + curr_datum = curr_datum + char + continue + + if char == "}": + curr_datum = curr_datum + char + in_varedit_block = False + continue + + curr_datum = curr_datum + char + continue + + if char == "{": + curr_datum = curr_datum + char + in_varedit_block = True + continue + + if char == ",": + curr_data.append(curr_datum) + curr_datum = "" + continue + + if char == ")": + curr_data.append(curr_datum) + dictionary[curr_key] = tuple(curr_data) + curr_data = list() + curr_datum = "" + curr_key = "" + in_data_block = False + after_data_block = True + continue + + curr_datum = curr_datum + char + continue + + if in_key_block: + if char == "\"": + in_key_block = False + key_length = len(curr_key) + else: + curr_key = curr_key + char + continue + #else we're looking for a key block, a data block or the map block + + if char == "\"": + in_key_block = True + after_data_block = False + continue + + if char == "(": + if after_data_block: + in_map_block = True + in_coord_block = True + after_data_block = False + curr_key = "" + continue + else: + in_data_block = True + after_data_block = False + continue + + else: + + if in_coord_block: + if char == ",": + if reading_coord == "x": + curr_x = string_to_num(curr_num) + if curr_x > maxx: + maxx = curr_x + iter_x = 0 + curr_num = "" + reading_coord = "y" + elif reading_coord == "y": + curr_y = string_to_num(curr_num) + if curr_y > maxy: + maxy = curr_y + curr_num = "" + reading_coord = "z" + else: + pass + continue + + if char == ")": + in_coord_block = False + reading_coord = "x" + curr_num = "" + #read z here if needed + continue + + curr_num = curr_num + char + continue + + if in_map_string: + + if char == "\"": + in_map_string = False + adjust_y = True + curr_y -= 1 + continue + + if char == "\n": + if adjust_y: + adjust_y = False + else: + curr_y += 1 + if curr_x > maxx: + maxx = curr_x + if iter_x > 1: + curr_x = 1 + iter_x = 0 + continue + + + curr_key = curr_key + char + if len(curr_key) == key_length: + iter_x += 1 + if iter_x > 1: + curr_x += 1 + + grid[curr_x, curr_y] = curr_key + curr_key = "" + continue + + + #else look for coordinate block or a map string + + if char == "(": + in_coord_block = True + continue + if char == "\"": + in_map_string = True + continue + + if curr_y > maxy: + maxy = curr_y + + data = dict() + data["dictionary"] = dictionary + data["grid"] = grid + return data + +#subtract keyB from keyA +def key_difference(keyA, keyB): + if len(keyA) != len(keyB): + return "you fucked up" + + Ayek = keyA[::-1] + Byek = keyB[::-1] + + result = 0 + for i in range(0, len(keyA)): + base = 52**i + A = 26 if Ayek[i].isupper() else 0 + B = 26 if Byek[i].isupper() else 0 + result += ( (ord(Byek[i].lower()) + B) - (ord(Ayek[i].lower()) + A) ) * base + return result + +def string_to_num(s): + try: + return int(s) + except ValueError: + return -1 + +#writes a tile data dictionary the same way Dreammaker does +def write_dictionary_dmm(output, dictionary): + for key, value in dictionary.items(): + output.write("\"{}\" = ({})\n".format(key, ",".join(value))) + +#writes a map grid the same way Dreammaker does +def write_grid_dmm(output, grid): + output.write("\n") + output.write("(1,1,1) = {\"\n") + + for y in range(1, maxy+1): + for x in range(1, maxx+1): + try: + output.write(grid[x,y]) + except KeyError: + print("Key error: ({},{})".format(x,y)) + output.write("\n") + output.write("\"}") + output.write("\n") + +#inflated map grid; unused +def write_grid_coord(filename, grid): + with open(filename, "a") as output: + output.write("\n") + for y in range(1, maxy+1): + for x in range(1, maxx+1): + output.write("({},{},1) = {{\"{}\"}}\n".format(x, y, grid[x,y])) + +def key_compare(keyA, keyB): #thanks byond for not respecting ascii + pos = 0 + for a in keyA: + pos += 1 + count = pos + for b in keyB: + if(count > 1): + count -= 1 + continue + if a.islower() and b.islower(): + if(a < b): + return -1 + if(a > b): + return 1 + break + if a.islower() and b.isupper(): + return -1 + if a.isupper() and b.islower(): + return 1 + if a.isupper() and b.isupper(): + if(a < b): + return -1 + if(a > b): + return 1 + break + return 0 diff --git a/tools/mapmergepy/mapmerger.py b/tools/mapmergepy/mapmerger.py new file mode 100644 index 0000000000..0a177eb07a --- /dev/null +++ b/tools/mapmergepy/mapmerger.py @@ -0,0 +1,81 @@ +#!/usr/bin/python3 + +import sys +import os +import pathlib +import map_helpers +import shutil + +def main(map_folder): + list_of_files = list() + for root, directories, filenames in os.walk(map_folder): + for filename in [f for f in filenames if f.endswith(".dmm")]: + list_of_files.append(pathlib.Path(root, filename)) + + last_dir = "" + for i in range(0, len(list_of_files)): + this_dir = list_of_files[i].parent + if last_dir != this_dir: + print("--------------------------------") + last_dir = this_dir + print("[{}]: {}".format(i, str(list_of_files[i])[len(map_folder):])) + + print("--------------------------------") + in_list = input("List the maps you want to merge (example: 1,3-5,12):\n") + in_list = in_list.replace(" ", "") + in_list = in_list.split(",") + + valid_indices = list() + for m in in_list: + index_range = m.split("-") + if len(index_range) == 1: + index = string_to_num(index_range[0]) + if index >= 0 and index < len(list_of_files): + valid_indices.append(index) + elif len(index_range) == 2: + index0 = string_to_num(index_range[0]) + index1 = string_to_num(index_range[1]) + if index0 >= 0 and index0 <= index1 and index1 < len(list_of_files): + valid_indices.extend(range(index0, index1 + 1)) + +# if tgm == "1": +# print("\nMaps will be converted to tgm.") +# tgm = True +# else: +# print("\nMaps will not be converted to tgm.") +# tgm = False + tgm = False + + print("\nMerging these maps:") + for i in valid_indices: + print(str(list_of_files[i])[len(map_folder):]) + merge = input("\nPress Enter to merge...") + if merge == "abort": + print("\nAborted map merge.") + sys.exit() + else: + for i in valid_indices: + path_str = str(list_of_files[i]) + shutil.copyfile(path_str, path_str + ".before") + path_str_pretty = path_str[len(map_folder):] + try: + if map_helpers.merge_map(path_str, path_str + ".backup", tgm) != 1: + print("ERROR MERGING: {}".format(path_str_pretty)) + os.remove(path_str + ".before") + continue + print("MERGED: {}".format(path_str_pretty)) + except FileNotFoundError: + print("\nERROR: File not found! Make sure you run 'Prepare Maps.bat' before merging.") + print(path_str_pretty + " || " + path_str_pretty + ".backup") + + print("\nFinished merging.") + print("\nNOTICE: A version of the map files from before merging have been created for debug purposes.\nDo not delete these files until it is sure your map edits have no undesirable changes.") + +def string_to_num(s): + try: + return int(s) + except ValueError: + return -1 + +if __name__ == "__main__": + main(sys.argv[1]) diff --git a/tools/mapmergepy/prepare_maps.sh b/tools/mapmergepy/prepare_maps.sh new file mode 100644 index 0000000000..f1ea86ce45 --- /dev/null +++ b/tools/mapmergepy/prepare_maps.sh @@ -0,0 +1,2 @@ +#!/bin/bash +find ../../maps | grep \.dmm$ | xargs -l1 -I{} cp {} {}.backup \ No newline at end of file