Files
Bubberstation/code/modules/mapping
SyncIt21 04b667b7ba Fixes 4 bugs with /datum/parsed_map/readlist() (#92652)
## About The Pull Request
- Fixes the proc skipping `0` & `null` values. Text like `"0"` &
`"null"` when sent to `parse_constant()` will yield `0` & `null`
respectively but when checked against `!` operator

c3e716323e/code/modules/mapping/reader.dm (L1019)
It gets mistaken as an empty value/new line so its skipped So if you had
a list such as `list("Hello", 0, "null")` When parsed it would yield
`list("Hello")`. That's fixed now. We check the text before parsing it

- Fixes `=` symbol getting mistaken for a key/value pair if it is
embedded inside a string expression. Consider this list `list("A", "B =
C")`. This list should just be linear because the equals symbol is meant
to escaped as it is within a string literal. However `findtext()` proc
doesn't account for that

c3e716323e/code/modules/mapping/reader.dm (L1014)
So we end up creating a key/value pair and a linear element, creating a
broken list like that runtimes(because of the missing `"` symbol in
breaking up the string at the middle)
The solution is simple, we already have the proc
`find_next_delimiter_position()` that will escape everything between `"`
so we now use that to find the position of `=`

- Fixes the proc being unable to parse alists who's values themselves
are lists. Consider the example `list("A" = list(1, 2))`
When we look for `,` symbol to check for the next list element here

c3e716323e/code/modules/mapping/reader.dm (L1015)
You get a broken left literal like this `"A" = list(1` because the comma
within the list is getting mistaken for a new element. Now we check for
such edge cases and remember to parse the full list before checking for
the next comma & now your alists can contain lists as elements
themselves

- Map reader can read nested lists to any degree e.g. `list(list(3, 4),
list(5, 6))` parses correctly

## Changelog
🆑
fix: the map reader now reads null & 0 values into lists
fix: the map reader now parses associative lists(maps/alists) correctly
in cases where = sign is embedded within a string
fix: the map reader now parses associative lists(maps/alists) who's
values themselves can be lists
fix: the map reader can now parse nested lists to any degree
/🆑
2025-09-07 11:10:51 +02:00
..

The code in this module originally evolved from dmm_suite and has since been
specialized for SS13 and otherwise tweaked to fit /tg/station's needs.

dmm_suite version 1.0
	Released January 30th, 2011.

NOTE: Map saving functionality removed

defines the object /dmm_suite
	- Provides the proc load_map()
		- Loads the specified map file onto the specified z-level.
	- provides the proc write_map()
		- Returns a text string of the map in dmm format
			ready for output to a file.
	- provides the proc save_map()
		- Returns a .dmm file if map is saved
		- Returns FALSE if map fails to save

The dmm_suite provides saving and loading of map files in BYOND's native DMM map
format. It approximates the map saving and loading processes of the Dream Maker
and Dream Seeker programs so as to allow editing, saving, and loading of maps at
runtime.

------------------------

To save a map at runtime, create an instance of /dmm_suite, and then call
write_map(), which accepts three arguments:
	- A turf representing one corner of a three dimensional grid (Required).
	- Another turf representing the other corner of the same grid (Required).
	- Any, or a combination, of several bit flags (Optional, see documentation).

The order in which the turfs are supplied does not matter, the /dmm_writer will
determine the grid containing both, in much the same way as DM's block() function.
write_map() will then return a string representing the saved map in dmm format;
this string can then be saved to a file, or used for any other purose.

------------------------

To load a map at runtime, create an instance of /dmm_suite, and then call load_map(),
which accepts two arguments:
	- A .dmm file to load (Required).
	- A number representing the z-level on which to start loading the map (Optional).

The /dmm_suite will load the map file starting on the specified z-level. If no
z-level	was specified, world.maxz will be increased so as to fit the map. Note
that if you wish to load a map onto a z-level that already has objects on it,
you will have to handle the removal of those objects. Otherwise the new map will
simply load the new objects on top of the old ones.

Also note that all type paths specified in the .dmm file must exist in the world's
code, and that the /dmm_reader trusts that files to be loaded are in fact valid
.dmm files. Errors in the .dmm format will cause runtime errors.