Fix map_export admin verb not saving objects properly (#90998)

## About The Pull Request

When using the `map_export` admin verb the following things are fixed:
- All objects density, anchored, opacity, atom_integrity, and
resistance_flags vars are saved
- Multi-tile objects being spammed on all tiles the sprite reaches
- Dirt decals error icon
- Airlocks error icon and to save welded state
- Dark Wizard Simple Mobs error icon
- Closets to save welded, open, and locked states
- Air alarms to save name
- Air scrubbers/vents to save name and welded states
- APCs to save name, charge, cell, lighting, equipment, and
environmental states
- APCs spawning a duplicated terminal underneath it when one already
exists
- SMES to save charge, input, and output states
- Holodecks to revert any holodeck turfs to the empty turf and skip
saving any hologram items
- Photos and Paintings error icons
- Bloody Footprints error icons
- False Walls error icons
- Docking Ports runtimes because the map template var would change
- Effects (lasers, portals, beams, sparks, etc.) saving when they should
be omitted

I would have loved to get `component_parts` to save for machines and
turf decals, but perhaps that is for another day since it requires
complicated solutions.

Here are some before and after pictures:


![StrongDMM_209k6PXSaQ](https://github.com/user-attachments/assets/27f0a80b-3cbc-4862-a218-612d52fa0e4f)


![StrongDMM_5PdRfLTZ4l](https://github.com/user-attachments/assets/3bbfd724-4b51-47c5-8cff-02687250fc1e)


![StrongDMM_F4DPOGz5K7](https://github.com/user-attachments/assets/1130ded8-3062-469a-ad4a-d437d89a68da)


![StrongDMM_BIa554dsGv](https://github.com/user-attachments/assets/440d6b38-dbbf-47c0-ad9a-5165504d104e)

## Why It's Good For The Game
Better map saving code.

## Changelog
🆑
fix: Fix `map_export` admin verb not properly saving a massive amount of
objects.
/🆑
This commit is contained in:
Tim
2025-05-17 00:43:09 -05:00
committed by GitHub
parent 62fcace82c
commit e698c965b3
17 changed files with 172 additions and 39 deletions
+68 -30
View File
@@ -74,44 +74,63 @@ ADMIN_VERB(map_export, R_DEBUG, "Map Export", "Select a part of the map by coord
**/
/atom/proc/get_save_vars()
return list(
NAMEOF(src, color),
NAMEOF(src, dir),
NAMEOF(src, icon),
NAMEOF(src, icon_state),
NAMEOF(src, name),
NAMEOF(src, pixel_x),
NAMEOF(src, pixel_y),
)
. = list()
. += NAMEOF(src, color)
. += NAMEOF(src, dir)
. += NAMEOF(src, icon)
. += NAMEOF(src, icon_state)
. += NAMEOF(src, name)
. += NAMEOF(src, pixel_x)
. += NAMEOF(src, pixel_y)
. += NAMEOF(src, density)
. += NAMEOF(src, opacity)
if(uses_integrity)
if(atom_integrity != max_integrity) // Only save if atom_integrity differs from max_integrity to avoid redundant saving
. += NAMEOF(src, atom_integrity)
. += NAMEOF(src, max_integrity)
. += NAMEOF(src, integrity_failure)
. += NAMEOF(src, damage_deflection)
. += NAMEOF(src, resistance_flags)
return .
/atom/movable/get_save_vars()
. = ..()
. += NAMEOF(src, anchored)
return .
/obj/get_save_vars()
return ..() + list(NAMEOF(src, req_access), NAMEOF(src, id_tag))
. = ..()
. += NAMEOF(src, req_access)
. += NAMEOF(src, id_tag)
return .
/obj/item/stack/get_save_vars()
return ..() + NAMEOF(src, amount)
. = ..()
. += NAMEOF(src, amount)
return .
/obj/docking_port/get_save_vars()
return ..() + list(
NAMEOF(src, dheight),
NAMEOF(src, dwidth),
NAMEOF(src, height),
NAMEOF(src, shuttle_id),
NAMEOF(src, width),
)
/obj/docking_port/stationary/get_save_vars()
return ..() + NAMEOF(src, roundstart_template)
. = ..()
. += NAMEOF(src, dheight)
. += NAMEOF(src, dwidth)
. += NAMEOF(src, height)
. += NAMEOF(src, shuttle_id)
. += NAMEOF(src, width)
return .
/obj/machinery/atmospherics/get_save_vars()
return ..() + list(
NAMEOF(src, piping_layer),
NAMEOF(src, pipe_color),
)
. = ..()
. += NAMEOF(src, piping_layer)
. += NAMEOF(src, pipe_color)
return .
/obj/item/pipe/get_save_vars()
return ..() + list(
NAMEOF(src, piping_layer),
NAMEOF(src, pipe_color),
)
. = ..()
. += NAMEOF(src, piping_layer)
. += NAMEOF(src, pipe_color)
return .
GLOBAL_LIST_INIT(save_file_chars, list(
"a","b","c","d","e",
@@ -176,12 +195,20 @@ GLOBAL_LIST_INIT(save_file_chars, list(
maxz,
save_flag = ALL,
shuttle_area_flag = SAVE_SHUTTLEAREA_DONTCARE,
list/obj_blacklist = list(),
list/obj_blacklist = typesof(/obj/effect),
)
var/width = maxx - minx
var/height = maxy - miny
var/depth = maxz - minz
if(!islist(obj_blacklist))
CRASH("Non-list being used as object blacklist for map writing")
// we want to keep crayon writings, blood splatters, cobwebs, etc.
obj_blacklist -= typesof(/obj/effect/decal)
obj_blacklist -= typesof(/obj/effect/turf_decal)
obj_blacklist -= typesof(/obj/effect/landmark) // most landmarks get deleted except for latejoin arrivals shuttle
//Step 0: Calculate the amount of letters we need (26 ^ n > turf count)
var/turfs_needed = width * height
var/layers = FLOOR(log(GLOB.save_file_chars.len, turfs_needed) + 0.999,1)
@@ -221,6 +248,10 @@ GLOBAL_LIST_INIT(save_file_chars, list(
place = /turf/template_noop
location = /area/template_noop
pull_from = null
//====Saving holodeck areas====
// All hologram objects get skipped and floor tiles get replaced with empty plating
if(ispath(location, /area/station/holodeck) && istype(place, /turf/open/floor/holofloor))
place = /turf/open/floor/holofloor/plating
//====For toggling not saving areas and turfs====
if(!(save_flag & SAVE_AREAS))
location = /area/template_noop
@@ -239,6 +270,11 @@ GLOBAL_LIST_INIT(save_file_chars, list(
CHECK_TICK
if(obj_blacklist[thing.type])
continue
if(thing.flags_1 & HOLOGRAM_1)
continue
if(is_multi_tile_object(thing) && (thing.loc != pull_from))
continue
var/metadata = generate_tgm_metadata(thing)
current_header += "[empty ? "" : ",\n"][thing.type][metadata]"
empty = FALSE
@@ -272,8 +308,8 @@ GLOBAL_LIST_INIT(save_file_chars, list(
/proc/generate_tgm_metadata(atom/object)
var/list/data_to_add = list()
var/list/vars_to_save = object.get_save_vars()
for(var/variable in vars_to_save)
CHECK_TICK
var/value = object.vars[variable]
@@ -281,6 +317,8 @@ GLOBAL_LIST_INIT(save_file_chars, list(
continue
if(variable == "icon_state" && object.smoothing_flags)
continue
if(variable == "icon" && object.smoothing_flags)
continue
var/text_value = tgm_encode(value)
if(!text_value)