mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-05-19 13:20:47 +01:00
9f124e5b14
* Initial * Remove corrupt dmis * Fixup maps in TGM format4e5a32721f: maps/_templates_and_guidance/Public Event Templates/Maze_Reward_-_Copy.dmm4e5a32721f: maps/_templates_and_guidance/Templates/shelter_Medical.dmm4e5a32721f: maps/expedition_vr/aerostat/aerostat.dmm4e5a32721f: maps/expedition_vr/aerostat/aerostat_science_outpost.dmm4e5a32721f: maps/expedition_vr/beach/submaps/deadBeacon.dmm4e5a32721f: maps/expedition_vr/wild/tether_wild-crash-alt.dmm4e5a32721f: maps/expedition_vr/wild/tether_wild-crash.dmm4e5a32721f: maps/expedition_vr/wild/tether_wild-surface.dmm4e5a32721f: maps/expedition_vr/wild/tether_wild-temple.dmm4e5a32721f: maps/gateway_vr/lucky_7.dmm4e5a32721f: maps/gateway_vr/snow_outpost.dmm4e5a32721f: maps/overmap/_map.dmm4e5a32721f: maps/overmap/bearcat/bearcat.dmm4e5a32721f: maps/overmap/example_sector1.dmm4e5a32721f: maps/overmap/example_sector2.dmm4e5a32721f: maps/redgate/falls/falls.dmm4e5a32721f: maps/submaps/pois_vr/aerostat/CaveS.dmm4e5a32721f: maps/submaps/pois_vr/aerostat/DeadSettlers1.dmm4e5a32721f: maps/submaps/pois_vr/aerostat/DeadSettlers2.dmm4e5a32721f: maps/submaps/pois_vr/aerostat/DoomP.dmm4e5a32721f: maps/submaps/pois_vr/aerostat/Lab1.dmm4e5a32721f: maps/submaps/pois_vr/aerostat/Rockybase.dmm4e5a32721f: maps/submaps/pois_vr/debris_field/debris14.dmm4e5a32721f: maps/submaps/pois_vr/debris_field/derelict.dmm4e5a32721f: maps/submaps/pois_vr/debris_field/new_escapepod_xeno.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/BlastMine1.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/CaveTrench.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/Cavelake.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/Cliff1.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/CrashedMedShuttle1.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/Geyser1.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/Geyser2.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/Geyser3.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/Mineshaft1.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/Scave1.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/SupplyDrop1.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/crashed_ufo.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/crashed_ufo_frigate.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/crashedcontainmentshuttle.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/crystal1.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/crystal2.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/crystal3.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/deadBeacon.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/deadly_rabbit_vr.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/deadspy.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/digsite.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/excavation1.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/lava_trench.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/prepper1.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/ritual.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/spatial_anomaly.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/speakeasy_vr.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/vault1.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/vault2.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/vault3.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/vault4.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/vault5.dmm4e5a32721f: maps/submaps/surface_submaps/mountains/vault6.dmm4e5a32721f: maps/submaps/surface_submaps/plains/Boathouse.dmm4e5a32721f: maps/submaps/surface_submaps/plains/BuriedTreasure.dmm4e5a32721f: maps/submaps/surface_submaps/plains/BuriedTreasure2.dmm4e5a32721f: maps/submaps/surface_submaps/plains/BuriedTreasure3.dmm4e5a32721f: maps/submaps/surface_submaps/plains/Oldhouse.dmm4e5a32721f: maps/submaps/surface_submaps/plains/PooledR.dmm4e5a32721f: maps/submaps/surface_submaps/plains/Rocky5.dmm4e5a32721f: maps/submaps/surface_submaps/plains/Shakden.dmm4e5a32721f: maps/submaps/surface_submaps/plains/Thiefc.dmm4e5a32721f: maps/submaps/surface_submaps/plains/beacons.dmm4e5a32721f: maps/submaps/surface_submaps/plains/chemspill1.dmm4e5a32721f: maps/submaps/surface_submaps/plains/farm1.dmm4e5a32721f: maps/submaps/surface_submaps/plains/house1.dmm4e5a32721f: maps/submaps/surface_submaps/plains/lonehome.dmm4e5a32721f: maps/submaps/surface_submaps/plains/smol2.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Blackshuttledown.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Blueshuttledown.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Boombase.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/CaveS.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Chapel.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Cragzone1.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/DJOutpost1.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/DJOutpost2.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/DJOutpost3.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/DJOutpost4.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/DecoupledEngine.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/DoomP.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Drugden.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Epod3.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Epod4.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Flake.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/FrostflyNest.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/MCamp1.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/MHR.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Manor1.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Mudpit.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Rocky1.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Rocky3.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Rocky4.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Rockybase.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Shack1.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Shelter.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Smol1.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/Snowrock1.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/borglab.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/butchershack.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/chasm.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/chemspill2.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/deathden.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/derelictengine.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/frostoasis.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/kururakden.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/spider1.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/wolfden.dmm4e5a32721f: maps/submaps/surface_submaps/wilderness/xenohive.dmm4e5a32721f: maps/tether/tether-02-surface2.dmm4e5a32721f: maps/virgo_minitest/virgo_minitest-sector-2.dmm Automatically commited by: tools\mapmerge2\fixup.py * Remove unnecessary whitespace edits from mapmerger * Cable dirs update path * Fix area var edits * Put the area over there * Ignore archive maps folder * Forgot to port multivar support too * A few changes I forgot about for hook install * restore multivar support that chomp doesn't have yet * ban those * Forgot to add code for the marker too * Couple more of these invalid cables were added in master * Update multiple_blood_effects.yml * Update multiple_blood_effects.yml * Fixup maps in TGM format612ca9cbb9: maps/tether/submaps/tether_misc.dmm Automatically commited by: tools\mapmerge2\fixup.py * Fixup now logs the map its currently checking * Final fixes? * Fixup maps in TGM format3078e5cd0a: maps/expedition_vr/beach/submaps/crashedcontainmentshuttle.dmm3078e5cd0a: maps/redgate/fantasy_dungeon.dmm3078e5cd0a: maps/submaps/pois_vr/aerostat/Rockybase.dmm3078e5cd0a: maps/submaps/surface_submaps/mountains/crashedcontainmentshuttle_vr.dmm3078e5cd0a: maps/submaps/surface_submaps/plains/Oldhouse_vr.dmm3078e5cd0a: maps/submaps/surface_submaps/plains/dogbase.dmm3078e5cd0a: maps/submaps/surface_submaps/plains/greatwolfden.dmm3078e5cd0a: maps/submaps/surface_submaps/plains/lonehome_vr.dmm3078e5cd0a: maps/submaps/surface_submaps/plains/methlab.dmm3078e5cd0a: maps/submaps/surface_submaps/plains/oldhotel.dmm3078e5cd0a: maps/submaps/surface_submaps/plains/priderock.dmm3078e5cd0a: maps/submaps/surface_submaps/wilderness/Rockybase.dmm3078e5cd0a: maps/submaps/surface_submaps/wilderness/demonpool.dmm3078e5cd0a: maps/submaps/surface_submaps/wilderness/dogbase.dmm3078e5cd0a: maps/submaps/surface_submaps/wilderness/greatwolfden.dmm3078e5cd0a: maps/tether/submaps/underdark_pois/abandonded_outpost.dmm3078e5cd0a: maps/tether/submaps/underdark_pois/phoron_rat_den.dmm Automatically commited by: tools\mapmerge2\fixup.py * Fix tether_misc error * Remap reused solar farm area * Fix erroneous bearcat entries * Fix weird whitespace (most archive maps also affected but didn't bother) * misc mdb cleanup * moar * grr --------- Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> Co-authored-by: Cameron Lennox <killer65311@gmail.com>
196 lines
6.2 KiB
Python
196 lines
6.2 KiB
Python
# I know we already have one in mapmerge, but this one can afford to be significantly simpler to interface with
|
|
# by virtue of being read-only.
|
|
import re
|
|
from dataclasses import dataclass, field
|
|
from typing import IO
|
|
|
|
from .common import Constant, Filename, Null, Typepath
|
|
from .error import MapParseError, MaplintError
|
|
|
|
REGEX_POP_ID = re.compile(r'^"(?P<key>.+)" = \($')
|
|
REGEX_POP_CONTENT_HEADER = re.compile(r'^(?P<path>[/\w]+?)(?P<end>[{,)])$')
|
|
REGEX_ROW_BEGIN = re.compile(r'^\((?P<x>\d+),(?P<y>\d+),(?P<z>\d+)\) = {"$')
|
|
REGEX_VAR_EDIT = re.compile(r'^\t(?P<name>.+?) = (?P<definition>.+?);?$')
|
|
|
|
@dataclass
|
|
class Content:
|
|
path: Typepath
|
|
filename: str
|
|
starting_line: int
|
|
var_edits: dict[str, Constant] = field(default_factory = dict)
|
|
|
|
@dataclass
|
|
class DMM:
|
|
pops: dict[str, list[Content]] = field(default_factory = dict)
|
|
|
|
# Z -> X -> Y -> Pop
|
|
turfs: list[list[list[str]]] = field(default_factory = list)
|
|
|
|
def size(self):
|
|
return (len(self.turfs[0]), len(self.turfs[0][0]))
|
|
|
|
def turfs_for_pop(self, key: str):
|
|
for z, z_level in enumerate(self.turfs):
|
|
for x, x_level in enumerate(z_level):
|
|
for y, turf in enumerate(x_level):
|
|
if turf == key:
|
|
yield (x, y, z)
|
|
|
|
class DMMParser:
|
|
dmm: DMM
|
|
line = 0
|
|
|
|
def __init__(self, reader: IO):
|
|
self.dmm = DMM()
|
|
self.reader = reader
|
|
|
|
def parse(self):
|
|
if "dmm2tgm" not in self.next_line():
|
|
self.raise_error("Map isn't in TGM format. Consider using StrongDMM instead of Dream Maker.\n Please also consider installing the map merge tools, found through Install.bat in the tools/hooks folder.")
|
|
|
|
try:
|
|
while self.parse_pop():
|
|
pass
|
|
|
|
while self.parse_row():
|
|
pass
|
|
except MapParseError as error:
|
|
raise self.raise_error(error)
|
|
|
|
return self.dmm
|
|
|
|
def next_line(self):
|
|
self.line += 1
|
|
|
|
try:
|
|
return next(self.reader).removesuffix("\n")
|
|
except StopIteration:
|
|
return None
|
|
|
|
def parse_pop(self):
|
|
line = self.next_line()
|
|
if line == "":
|
|
return False
|
|
|
|
pop_match = REGEX_POP_ID.match(line)
|
|
if pop_match is None:
|
|
self.raise_error("Pops ended too early, expected a newline in between.")
|
|
|
|
pop_key = pop_match.group("key")
|
|
contents = []
|
|
|
|
while next_line := self.next_line():
|
|
next_line = next_line.rstrip()
|
|
content_match = REGEX_POP_CONTENT_HEADER.match(next_line)
|
|
if content_match is None:
|
|
self.raise_error("Pop content didn't lead to a path")
|
|
|
|
content = Content(Typepath(content_match.group("path")), self.reader.name, self.line)
|
|
contents.append(content)
|
|
|
|
content_end = content_match.group("end")
|
|
|
|
if content_end == ")":
|
|
break
|
|
elif content_end == "{":
|
|
while (var_edit := self.parse_var_edit()) is not None:
|
|
if var_edit[0] == None and var_edit[1] == None:
|
|
break
|
|
content.var_edits[var_edit[0]] = var_edit[1]
|
|
else:
|
|
continue # inner loop didn't break
|
|
break # inner loop did break indicating a })
|
|
elif content_end == ",":
|
|
continue
|
|
|
|
self.dmm.pops[pop_key] = contents
|
|
|
|
return True
|
|
|
|
def parse_var_edit(self):
|
|
line = self.next_line()
|
|
if line == "\t},":
|
|
return None
|
|
if line == "\t})":
|
|
return None, None
|
|
|
|
var_edit_match = REGEX_VAR_EDIT.match(line)
|
|
self.expect(var_edit_match is not None, "Var edits ended too early, expected a newline in between.")
|
|
|
|
return (var_edit_match.group("name"), self.parse_constant(var_edit_match.group("definition")))
|
|
|
|
def parse_constant(self, constant):
|
|
if (float_constant := self.safe_float(constant)) is not None:
|
|
if(constant.isdigit()):
|
|
return int(constant)
|
|
return float_constant
|
|
elif re.match(r'^/[/\w]+$', constant):
|
|
return Typepath(constant)
|
|
elif re.match(r'^".*"$', constant):
|
|
# This should do escaping in the future
|
|
return constant[1:-1]
|
|
elif re.match(r'^null$', constant):
|
|
return Null()
|
|
elif re.match(r"^'.*'$", constant):
|
|
return Filename(constant[1:-1])
|
|
elif (list_match := re.match(r'^list\((?P<contents>.*)\)$', constant)):
|
|
return ["NYI: list"]
|
|
elif (list_match := re.match(r'^newlist\((?P<contents>.*)\)$', constant)):
|
|
return ["NYI: newlist"]
|
|
else:
|
|
self.raise_error(f"Unknown constant type: {constant}")
|
|
|
|
def parse_row(self):
|
|
line = self.next_line()
|
|
|
|
if line is None:
|
|
return False
|
|
|
|
if line == "":
|
|
# Starting a new z level
|
|
return True
|
|
|
|
row_match = REGEX_ROW_BEGIN.match(line)
|
|
self.expect(row_match is not None, "Rows ended too early, expected a newline in between.")
|
|
self.expect(row_match.group("y") == "1", "TGM should only be producing individual rows.")
|
|
|
|
x = int(row_match.group("x")) - 1
|
|
z = int(row_match.group("z")) - 1
|
|
|
|
if len(self.dmm.turfs) <= z:
|
|
self.dmm.turfs.append([])
|
|
self.expect(len(self.dmm.turfs) == z + 1, "Z coordinate is not sequential")
|
|
|
|
z_level = self.dmm.turfs[z]
|
|
self.expect(len(z_level) == x, "X coordinate is not sequential")
|
|
|
|
contents = []
|
|
|
|
while (next_line := self.next_line()) is not None:
|
|
next_line = next_line.rstrip()
|
|
if next_line == '"}':
|
|
break
|
|
|
|
self.expect(next_line in self.dmm.pops, f"Pop {next_line} is not defined")
|
|
contents.append(next_line)
|
|
|
|
z_level.append(contents)
|
|
|
|
return True
|
|
|
|
def safe_float(self, value):
|
|
try:
|
|
return float(value)
|
|
except ValueError:
|
|
return None
|
|
|
|
def expect(self, condition, message):
|
|
if not condition:
|
|
self.raise_error(message)
|
|
|
|
def raise_error(self, message):
|
|
raise MaplintError(message, self.reader.name, self.line)
|
|
|
|
def parse_dmm(reader: IO):
|
|
return DMMParser(reader).parse()
|