oops updates asset cache
This commit is contained in:
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
Asset cache quick users guide:
|
||||
|
||||
Make a datum in asset_list_items.dm with your assets for your thing.
|
||||
Checkout asset_list.dm for the helper subclasses
|
||||
The simple subclass will most like be of use for most cases.
|
||||
Then call get_asset_datum() with the type of the datum you created and store the return
|
||||
Then call .send(client) on that stored return value.
|
||||
|
||||
Note: If your code uses output() with assets you will need to call asset_flush on the client and wait for it to return before calling output(). You only need do this if .send(client) returned TRUE
|
||||
*/
|
||||
|
||||
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
|
||||
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
|
||||
|
||||
//This proc sends the asset to the client, but only if it needs it.
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset(client/client, asset_name)
|
||||
return send_asset_list(client, list(asset_name))
|
||||
|
||||
/// Sends a list of assets to a client
|
||||
/// This proc will no longer block, use client.asset_flush() if you to need know when the client has all assets (such as for output()). (This is not required for browse() calls as they use the same message queue as asset sends)
|
||||
/// client - a client or mob
|
||||
/// asset_list - A list of asset filenames to be sent to the client.
|
||||
/// Returns TRUE if any assets were sent.
|
||||
/proc/send_asset_list(client/client, list/asset_list)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
else
|
||||
return
|
||||
else
|
||||
return
|
||||
|
||||
var/list/unreceived = list()
|
||||
|
||||
for (var/asset_name in asset_list)
|
||||
var/datum/asset_cache_item/asset = SSassets.cache[asset_name]
|
||||
if (!asset)
|
||||
continue
|
||||
var/asset_file = asset.resource
|
||||
if (!asset_file)
|
||||
continue
|
||||
|
||||
var/asset_md5 = asset.md5
|
||||
if (client.sent_assets[asset_name] == asset_md5)
|
||||
continue
|
||||
unreceived[asset_name] = asset_md5
|
||||
|
||||
if (unreceived.len)
|
||||
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
|
||||
to_chat(client, "Sending Resources...")
|
||||
|
||||
for(var/asset in unreceived)
|
||||
var/datum/asset_cache_item/ACI
|
||||
if ((ACI = SSassets.cache[asset]))
|
||||
log_asset("Sending asset [asset] to client [client]")
|
||||
client << browse_rsc(ACI.resource, asset)
|
||||
|
||||
client.sent_assets |= unreceived
|
||||
addtimer(CALLBACK(client, /client/proc/asset_cache_update_json), 1 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
|
||||
//The proc calls procs that sleep for long times.
|
||||
/proc/getFilesSlow(client/client, list/files, register_asset = TRUE, filerate = 3)
|
||||
var/startingfilerate = filerate
|
||||
for(var/file in files)
|
||||
if (!client)
|
||||
break
|
||||
if (register_asset)
|
||||
register_asset(file, files[file])
|
||||
|
||||
if (send_asset(client, file))
|
||||
if (!(--filerate))
|
||||
filerate = startingfilerate
|
||||
client.asset_flush()
|
||||
stoplag(0) //queuing calls like this too quickly can cause issues in some client versions
|
||||
|
||||
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
|
||||
//icons and virtual assets get copied to the dyn rsc before use
|
||||
/proc/register_asset(asset_name, asset)
|
||||
var/datum/asset_cache_item/ACI = new(asset_name, asset)
|
||||
|
||||
//this is technically never something that was supported and i want metrics on how often it happens if at all.
|
||||
if (SSassets.cache[asset_name])
|
||||
var/datum/asset_cache_item/OACI = SSassets.cache[asset_name]
|
||||
if (OACI.md5 != ACI.md5)
|
||||
stack_trace("ERROR: new asset added to the asset cache with the same name as another asset: [asset_name] existing asset md5: [OACI.md5] new asset md5:[ACI.md5]")
|
||||
else
|
||||
var/list/stacktrace = gib_stack_trace()
|
||||
log_asset("WARNING: dupe asset added to the asset cache: [asset_name] existing asset md5: [OACI.md5] new asset md5:[ACI.md5]\n[stacktrace.Join("\n")]")
|
||||
SSassets.cache[asset_name] = ACI
|
||||
return ACI
|
||||
|
||||
/// Returns the url of the asset, currently this is just its name, here to allow further work cdn'ing assets.
|
||||
/// Can be given an asset as well, this is just a work around for buggy edge cases where two assets may have the same name, doesn't matter now, but it will when the cdn comes.
|
||||
/proc/get_asset_url(asset_name, asset = null)
|
||||
var/datum/asset_cache_item/ACI = SSassets.cache[asset_name]
|
||||
return ACI?.url
|
||||
|
||||
//Generated names do not include file extention.
|
||||
//Used mainly for code that deals with assets in a generic way
|
||||
//The same asset will always lead to the same asset name
|
||||
/proc/generate_asset_name(file)
|
||||
return "asset.[md5(fcopy_rsc(file))]"
|
||||
|
||||
@@ -12,10 +12,6 @@
|
||||
|
||||
/// Process asset cache client topic calls for "asset_cache_preload_data=[HTML+JSON_STRING]
|
||||
/client/proc/asset_cache_preload_data(data)
|
||||
/*var/jsonend = findtextEx(data, "{{{ENDJSONDATA}}}")
|
||||
if (!jsonend)
|
||||
CRASH("invalid asset_cache_preload_data, no jsonendmarker")*/
|
||||
//var/json = html_decode(copytext(data, 1, jsonend))
|
||||
var/json = data
|
||||
var/list/preloaded_assets = json_decode(json)
|
||||
|
||||
@@ -26,19 +22,17 @@
|
||||
sent_assets |= preloaded_assets
|
||||
|
||||
|
||||
/// Updates the client side stored html/json combo file used to keep track of what assets the client has between restarts/reconnects.
|
||||
/client/proc/asset_cache_update_json(verify = FALSE, list/new_assets = list())
|
||||
/// Updates the client side stored json file used to keep track of what assets the client has between restarts/reconnects.
|
||||
/client/proc/asset_cache_update_json()
|
||||
if (world.time - connection_time < 10 SECONDS) //don't override the existing data file on a new connection
|
||||
return
|
||||
if (!islist(new_assets))
|
||||
new_assets = list("[new_assets]" = md5(SSassets.cache[new_assets]))
|
||||
|
||||
src << browse(json_encode(new_assets|sent_assets), "file=asset_data.json&display=0")
|
||||
src << browse(json_encode(sent_assets), "file=asset_data.json&display=0")
|
||||
|
||||
/// Blocks until all currently sending browser assets have been sent.
|
||||
/// Blocks until all currently sending browse and browse_rsc assets have been sent.
|
||||
/// Due to byond limitations, this proc will sleep for 1 client round trip even if the client has no pending asset sends.
|
||||
/// This proc will return an untrue value if it had to return before confirming the send, such as timeout or the client going away.
|
||||
/client/proc/asset_flush(timeout = 50)
|
||||
/client/proc/browse_queue_flush(timeout = 50)
|
||||
var/job = ++last_asset_job
|
||||
var/t = 0
|
||||
var/timeout_time = timeout
|
||||
|
||||
@@ -1,23 +1,43 @@
|
||||
/**
|
||||
* # asset_cache_item
|
||||
*
|
||||
* An internal datum containing info on items in the asset cache. Mainly used to cache md5 info for speed.
|
||||
**/
|
||||
* # asset_cache_item
|
||||
*
|
||||
* An internal datum containing info on items in the asset cache. Mainly used to cache md5 info for speed.
|
||||
*/
|
||||
/datum/asset_cache_item
|
||||
var/name
|
||||
var/url
|
||||
var/md5
|
||||
var/hash
|
||||
var/resource
|
||||
var/ext = ""
|
||||
/// Should this file also be sent via the legacy browse_rsc system
|
||||
/// when cdn transports are enabled?
|
||||
var/legacy = FALSE
|
||||
/// Used by the cdn system to keep legacy css assets with their parent
|
||||
/// css file. (css files resolve urls relative to the css file, so the
|
||||
/// legacy system can't be used if the css file itself could go out over
|
||||
/// the cdn)
|
||||
var/namespace = null
|
||||
/// True if this is the parent css or html file for an asset's namespace
|
||||
var/namespace_parent = FALSE
|
||||
/// TRUE for keeping local asset names when browse_rsc backend is used
|
||||
var/keep_local_name = FALSE
|
||||
|
||||
/datum/asset_cache_item/New(name, file)
|
||||
if (!isfile(file))
|
||||
file = fcopy_rsc(file)
|
||||
md5 = md5(file)
|
||||
if (!md5)
|
||||
md5 = md5(fcopy_rsc(file))
|
||||
if (!md5)
|
||||
hash = md5(file)
|
||||
if (!hash)
|
||||
hash = md5(fcopy_rsc(file))
|
||||
if (!hash)
|
||||
CRASH("invalid asset sent to asset cache")
|
||||
debug_world_log("asset cache unexpected success of second fcopy_rsc")
|
||||
src.name = name
|
||||
url = name
|
||||
var/extstart = findlasttext(name, ".")
|
||||
if (extstart)
|
||||
ext = ".[copytext(name, extstart+1)]"
|
||||
resource = file
|
||||
|
||||
/datum/asset_cache_item/vv_edit_var(var_name, var_value)
|
||||
return FALSE
|
||||
|
||||
/datum/asset_cache_item/CanProcCall(procname)
|
||||
return FALSE
|
||||
|
||||
@@ -26,25 +26,38 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
return
|
||||
|
||||
|
||||
//If you don't need anything complicated.
|
||||
/// If you don't need anything complicated.
|
||||
/datum/asset/simple
|
||||
_abstract = /datum/asset/simple
|
||||
/// list of assets for this datum in the form of:
|
||||
/// asset_filename = asset_file. At runtime the asset_file will be
|
||||
/// converted into a asset_cache datum.
|
||||
var/assets = list()
|
||||
/// Set to true to have this asset also be sent via the legacy browse_rsc
|
||||
/// system when cdn transports are enabled?
|
||||
var/legacy = FALSE
|
||||
/// TRUE for keeping local asset names when browse_rsc backend is used
|
||||
var/keep_local_name = FALSE
|
||||
|
||||
/datum/asset/simple/register()
|
||||
for(var/asset_name in assets)
|
||||
assets[asset_name] = register_asset(asset_name, assets[asset_name])
|
||||
var/datum/asset_cache_item/ACI = SSassets.transport.register_asset(asset_name, assets[asset_name])
|
||||
if (!ACI)
|
||||
log_asset("ERROR: Invalid asset: [type]:[asset_name]:[ACI]")
|
||||
continue
|
||||
if (legacy)
|
||||
ACI.legacy = legacy
|
||||
if (keep_local_name)
|
||||
ACI.keep_local_name = keep_local_name
|
||||
assets[asset_name] = ACI
|
||||
|
||||
/datum/asset/simple/send(client)
|
||||
. = send_asset_list(client, assets)
|
||||
. = SSassets.transport.send_assets(client, assets)
|
||||
|
||||
/datum/asset/simple/get_url_mappings()
|
||||
. = list()
|
||||
for (var/asset_name in assets)
|
||||
var/datum/asset_cache_item/ACI = assets[asset_name]
|
||||
if (!ACI)
|
||||
continue
|
||||
.[asset_name] = ACI.url
|
||||
.[asset_name] = SSassets.transport.get_asset_url(asset_name, assets[asset_name])
|
||||
|
||||
|
||||
// For registering or sending multiple others at once
|
||||
@@ -88,12 +101,12 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
ensure_stripped()
|
||||
for(var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
|
||||
SSassets.transport.register_asset("[name]_[size_id].png", size[SPRSZ_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))
|
||||
SSassets.transport.register_asset(res_name, fcopy_rsc(fname))
|
||||
fdel(fname)
|
||||
|
||||
/datum/asset/spritesheet/send(client/C)
|
||||
@@ -102,14 +115,14 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
var/all = list("spritesheet_[name].css")
|
||||
for(var/size_id in sizes)
|
||||
all += "[name]_[size_id].png"
|
||||
. = send_asset_list(C, all)
|
||||
. = SSassets.transport.send_assets(C, all)
|
||||
|
||||
/datum/asset/spritesheet/get_url_mappings()
|
||||
if (!name)
|
||||
return
|
||||
. = list("spritesheet_[name].css" = get_asset_url("spritesheet_[name].css"))
|
||||
. = list("spritesheet_[name].css" = SSassets.transport.get_asset_url("spritesheet_[name].css"))
|
||||
for(var/size_id in sizes)
|
||||
.["[name]_[size_id].png"] = get_asset_url("[name]_[size_id].png")
|
||||
.["[name]_[size_id].png"] = SSassets.transport.get_asset_url("[name]_[size_id].png")
|
||||
|
||||
|
||||
|
||||
@@ -134,7 +147,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
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('[get_asset_url("[name]_[size_id].png")]') no-repeat;}"
|
||||
out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[SSassets.transport.get_asset_url("[name]_[size_id].png")]') no-repeat;}"
|
||||
|
||||
for (var/sprite_id in sprites)
|
||||
var/sprite = sprites[sprite_id]
|
||||
@@ -188,7 +201,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
return {"<link rel="stylesheet" href="[css_filename()]" />"}
|
||||
|
||||
/datum/asset/spritesheet/proc/css_filename()
|
||||
return get_asset_url("spritesheet_[name].css")
|
||||
return SSassets.transport.get_asset_url("spritesheet_[name].css")
|
||||
|
||||
/datum/asset/spritesheet/proc/icon_tag(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
@@ -243,7 +256,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
if (generic_icon_names)
|
||||
asset_name = "[generate_asset_name(asset)].png"
|
||||
|
||||
register_asset(asset_name, asset)
|
||||
SSassets.transport.register_asset(asset_name, asset)
|
||||
|
||||
/datum/asset/simple/icon_states/multiple_icons
|
||||
_abstract = /datum/asset/simple/icon_states/multiple_icons
|
||||
@@ -253,4 +266,52 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
for(var/i in icons)
|
||||
..(i)
|
||||
|
||||
/// Namespace'ed assets (for static css and html files)
|
||||
/// When sent over a cdn transport, all assets in the same asset datum will exist in the same folder, as their plain names.
|
||||
/// Used to ensure css files can reference files by url() without having to generate the css at runtime, both the css file and the files it depends on must exist in the same namespace asset datum. (Also works for html)
|
||||
/// For example `blah.css` with asset `blah.png` will get loaded as `namespaces/a3d..14f/f12..d3c.css` and `namespaces/a3d..14f/blah.png`. allowing the css file to load `blah.png` by a relative url rather then compute the generated url with get_url_mappings().
|
||||
/// The namespace folder's name will change if any of the assets change. (excluding parent assets)
|
||||
/datum/asset/simple/namespaced
|
||||
_abstract = /datum/asset/simple/namespaced
|
||||
/// parents - list of the parent asset or assets (in name = file assoicated format) for this namespace.
|
||||
/// parent assets must be referenced by their generated url, but if an update changes a parent asset, it won't change the namespace's identity.
|
||||
var/list/parents = list()
|
||||
|
||||
/datum/asset/simple/namespaced/register()
|
||||
if (legacy)
|
||||
assets |= parents
|
||||
var/list/hashlist = list()
|
||||
var/list/sorted_assets = sortList(assets)
|
||||
|
||||
for (var/asset_name in sorted_assets)
|
||||
var/datum/asset_cache_item/ACI = new(asset_name, sorted_assets[asset_name])
|
||||
if (!ACI?.hash)
|
||||
log_asset("ERROR: Invalid asset: [type]:[asset_name]:[ACI]")
|
||||
continue
|
||||
hashlist += ACI.hash
|
||||
sorted_assets[asset_name] = ACI
|
||||
var/namespace = md5(hashlist.Join())
|
||||
|
||||
for (var/asset_name in parents)
|
||||
var/datum/asset_cache_item/ACI = new(asset_name, parents[asset_name])
|
||||
if (!ACI?.hash)
|
||||
log_asset("ERROR: Invalid asset: [type]:[asset_name]:[ACI]")
|
||||
continue
|
||||
ACI.namespace_parent = TRUE
|
||||
sorted_assets[asset_name] = ACI
|
||||
|
||||
for (var/asset_name in sorted_assets)
|
||||
var/datum/asset_cache_item/ACI = sorted_assets[asset_name]
|
||||
if (!ACI?.hash)
|
||||
log_asset("ERROR: Invalid asset: [type]:[asset_name]:[ACI]")
|
||||
continue
|
||||
ACI.namespace = namespace
|
||||
|
||||
assets = sorted_assets
|
||||
..()
|
||||
|
||||
/// Get a html string that will load a html asset.
|
||||
/// Needed because byond doesn't allow you to browse() to a url.
|
||||
/datum/asset/simple/namespaced/proc/get_htmlloader(filename)
|
||||
return url2htmlloader(SSassets.transport.get_asset_url(filename, assets[filename]))
|
||||
|
||||
|
||||
@@ -1,81 +1,95 @@
|
||||
//DEFINITIONS FOR ASSET DATUMS START HERE.
|
||||
|
||||
/datum/asset/simple/tgui_common
|
||||
keep_local_name = TRUE
|
||||
assets = list(
|
||||
"tgui-common.chunk.js" = 'tgui/packages/tgui/public/tgui-common.chunk.js',
|
||||
)
|
||||
|
||||
/datum/asset/simple/tgui
|
||||
keep_local_name = TRUE
|
||||
assets = list(
|
||||
"tgui.bundle.js" = 'tgui/packages/tgui/public/tgui.bundle.js',
|
||||
"tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css',
|
||||
)
|
||||
|
||||
/datum/asset/simple/tgui_panel
|
||||
keep_local_name = TRUE
|
||||
assets = list(
|
||||
"tgui-panel.bundle.js" = 'tgui/packages/tgui/public/tgui-panel.bundle.js',
|
||||
"tgui-panel.bundle.css" = 'tgui/packages/tgui/public/tgui-panel.bundle.css',
|
||||
)
|
||||
|
||||
/datum/asset/simple/headers
|
||||
assets = list(
|
||||
"alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
|
||||
"alarm_red.gif" = 'icons/program_icons/alarm_red.gif',
|
||||
"batt_5.gif" = 'icons/program_icons/batt_5.gif',
|
||||
"batt_20.gif" = 'icons/program_icons/batt_20.gif',
|
||||
"batt_40.gif" = 'icons/program_icons/batt_40.gif',
|
||||
"batt_60.gif" = 'icons/program_icons/batt_60.gif',
|
||||
"batt_80.gif" = 'icons/program_icons/batt_80.gif',
|
||||
"batt_100.gif" = 'icons/program_icons/batt_100.gif',
|
||||
"charging.gif" = 'icons/program_icons/charging.gif',
|
||||
"downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif',
|
||||
"downloader_running.gif" = 'icons/program_icons/downloader_running.gif',
|
||||
"ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif',
|
||||
"ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif',
|
||||
"power_norm.gif" = 'icons/program_icons/power_norm.gif',
|
||||
"power_warn.gif" = 'icons/program_icons/power_warn.gif',
|
||||
"sig_high.gif" = 'icons/program_icons/sig_high.gif',
|
||||
"sig_low.gif" = 'icons/program_icons/sig_low.gif',
|
||||
"sig_lan.gif" = 'icons/program_icons/sig_lan.gif',
|
||||
"sig_none.gif" = 'icons/program_icons/sig_none.gif',
|
||||
"smmon_0.gif" = 'icons/program_icons/smmon_0.gif',
|
||||
"smmon_1.gif" = 'icons/program_icons/smmon_1.gif',
|
||||
"smmon_2.gif" = 'icons/program_icons/smmon_2.gif',
|
||||
"smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
|
||||
"smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
|
||||
"smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
|
||||
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif',
|
||||
"borg_mon.gif" = 'icons/program_icons/borg_mon.gif'
|
||||
"alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
|
||||
"alarm_red.gif" = 'icons/program_icons/alarm_red.gif',
|
||||
"batt_5.gif" = 'icons/program_icons/batt_5.gif',
|
||||
"batt_20.gif" = 'icons/program_icons/batt_20.gif',
|
||||
"batt_40.gif" = 'icons/program_icons/batt_40.gif',
|
||||
"batt_60.gif" = 'icons/program_icons/batt_60.gif',
|
||||
"batt_80.gif" = 'icons/program_icons/batt_80.gif',
|
||||
"batt_100.gif" = 'icons/program_icons/batt_100.gif',
|
||||
"charging.gif" = 'icons/program_icons/charging.gif',
|
||||
"downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif',
|
||||
"downloader_running.gif" = 'icons/program_icons/downloader_running.gif',
|
||||
"ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif',
|
||||
"ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif',
|
||||
"power_norm.gif" = 'icons/program_icons/power_norm.gif',
|
||||
"power_warn.gif" = 'icons/program_icons/power_warn.gif',
|
||||
"sig_high.gif" = 'icons/program_icons/sig_high.gif',
|
||||
"sig_low.gif" = 'icons/program_icons/sig_low.gif',
|
||||
"sig_lan.gif" = 'icons/program_icons/sig_lan.gif',
|
||||
"sig_none.gif" = 'icons/program_icons/sig_none.gif',
|
||||
"smmon_0.gif" = 'icons/program_icons/smmon_0.gif',
|
||||
"smmon_1.gif" = 'icons/program_icons/smmon_1.gif',
|
||||
"smmon_2.gif" = 'icons/program_icons/smmon_2.gif',
|
||||
"smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
|
||||
"smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
|
||||
"smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
|
||||
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif',
|
||||
"borg_mon.gif" = 'icons/program_icons/borg_mon.gif'
|
||||
)
|
||||
|
||||
/datum/asset/simple/radar_assets
|
||||
assets = list(
|
||||
"ntosradarbackground.png" = 'icons/UI_Icons/tgui/ntosradar_background.png',
|
||||
"ntosradarpointer.png" = 'icons/UI_Icons/tgui/ntosradar_pointer.png',
|
||||
"ntosradarpointerS.png" = 'icons/UI_Icons/tgui/ntosradar_pointer_S.png'
|
||||
"ntosradarbackground.png" = 'icons/UI_Icons/tgui/ntosradar_background.png',
|
||||
"ntosradarpointer.png" = 'icons/UI_Icons/tgui/ntosradar_pointer.png',
|
||||
"ntosradarpointerS.png" = 'icons/UI_Icons/tgui/ntosradar_pointer_S.png'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/pda
|
||||
name = "pda"
|
||||
assets = list(
|
||||
"atmos" = 'icons/pda_icons/pda_atmos.png',
|
||||
"back" = 'icons/pda_icons/pda_back.png',
|
||||
"bell" = 'icons/pda_icons/pda_bell.png',
|
||||
"blank" = 'icons/pda_icons/pda_blank.png',
|
||||
"boom" = 'icons/pda_icons/pda_boom.png',
|
||||
"bucket" = 'icons/pda_icons/pda_bucket.png',
|
||||
"medbot" = 'icons/pda_icons/pda_medbot.png',
|
||||
"floorbot" = 'icons/pda_icons/pda_floorbot.png',
|
||||
"cleanbot" = 'icons/pda_icons/pda_cleanbot.png',
|
||||
"crate" = 'icons/pda_icons/pda_crate.png',
|
||||
"cuffs" = 'icons/pda_icons/pda_cuffs.png',
|
||||
"eject" = 'icons/pda_icons/pda_eject.png',
|
||||
"flashlight" = 'icons/pda_icons/pda_flashlight.png',
|
||||
"honk" = 'icons/pda_icons/pda_honk.png',
|
||||
"mail" = 'icons/pda_icons/pda_mail.png',
|
||||
"medical" = 'icons/pda_icons/pda_medical.png',
|
||||
"menu" = 'icons/pda_icons/pda_menu.png',
|
||||
"mule" = 'icons/pda_icons/pda_mule.png',
|
||||
"notes" = 'icons/pda_icons/pda_notes.png',
|
||||
"power" = 'icons/pda_icons/pda_power.png',
|
||||
"rdoor" = 'icons/pda_icons/pda_rdoor.png',
|
||||
"reagent" = 'icons/pda_icons/pda_reagent.png',
|
||||
"refresh" = 'icons/pda_icons/pda_refresh.png',
|
||||
"scanner" = 'icons/pda_icons/pda_scanner.png',
|
||||
"signaler" = 'icons/pda_icons/pda_signaler.png',
|
||||
// "skills" = 'icons/pda_icons/pda_skills.png',
|
||||
"status" = 'icons/pda_icons/pda_status.png',
|
||||
"dronephone" = 'icons/pda_icons/pda_dronephone.png',
|
||||
"emoji" = 'icons/pda_icons/pda_emoji.png'
|
||||
"atmos" = 'icons/pda_icons/pda_atmos.png',
|
||||
"back" = 'icons/pda_icons/pda_back.png',
|
||||
"bell" = 'icons/pda_icons/pda_bell.png',
|
||||
"blank" = 'icons/pda_icons/pda_blank.png',
|
||||
"boom" = 'icons/pda_icons/pda_boom.png',
|
||||
"bucket" = 'icons/pda_icons/pda_bucket.png',
|
||||
"medbot" = 'icons/pda_icons/pda_medbot.png',
|
||||
"floorbot" = 'icons/pda_icons/pda_floorbot.png',
|
||||
"cleanbot" = 'icons/pda_icons/pda_cleanbot.png',
|
||||
"crate" = 'icons/pda_icons/pda_crate.png',
|
||||
"cuffs" = 'icons/pda_icons/pda_cuffs.png',
|
||||
"eject" = 'icons/pda_icons/pda_eject.png',
|
||||
"flashlight" = 'icons/pda_icons/pda_flashlight.png',
|
||||
"honk" = 'icons/pda_icons/pda_honk.png',
|
||||
"mail" = 'icons/pda_icons/pda_mail.png',
|
||||
"medical" = 'icons/pda_icons/pda_medical.png',
|
||||
"menu" = 'icons/pda_icons/pda_menu.png',
|
||||
"mule" = 'icons/pda_icons/pda_mule.png',
|
||||
"notes" = 'icons/pda_icons/pda_notes.png',
|
||||
"power" = 'icons/pda_icons/pda_power.png',
|
||||
"rdoor" = 'icons/pda_icons/pda_rdoor.png',
|
||||
"reagent" = 'icons/pda_icons/pda_reagent.png',
|
||||
"refresh" = 'icons/pda_icons/pda_refresh.png',
|
||||
"scanner" = 'icons/pda_icons/pda_scanner.png',
|
||||
"signaler" = 'icons/pda_icons/pda_signaler.png',
|
||||
// "skills" = 'icons/pda_icons/pda_skills.png',
|
||||
"status" = 'icons/pda_icons/pda_status.png',
|
||||
"dronephone" = 'icons/pda_icons/pda_dronephone.png',
|
||||
"emoji" = 'icons/pda_icons/pda_emoji.png'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/paper
|
||||
@@ -92,7 +106,7 @@
|
||||
"stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png',
|
||||
"stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png',
|
||||
"stamp-law" = 'icons/stamp_icons/large_stamp-law.png'
|
||||
// "stamp-chap" = 'icons/stamp_icons/large_stamp-chap.png'
|
||||
// "stamp-chap" = 'icons/stamp_icons/large_stamp-chap.png',
|
||||
// "stamp-mime" = 'icons/stamp_icons/large_stamp-mime.png',
|
||||
// "stamp-centcom" = 'icons/stamp_icons/large_stamp-centcom.png',
|
||||
// "stamp-syndicate" = 'icons/stamp_icons/large_stamp-syndicate.png'
|
||||
@@ -110,7 +124,7 @@
|
||||
/datum/asset/simple/IRV
|
||||
)
|
||||
|
||||
/datum/asset/simple/changelog
|
||||
/datum/asset/simple/namespaced/changelog
|
||||
assets = list(
|
||||
"88x31.png" = 'html/88x31.png',
|
||||
"bug-minus.png" = 'html/bug-minus.png',
|
||||
@@ -132,43 +146,30 @@
|
||||
"chrome-wrench.png" = 'html/chrome-wrench.png',
|
||||
"changelog.css" = 'html/changelog.css'
|
||||
)
|
||||
parents = list("changelog.html" = 'html/changelog.html')
|
||||
|
||||
/datum/asset/group/goonchat
|
||||
children = list(
|
||||
/datum/asset/simple/jquery,
|
||||
/datum/asset/simple/goonchat,
|
||||
/datum/asset/spritesheet/goonchat,
|
||||
/datum/asset/simple/fontawesome
|
||||
)
|
||||
|
||||
/datum/asset/simple/jquery
|
||||
legacy = TRUE
|
||||
assets = list(
|
||||
"jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js',
|
||||
"jquery.min.js" = 'html/jquery.min.js',
|
||||
)
|
||||
|
||||
/datum/asset/simple/goonchat
|
||||
assets = list(
|
||||
"json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
|
||||
"browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js',
|
||||
"browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
|
||||
"browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css',
|
||||
"browserOutput_light.css" = 'code/modules/goonchat/browserassets/css/browserOutput_light.css'
|
||||
)
|
||||
|
||||
/datum/asset/simple/fontawesome
|
||||
/datum/asset/simple/namespaced/fontawesome
|
||||
legacy = TRUE
|
||||
assets = list(
|
||||
"fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot',
|
||||
"fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff',
|
||||
"fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot',
|
||||
"fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff',
|
||||
"font-awesome.css" = 'html/font-awesome/css/all.min.css',
|
||||
"v4shim.css" = 'html/font-awesome/css/v4-shims.min.css'
|
||||
)
|
||||
parents = list("font-awesome.css" = 'html/font-awesome/css/all.min.css')
|
||||
|
||||
/datum/asset/spritesheet/goonchat
|
||||
/datum/asset/spritesheet/chat
|
||||
name = "chat"
|
||||
|
||||
/datum/asset/spritesheet/goonchat/register()
|
||||
/datum/asset/spritesheet/chat/register()
|
||||
InsertAll("emoji", 'icons/emoji.dmi')
|
||||
InsertAll("emoji", 'icons/emoji_32.dmi')
|
||||
|
||||
@@ -181,12 +182,27 @@
|
||||
if (icon != 'icons/misc/language.dmi')
|
||||
var/icon_state = initial(L.icon_state)
|
||||
Insert("language-[icon_state]", icon, icon_state=icon_state)
|
||||
|
||||
..()
|
||||
|
||||
/datum/asset/simple/lobby
|
||||
assets = list(
|
||||
"playeroptions.css" = 'html/browser/playeroptions.css'
|
||||
)
|
||||
|
||||
/datum/asset/simple/namespaced/common
|
||||
assets = list("padlock.png" = 'html/padlock.png')
|
||||
parents = list("common.css" = 'html/browser/common.css')
|
||||
|
||||
/datum/asset/simple/permissions
|
||||
assets = list(
|
||||
"padlock.png" = 'html/padlock.png'
|
||||
"search.js" = 'html/admin/search.js',
|
||||
"panels.css" = 'html/admin/panels.css'
|
||||
)
|
||||
|
||||
/datum/asset/group/permissions
|
||||
children = list(
|
||||
/datum/asset/simple/permissions,
|
||||
/datum/asset/simple/namespaced/common
|
||||
)
|
||||
|
||||
/datum/asset/simple/notes
|
||||
@@ -206,26 +222,50 @@
|
||||
"boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif',
|
||||
"boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif',
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/minesweeper
|
||||
name = "minesweeper"
|
||||
/*
|
||||
/datum/asset/spritesheet/simple/achievements
|
||||
name ="achievements"
|
||||
assets = list(
|
||||
"1" = 'icons/UI_Icons/minesweeper_tiles/one.png',
|
||||
"2" = 'icons/UI_Icons/minesweeper_tiles/two.png',
|
||||
"3" = 'icons/UI_Icons/minesweeper_tiles/three.png',
|
||||
"4" = 'icons/UI_Icons/minesweeper_tiles/four.png',
|
||||
"5" = 'icons/UI_Icons/minesweeper_tiles/five.png',
|
||||
"6" = 'icons/UI_Icons/minesweeper_tiles/six.png',
|
||||
"7" = 'icons/UI_Icons/minesweeper_tiles/seven.png',
|
||||
"8" = 'icons/UI_Icons/minesweeper_tiles/eight.png',
|
||||
"empty" = 'icons/UI_Icons/minesweeper_tiles/empty.png',
|
||||
"flag" = 'icons/UI_Icons/minesweeper_tiles/flag.png',
|
||||
"hidden" = 'icons/UI_Icons/minesweeper_tiles/hidden.png',
|
||||
"mine" = 'icons/UI_Icons/minesweeper_tiles/mine.png',
|
||||
"minehit" = 'icons/UI_Icons/minesweeper_tiles/minehit.png'
|
||||
"default" = 'icons/UI_Icons/Achievements/default.png',
|
||||
"basemisc" = 'icons/UI_Icons/Achievements/basemisc.png',
|
||||
"baseboss" = 'icons/UI_Icons/Achievements/baseboss.png',
|
||||
"baseskill" = 'icons/UI_Icons/Achievements/baseskill.png',
|
||||
"bbgum" = 'icons/UI_Icons/Achievements/Boss/bbgum.png',
|
||||
"colossus" = 'icons/UI_Icons/Achievements/Boss/colossus.png',
|
||||
"hierophant" = 'icons/UI_Icons/Achievements/Boss/hierophant.png',
|
||||
"legion" = 'icons/UI_Icons/Achievements/Boss/legion.png',
|
||||
"miner" = 'icons/UI_Icons/Achievements/Boss/miner.png',
|
||||
"swarmer" = 'icons/UI_Icons/Achievements/Boss/swarmer.png',
|
||||
"tendril" = 'icons/UI_Icons/Achievements/Boss/tendril.png',
|
||||
"featofstrength" = 'icons/UI_Icons/Achievements/Misc/featofstrength.png',
|
||||
"helbital" = 'icons/UI_Icons/Achievements/Misc/helbital.png',
|
||||
"jackpot" = 'icons/UI_Icons/Achievements/Misc/jackpot.png',
|
||||
"meteors" = 'icons/UI_Icons/Achievements/Misc/meteors.png',
|
||||
"timewaste" = 'icons/UI_Icons/Achievements/Misc/timewaste.png',
|
||||
"upgrade" = 'icons/UI_Icons/Achievements/Misc/upgrade.png',
|
||||
"clownking" = 'icons/UI_Icons/Achievements/Misc/clownking.png',
|
||||
"clownthanks" = 'icons/UI_Icons/Achievements/Misc/clownthanks.png',
|
||||
"rule8" = 'icons/UI_Icons/Achievements/Misc/rule8.png',
|
||||
"snail" = 'icons/UI_Icons/Achievements/Misc/snail.png',
|
||||
"mining" = 'icons/UI_Icons/Achievements/Skills/mining.png',
|
||||
"assistant" = 'icons/UI_Icons/Achievements/Mafia/assistant.png',
|
||||
"changeling" = 'icons/UI_Icons/Achievements/Mafia/changeling.png',
|
||||
"chaplain" = 'icons/UI_Icons/Achievements/Mafia/chaplain.png',
|
||||
"clown" = 'icons/UI_Icons/Achievements/Mafia/clown.png',
|
||||
"detective" = 'icons/UI_Icons/Achievements/Mafia/detective.png',
|
||||
"fugitive" = 'icons/UI_Icons/Achievements/Mafia/fugitive.png',
|
||||
"hated" = 'icons/UI_Icons/Achievements/Mafia/hated.png',
|
||||
"hop" = 'icons/UI_Icons/Achievements/Mafia/hop.png',
|
||||
"lawyer" = 'icons/UI_Icons/Achievements/Mafia/lawyer.png',
|
||||
"md" = 'icons/UI_Icons/Achievements/Mafia/md.png',
|
||||
"nightmare" = 'icons/UI_Icons/Achievements/Mafia/nightmare.png',
|
||||
"obsessed" = 'icons/UI_Icons/Achievements/Mafia/obsessed.png',
|
||||
"psychologist" = 'icons/UI_Icons/Achievements/Mafia/psychologist.png',
|
||||
"thoughtfeeder" = 'icons/UI_Icons/Achievements/Mafia/thoughtfeeder.png',
|
||||
"traitor" = 'icons/UI_Icons/Achievements/Mafia/traitor.png',
|
||||
"basemafia" ='icons/UI_Icons/Achievements/basemafia.png'
|
||||
)
|
||||
|
||||
|
||||
*/
|
||||
/datum/asset/spritesheet/simple/pills
|
||||
name ="pills"
|
||||
assets = list(
|
||||
@@ -264,7 +304,7 @@
|
||||
name = "pipes"
|
||||
|
||||
/datum/asset/spritesheet/pipes/register()
|
||||
for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi'))
|
||||
for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi')) //, 'icons/obj/plumbing/fluid_ducts.dmi'))
|
||||
InsertAll("", each, GLOB.alldirs)
|
||||
..()
|
||||
|
||||
@@ -363,9 +403,9 @@
|
||||
|
||||
/datum/asset/simple/genetics
|
||||
assets = list(
|
||||
"dna_discovered.gif" = 'html/dna_discovered.gif',
|
||||
"dna_undiscovered.gif" = 'html/dna_undiscovered.gif',
|
||||
"dna_extra.gif" = 'html/dna_extra.gif'
|
||||
"dna_discovered.gif" = 'html/dna_discovered.gif',
|
||||
"dna_undiscovered.gif" = 'html/dna_undiscovered.gif',
|
||||
"dna_extra.gif" = 'html/dna_extra.gif'
|
||||
)
|
||||
|
||||
/datum/asset/simple/orbit
|
||||
|
||||
37
code/modules/asset_cache/readme.md
Normal file
37
code/modules/asset_cache/readme.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Asset cache system
|
||||
|
||||
## Framework for managing browser assets (javascript,css,images,etc)
|
||||
|
||||
This manages getting the asset to the client without doing unneeded re-sends, as well as utilizing any configured cdns.
|
||||
|
||||
There are two frameworks for using this system:
|
||||
|
||||
### Asset datum:
|
||||
|
||||
Make a datum in asset_list_items.dm with your browser assets for your thing.
|
||||
|
||||
Checkout asset_list.dm for the helper subclasses
|
||||
|
||||
The `simple` subclass will most likely be of use for most cases.
|
||||
|
||||
Call get_asset_datum() with the type of the datum you created to get your asset cache datum
|
||||
|
||||
Call .send(client|usr) on that datum to send the asset to the client. Depending on the asset transport this may or may not block.
|
||||
|
||||
Call .get_url_mappings() to get an associated list with the urls your assets can be found at.
|
||||
|
||||
### Manual backend:
|
||||
|
||||
See the documentation for `/datum/asset_transport` for the backend api the asset datums utilize.
|
||||
|
||||
The global variable `SSassets.transport` contains the currently configured transport.
|
||||
|
||||
|
||||
|
||||
### Notes:
|
||||
|
||||
Because byond browse() calls use non-blocking queues, if your code uses output() (which bypasses all of these queues) to invoke javascript functions you will need to first have the javascript announce to the server it has loaded before trying to invoke js functions.
|
||||
|
||||
To make your code work with any CDNs configured by the server, you must make sure assets are referenced from the url returned by `get_url_mappings()` or by asset_transport's `get_asset_url()`. (TGUI also has helpers for this.) If this can not be easily done, you can bypass the cdn using legacy assets, see the simple asset datum for details.
|
||||
|
||||
CSS files that use url() can be made to use the CDN without needing to rewrite all url() calls in code by using the namespaced helper datum. See the documentation for `/datum/asset/simple/namespaced` for details.
|
||||
154
code/modules/asset_cache/transports/asset_transport.dm
Normal file
154
code/modules/asset_cache/transports/asset_transport.dm
Normal file
@@ -0,0 +1,154 @@
|
||||
/// When sending mutiple assets, how many before we give the client a quaint little sending resources message
|
||||
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
|
||||
|
||||
/// Base browse_rsc asset transport
|
||||
/datum/asset_transport
|
||||
var/name = "Simple browse_rsc asset transport"
|
||||
var/static/list/preload
|
||||
/// Don't mutate the filename of assets when sending via browse_rsc.
|
||||
/// This is to make it easier to debug issues with assets, and allow server operators to bypass issues that make it to production.
|
||||
/// If turning this on fixes asset issues, something isn't using get_asset_url and the asset isn't marked legacy, fix one of those.
|
||||
var/dont_mutate_filenames = FALSE
|
||||
|
||||
/// Called when the transport is loaded by the config controller, not called on the default transport unless it gets loaded by a config change.
|
||||
/datum/asset_transport/proc/Load()
|
||||
if (CONFIG_GET(flag/asset_simple_preload))
|
||||
for(var/client/C in GLOB.clients)
|
||||
addtimer(CALLBACK(src, .proc/send_assets_slow, C, preload), 1 SECONDS)
|
||||
|
||||
/// Initialize - Called when SSassets initializes.
|
||||
/datum/asset_transport/proc/Initialize(list/assets)
|
||||
preload = assets.Copy()
|
||||
if (!CONFIG_GET(flag/asset_simple_preload))
|
||||
return
|
||||
for(var/client/C in GLOB.clients)
|
||||
addtimer(CALLBACK(src, .proc/send_assets_slow, C, preload), 1 SECONDS)
|
||||
|
||||
|
||||
/// Register a browser asset with the asset cache system
|
||||
/// asset_name - the identifier of the asset
|
||||
/// asset - the actual asset file (or an asset_cache_item datum)
|
||||
/// returns a /datum/asset_cache_item.
|
||||
/// mutiple calls to register the same asset under the same asset_name return the same datum
|
||||
/datum/asset_transport/proc/register_asset(asset_name, asset)
|
||||
var/datum/asset_cache_item/ACI = asset
|
||||
if (!istype(ACI))
|
||||
ACI = new(asset_name, asset)
|
||||
if (!ACI || !ACI.hash)
|
||||
CRASH("ERROR: Invalid asset: [asset_name]:[asset]:[ACI]")
|
||||
if (SSassets.cache[asset_name])
|
||||
var/datum/asset_cache_item/OACI = SSassets.cache[asset_name]
|
||||
OACI.legacy = ACI.legacy = (ACI.legacy|OACI.legacy)
|
||||
OACI.namespace_parent = ACI.namespace_parent = (ACI.namespace_parent | OACI.namespace_parent)
|
||||
OACI.namespace = OACI.namespace || ACI.namespace
|
||||
if (OACI.hash != ACI.hash)
|
||||
var/error_msg = "ERROR: new asset added to the asset cache with the same name as another asset: [asset_name] existing asset hash: [OACI.hash] new asset hash:[ACI.hash]"
|
||||
stack_trace(error_msg)
|
||||
log_asset(error_msg)
|
||||
else
|
||||
if (length(ACI.namespace))
|
||||
return ACI
|
||||
return OACI
|
||||
|
||||
SSassets.cache[asset_name] = ACI
|
||||
return ACI
|
||||
|
||||
|
||||
/// Returns a url for a given asset.
|
||||
/// asset_name - Name of the asset.
|
||||
/// asset_cache_item - asset cache item datum for the asset, optional, overrides asset_name
|
||||
/datum/asset_transport/proc/get_asset_url(asset_name, datum/asset_cache_item/asset_cache_item)
|
||||
if (!istype(asset_cache_item))
|
||||
asset_cache_item = SSassets.cache[asset_name]
|
||||
// To ensure code that breaks on cdns breaks in local testing, we only
|
||||
// use the normal filename on legacy assets and name space assets.
|
||||
var/keep_local_name = dont_mutate_filenames \
|
||||
|| asset_cache_item.legacy \
|
||||
|| asset_cache_item.keep_local_name \
|
||||
|| (asset_cache_item.namespace && !asset_cache_item.namespace_parent)
|
||||
if (keep_local_name)
|
||||
return url_encode(asset_cache_item.name)
|
||||
return url_encode("asset.[asset_cache_item.hash][asset_cache_item.ext]")
|
||||
|
||||
|
||||
/// Sends a list of browser assets to a client
|
||||
/// client - a client or mob
|
||||
/// asset_list - A list of asset filenames to be sent to the client. Can optionally be assoicated with the asset's asset_cache_item datum.
|
||||
/// Returns TRUE if any assets were sent.
|
||||
/datum/asset_transport/proc/send_assets(client/client, list/asset_list)
|
||||
if (!istype(client))
|
||||
if (ismob(client))
|
||||
var/mob/M = client
|
||||
if (M.client)
|
||||
client = M.client
|
||||
else //no stacktrace because this will mainly happen because the client went away
|
||||
return
|
||||
else
|
||||
CRASH("Invalid argument: client: `[client]`")
|
||||
if (!islist(asset_list))
|
||||
asset_list = list(asset_list)
|
||||
var/list/unreceived = list()
|
||||
|
||||
for (var/asset_name in asset_list)
|
||||
var/datum/asset_cache_item/ACI = asset_list[asset_name]
|
||||
if (!istype(ACI) && !(ACI = SSassets.cache[asset_name]))
|
||||
log_asset("ERROR: can't send asset `[asset_name]`: unregistered or invalid state: `[ACI]`")
|
||||
continue
|
||||
var/asset_file = ACI.resource
|
||||
if (!asset_file)
|
||||
log_asset("ERROR: can't send asset `[asset_name]`: invalid registered resource: `[ACI.resource]`")
|
||||
continue
|
||||
|
||||
var/asset_hash = ACI.hash
|
||||
var/new_asset_name = asset_name
|
||||
var/keep_local_name = dont_mutate_filenames \
|
||||
|| ACI.legacy \
|
||||
|| ACI.keep_local_name \
|
||||
|| (ACI.namespace && !ACI.namespace_parent)
|
||||
if (!keep_local_name)
|
||||
new_asset_name = "asset.[ACI.hash][ACI.ext]"
|
||||
if (client.sent_assets[new_asset_name] == asset_hash)
|
||||
if (GLOB.Debug2)
|
||||
log_asset("DEBUG: Skipping send of `[asset_name]` (as `[new_asset_name]`) for `[client]` because it already exists in the client's sent_assets list")
|
||||
continue
|
||||
unreceived[asset_name] = ACI
|
||||
|
||||
if (unreceived.len)
|
||||
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
|
||||
to_chat(client, "Sending Resources...")
|
||||
|
||||
for (var/asset_name in unreceived)
|
||||
var/new_asset_name = asset_name
|
||||
var/datum/asset_cache_item/ACI = unreceived[asset_name]
|
||||
var/keep_local_name = dont_mutate_filenames \
|
||||
|| ACI.legacy \
|
||||
|| ACI.keep_local_name \
|
||||
|| (ACI.namespace && !ACI.namespace_parent)
|
||||
if (!keep_local_name)
|
||||
new_asset_name = "asset.[ACI.hash][ACI.ext]"
|
||||
log_asset("Sending asset `[asset_name]` to client `[client]` as `[new_asset_name]`")
|
||||
client << browse_rsc(ACI.resource, new_asset_name)
|
||||
|
||||
client.sent_assets[new_asset_name] = ACI.hash
|
||||
|
||||
addtimer(CALLBACK(client, /client/proc/asset_cache_update_json), 1 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
/// Precache files without clogging up the browse() queue, used for passively sending files on connection start.
|
||||
/datum/asset_transport/proc/send_assets_slow(client/client, list/files, filerate = 3)
|
||||
var/startingfilerate = filerate
|
||||
for (var/file in files)
|
||||
if (!client)
|
||||
break
|
||||
if (send_assets(client, file))
|
||||
if (!(--filerate))
|
||||
filerate = startingfilerate
|
||||
client.browse_queue_flush()
|
||||
stoplag(0) //queuing calls like this too quickly can cause issues in some client versions
|
||||
|
||||
/// Check the config is valid to load this transport
|
||||
/// Returns TRUE or FALSE
|
||||
/datum/asset_transport/proc/validate_config(log = TRUE)
|
||||
return TRUE
|
||||
87
code/modules/asset_cache/transports/webroot_transport.dm
Normal file
87
code/modules/asset_cache/transports/webroot_transport.dm
Normal file
@@ -0,0 +1,87 @@
|
||||
/// CDN Webroot asset transport.
|
||||
/datum/asset_transport/webroot
|
||||
name = "CDN Webroot asset transport"
|
||||
|
||||
/datum/asset_transport/webroot/Load()
|
||||
if (validate_config(log = FALSE))
|
||||
load_existing_assets()
|
||||
|
||||
/// Processes thru any assets that were registered before we were loaded as a transport.
|
||||
/datum/asset_transport/webroot/proc/load_existing_assets()
|
||||
for (var/asset_name in SSassets.cache)
|
||||
var/datum/asset_cache_item/ACI = SSassets.cache[asset_name]
|
||||
save_asset_to_webroot(ACI)
|
||||
|
||||
/// Register a browser asset with the asset cache system
|
||||
/// We also save it to the CDN webroot at this step instead of waiting for send_assets()
|
||||
/// asset_name - the identifier of the asset
|
||||
/// asset - the actual asset file or an asset_cache_item datum.
|
||||
/datum/asset_transport/webroot/register_asset(asset_name, asset)
|
||||
. = ..()
|
||||
var/datum/asset_cache_item/ACI = .
|
||||
|
||||
if (istype(ACI) && ACI.hash)
|
||||
save_asset_to_webroot(ACI)
|
||||
|
||||
/// Saves the asset to the webroot taking into account namespaces and hashes.
|
||||
/datum/asset_transport/webroot/proc/save_asset_to_webroot(datum/asset_cache_item/ACI)
|
||||
var/webroot = CONFIG_GET(string/asset_cdn_webroot)
|
||||
var/newpath = "[webroot][get_asset_suffex(ACI)]"
|
||||
if (fexists(newpath))
|
||||
return
|
||||
if (fexists("[newpath].gz")) //its a common pattern in webhosting to save gzip'ed versions of text files and let the webserver serve them up as gzip compressed normal files, sometimes without keeping the original version.
|
||||
return
|
||||
return fcopy(ACI.resource, newpath)
|
||||
|
||||
/// Returns a url for a given asset.
|
||||
/// asset_name - Name of the asset.
|
||||
/// asset_cache_item - asset cache item datum for the asset, optional, overrides asset_name
|
||||
/datum/asset_transport/webroot/get_asset_url(asset_name, datum/asset_cache_item/asset_cache_item)
|
||||
if (!istype(asset_cache_item))
|
||||
asset_cache_item = SSassets.cache[asset_name]
|
||||
var/url = CONFIG_GET(string/asset_cdn_url) //config loading will handle making sure this ends in a /
|
||||
return "[url][get_asset_suffex(asset_cache_item)]"
|
||||
|
||||
/datum/asset_transport/webroot/proc/get_asset_suffex(datum/asset_cache_item/asset_cache_item)
|
||||
var/base = ""
|
||||
var/filename = "asset.[asset_cache_item.hash][asset_cache_item.ext]"
|
||||
if (length(asset_cache_item.namespace))
|
||||
base = "namespaces/[asset_cache_item.namespace]/"
|
||||
if (!asset_cache_item.namespace_parent)
|
||||
filename = "[asset_cache_item.name]"
|
||||
return base + filename
|
||||
|
||||
|
||||
/// webroot asset sending - does nothing unless passed legacy assets
|
||||
/datum/asset_transport/webroot/send_assets(client/client, list/asset_list)
|
||||
. = FALSE
|
||||
var/list/legacy_assets = list()
|
||||
if (!islist(asset_list))
|
||||
asset_list = list(asset_list)
|
||||
for (var/asset_name in asset_list)
|
||||
var/datum/asset_cache_item/ACI = asset_list[asset_name]
|
||||
if (!istype(ACI))
|
||||
ACI = SSassets.cache[asset_name]
|
||||
if (!ACI)
|
||||
legacy_assets += asset_name //pass it on to base send_assets so it can output an error
|
||||
continue
|
||||
if (ACI.legacy)
|
||||
legacy_assets[asset_name] = ACI
|
||||
if (length(legacy_assets))
|
||||
. = ..(client, legacy_assets)
|
||||
|
||||
|
||||
/// webroot slow asset sending - does nothing.
|
||||
/datum/asset_transport/webroot/send_assets_slow(client/client, list/files, filerate)
|
||||
return FALSE
|
||||
|
||||
/datum/asset_transport/webroot/validate_config(log = TRUE)
|
||||
if (!CONFIG_GET(string/asset_cdn_url))
|
||||
if (log)
|
||||
log_asset("ERROR: [type]: Invalid Config: ASSET_CDN_URL")
|
||||
return FALSE
|
||||
if (!CONFIG_GET(string/asset_cdn_webroot))
|
||||
if (log)
|
||||
log_asset("ERROR: [type]: Invalid Config: ASSET_CDN_WEBROOT")
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -26,4 +26,4 @@
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user