diff --git a/dynmap2bluemap.py b/dynmap2bluemap.py new file mode 100755 index 0000000..a376388 --- /dev/null +++ b/dynmap2bluemap.py @@ -0,0 +1,108 @@ +#!/usr/bin/python3 + +""" +A simple python3 script to convert Dynmap Markers to BlueMap markers. +Copyright (C) 2025 Benjamin Burkhardt + +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 . +""" + + +import yaml # to read from the Dynmap input file format (YAML!) +import json # to output in proper JSON format +import argparse # to parse the cli args! +import html # to unescape certain html-escaped strings (e.g. dynmap converts ' to ') + +parser = argparse.ArgumentParser( + prog='dynmap2bluemap - Markers', + description='A small helper script converting the basic structure of Dynmap markers to the one of BlueMap.', + epilog='© Benjamin Burkhardt, 2025') + +parser.add_argument('-m', '--minimal', help='Choose wether the output shall be minimal or not (»beautified«)!', action='store_true') +parser.add_argument('-n', '--indent', help='Specify the number of whitespaces to introduce for indentation in outputted json', default=4, type=int) +parser.add_argument('-i', '--input', help='Specify the file to read Dynmap formatted input from', default='input.yaml') +parser.add_argument('-o', '--output', help='Specify the file to write BlueMap formatted output to (if left, will be printed out on stdout)') +parser.add_argument('-p', '--privacynerd', help='Change how labels are converted according to the PrivacynerdMC conventions; DO NOT USE if you don\'t know what you are doing.', action='store_true') + +args = parser.parse_args() + +distance_mapping = { + 0: 15000, + 1: 3000, + 2: 2000, + 3: 1300, + 4: 800, + 5: 500, + 6: 300, +} + +with open(f"{args.input}") as stream: + try: + print(f"Reading from {args.input}...") + input_parsed = yaml.safe_load(stream) + print(f"Read the dynmap markers from {args.input}!\n") + except yaml.YAMLError as exc: + print(exc) + exit(1) + +print("Converting the Dynmap's marker structure to fit BlueMap...") +output = "" +for nr,marker_set in enumerate(input_parsed['sets'].values()): + out_marker_set = dict() + out_marker_set['label'] = marker_set['label'] + out_marker_set['toggleable'] = True + out_marker_set['default_hidden'] = marker_set['hide'] + out_markers = {} + for i,old_marker in enumerate(marker_set['markers'].values()): + if args.privacynerd: + new_label = html.unescape(old_marker['label']).split(' - ')[0] + new_detail = "
".join([''+new_label+'', '' + html.unescape(old_marker['label']).split(' - ')[1] + '']) + else: + new_label = html.unescape(old_marker['label']) + new_detail = "" + new_min_distance = (distance_mapping[old_marker["maxzoom"]] if "maxzoom" in old_marker.keys() else 0) + new_max_distance = (distance_mapping[old_marker["minzoom"]] if "minzoom" in old_marker.keys() else 100000000) + new_marker = { + 'type': 'poi', + 'label': new_label, + 'detail': new_detail, + 'listed': True, + 'min-distance': new_min_distance, + 'max-distance': new_max_distance, + 'position': {'x':old_marker['x'], 'y': old_marker['y'], 'z': old_marker['z']}, + 'icon': f'assets/custom-poi/{old_marker["icon"]}.png', + 'anchor': {'x': 16, 'y': 16}, + } + out_markers[f'marker_{i}'] = new_marker + out_marker_set['markers'] = out_markers + + if args.minimal: + output = f"{output}\nmarker_set_{nr}: {json.dumps(out_marker_set)}" + else: + output = f"{output}\nmarker_set_{nr}: {json.dumps(out_marker_set, indent=args.indent)}" + +output = output[1:] +print("Converted to BlueMap format.\n") + +if args.output: + with open(f"{args.output}", "w") as o: + print(f"Writing into {args.output} (this overrides currently existing contents of the file!)...") + o.write(output) + print(f"Wrote the output into {args.output}!") +else: + print("Copy the following lines into the marker_sets dict of any world.conf that you BlueMap instance reads.\nSee also: https://bluemap.bluecolored.de/wiki/customization/Markers.html\n") + print("------- CONFIG START -------") + print(output) + print("------- CONFIG END -------") + diff --git a/input.yaml b/input.yaml new file mode 100644 index 0000000..726657d --- /dev/null +++ b/input.yaml @@ -0,0 +1,29 @@ +%YAML 1.1 +--- +isSafe: true +sets: + markers: + hide: false + circles: { + } + deficon: default + areas: { + } + label: Markers + markers: + marker_1: + world: world + markup: false + x: 0 + icon: spawn + y: 64 + z: 0 + label: Spawn + minzoom: 1 + + lines: { + } + layerprio: 0 +playersets: { + } + diff --git a/output.json b/output.json new file mode 100644 index 0000000..39828c4 --- /dev/null +++ b/output.json @@ -0,0 +1,25 @@ +marker_set_0: { + "label": "Markers", + "toggleable": true, + "default_hidden": false, + "markers": { + "marker_0": { + "type": "poi", + "label": "Spawn", + "detail": "", + "listed": true, + "min-distance": 0, + "max-distance": 3000, + "position": { + "x": 0, + "y": 64, + "z": 0 + }, + "icon": "assets/custom-poi/spawn.png", + "anchor": { + "x": 16, + "y": 16 + } + } + } +} \ No newline at end of file