-
Notifications
You must be signed in to change notification settings - Fork 0
/
mapmerge.py
executable file
·233 lines (193 loc) · 7.9 KB
/
mapmerge.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#!/usr/bin/env python3
"""Merge webmap-data and CampaignCartographer(CC) exports into a single CC-File"""
import argparse
import json
import logging
from datetime import datetime
from lib.pathfinder.util import get_trader_type, trader_colors, trader_descriptions, manhattan
logging.basicConfig(level=logging.DEBUG)
log = logging.getLogger()
known_features = {} # (x,z) key -> feature_spec
doublets = 0
def is_doubled(pos, feature):
"""
:param tuple pos: (x,z)
:param feature: feature-spec in CC-Format
:return bool: Is feature double?
"""
global doublets
server_icon = feature["ServerIcon"]
trader_type = get_trader_type(feature['Title'])
for key in known_features:
if manhattan(key, pos) < 10:
item = known_features[key]
if item['ServerIcon'] == server_icon and trader_type == get_trader_type(item['Title']):
log.debug(f"Considered doublet: {feature['Title']} {pos} =~ {key} {item['Title']}")
doublets += 1
return True
return False
def process_translocator(indata, waypoints, offset):
"""Add single translocator in webmap-format to waypoints
:param indata:
:param waypoints:
:param tuple offset: Worldspawn in absolute coordinates
:return: waypoints
"""
global known_features
def tl_spec(tl, depth):
nonlocal offset
global doublets
spec = {
"Title": f"Translocator to ({tl[0]}, {depth}, {-tl[1]})",
"DetailText": None,
"ServerIcon": "spiral",
"DisplayedIcon": "spiral",
"Colour": "#FFFF00FF",
"Position": dict(X=tl[0] + offset[0], Y=depth, Z=-tl[1] + offset[1]), # Webmap has Z * -1 for "reasons"
"Pinned": False,
"Selected": True
}
pos = (spec['Position']['X'], spec['Position']['Z'])
if pos in known_features:
log.debug(f"Coordinate {pos} already has a feature")
doublets += 1
return False
known_features[pos] = spec
return spec
d1, d2 = indata['properties']['depth1'], indata['properties']['depth2']
tl1, tl2 = indata['geometry']['coordinates']
tl1_spec = tl_spec(tl1, d1)
tl2_spec = tl_spec(tl2, d2)
if tl1_spec:
waypoints.append(tl1_spec)
if tl2_spec:
waypoints.append(tl2_spec)
return waypoints
def process_trader(indata, waypoints, offset):
"""Add single Trader in webmap-format to waypoints
:param indata:
:param waypoints:
:param tuple offset: Worldspawn in absolute coordinates
:return: waypoints
"""
global known_features
global doublets
spec = {
"Title": "Unknown Trader",
"DetailText": None,
"ServerIcon": "trader",
"DisplayedIcon": "trader",
"Colour": "#303030",
"Position": dict(X=0, Y=0, Z=0),
"Pinned": False,
"Selected": True
}
name = indata['properties']['name']
wares = indata['properties']['wares']
trader_type = get_trader_type(wares)
spec['Title'] = f"{name} the {trader_descriptions[trader_type]}"
spec['Colour'] = trader_colors[trader_type]
x = spec['Position']['X'] = indata['geometry']['coordinates'][0] + offset[0]
spec['Position']['Y'] = indata['properties']['z'] # Webmap calls the vs-Y "z"
z = spec['Position']['Z'] = -indata['geometry']['coordinates'][1] + offset[1] # Webmap has Z * -1 for "reasons"
if not is_doubled((x, z), spec):
waypoints.append(spec)
known_features[(x, z)] = spec
return waypoints
def process_landmark(indata, outdata, offset):
raise NotImplementedError
def process_base(indata, outdata, offset):
raise NotImplementedError
def process_geojson(filename, map_features=[], no_traders=False, no_tls=False):
"""
The webmap uses a geojson file for each type of feature.
Figure out the type, convert coordinates to absolute and
attach the features to the featurelist.
:param filename: path to geojson
:param map_features: List of Features
:param bool no_traders: Ignore Waypoints with Trader-Icon
:param bool no_tls: Ignore Waypoints with Spiral-Icon
:return: map_features
"""
with open(filename) as f:
data = json.load(f)
if data['name'] == 'translocators':
if no_tls:
logging.warning(f"--notls was set but {filename} only contains TL's! (ignoring file)")
return map_features
process = process_translocator
elif data['name'] == 'traders':
if no_traders:
logging.warning(f"--notraders was set but {filename} only contains Traders! (ignoring file)")
return map_features
process = process_trader
elif data['name'] == 'landmarks':
process = process_landmark
elif data['name'] == 'players_bases':
process = process_base
for item in data['features']:
process(item, map_features, offset)
return map_features
def process_cc_json(filename, map_features, no_traders=False, no_tls=False):
"""Attach features from a CampaignCartographer file
Apply filters, but leave entries otherwise unmodified.
:param filename: path to the export.json
:param list map_features: existing features
:param bool no_traders: Ignore trader-icons
:param no_tls: Ignore spiral-icons
:return: map_features
"""
global known_features
global doublets
with open(filename) as f:
data = json.load(f)
for item in data['Waypoints']:
pos = (int(item['Position']['X']), int(item['Position']['Y']))
if no_traders and item['ServerIcon'] == 'trader':
continue
if no_tls and item['ServerIcon'] == 'spiral':
continue
if not is_doubled(pos, item):
map_features.append(item)
known_features[pos] = item
return map_features
if __name__ == '__main__':
epilog = \
""" Caveats:
- Only the first feature for any given map-position will be processed
- Remember to specify the correct spawn-offset for your world!
TODO:
- Importing landmarks / bases from the webmap not yet supported
"""
parser = argparse.ArgumentParser(description=__doc__,
epilog=epilog,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('inputfiles', nargs='+', metavar='inputfile',
help="Any number of import files in decreasing preference. Both webmap and CC format accepted. ")
parser.add_argument('-w', '--worldname', default='Unknown World',
help="Inserts this worldname to the export - recognized by CC")
parser.add_argument('-o', '--output', default='export.json',
help="write export to this file")
parser.add_argument('--offset', metavar='x,z', help="absolute pos of the world spawn", default='500000,500000')
parser.add_argument('--notraders', action='store_true', help="Ignore all landmarks with Trader icon")
parser.add_argument('--notls', action='store_true', help="Ignore all landmarks with Spiral icon")
args = parser.parse_args()
x, z = args.offset.split(',')
offset = (int(x), int(z))
map_features = []
for filename in args.inputfiles:
if filename.endswith('.geojson'):
process_geojson(filename, map_features, args.notraders, args.notls)
else:
process_cc_json(filename, map_features, args.notraders, args.notls)
outdata = {
"Name": f"Webmap Waypoints",
"World": args.worldname,
"Count": len(map_features),
"DateCreated": datetime.utcnow().isoformat(),
"Waypoints": map_features
}
log.info(f" Encountered {doublets} double landmarks")
log.info(f" Export File contains {len(map_features)} map features total.")
with open(args.output, 'w') as f:
json.dump(outdata, f, indent=4)