User:Warriorstar/Guide to Mapmerge

From Paradise Station Wiki
Jump to navigation Jump to search

Welcome to the guide to Mapmerge! This guide is divided up into two sections: the theory section, which explains how Mapmerge works, and how it's necessary, and the instructions section, which explains how to use Mapmerge and handle merge conflicts. You don't need to read the first part if you just want to learn how to use Mapmerge, but you might learn something interesting, and it's always helpful to know what's going on under the hood when troubleshooting problems.

Theory: Why do we need Mapmerge?

Paradise's source code, including its maps, are stored in a git repository. Git is a fantastic tool for keeping track of changes to files over time, but it has no "knowledge" of the contents of the files. In addition, when multiple people make changes to the same file, it is possible for git to not know how to combine these changes in an acceptable way.

Git and Text Files

Git and Text Files: Simple Merges

Let's start with a plain text example. Let's say we have a file that looks like this in a git repository.

This is the start of the file!

This is the middle of the file!

This is the end of the file!

Now let's say we have two programmers, Alice and Bob. Alice adds a sentence to the file, between the start and the middle:

This is the start of the file!

This is before the middle of the file! <--- Alice adds this line

This is the middle of the file!

This is the end of the file!

Bob adds a sentence to the file, between the middle and the end:

This is the start of the file!

This is the middle of the file!

This is before the end of the file! <--- Bob adds this line

This is the end of the file!

Now let's say that Bob merges in Alice's changes, via `git merge`. Now, on Bob's branch, the file contains both changes:

This is the start of the file!

This is before the middle of the file!

This is the middle of the file!

This is before the end of the file!

This is the end of the file!

This merged without issue because git has enough information about the context between the changes. It can "tell" that Alice's change was made above the middle line, and Bob's change was made below it, which is enough for git to pull both changes in without requiring any help from the user.

Git and Text Files: Merge Conflicts

Now let's look at an example that causes a merge conflict.

Git and Map Files

That is the basic concept of merging and merge conflicts. When git can tell that changes are distinct and in separate parts of the file, it can merge them largely without incident. However, if these changes touch the same part of the file, then merge conflicts occur, and git has no choice but to ask the user to resolve the conflict manually before committing the changes.

Now we are going to see how this applies to map files. When git can tell that changes are distinct and in separate parts of the file, it can merge them largely without incident. However, if these changes touch the same part of the file, then merge conflicts occur, and git has no choice but to ask the user to resolve the conflict manually before committing the changes.

Structure of Map Files

First, we are going to briefly go over the different parts of a map file. Map files end with the .dmm extension, and are plain text. They consist of three separate parts:

  1. . The preamble, which we can ignore.
  2. . The key definitions.
  3. . The tile definitions.

Key definitions look like this:

"adw" = (
/obj/structure/cable{
    d1 = 4;
    d2 = 8;
    icon_state = "4-8"
    },
/obj/machinery/hologram/holopad,
/turf/simulated/floor/plasteel{
    icon_state = "dark"
    },
/area/station/security/armory/secure)

It starts with the key, followed by a list of prefabs. A prefab can be as simple as a type path, or it can include modifications to the type, known as varedits, which can change values of the object, such as their icon state. Depending on the size and design of the station map, there can be anywhere from 100 to 10,000 unique keys. If every single tile on a 255x255x1 map is unique, this means there would be 62,025 keys in total.

Keys are assigned at random by most tools in order to prevent collisions where two people add a unique key to a map at the same time. Keys are technically integers, but are represented as strings of letters in most cases.

The tile definitions assign a key to every single coordinate on the map. The tile definitions look like this:

(1,1,1) = {"
aaa
aaa
aaa
adw
... // 255 keys per column 1
"}
(2,1,1) = {"
aaa
aaa
aaa
dAc
... // 255 keys per column 2
"}

As you can see, we start with the first tile on the first z-index, (1, 1, 1), and then list all 255 keys that we want to assign to the tiles on that row. Then we start again with the second row, (2, 1, 1) and so on, until we get to (255, 1, 1).

When creating a new unique tile, nearly all mapping tools will choose a new key at random, in order to prevent collisions. If Alice and Bob are working on a map, and the last used key is "aaa", then having the next key for both of them be "aab" would immediately cause conflicts. So Alice's map editor may choose "ceD" and Bob's will choose "gJU".

Git and Map Files: Silent Merge Errors

Now let's say Alice and Bob are working on a map. To keep things simple, we'll make it a small, 2x2 map, with only a handful of objects. This is the original map:

Guide mapmerge map original@4x.png

Guide mapmerge map silentfail alice@4x.png

Guide mapmerge map silentfail bob@4x.png

Guide mapmerge map silentfail merge@4x.png


Git and Map Files: Non-Conformant Maps

//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
"a" = (
/obj/item/crowbar,
/obj/item/wrench,
/turf,
/area/space)
"g" = (
/obj/item/weldingtool,
/turf,
/area/space)
"I" = (
/obj/item/weldingtool,
/turf,
/area/space)
"S" = (
/obj/item/crowbar,
/obj/item/wrench,
/turf,
/area/space)

(1,1,1) = {"
S
a
"}
(2,1,1) = {"
g
I
"}

Git and Map Files: Merge Conflicts

//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
"a" = (
/turf/simulated/floor/plasteel,
/area/space)
 <<<<<<< HEAD
"h" = (
/obj/item/weldingtool,
/turf,
/area/space)
"X" = (
/obj/item/wrench,
/turf,
 =======
"v" = (
/obj/item/wrench,
/turf/simulated/floor/plasteel,
/area/space)
"E" = (
/obj/item/weldingtool,
/turf/simulated/floor/plasteel,
 >>>>>>> mapmerge_wiki_guide-2-alice
/area/space)

(1,1,1) = {"
v
E
"}
(2,1,1) = {"
h
X
"}

Instructions: How do I use Mapmerge?