mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-06-25 16:14:50 +01:00
57144e0243
## About The Pull Request Converts species and antagonist icon generation to the batched spritesheet system using IconForge, thanks to the new `get_flat_uni_icon` implementation. Unfortunately the cost of *building* the sprite is still expensive (GFI is always expensive, even a fancy list-based one), but the generation is SIGNIFICANTLY faster. We will see evidence of parity in the screenshot tests. but here: <img width="892" height="634" alt="image" src="https://github.com/user-attachments/assets/2a17f2e3-c024-41f6-9d1e-c2cb70642a81" /> The main advantage is that species and antag icons can now take advantage of the development-time smart cache which invalidates automatically. On the server this PR does very little except make antag icon generation a little bit more likely to find and announce errors (BYOND has a habit of silently eating weird icon proc calls). Also optimizes the greyscale preview generator from #90940 (~2x speedup) using `rustg_iconforge_generate_headless` instead of `Insert()` to build the resulting sheets. This can be further optimized in the future by implementing a smart cache, like batched spritesheets, and storing it in the repo, but for now it's not important/slow enough to be worth the effort. Also fixes a silent compilation error that would always happen outside unit tests, but for some reason doesn't appear on local? Notice how `map_icon_key` is not a defined variable anywhere. That's because `USE_RUSTG_ICONFORGE_GAGS` is *never* defined at this point, so it was always using the 'slow' generation. I also took the liberty of cleaning up the cultist and heretic icon generation randomly initializing a blade object when it could just use a static access. ## Why It's Good For The Game The subsystem timing may not be much faster, but the interactivity benefits during spritesheet realization are undeniable. Opening the preferences menu during init on local is orders of magnitude faster. **Old** Early Assets: 5.02 seconds Greyscale Previews: 1.38 seconds **Fresh (No Cache)** Early Assets: 4.21 seconds Greyscale Previews: 0.5 seconds **Cache Invalidated** Early Assets: 4.27 seconds **Cache Hit** Early Assets: 4.05~4.2 seconds **Preferences lag:** ~6 sec to open to ~2 sec to open due to caching in dev ## Changelog 🆑 code: Optimized species and antagonist icon loading in the preferences menu on local, speeding up time to open in development. fix: GAGS map preview generation no longer silently errors outside of unit tests due to a compilation error. /🆑
105 lines
4.1 KiB
Plaintext
105 lines
4.1 KiB
Plaintext
PROCESSING_SUBSYSTEM_DEF(greyscale)
|
|
name = "Greyscale"
|
|
flags = SS_BACKGROUND
|
|
wait = 3 SECONDS
|
|
init_stage = INITSTAGE_EARLY
|
|
var/list/datum/greyscale_config/configurations = list()
|
|
var/list/datum/greyscale_layer/layer_types = list()
|
|
#ifdef USE_RUSTG_ICONFORGE_GAGS
|
|
/// Cache containing a list of [UID (config path + colors)] -> [DMI file / RSC object] in the tmp directory from iconforge
|
|
var/list/gags_cache = list()
|
|
#endif
|
|
|
|
/datum/controller/subsystem/processing/greyscale/Initialize()
|
|
for(var/datum/greyscale_layer/greyscale_layer as anything in subtypesof(/datum/greyscale_layer))
|
|
layer_types[initial(greyscale_layer.layer_type)] = greyscale_layer
|
|
|
|
for(var/greyscale_type in subtypesof(/datum/greyscale_config))
|
|
var/datum/greyscale_config/config = new greyscale_type()
|
|
configurations["[greyscale_type]"] = config
|
|
|
|
// We do this after all the types have been loaded into the listing so reference layers don't care about init order
|
|
for(var/greyscale_type in configurations)
|
|
CHECK_TICK
|
|
var/datum/greyscale_config/config = configurations[greyscale_type]
|
|
config.Refresh()
|
|
|
|
#ifdef USE_RUSTG_ICONFORGE_GAGS
|
|
var/list/job_ids = list()
|
|
#endif
|
|
|
|
// This final verification step is for things that need other greyscale configurations to be finished loading
|
|
for(var/greyscale_type in configurations)
|
|
CHECK_TICK
|
|
var/datum/greyscale_config/config = configurations[greyscale_type]
|
|
config.CrossVerify()
|
|
#ifdef USE_RUSTG_ICONFORGE_GAGS
|
|
job_ids += rustg_iconforge_load_gags_config_async(greyscale_type, config.raw_json_string, config.string_icon_file)
|
|
|
|
UNTIL(jobs_completed(job_ids))
|
|
#endif
|
|
|
|
return SS_INIT_SUCCESS
|
|
|
|
#ifdef USE_RUSTG_ICONFORGE_GAGS
|
|
/datum/controller/subsystem/processing/greyscale/proc/jobs_completed(list/job_ids)
|
|
for(var/job in job_ids)
|
|
var/result = rustg_iconforge_check(job)
|
|
if(result == RUSTG_JOB_NO_RESULTS_YET)
|
|
return FALSE
|
|
if(result != "OK")
|
|
stack_trace("Error during rustg_iconforge_load_gags_config job: [result]")
|
|
job_ids -= job
|
|
return TRUE
|
|
#endif
|
|
|
|
/datum/controller/subsystem/processing/greyscale/proc/RefreshConfigsFromFile()
|
|
for(var/i in configurations)
|
|
configurations[i].Refresh(TRUE)
|
|
|
|
/datum/controller/subsystem/processing/greyscale/proc/GetColoredIconByType(type, list/colors)
|
|
if(!ispath(type, /datum/greyscale_config))
|
|
CRASH("An invalid greyscale configuration was given to `GetColoredIconByType()`: [type]")
|
|
if(!initialized)
|
|
CRASH("GetColoredIconByType() called before greyscale subsystem initialized!")
|
|
type = "[type]"
|
|
if(istype(colors)) // It's the color list format
|
|
colors = colors.Join()
|
|
else if(!istext(colors))
|
|
CRASH("Invalid colors were given to `GetColoredIconByType()`: [colors]")
|
|
#ifdef USE_RUSTG_ICONFORGE_GAGS
|
|
var/uid = "[replacetext(replacetext(type, "/datum/greyscale_config/", ""), "/", "-")]-[colors]"
|
|
var/cached_file = gags_cache[uid]
|
|
if(cached_file)
|
|
return cached_file
|
|
var/output_path = "tmp/gags/icons/gags-[uid].dmi"
|
|
var/iconforge_output = rustg_iconforge_gags(type, colors, output_path)
|
|
// Handle errors from IconForge
|
|
if(iconforge_output != "OK")
|
|
CRASH(iconforge_output)
|
|
// We'll just explicitly do fcopy_rsc here, so the game doesn't have to do it again later from the cached file.
|
|
var/rsc_gags_icon = fcopy_rsc(file(output_path))
|
|
gags_cache[uid] = rsc_gags_icon
|
|
return rsc_gags_icon
|
|
#else
|
|
return configurations[type].Generate(colors)
|
|
#endif
|
|
|
|
/datum/controller/subsystem/processing/greyscale/proc/GetColoredIconByTypeUniversalIcon(type, list/colors, target_icon_state)
|
|
if(!ispath(type, /datum/greyscale_config))
|
|
CRASH("An invalid greyscale configuration was given to `GetColoredIconByTypeUniversalIcon()`: [type]")
|
|
type = "[type]"
|
|
if(istype(colors)) // It's the color list format
|
|
colors = colors.Join()
|
|
else if(!istext(colors))
|
|
CRASH("Invalid colors were given to `GetColoredIconByTypeUniversalIcon()`: [colors]")
|
|
return configurations[type].GenerateUniversalIcon(colors, target_icon_state)
|
|
|
|
/datum/controller/subsystem/processing/greyscale/proc/ParseColorString(color_string)
|
|
. = list()
|
|
var/list/split_colors = splittext(color_string, "#")
|
|
for(var/color in 2 to length(split_colors))
|
|
. += "#[split_colors[color]]"
|
|
|
|
#undef USE_RUSTG_ICONFORGE_GAGS
|