Files
Bubberstation/code/datums/map_config.dm
LemonInTheDark 0c4af38f41 [MDB IGNORE] TGUI library, plus polish (#65326)
* Prevents potentially infinite length books from being written and stored. I'm not sure if this is an actual issue, but I have a funny feeling it may become one someday

* Moves the paper defines to their own file

* It's become clear to me that I am stupid

* git add --all

* Makes book info into a datum to allow for easy passing around

* Converts the library scanner to tgui, lays the groundwork for tgui visitor consoles

* Makes the db request for book info sort
Adds the frontend for the visitor's console
Adds a hash to prevent duplicate db requests
Adds a prams changed var to help facilitate a better search button
Makes the page number code accept text as input

* Makes the ui index at 1 even tho we index at 0 internally

* Begins the conversion process for the library console.

Changes the library console to override the visitor, to utalize for the archive access portion of the ui
Makes scanner into a weakref, I'm coming for you handheld scanner
Renames some vars to make things clearer

* Converts the remaining refs of the old console typepath over, adds a circuit board for consoles because pain

* Changes how bookshelves load in books
Instead of loading them in lazyally, we load them during init
This lets us track what books are stored in which areas

Somewhat jutting off of this, adds map config for designating something as "part of the library"
This will be useful later

* Renames the random poster, adds a spritesheet for bibles. Both will be useful in a moment

* Ok. This is a bit of a mess.
Converts the library console to tgui.
This comes with a few minor behavior changes:
You can now select what type of poster you want to print, instead of just printing a random one
It's now possible to heed the console's emag warning
The console's inventory page will fill at roundstart with the books in your area/if you're in a library, any
areas designated as "library like" in the map config
You can see what type of bible the chaplin has selected?

"Fixes":
You can no longer just dump books into the scanner forever

Implementation details:
Any input that makes a db request will now A: freeze up any other db inputs until it's finished, and B: Start a
1 second timer before any new db requests can be made
Of note, I'm handling html encoding in a very targeted way.
All book_data datums need to have html encoded values. get_title/author/content exist so a defaulting and tgui
appropriate version can be loaded in. This somewhat matches with the trusted var on set_title, it exists to
prevent double html encoding.

While we're here

Input/DB (Book data should be html encoded)
Inside book datum (Book data should be html encoded)
Sending to tgui (Book data should be decoded during extraction with the get_() procs)
Sending anywhere else (Book data should be html encoded, otherwise it's an xss vuln)

Uhhhh tgui stuff?
I'm using a custom theme for emag visuals, I'll get into that more later
The visitor and book management console share the same data/act pipeline, which is why they're parented/subtyped
They also share a page selection component, which is why the visitor's console imports it.

Uhhhhh
Oh right, fuck.
Ok so the page selection component is kinda cursed, the left and right controls are fine
But I'm trying to get a << < [page/max] > >> setup going, and that means resetting the center input past change
so the default value can be used
This ends up being slightly hacky. I'm sorry.

Oh also, I implemented a custom tab setup for this ui. I have no idea why it was literally like 5 months ago.
I think it looks pretty nice, but if you want me to nuke it I can. Sorry for any headache around this.

More tgui stuff next

* Scanner/visitor cleanup, some other odds and ends

* Adds in a dark red and black theme for library computers to be triggered by an emag.
Things of note: I'm overriding some lists that get passed into buttons and one other thing using set, since the
list is alreadt generated by that step in the process? I think?
I've added dimness control to the dimmer component, since well, it was dimming already dark uis.
I also made and added a rather large background svg. I've got no experience with this sort of thing, and all the
compression methods I found for this ended up being busts. I know this isn't acceptable as an end product, but I
don't know how to get it there.

Somewhat on that note, this ui might not be worth the size for the amount of use it gets. I'm fine with nuking
it if that's the case, I bring this up because I have a very poor understanding of the logistics of something
like this, so I have a feeling I've fucked up somewhere

* Forgot these, just a scss file for library computers, barely used but I think it's worthwhile

* Missed this eariler. As a part of the uploading tab, I'm displaying the contents of books. I'm loading in that
context as raw html so paper -> book books look close to right. Means I need more html tags then our current
sanitize provides. I don't think any of these will cause issues, and there's also a good chance I'm missing
some. Will come up with a list later

* Updates the rest of the maps to use the new management typepath

* Fixes the default bible name being Default Bible Name, I am sorry

* Turns out I had the scaling wrong for bible names, lead to weird stacking because the bible icon doesn't scale, so I lowered its sizing

* Yeets unneeded exports (Thank you jlsnow)

Haha wouldn't it be funny if I didn't know how components worked

Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>

* Resets the maps to master

* Fixes oversights from merge commit, changes maps

* Removes needless Flex's from the scanner

* Gives the library console the ability to parse markdown. Expands the list of acceptable html elements a bit

* Adds audio cues for printing and inserting/removing from the scanner, makes the scanner nicer to use in general

* Uses a compressed version of the background. It's still huge, but smaller at least

* Adds the printing audio to the book binder

* Cleans up tram

* curse you tram

* AHHHHHHHH

* MY LIFE IS TRUE PAIN

* Adds a path conversion statement to make people's lives easier

* Apply's style's suggestions

thx style

Co-authored-by: Aleksej Komarov <stylemistake@gmail.com>

* Compresses the background svg

* Further js cleanup

* We no longer render markdown in the ui, since any source of markdown is converted to html anyway

* More ui changes

Makes the tab/main screen logic use Flex rather then manuel offsets
Makes modals better fit the size of their contents
Readjusts the width of some inputs
Properly uses the header prop for a table
Makes the buttons in the upload panel look nicer
Restructures the print tab a bit

* Increase a modal's size

* Fixes computers with no keyboard overlay showing their screen even when the power is out

* Moves some data and logic onto the library subsystem. Kyler's review

Fixes harddels held by the library scanner. Makes the scanner's buffer
actually do something

* Makes book icon randomization a proc rather then just copypasta'd code

* Removes the kilo library edit, the soul was removed

* Damn you san (Fixes mapconflicts)

* Pain

Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
Co-authored-by: Aleksej Komarov <stylemistake@gmail.com>
2022-03-30 19:56:53 -07:00

204 lines
6.1 KiB
Plaintext

//used for holding information about unique properties of maps
//feed it json files that match the datum layout
//defaults to box
// -Cyberboss
/datum/map_config
// Metadata
var/config_filename = "_maps/metastation.json"
var/defaulted = TRUE // set to FALSE by LoadConfig() succeeding
// Config from maps.txt
var/config_max_users = 0
var/config_min_users = 0
var/voteweight = 1
var/votable = FALSE
// Config actually from the JSON - should default to Meta
var/map_name = "Meta Station"
var/map_path = "map_files/MetaStation"
var/map_file = "MetaStation.dmm"
var/traits = null
var/space_ruin_levels = 7
var/space_empty_levels = 1
var/minetype = "lavaland"
var/allow_custom_shuttles = TRUE
var/shuttles = list(
"cargo" = "cargo_box",
"ferry" = "ferry_fancy",
"whiteship" = "whiteship_box",
"emergency" = "emergency_box")
/// Dictionary of job sub-typepath to template changes dictionary
var/job_changes = list()
/// List of additional areas that count as a part of the library
var/library_areas = list()
/**
* Proc that simply loads the default map config, which should always be functional.
*/
/proc/load_default_map_config()
return new /datum/map_config
/**
* Proc handling the loading of map configs. Will return the default map config using [/proc/load_default_map_config] if the loading of said file fails for any reason whatsoever, so we always have a working map for the server to run.
* Arguments:
* * filename - Name of the config file for the map we want to load. The .json file extension is added during the proc, so do not specify filenames with the extension.
* * directory - Name of the directory containing our .json - Must be in MAP_DIRECTORY_WHITELIST. We default this to MAP_DIRECTORY_MAPS as it will likely be the most common usecase. If no filename is set, we ignore this.
* * error_if_missing - Bool that says whether failing to load the config for the map will be logged in log_world or not as it's passed to LoadConfig().
*
* Returns the config for the map to load.
*/
/proc/load_map_config(filename = null, directory = null, error_if_missing = TRUE)
var/datum/map_config/config = load_default_map_config()
if(filename) // If none is specified, then go to look for next_map.json, for map rotation purposes.
//Default to MAP_DIRECTORY_MAPS if no directory is passed
if(directory)
if(!(directory in MAP_DIRECTORY_WHITELIST))
log_world("map directory not in whitelist: [directory] for map [filename]")
return config
else
directory = MAP_DIRECTORY_MAPS
filename = "[directory]/[filename].json"
else
filename = PATH_TO_NEXT_MAP_JSON
if (!config.LoadConfig(filename, error_if_missing))
qdel(config)
return load_default_map_config()
return config
#define CHECK_EXISTS(X) if(!istext(json[X])) { log_world("[##X] missing from json!"); return; }
/datum/map_config/proc/LoadConfig(filename, error_if_missing)
if(!fexists(filename))
if(error_if_missing)
log_world("map_config not found: [filename]")
return
var/json = file(filename)
if(!json)
log_world("Could not open map_config: [filename]")
return
json = file2text(json)
if(!json)
log_world("map_config is not text: [filename]")
return
json = json_decode(json)
if(!json)
log_world("map_config is not json: [filename]")
return
config_filename = filename
if(!json["version"])
log_world("map_config missing version!")
return
if(json["version"] != MAP_CURRENT_VERSION)
log_world("map_config has invalid version [json["version"]]!")
return
CHECK_EXISTS("map_name")
map_name = json["map_name"]
CHECK_EXISTS("map_path")
map_path = json["map_path"]
map_file = json["map_file"]
// "map_file": "MetaStation.dmm"
if (istext(map_file))
if (!fexists("_maps/[map_path]/[map_file]"))
log_world("Map file ([map_path]/[map_file]) does not exist!")
return
// "map_file": ["Lower.dmm", "Upper.dmm"]
else if (islist(map_file))
for (var/file in map_file)
if (!fexists("_maps/[map_path]/[file]"))
log_world("Map file ([map_path]/[file]) does not exist!")
return
else
log_world("map_file missing from json!")
return
if (islist(json["shuttles"]))
var/list/L = json["shuttles"]
for(var/key in L)
var/value = L[key]
shuttles[key] = value
else if ("shuttles" in json)
log_world("map_config shuttles is not a list!")
return
traits = json["traits"]
// "traits": [{"Linkage": "Cross"}, {"Space Ruins": true}]
if (islist(traits))
// "Station" is set by default, but it's assumed if you're setting
// traits you want to customize which level is cross-linked
for (var/level in traits)
if (!(ZTRAIT_STATION in level))
level[ZTRAIT_STATION] = TRUE
// "traits": null or absent -> default
else if (!isnull(traits))
log_world("map_config traits is not a list!")
return
var/temp = json["space_ruin_levels"]
if (isnum(temp))
space_ruin_levels = temp
else if (!isnull(temp))
log_world("map_config space_ruin_levels is not a number!")
return
temp = json["space_empty_levels"]
if (isnum(temp))
space_empty_levels = temp
else if (!isnull(temp))
log_world("map_config space_empty_levels is not a number!")
return
if ("minetype" in json)
minetype = json["minetype"]
allow_custom_shuttles = json["allow_custom_shuttles"] != FALSE
if ("job_changes" in json)
if(!islist(json["job_changes"]))
log_world("map_config \"job_changes\" field is missing or invalid!")
return
job_changes = json["job_changes"]
if("library_areas" in json)
if(!islist(json["library_areas"]))
log_world("map_config \"library_areas\" field is missing or invalid!")
return
for(var/path_as_text in json["library_areas"])
var/path = text2path(path_as_text)
if(!ispath(path, /area))
stack_trace("Invalid path in mapping config for additional library areas: \[[path_as_text]\]")
continue
library_areas += path
defaulted = FALSE
return TRUE
#undef CHECK_EXISTS
/datum/map_config/proc/GetFullMapPaths()
if (istext(map_file))
return list("_maps/[map_path]/[map_file]")
. = list()
for (var/file in map_file)
. += "_maps/[map_path]/[file]"
/datum/map_config/proc/MakeNextMap()
return config_filename == PATH_TO_NEXT_MAP_JSON || fcopy(config_filename, PATH_TO_NEXT_MAP_JSON)