Difference between revisions of "User:Warriorstar/Guide to Mapmerge"

From Paradise Station Wiki
Jump to navigation Jump to search
 
(5 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{Wip|assign=Warriorstar}}
'''NOTE: This guide is not yet complete.'''
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? ==
== 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.
<pre>
This is the start of the file!
This is the middle of the file!
This is the end of the file!
</pre>
Now let's say we have two programmers, Alice and Bob. Alice adds a sentence to
the file, between the start and the middle:
<pre>
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!
</pre>
Bob adds a sentence to the file, between the middle and the end:
<pre>
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!
</pre>
Now let's say that Bob merges in Alice's changes, via `git merge`. Now, on Bob's
branch, the file contains both changes:
<pre>
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!
</pre>
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 ===
=== Git and Map Files ===


==== Git and Map Files: Silent Failures ====
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 <code>.dmm</code> extension, and are plain text. They consist
of three separate parts:
 
#. The preamble, which we can ignore.
#. The key definitions.
#. The tile definitions.
 
Key definitions look like this:
 
<pre>
"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)
</pre>
 
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:
 
<pre>
(1,1,1) = {"
aaa
aaa
aaa
adw
... // 255 keys per column 1
"}
(2,1,1) = {"
aaa
aaa
aaa
dAc
... // 255 keys per column 2
"}
</pre>
 
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.
 
{| class="wikitable"
|+Silent Map Merge Failure
|-
|Original Version
|-
|Alice's Version
|-
|Bob's Version
|-
|Silent Merge Error
|}
 
 
=== Git and Map Files: Non-Conformant Maps ===
 
 
 
<pre>
//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
"}
</pre>
 
=== Git and Map Files: Merge Conflicts ===
 
<pre>
//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
"}
</pre>


== Instructions: How do I use Mapmerge? ==
== Instructions: How do I use Mapmerge? ==

Latest revision as of 20:32, 31 July 2024

Sloth construction.png
Sloth construction.png
This article or section is a Work in Progress.
Assigned to:
Warriorstar
Please discuss changes with assigned users. If no one is assigned, or if the user is inactive, feel free to edit.

NOTE: This guide is not yet complete.

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.

Silent Map Merge Failure
Original Version Guide mapmerge map original@4x.png
Alice's Version Guide mapmerge map silentfail alice@4x.png
Bob's Version Guide mapmerge map silentfail bob@4x.png
Silent Merge Error 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?