Skip to content

Commit

Permalink
FIx: Map Conflict Fixer & DMI Conflict Fixer (ss220-space#1706)
Browse files Browse the repository at this point in the history
* Fix: Map conflict fixer & DMI conflict fixer

* Add: Merge Conflict Marker
  • Loading branch information
dj-34 authored Dec 14, 2022
1 parent abdf5fe commit c95e73f
Show file tree
Hide file tree
Showing 86 changed files with 275 additions and 6,621 deletions.
18 changes: 18 additions & 0 deletions code/game/objects/effects/mapping_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,21 @@
T.light_power = light_power
T.light_range = light_range
. = ..()

// Used by mapmerge2 to denote the existence of a merge conflict (or when it has to complete a "best intent" merge where it dumps the movable contents of an old key and a new key on the same tile).
// We define it explicitly here to ensure that it shows up on the highest possible plane (while giving off a verbose icon) to aide mappers in resolving these conflicts.
// DO NOT USE THIS IN NORMAL MAPPING!!! Linters WILL fail.

/obj/merge_conflict_marker
name = "Merge Conflict Marker - DO NOT USE"
icon = 'icons/effects/mapping_helpers.dmi'
icon_state = "merge_conflict_marker"
desc = "If you are seeing this in-game: someone REALLY, REALLY, REALLY fucked up. Please make an issue report on GitHub or contact a coder as soon as possible."
plane = POINT_LAYER

///We REALLY do not want un-addressed merge conflicts in maps for an inexhaustible list of reasons. This should help ensure that this will not be missed in case linters fail to catch it for any reason what-so-ever.
/obj/merge_conflict_marker/Initialize(mapload)
. = ..()
var/msg = "HEY, LISTEN!!! Merge Conflict Marker detected at [AREACOORD(src)]! Please manually address all potential merge conflicts!!!"
warning(msg)
to_chat(world, "<span class='boldannounce'>[msg]</span>")
Binary file modified icons/effects/mapping_helpers.dmi
Binary file not shown.
6 changes: 6 additions & 0 deletions tools/UpdatePaths/Scripts/17259_dirbump_part1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/obj/machinery/firealarm : /obj/machinery/firealarm {@OLD;name="custom placement"}
/obj/structure/extinguisher_cabinet : /obj/structure/extinguisher_cabinet {@OLD;name="custom placement"}
/obj/item/radio/intercom : /obj/item/radio/intercom {@OLD;name="custom placement";dir=2}
/obj/machinery/light_switch : /obj/machinery/light_switch {@OLD;name="custom placement"}
/obj/machinery/alarm : /obj/machinery/alarm {@OLD;name="custom placement"}
/obj/machinery/newscaster : /obj/machinery/newscaster {@OLD;name="custom placement"}
24 changes: 24 additions & 0 deletions tools/UpdatePaths/Scripts/17259_dirbump_part2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/obj/machinery/firealarm {pixel_x=24; pixel_y=@UNSET} : /obj/machinery/firealarm {@OLD;name="east bump"}
/obj/machinery/firealarm {pixel_x=-24; pixel_y=@UNSET} : /obj/machinery/firealarm {@OLD;name="west bump"}
/obj/machinery/firealarm {pixel_y=24; pixel_x=@UNSET} : /obj/machinery/firealarm {@OLD;name="north bump"}
/obj/machinery/firealarm {pixel_y=-24; pixel_x=@UNSET} : /obj/machinery/firealarm {@OLD;name="south bump"}
/obj/structure/extinguisher_cabinet {pixel_x=27; pixel_y=@UNSET} : /obj/structure/extinguisher_cabinet {@OLD;name="east bump"}
/obj/structure/extinguisher_cabinet {pixel_x=-27; pixel_y=@UNSET} : /obj/structure/extinguisher_cabinet {@OLD;name="west bump"}
/obj/structure/extinguisher_cabinet {pixel_y=30; pixel_x=@UNSET} : /obj/structure/extinguisher_cabinet {@OLD;name="north bump"}
/obj/structure/extinguisher_cabinet {pixel_y=-30; pixel_x=@UNSET} : /obj/structure/extinguisher_cabinet {@OLD;name="south bump"}
/obj/item/radio/intercom {pixel_x=28; pixel_y=@UNSET} : /obj/item/radio/intercom {@OLD;name="east bump"}
/obj/item/radio/intercom {pixel_x=-28; pixel_y=@UNSET} : /obj/item/radio/intercom {@OLD;name="west bump"}
/obj/item/radio/intercom {pixel_y=28; pixel_x=@UNSET} : /obj/item/radio/intercom {@OLD;name="north bump"}
/obj/item/radio/intercom {pixel_y=-28; pixel_x=@UNSET} : /obj/item/radio/intercom {@OLD;name="south bump"}
/obj/machinery/light_switch {pixel_x=24; pixel_y=@UNSET} : /obj/machinery/light_switch {@OLD;name="east bump"}
/obj/machinery/light_switch {pixel_x=-24; pixel_y=@UNSET} : /obj/machinery/light_switch {@OLD;name="west bump"}
/obj/machinery/light_switch {pixel_y=24; pixel_x=@UNSET} : /obj/machinery/light_switch {@OLD;name="north bump"}
/obj/machinery/light_switch {pixel_y=-24; pixel_x=@UNSET} : /obj/machinery/light_switch {@OLD;name="south bump"}
/obj/machinery/alarm {pixel_x=24; pixel_y=@UNSET} : /obj/machinery/alarm {@OLD;name="east bump"}
/obj/machinery/alarm {pixel_x=-24; pixel_y=@UNSET} : /obj/machinery/alarm {@OLD;name="west bump"}
/obj/machinery/alarm {pixel_y=24; pixel_x=@UNSET} : /obj/machinery/alarm {@OLD;name="north bump"}
/obj/machinery/alarm {pixel_y=-24; pixel_x=@UNSET} : /obj/machinery/alarm {@OLD;name="south bump"}
/obj/machinery/newscaster {pixel_x=32; pixel_y=@UNSET} : /obj/machinery/newscaster {@OLD;name="east bump"}
/obj/machinery/newscaster {pixel_x=-32; pixel_y=@UNSET} : /obj/machinery/newscaster {@OLD;name="west bump"}
/obj/machinery/newscaster {pixel_y=32; pixel_x=@UNSET} : /obj/machinery/newscaster {@OLD;name="north bump"}
/obj/machinery/newscaster {pixel_y=-32; pixel_x=@UNSET} : /obj/machinery/newscaster {@OLD;name="south bump"}
2 changes: 2 additions & 0 deletions tools/UpdatePaths/Scripts/17980_rust_converter.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/turf/simulated/wall/r_wall/rust : /turf/simulated/wall/r_wall , /obj/effect/spawner/random_spawners/wall_rusted_always
/turf/simulated/wall/rust : /turf/simulated/wall , /obj/effect/spawner/random_spawners/wall_rusted_always
8 changes: 8 additions & 0 deletions tools/UpdatePaths/Scripts/19252_newscaster_directionality.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/obj/machinery/newscaster {pixel_x=32} : /obj/machinery/newscaster {dir=8;name="east bump";pixel_x=28}
/obj/machinery/newscaster {pixel_x=-32} : /obj/machinery/newscaster {dir=4;name="west bump";pixel_x=-28}
/obj/machinery/newscaster {pixel_y=32} : /obj/machinery/newscaster {dir=2;name="north bump";pixel_y=28}
/obj/machinery/newscaster {pixel_y=-32} : /obj/machinery/newscaster {dir=1;name="south bump";pixel_y=-28}
/obj/machinery/newscaster/security_unit {pixel_x=32} : /obj/machinery/newscaster/security_unit {dir=8;name="east bump";pixel_x=28}
/obj/machinery/newscaster/security_unit {pixel_x=-32} : /obj/machinery/newscaster/security_unit {dir=4;name="west bump";pixel_x=-28}
/obj/machinery/newscaster/security_unit {pixel_y=32} : /obj/machinery/newscaster/security_unit {dir=2;name="north bump";pixel_y=28}
/obj/machinery/newscaster/security_unit {pixel_y=-32} : /obj/machinery/newscaster/security_unit {dir=1;name="south bump";pixel_y=-28}
3 changes: 3 additions & 0 deletions tools/UpdatePaths/Scripts/19351_bushes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/obj/structure/flora/grass/jungle/b : /obj/structure/flora/grass/jungle
/obj/structure/flora/junglebush/b : /obj/structure/flora/junglebush
/obj/structure/flora/junglebush/c : /obj/structure/flora/junglebush
3 changes: 3 additions & 0 deletions tools/UpdatePaths/Update_Paths.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@echo off
call "%~dp0\..\bootstrap\python" -m UpdatePaths %*
pause
78 changes: 55 additions & 23 deletions tools/mapmerge2/update_paths.py → tools/UpdatePaths/__main__.py
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
# A script and syntax for applying path updates to maps.
import re
import os
import argparse
import frontend
from dmm import *
import re, os, sys, argparse
from mapmerge2 import frontend
from mapmerge2.dmm import *

desc = """
Update dmm files given update file/string.
Replacement syntax example:
/turf/open/floor/plasteel/warningline : /obj/effect/turf_decal {dir = @OLD ;tag = @SKIP;icon_state = @SKIP}
/turf/open/floor/plasteel/warningline : /obj/effect/turf_decal {@OLD} , /obj/thing {icon_state = @OLD:name; name = "meme"}
/turf/open/floor/plasteel/warningline{dir=2} : /obj/thing
/turf/open/floor/iron/warningline : /obj/effect/turf_decal {dir = @OLD ;tag = @SKIP;icon_state = @SKIP}
/turf/open/floor/iron/warningline : /obj/effect/turf_decal {@OLD} , /obj/thing {icon_state = @OLD:name; name = "meme"}
/turf/open/floor/iron/warningline{dir=2} : /obj/thing
/obj/effect/landmark/start/virologist : @DELETE
Syntax for subtypes also exist, to update a path's type but maintain subtypes:
/obj/structure/closet/crate/@SUBTYPES : /obj/structure/new_box/@SUBTYPES {@OLD}
New paths properties:
@DELETE - if used as new path name the old path will be deleted
@OLD - if used as property name copies all modified properties from original path to this one
property = @SKIP - will not copy this property through when global @OLD is used.
property = @OLD - will copy this modified property from original object even if global @OLD is not used
Expand All @@ -23,14 +25,14 @@
"""

default_map_directory = "../../_maps"
replacement_re = re.compile('\s*([^{]*)\s*(\{(.*)\})?')
replacement_re = re.compile(r'\s*(?P<path>[^{]*)\s*(\{(?P<props>.*)\})?')

#urgent todo: replace with actual parser, this is slow as janitor in crit
split_re = re.compile('((?:[A-Za-z0-9_\-$]+)\s*=\s*(?:"(?:.+?)"|[^";]*)|@OLD)')
split_re = re.compile(r'((?:[A-Za-z0-9_\-$]+)\s*=\s*(?:"(?:.+?)"|[^";][^;]*)|@OLD);?')


def props_to_string(props):
return "{{{0}}}".format(";".join([k+" = "+props[k] for k in props]))
return "{{{}}}".format(";".join([f"{k} = {v}" for k, v in props.items()]))


def string_to_props(propstring, verbose = False):
Expand All @@ -48,8 +50,8 @@ def string_to_props(propstring, verbose = False):
def parse_rep_string(replacement_string, verbose = False):
# translates /blah/blah {meme = "test",} into path,prop dictionary tuple
match = re.match(replacement_re, replacement_string)
path = match.group(1)
props = match.group(3)
path = match['path']
props = match['props']
if props:
prop_dict = string_to_props(props, verbose)
else:
Expand All @@ -65,9 +67,18 @@ def update_path(dmm_data, replacement_string, verbose=False):
new_path, new_path_props = parse_rep_string(replacement_def, verbose)
new_paths.append((new_path, new_path_props))

subtypes = ""
if old_path.endswith("/@SUBTYPES"):
old_path = old_path[:-len("/@SUBTYPES")]
if verbose:
print("Looking for subtypes of", old_path)
subtypes = r"(?:/\w+)*"

replacement_pattern = re.compile(rf"(?P<path>{re.escape(old_path)}(?P<subtype>{subtypes}))\s*(:?{{(?P<props>.*)}})?$")

def replace_def(match):
if match.group(2):
old_props = string_to_props(match.group(2), verbose)
if match['props']:
old_props = string_to_props(match['props'], verbose)
else:
old_props = dict()
for filter_prop in old_path_props:
Expand All @@ -83,7 +94,18 @@ def replace_def(match):
print("Found match : {0}".format(match.group(0)))
out_paths = []
for new_path, new_props in new_paths:
out = new_path
if new_path == "@OLD":
out = match.group('path')
elif new_path == "@DELETE":
if verbose:
print("Deleting match : {0}".format(match.group(0)))
return [None]
elif new_path.endswith("/@SUBTYPES"):
path_start = new_path[:-len("/@SUBTYPES")]
out = path_start + match.group('subtype')
else:
out = new_path

out_props = dict()
for prop_name, prop_value in new_props.items():
if prop_name == "@OLD":
Expand All @@ -106,29 +128,33 @@ def replace_def(match):
return out_paths

def get_result(element):
p = re.compile("{0}\s*({{(.*)}})?$".format(re.escape(old_path)))
match = p.match(element)
match = replacement_pattern.match(element)
if match:
return replace_def(match) # = re.sub(p,replace_def,element)
return replace_def(match)
else:
return [element]

bad_keys = {}
modified_keys = []
keys = list(dmm_data.dictionary.keys())
for definition_key in keys:
def_value = dmm_data.dictionary[definition_key]
new_value = tuple(y for x in def_value for y in get_result(x))
new_value = tuple(y for x in def_value for y in get_result(x) if y != None)
if new_value != def_value:
dmm_data.overwrite_key(definition_key, new_value, bad_keys)
modified_keys.append(definition_key)
dmm_data.reassign_bad_keys(bad_keys)
return modified_keys


def update_map(map_filepath, updates, verbose=False):
print("Updating: {0}".format(map_filepath))
dmm_data = DMM.from_file(map_filepath)
modified_keys = []
for update_string in updates:
update_path(dmm_data, update_string, verbose)
dmm_data.to_file(map_filepath, True)
modified_keys.extend(update_path(dmm_data, update_string, verbose))
dmm_data.remove_unused_keys(modified_keys)
dmm_data.to_file(map_filepath)


def update_all_maps(map_directory, updates, verbose=False):
Expand All @@ -141,10 +167,12 @@ def update_all_maps(map_directory, updates, verbose=False):

def main(args):
if args.inline:
print("Using replacement:", args.update_source)
updates = [args.update_source]
else:
with open(args.update_source) as f:
updates = [line for line in f if line and not line.startswith("#") and not line.isspace()]
print(f"Using {len(updates)} replacements from file:", args.update_source)

if args.map:
update_map(args.map, updates, verbose=args.verbose)
Expand All @@ -154,7 +182,11 @@ def main(args):


if __name__ == "__main__":
parser = argparse.ArgumentParser(description=desc, formatter_class=argparse.RawTextHelpFormatter)
prog = __spec__.name.replace('.__main__', '')
if os.name == 'nt' and len(sys.argv) <= 1:
print("usage: drag-and-drop a path script .txt onto `Update_Paths.bat`\n or")

parser = argparse.ArgumentParser(prog=prog, description=desc, formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("update_source", help="update file path / line of update notation")
parser.add_argument("--map", "-m", help="path to update, defaults to all maps in maps directory")
parser.add_argument("--directory", "-d", help="path to maps directory, defaults to _maps/")
Expand Down
32 changes: 32 additions & 0 deletions tools/UpdatePaths/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
HOW TO USE:
Drag one of the scripts in the “Scripts” folder onto the .bat file “Update_Paths” to open it with the .bat file. Let the script run.

Use this tool before using mapmerge or opening the map in an editor.

IMPORTANT:
Please tie the script you are making to the associated PR on github and put it in the scripts folder when you are done.

For example: 17980_rust_converter ties into https://github.com/ParadiseSS13/Paradise/pull/17980

HOW TO MAKE A SCRIPT:
This tool updates paths in the game to new paths. For instance:
If you have a path labeled

/obj/structure/door/airlock/science/closed/rd

and wanted it to be

/obj/structure/door/airlock/science/rd/closed

This tool would update it for you! This is extremely helpful if you want to be nice to people who have to resolve merge conflicts from the PRs that you make updating these areas.

How do you do it?
Simply open a notepad and type this on a line:

/obj/structure/door/airlock/science/closed/rd : /obj/structure/door/airlock/science/rd/closed

The path on the left is the old, the path on the right is the new. It is seperated by a ":"
If you want to make multiple path changes in one script, simply add more changes on new lines.

If you get lost, look at other scripts for examples.

73 changes: 0 additions & 73 deletions tools/bootstrap/node

This file was deleted.

20 changes: 0 additions & 20 deletions tools/bootstrap/node.bat

This file was deleted.

Loading

0 comments on commit c95e73f

Please sign in to comment.