mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 12:41:09 +01:00
+37






![tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com>](/assets/img/avatar_default.png)


Alexis
GitHub
tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com>
ArcaneMusic
MrMelbert
Rhials
rageguy505
LemonInTheDark
John Willard
Aliceee2ch
Time-Green
Tsar-Salat
SmArtKar
Maxipat
SyncIt21
deltanedas
SimplyLogan
loganuk
Leland Kemble
FalloutFalcon
Roxy
Lucy
siliconOpossum
Isratosh
TheRyeGuyWhoWillNowDie
Neocloudy
Alexander V.
ElGitificador
Twaticus
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bloop
Cameron Lennox
Tim
Iamgoofball
Layzu666
Arturlang
_0Steven
mrmanlikesbt
Ben10Omintrix
John F. Kennedy
Cursor
Josh
Josh Powell
Yobrocharlie
Hardly3D
shayoki
LT3
21b4095dfd
Upstream 04/17/2026 fixes https://github.com/Bubberstation/Bubberstation/issues/5549 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com> Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com> Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Rhials <28870487+Rhials@users.noreply.github.com> Co-authored-by: rageguy505 <54517726+rageguy505@users.noreply.github.com> Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Co-authored-by: Aliceee2ch <160794176+Aliceee2ch@users.noreply.github.com> Co-authored-by: Time-Green <7501474+Time-Green@users.noreply.github.com> Co-authored-by: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Co-authored-by: Maxipat <108554989+Maxipat112@users.noreply.github.com> Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com> Co-authored-by: SimplyLogan <47579821+loganuk@users.noreply.github.com> Co-authored-by: loganuk <fakeemail123@aol.com> Co-authored-by: Leland Kemble <70413276+lelandkemble@users.noreply.github.com> Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com> Co-authored-by: Roxy <75404941+TealSeer@users.noreply.github.com> Co-authored-by: Lucy <lucy@absolucy.moe> Co-authored-by: siliconOpossum <138069572+siliconOpossum@users.noreply.github.com> Co-authored-by: Isratosh <Isratosh@hotmail.com> Co-authored-by: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com> Co-authored-by: Neocloudy <88008002+Neocloudy@users.noreply.github.com> Co-authored-by: Alexander V. <volas@ya.ru> Co-authored-by: ElGitificador <168473461+ElGitificador@users.noreply.github.com> Co-authored-by: Twaticus <46540570+Twaticus@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Cameron Lennox <killer65311@gmail.com> Co-authored-by: Tim <timothymtorres@gmail.com> Co-authored-by: Iamgoofball <iamgoofball@gmail.com> Co-authored-by: Layzu666 <121319428+Layzu666@users.noreply.github.com> Co-authored-by: Arturlang <24881678+Arturlang@users.noreply.github.com> Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com> Co-authored-by: mrmanlikesbt <99309552+mrmanlikesbt@users.noreply.github.com> Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> Co-authored-by: John F. Kennedy <54908920+MacaroniCritter@users.noreply.github.com> Co-authored-by: Cursor <102828457+theselfish@users.noreply.github.com> Co-authored-by: Josh <josh.adam.powell@gmail.com> Co-authored-by: Josh Powell <josh.powell@softwire.com> Co-authored-by: Yobrocharlie <Charliemiller5617@gmail.com> Co-authored-by: Hardly3D <66234359+Hardly3D@users.noreply.github.com> Co-authored-by: shayoki <96078776+shayoki@users.noreply.github.com> Co-authored-by: LT3 <83487515+lessthnthree@users.noreply.github.com>
419 lines
14 KiB
Plaintext
419 lines
14 KiB
Plaintext
|
|
// spritesheet implementation - coalesces various icons into a single .png file
|
|
// and uses CSS to select icons out of that file - saves on transferring some
|
|
// 1400-odd individual PNG files
|
|
#define SPR_SIZE 1
|
|
#define SPR_IDX 2
|
|
#define SPRSZ_COUNT 1
|
|
#define SPRSZ_ICON 2
|
|
#define SPRSZ_STRIPPED 3
|
|
|
|
/// Deprecated: Use /datum/asset/spritesheet_batched where possible
|
|
/datum/asset/spritesheet
|
|
abstract_type = /datum/asset/spritesheet
|
|
cross_round_cachable = TRUE
|
|
var/name
|
|
/// List of arguments to pass into queuedInsert
|
|
/// Exists so we can queue icon insertion, mostly for stuff like preferences
|
|
var/list/to_generate = list()
|
|
var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped)
|
|
var/list/sprites = list() // "foo_bar" -> list("32x32", 5)
|
|
var/list/cached_spritesheets_needed
|
|
var/generating_cache = FALSE
|
|
var/fully_generated = FALSE
|
|
/// If this asset should be fully loaded on new
|
|
/// Defaults to false so we can process this stuff nicely
|
|
var/load_immediately = FALSE
|
|
// Kept in state so that the result is the same, even when the files are created, for this run
|
|
VAR_PRIVATE/should_refresh = null
|
|
|
|
/datum/asset/spritesheet/proc/should_load_immediately()
|
|
#ifdef DO_NOT_DEFER_ASSETS
|
|
return TRUE
|
|
#else
|
|
return load_immediately
|
|
#endif
|
|
|
|
|
|
/datum/asset/spritesheet/should_refresh()
|
|
if (..())
|
|
return TRUE
|
|
|
|
if (isnull(should_refresh))
|
|
// `fexists` seems to always fail on static-time
|
|
should_refresh = !fexists(css_cache_filename()) || !fexists(data_cache_filename())
|
|
|
|
return should_refresh
|
|
|
|
/datum/asset/spritesheet/unregister()
|
|
SSassets.transport.unregister_asset("spritesheet_[name].css")
|
|
if(length(sizes))
|
|
for(var/size_id in sizes)
|
|
SSassets.transport.unregister_asset("[name]_[size_id].png")
|
|
else
|
|
for(var/sheet in cached_spritesheets_needed)
|
|
SSassets.transport.unregister_asset(sheet)
|
|
|
|
/datum/asset/spritesheet/regenerate()
|
|
unregister()
|
|
sprites = list()
|
|
fdel("[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].css")
|
|
for(var/sheet in cached_spritesheets_needed)
|
|
fdel("[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[sheet].png")
|
|
fdel("data/spritesheets/spritesheet_[name].css")
|
|
for(var/size_id in sizes)
|
|
fdel("data/spritesheets/[name]_[size_id].png")
|
|
sizes = list()
|
|
to_generate = list()
|
|
cached_serialized_url_mappings = null
|
|
cached_serialized_url_mappings_transport_type = null
|
|
fully_generated = FALSE
|
|
var/old_load = load_immediately
|
|
load_immediately = TRUE
|
|
create_spritesheets()
|
|
realize_spritesheets(yield = FALSE)
|
|
load_immediately = old_load
|
|
|
|
/datum/asset/spritesheet/register()
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
|
|
if (!name)
|
|
CRASH("spritesheet [type] cannot register without a name")
|
|
|
|
if (!should_refresh() && read_from_cache())
|
|
fully_generated = TRUE
|
|
return
|
|
|
|
// If it's cached, may as well load it now, while the loading is cheap
|
|
if(CONFIG_GET(flag/cache_assets) && cross_round_cachable)
|
|
load_immediately = TRUE
|
|
|
|
create_spritesheets()
|
|
if(should_load_immediately())
|
|
realize_spritesheets(yield = FALSE)
|
|
else
|
|
SSasset_loading.queue_asset(src)
|
|
|
|
/datum/asset/spritesheet/proc/realize_spritesheets(yield)
|
|
if(fully_generated)
|
|
return
|
|
while(length(to_generate))
|
|
var/list/stored_args = to_generate[to_generate.len]
|
|
to_generate.len--
|
|
queuedInsert(arglist(stored_args))
|
|
if(yield && TICK_CHECK)
|
|
return
|
|
|
|
ensure_stripped()
|
|
for(var/size_id in sizes)
|
|
var/size = sizes[size_id]
|
|
var/file_path = size[SPRSZ_STRIPPED]
|
|
var/file_hash = rustg_hash_file(RUSTG_HASH_MD5, file_path)
|
|
SSassets.transport.register_asset("[name]_[size_id].png", file_path, file_hash=file_hash)
|
|
var/css_name = "spritesheet_[name].css"
|
|
var/file_directory = "data/spritesheets/[css_name]"
|
|
fdel(file_directory)
|
|
var/css = generate_css()
|
|
rustg_file_write(css, file_directory)
|
|
var/css_hash = rustg_hash_string(RUSTG_HASH_MD5, css)
|
|
SSassets.transport.register_asset(css_name, fcopy_rsc(file_directory), file_hash=css_hash)
|
|
|
|
if(CONFIG_GET(flag/save_spritesheets))
|
|
save_to_logs(file_name = css_name, file_location = file_directory)
|
|
|
|
fdel(file_directory)
|
|
|
|
if (CONFIG_GET(flag/cache_assets) && cross_round_cachable)
|
|
write_to_cache()
|
|
fully_generated = TRUE
|
|
// If we were ever in there, remove ourselves
|
|
SSasset_loading.dequeue_asset(src)
|
|
|
|
/datum/asset/spritesheet/queued_generation()
|
|
realize_spritesheets(yield = TRUE)
|
|
|
|
/datum/asset/spritesheet/ensure_ready()
|
|
if(!fully_generated)
|
|
realize_spritesheets(yield = FALSE)
|
|
return ..()
|
|
|
|
/datum/asset/spritesheet/send(client/client)
|
|
if (!name)
|
|
return
|
|
|
|
if (!should_refresh())
|
|
return send_from_cache(client)
|
|
|
|
var/all = list("spritesheet_[name].css")
|
|
for(var/size_id in sizes)
|
|
all += "[name]_[size_id].png"
|
|
. = SSassets.transport.send_assets(client, all)
|
|
|
|
/datum/asset/spritesheet/get_url_mappings()
|
|
if (!name)
|
|
return
|
|
|
|
if (!should_refresh())
|
|
return get_cached_url_mappings()
|
|
|
|
. = list("spritesheet_[name].css" = SSassets.transport.get_asset_url("spritesheet_[name].css"))
|
|
for(var/size_id in sizes)
|
|
.["[name]_[size_id].png"] = SSassets.transport.get_asset_url("[name]_[size_id].png")
|
|
|
|
/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes)
|
|
for(var/size_id in sizes_to_strip)
|
|
var/size = sizes[size_id]
|
|
if (size[SPRSZ_STRIPPED])
|
|
continue
|
|
|
|
// save flattened version
|
|
var/png_name = "[name]_[size_id].png"
|
|
var/file_directory = "data/spritesheets/[png_name]"
|
|
fcopy(size[SPRSZ_ICON], file_directory)
|
|
var/error = rustg_dmi_strip_metadata(file_directory)
|
|
if(length(error))
|
|
stack_trace("Failed to strip [png_name]: [error]")
|
|
size[SPRSZ_STRIPPED] = icon(file_directory)
|
|
|
|
// this is useful here for determining if weird sprite issues (like having a white background) are a cause of what we're doing DM-side or not since we can see the full flattened thing at-a-glance.
|
|
if(CONFIG_GET(flag/save_spritesheets))
|
|
save_to_logs(file_name = png_name, file_location = file_directory)
|
|
|
|
fdel(file_directory)
|
|
|
|
/datum/asset/spritesheet/proc/generate_css()
|
|
var/list/out = list()
|
|
|
|
for (var/size_id in sizes)
|
|
var/size = sizes[size_id]
|
|
var/list/dimensions = get_icon_dimensions(size[SPRSZ_ICON])
|
|
out += ".[name][size_id]{display:inline-block;width:[dimensions["width"]]px;height:[dimensions["height"]]px;background-image:url('[get_background_url("[name]_[size_id].png")]');background-repeat:no-repeat;}"
|
|
|
|
for (var/sprite_id in sprites)
|
|
var/sprite = sprites[sprite_id]
|
|
var/size_id = sprite[SPR_SIZE]
|
|
var/idx = sprite[SPR_IDX]
|
|
var/size = sizes[size_id]
|
|
|
|
var/list/tiny_dimensions = get_icon_dimensions(size[SPRSZ_ICON])
|
|
var/icon/big = size[SPRSZ_STRIPPED]
|
|
// big width won't be cached ever
|
|
var/per_line = big.Width() / tiny_dimensions["width"]
|
|
var/x = (idx % per_line) * tiny_dimensions["width"]
|
|
var/y = round(idx / per_line) * tiny_dimensions["height"]
|
|
|
|
out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}"
|
|
|
|
return out.Join("\n")
|
|
|
|
/datum/asset/spritesheet/proc/css_cache_filename()
|
|
return "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].css"
|
|
|
|
/datum/asset/spritesheet/proc/data_cache_filename()
|
|
return "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].json"
|
|
|
|
/datum/asset/spritesheet/proc/read_from_cache()
|
|
return read_css_from_cache() && read_data_from_cache()
|
|
|
|
/datum/asset/spritesheet/proc/read_css_from_cache()
|
|
var/replaced_css = rustg_file_read(css_cache_filename())
|
|
|
|
var/regex/find_background_urls = regex(@"background-image:url\('%(.+?)%'\)", "g")
|
|
while (find_background_urls.Find(replaced_css))
|
|
var/asset_id = find_background_urls.group[1]
|
|
var/file_path = "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[asset_id]"
|
|
// Hashing it here is a *lot* faster.
|
|
var/hash = rustg_hash_file(RUSTG_HASH_MD5, file_path)
|
|
var/asset_cache_item = SSassets.transport.register_asset(asset_id, file_path, file_hash=hash)
|
|
var/asset_url = SSassets.transport.get_asset_url(asset_cache_item = asset_cache_item)
|
|
replaced_css = replacetext(replaced_css, find_background_urls.match, "background-image:url('[asset_url]')")
|
|
LAZYADD(cached_spritesheets_needed, asset_id)
|
|
|
|
var/finalized_name = "spritesheet_[name].css"
|
|
var/replaced_css_filename = "data/spritesheets/[finalized_name]"
|
|
var/css_hash = rustg_hash_string(RUSTG_HASH_MD5, replaced_css)
|
|
rustg_file_write(replaced_css, replaced_css_filename)
|
|
SSassets.transport.register_asset(finalized_name, replaced_css_filename, file_hash=css_hash)
|
|
|
|
if(CONFIG_GET(flag/save_spritesheets))
|
|
save_to_logs(file_name = finalized_name, file_location = replaced_css_filename)
|
|
|
|
fdel(replaced_css_filename)
|
|
|
|
return TRUE
|
|
|
|
/datum/asset/spritesheet/proc/read_data_from_cache()
|
|
var/json = json_decode(rustg_file_read(data_cache_filename()))
|
|
|
|
if (islist(json["sprites"]))
|
|
sprites = json["sprites"]
|
|
|
|
return TRUE
|
|
|
|
/datum/asset/spritesheet/proc/send_from_cache(client/client)
|
|
if (isnull(cached_spritesheets_needed))
|
|
stack_trace("cached_spritesheets_needed was null when sending assets from [type] from cache")
|
|
cached_spritesheets_needed = list()
|
|
|
|
return SSassets.transport.send_assets(client, cached_spritesheets_needed + "spritesheet_[name].css")
|
|
|
|
/// Returns the URL to put in the background:url of the CSS asset
|
|
/datum/asset/spritesheet/proc/get_background_url(asset)
|
|
if (generating_cache)
|
|
return "%[asset]%"
|
|
else
|
|
return SSassets.transport.get_asset_url(asset)
|
|
|
|
/datum/asset/spritesheet/proc/write_to_cache()
|
|
write_css_to_cache()
|
|
write_data_to_cache()
|
|
|
|
/datum/asset/spritesheet/proc/write_css_to_cache()
|
|
for (var/size_id in sizes)
|
|
fcopy(SSassets.cache["[name]_[size_id].png"].resource, "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name]_[size_id].png")
|
|
|
|
generating_cache = TRUE
|
|
var/mock_css = generate_css()
|
|
generating_cache = FALSE
|
|
|
|
rustg_file_write(mock_css, css_cache_filename())
|
|
|
|
/datum/asset/spritesheet/proc/write_data_to_cache()
|
|
rustg_file_write(json_encode(list(
|
|
"sprites" = sprites,
|
|
)), data_cache_filename())
|
|
|
|
/datum/asset/spritesheet/proc/get_cached_url_mappings()
|
|
var/list/mappings = list()
|
|
mappings["spritesheet_[name].css"] = SSassets.transport.get_asset_url("spritesheet_[name].css")
|
|
|
|
for (var/asset_name in cached_spritesheets_needed)
|
|
mappings[asset_name] = SSassets.transport.get_asset_url(asset_name)
|
|
|
|
return mappings
|
|
|
|
/// Override this in order to start the creation of the spritehseet.
|
|
/// This is where all your Insert, InsertAll, etc calls should be inside.
|
|
/datum/asset/spritesheet/proc/create_spritesheets()
|
|
CRASH("create_spritesheets() not implemented for [type]!")
|
|
|
|
/datum/asset/spritesheet/proc/Insert(sprite_name, icon/inserted_icon, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
|
|
if(should_load_immediately())
|
|
queuedInsert(sprite_name, inserted_icon, icon_state, dir, frame, moving)
|
|
else
|
|
to_generate += list(args.Copy())
|
|
|
|
/datum/asset/spritesheet/proc/queuedInsert(sprite_name, icon/inserted_icon, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
|
|
#ifdef UNIT_TESTS
|
|
if (inserted_icon && icon_state && !icon_exists(inserted_icon, icon_state)) // check the base icon prior to extracting the state we want
|
|
stack_trace("Tried to insert nonexistent icon_state '[icon_state]' from [inserted_icon] into spritesheet [name] ([type])")
|
|
return
|
|
#endif
|
|
inserted_icon = icon(inserted_icon, icon_state=icon_state, dir=dir, frame=frame, moving=moving)
|
|
if (!inserted_icon || !length(icon_states(inserted_icon))) // that direction or state doesn't exist
|
|
return
|
|
|
|
var/start_usage = world.tick_usage
|
|
|
|
//any sprite modifications we want to do (aka, coloring a greyscaled asset)
|
|
inserted_icon = ModifyInserted(inserted_icon)
|
|
var/list/dimensions = get_icon_dimensions(inserted_icon)
|
|
var/size_id = "[dimensions["width"]]x[dimensions["height"]]"
|
|
var/size = sizes[size_id]
|
|
|
|
if (sprites[sprite_name])
|
|
CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])")
|
|
|
|
if (size)
|
|
var/position = size[SPRSZ_COUNT]++
|
|
// Icons are essentially representations of files + modifications
|
|
// Because of this, byond keeps them in a cache. It does this in a really dumb way tho
|
|
// It's essentially a FIFO queue. So after we do icon() some amount of times, our old icons go out of cache
|
|
// When this happens it becomes impossible to modify them, trying to do so will instead throw a
|
|
// "bad icon" error.
|
|
// What we're doing here is ensuring our icon is in the cache by refreshing it, so we can modify it w/o runtimes.
|
|
var/icon/sheet = size[SPRSZ_ICON]
|
|
var/icon/sheet_copy = icon(sheet)
|
|
size[SPRSZ_STRIPPED] = null
|
|
sheet_copy.Insert(inserted_icon, icon_state=sprite_name)
|
|
size[SPRSZ_ICON] = sheet_copy
|
|
|
|
sprites[sprite_name] = list(size_id, position)
|
|
else
|
|
sizes[size_id] = size = list(1, inserted_icon, null)
|
|
sprites[sprite_name] = list(size_id, 0)
|
|
|
|
SSblackbox.record_feedback("tally", "spritesheet_queued_insert_time", TICK_USAGE_TO_MS(start_usage), name)
|
|
|
|
/**
|
|
* A simple proc handing the Icon for you to modify before it gets turned into an asset.
|
|
*
|
|
* Arguments:
|
|
* * I: icon being turned into an asset
|
|
*/
|
|
/datum/asset/spritesheet/proc/ModifyInserted(icon/pre_asset)
|
|
return pre_asset
|
|
|
|
/datum/asset/spritesheet/proc/InsertAll(prefix, icon/inserted_icon, list/directions)
|
|
if (length(prefix))
|
|
prefix = "[prefix]-"
|
|
|
|
if (!directions)
|
|
directions = list(SOUTH)
|
|
|
|
for (var/icon_state_name in icon_states(inserted_icon))
|
|
for (var/direction in directions)
|
|
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : ""
|
|
Insert("[prefix][prefix2][icon_state_name]", inserted_icon, icon_state=icon_state_name, dir=direction)
|
|
|
|
/datum/asset/spritesheet/proc/css_tag()
|
|
return {"<link rel="stylesheet" href="[css_filename()]" />"}
|
|
|
|
/datum/asset/spritesheet/proc/css_filename()
|
|
return SSassets.transport.get_asset_url("spritesheet_[name].css")
|
|
|
|
/datum/asset/spritesheet/proc/icon_tag(sprite_name)
|
|
var/sprite = sprites[sprite_name]
|
|
if (!sprite)
|
|
return null
|
|
var/size_id = sprite[SPR_SIZE]
|
|
return {"<span class='[name][size_id] [sprite_name]'></span>"}
|
|
|
|
/datum/asset/spritesheet/proc/icon_class_name(sprite_name)
|
|
var/sprite = sprites[sprite_name]
|
|
if (!sprite)
|
|
return null
|
|
var/size_id = sprite[SPR_SIZE]
|
|
return {"[name][size_id] [sprite_name]"}
|
|
|
|
/**
|
|
* Returns the size class (ex design32x32) for a given sprite's icon
|
|
*
|
|
* Arguments:
|
|
* * sprite_name - The sprite to get the size of
|
|
*/
|
|
/datum/asset/spritesheet/proc/icon_size_id(sprite_name)
|
|
var/sprite = sprites[sprite_name]
|
|
if (!sprite)
|
|
return null
|
|
var/size_id = sprite[SPR_SIZE]
|
|
return "[name][size_id]"
|
|
|
|
#undef SPR_SIZE
|
|
#undef SPR_IDX
|
|
#undef SPRSZ_COUNT
|
|
#undef SPRSZ_ICON
|
|
#undef SPRSZ_STRIPPED
|
|
|
|
/// Spritesheet that only uses simple PNGs and CSS keys. See `assets` variable.
|
|
/// Deprecated: Use /datum/asset/spritesheet_batched where possible
|
|
/datum/asset/spritesheet/simple
|
|
abstract_type = /datum/asset/spritesheet/simple
|
|
/// Associative list of icon keys (CSS class names) -> PNG filepaths (single quote!)
|
|
/// File paths MUST be PNGs
|
|
var/list/assets
|
|
|
|
/datum/asset/spritesheet/simple/create_spritesheets()
|
|
for (var/key in assets)
|
|
Insert(key, assets[key])
|