mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-20 19:49:39 +01:00
Asset cache now caches the asset's md5 This should solve the high cpu usage issues with it. line by line profile suggests that the next hotspot is the asset log. Simplied asset cache code, moved verify functionality to a flush_assets proc that blocks until a client has all currently sending assets. (sidenote: there is an argument for moving most of asset_cache's global procs onto the client, get_asset_datum and register_asset are really the only valid global procs.) Re-added batched passive sends since it does speed up how quickly the asset cache pre-caches to clients.
231 lines
6.8 KiB
Plaintext
231 lines
6.8 KiB
Plaintext
|
|
//These datums are used to populate the asset cache, the proc "register()" does this.
|
|
//Place any asset datums you create in asset_list_items.dm
|
|
|
|
//all of our asset datums, used for referring to these later
|
|
GLOBAL_LIST_EMPTY(asset_datums)
|
|
|
|
//get an assetdatum or make a new one
|
|
/proc/get_asset_datum(type)
|
|
return GLOB.asset_datums[type] || new type()
|
|
|
|
/datum/asset
|
|
var/_abstract = /datum/asset
|
|
|
|
/datum/asset/New()
|
|
GLOB.asset_datums[type] = src
|
|
register()
|
|
|
|
/datum/asset/proc/register()
|
|
return
|
|
|
|
/datum/asset/proc/send(client)
|
|
return
|
|
|
|
|
|
//If you don't need anything complicated.
|
|
/datum/asset/simple
|
|
_abstract = /datum/asset/simple
|
|
var/assets = list()
|
|
|
|
/datum/asset/simple/register()
|
|
for(var/asset_name in assets)
|
|
register_asset(asset_name, assets[asset_name])
|
|
|
|
/datum/asset/simple/send(client)
|
|
. = send_asset_list(client, assets)
|
|
|
|
|
|
// For registering or sending multiple others at once
|
|
/datum/asset/group
|
|
_abstract = /datum/asset/group
|
|
var/list/children
|
|
|
|
/datum/asset/group/register()
|
|
for(var/type in children)
|
|
get_asset_datum(type)
|
|
|
|
/datum/asset/group/send(client/C)
|
|
for(var/type in children)
|
|
var/datum/asset/A = get_asset_datum(type)
|
|
. = A.send(C) || .
|
|
|
|
|
|
// 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
|
|
|
|
/datum/asset/spritesheet
|
|
_abstract = /datum/asset/spritesheet
|
|
var/name
|
|
var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped)
|
|
var/list/sprites = list() // "foo_bar" -> list("32x32", 5)
|
|
|
|
/datum/asset/spritesheet/register()
|
|
if (!name)
|
|
CRASH("spritesheet [type] cannot register without a name")
|
|
ensure_stripped()
|
|
|
|
var/res_name = "spritesheet_[name].css"
|
|
var/fname = "data/spritesheets/[res_name]"
|
|
fdel(fname)
|
|
text2file(generate_css(), fname)
|
|
register_asset(res_name, fcopy_rsc(fname))
|
|
fdel(fname)
|
|
|
|
for(var/size_id in sizes)
|
|
var/size = sizes[size_id]
|
|
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
|
|
|
|
/datum/asset/spritesheet/send(client/C)
|
|
if (!name)
|
|
return
|
|
var/all = list("spritesheet_[name].css")
|
|
for(var/size_id in sizes)
|
|
all += "[name]_[size_id].png"
|
|
. = send_asset_list(C, all)
|
|
|
|
/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/fname = "data/spritesheets/[name]_[size_id].png"
|
|
fcopy(size[SPRSZ_ICON], fname)
|
|
var/error = rustg_dmi_strip_metadata(fname)
|
|
if(length(error))
|
|
stack_trace("Failed to strip [name]_[size_id].png: [error]")
|
|
size[SPRSZ_STRIPPED] = icon(fname)
|
|
fdel(fname)
|
|
|
|
/datum/asset/spritesheet/proc/generate_css()
|
|
var/list/out = list()
|
|
|
|
for (var/size_id in sizes)
|
|
var/size = sizes[size_id]
|
|
var/icon/tiny = size[SPRSZ_ICON]
|
|
out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') 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/icon/tiny = size[SPRSZ_ICON]
|
|
var/icon/big = size[SPRSZ_STRIPPED]
|
|
var/per_line = big.Width() / tiny.Width()
|
|
var/x = (idx % per_line) * tiny.Width()
|
|
var/y = round(idx / per_line) * tiny.Height()
|
|
|
|
out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}"
|
|
|
|
return out.Join("\n")
|
|
|
|
/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
|
|
I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving)
|
|
if (!I || !length(icon_states(I))) // that direction or state doesn't exist
|
|
return
|
|
var/size_id = "[I.Width()]x[I.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]++
|
|
var/icon/sheet = size[SPRSZ_ICON]
|
|
size[SPRSZ_STRIPPED] = null
|
|
sheet.Insert(I, icon_state=sprite_name)
|
|
sprites[sprite_name] = list(size_id, position)
|
|
else
|
|
sizes[size_id] = size = list(1, I, null)
|
|
sprites[sprite_name] = list(size_id, 0)
|
|
|
|
/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions)
|
|
if (length(prefix))
|
|
prefix = "[prefix]-"
|
|
|
|
if (!directions)
|
|
directions = list(SOUTH)
|
|
|
|
for (var/icon_state_name in icon_states(I))
|
|
for (var/direction in directions)
|
|
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : ""
|
|
Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction)
|
|
|
|
/datum/asset/spritesheet/proc/css_tag()
|
|
return {"<link rel="stylesheet" href="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]"}
|
|
|
|
#undef SPR_SIZE
|
|
#undef SPR_IDX
|
|
#undef SPRSZ_COUNT
|
|
#undef SPRSZ_ICON
|
|
#undef SPRSZ_STRIPPED
|
|
|
|
|
|
/datum/asset/spritesheet/simple
|
|
_abstract = /datum/asset/spritesheet/simple
|
|
var/list/assets
|
|
|
|
/datum/asset/spritesheet/simple/register()
|
|
for (var/key in assets)
|
|
Insert(key, assets[key])
|
|
..()
|
|
|
|
//Generates assets based on iconstates of a single icon
|
|
/datum/asset/simple/icon_states
|
|
_abstract = /datum/asset/simple/icon_states
|
|
var/icon
|
|
var/list/directions = list(SOUTH)
|
|
var/frame = 1
|
|
var/movement_states = FALSE
|
|
|
|
var/prefix = "default" //asset_name = "[prefix].[icon_state_name].png"
|
|
var/generic_icon_names = FALSE //generate icon filenames using generate_asset_name() instead the above format
|
|
|
|
/datum/asset/simple/icon_states/register(_icon = icon)
|
|
for(var/icon_state_name in icon_states(_icon))
|
|
for(var/direction in directions)
|
|
var/asset = icon(_icon, icon_state_name, direction, frame, movement_states)
|
|
if (!asset)
|
|
continue
|
|
asset = fcopy_rsc(asset) //dedupe
|
|
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : ""
|
|
var/asset_name = sanitize_filename("[prefix].[prefix2][icon_state_name].png")
|
|
if (generic_icon_names)
|
|
asset_name = "[generate_asset_name(asset)].png"
|
|
|
|
register_asset(asset_name, asset)
|
|
|
|
/datum/asset/simple/icon_states/multiple_icons
|
|
_abstract = /datum/asset/simple/icon_states/multiple_icons
|
|
var/list/icons
|
|
|
|
/datum/asset/simple/icon_states/multiple_icons/register()
|
|
for(var/i in icons)
|
|
..(i)
|
|
|
|
|