Update asset_cache to modern /tg/, and make TGUI compatible with it. CDN support, etc.

This commit is contained in:
ShadowLarkens
2020-07-19 20:46:12 -07:00
parent f57cddf618
commit 126cc6b5da
27 changed files with 1110 additions and 405 deletions

View File

@@ -0,0 +1,110 @@
/*
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))]"

View File

@@ -0,0 +1,51 @@
/// Process asset cache client topic calls for "asset_cache_confirm_arrival=[INT]"
/client/proc/asset_cache_confirm_arrival(job_id)
var/asset_cache_job = round(text2num(job_id))
//because we skip the limiter, we have to make sure this is a valid arrival and not somebody tricking us into letting them append to a list without limit.
if (asset_cache_job > 0 && asset_cache_job <= last_asset_job && !(completed_asset_jobs["[asset_cache_job]"]))
completed_asset_jobs["[asset_cache_job]"] = TRUE
last_completed_asset_job = max(last_completed_asset_job, asset_cache_job)
else
return asset_cache_job || TRUE
/// 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)
for (var/preloaded_asset in preloaded_assets)
if (copytext(preloaded_asset, findlasttext(preloaded_asset, ".")+1) in list("js", "jsm", "htm", "html"))
preloaded_assets -= preloaded_asset
continue
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())
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")
/// Blocks until all currently sending browser 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)
var/job = ++last_asset_job
var/t = 0
var/timeout_time = timeout
src << browse({"<script>window.location.href="?asset_cache_confirm_arrival=[job]"</script>"}, "window=asset_cache_browser&file=asset_cache_send_verify.htm")
while(!completed_asset_jobs["[job]"] && t < timeout_time) // Reception is handled in Topic()
stoplag(1) // Lock up the caller until this is received.
t++
if (t < timeout_time)
return TRUE

View File

@@ -0,0 +1,23 @@
/**
* # 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/resource
/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)
CRASH("invalid asset sent to asset cache")
log_world("asset cache unexpected success of second fcopy_rsc")
src.name = name
url = name
resource = file

View File

@@ -0,0 +1,260 @@
//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/get_url_mappings()
return list()
/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)
assets[asset_name] = register_asset(asset_name, assets[asset_name])
/datum/asset/simple/send(client)
. = send_asset_list(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
// 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) || .
/datum/asset/group/get_url_mappings()
. = list()
for(var/type in children)
var/datum/asset/A = get_asset_datum(type)
. += A.get_url_mappings()
// 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()
for(var/size_id in sizes)
var/size = sizes[size_id]
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))
fdel(fname)
/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/get_url_mappings()
if (!name)
return
. = list("spritesheet_[name].css" = get_asset_url("spritesheet_[name].css"))
for(var/size_id in sizes)
.["[name]_[size_id].png"] = 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
#ifdef RUST_G
// save flattened version
var/fname = "data/spritesheets/[name]_[size_id].png"
fcopy(size[SPRSZ_ICON], fname)
var/error = call(RUST_G, "dmi_strip_metadata")(fname)
if(length(error))
stack_trace("Failed to strip [name]_[size_id].png: [error]")
size[SPRSZ_STRIPPED] = icon(fname)
fdel(fname)
#else
#warn It looks like you don't have RUST_G enabled. Without RUST_G, the RPD icons will not function, so it strongly recommended you reenable it.
#endif
/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('[get_asset_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="[css_filename()]" />"}
/datum/asset/spritesheet/proc/css_filename()
return 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]"}
#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)

View File

@@ -0,0 +1,445 @@
//DEFINITIONS FOR ASSET DATUMS START HERE.
/datum/asset/simple/tgui
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/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'
// )
// /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'
// )
// /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'
// )
// /datum/asset/spritesheet/simple/paper
// name = "paper"
// assets = list(
// "stamp-clown" = 'icons/stamp_icons/large_stamp-clown.png',
// "stamp-deny" = 'icons/stamp_icons/large_stamp-deny.png',
// "stamp-ok" = 'icons/stamp_icons/large_stamp-ok.png',
// "stamp-hop" = 'icons/stamp_icons/large_stamp-hop.png',
// "stamp-cmo" = 'icons/stamp_icons/large_stamp-cmo.png',
// "stamp-ce" = 'icons/stamp_icons/large_stamp-ce.png',
// "stamp-hos" = 'icons/stamp_icons/large_stamp-hos.png',
// "stamp-rd" = 'icons/stamp_icons/large_stamp-rd.png',
// "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-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'
// )
// /datum/asset/simple/irv
// assets = list(
// "jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js',
// )
// /datum/asset/group/irv
// children = list(
// /datum/asset/simple/jquery,
// /datum/asset/simple/irv
// )
/datum/asset/simple/generic
assets = list(
"search.js" = 'html/search.js',
"panels.css" = 'html/panels.css',
"loading.gif" = 'html/images/loading.gif',
"ntlogo.png" = 'html/images/ntlogo.png',
"sglogo.png" = 'html/images/sglogo.png',
"talisman.png" = 'html/images/talisman.png',
"paper_bg.png" = 'html/images/paper_bg.png',
"no_image32.png" = 'html/images/no_image32.png',
)
/datum/asset/simple/changelog
assets = list(
"88x31.png" = 'html/88x31.png',
"bug-minus.png" = 'html/bug-minus.png',
"cross-circle.png" = 'html/cross-circle.png',
"hard-hat-exclamation.png" = 'html/hard-hat-exclamation.png',
"image-minus.png" = 'html/image-minus.png',
"image-plus.png" = 'html/image-plus.png',
"map-pencil.png" = 'html/map-pencil.png',
"music-minus.png" = 'html/music-minus.png',
"music-plus.png" = 'html/music-plus.png',
"tick-circle.png" = 'html/tick-circle.png',
"wrench-screwdriver.png" = 'html/wrench-screwdriver.png',
"spell-check.png" = 'html/spell-check.png',
"burn-exclamation.png" = 'html/burn-exclamation.png',
"chevron.png" = 'html/chevron.png',
"chevron-expand.png" = 'html/chevron-expand.png',
"changelog.css" = 'html/changelog.css',
"changelog.js" = 'html/changelog.js',
"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
// assets = list(
// "jquery.min.js" = 'code/modules/goonchat/browserassets/js/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_white.css" = 'code/modules/goonchat/browserassets/css/browserOutput_white.css',
// )
/datum/asset/simple/fontawesome
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'
)
// /datum/asset/spritesheet/goonchat
// name = "chat"
// /datum/asset/spritesheet/goonchat/register()
// InsertAll("emoji", 'icons/emoji.dmi')
// // pre-loading all lanugage icons also helps to avoid meta
// InsertAll("language", 'icons/misc/language.dmi')
// // catch languages which are pulling icons from another file
// for(var/path in typesof(/datum/language))
// var/datum/language/L = path
// var/icon = initial(L.icon)
// 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/permissions
// assets = list(
// "padlock.png" = 'html/padlock.png'
// )
// /datum/asset/simple/notes
// assets = list(
// "high_button.png" = 'html/high_button.png',
// "medium_button.png" = 'html/medium_button.png',
// "minor_button.png" = 'html/minor_button.png',
// "none_button.png" = 'html/none_button.png',
// )
// /datum/asset/simple/arcade
// assets = list(
// "boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif',
// "boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif',
// "boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif',
// "boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif',
// "boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif',
// "boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif',
// )
// /datum/asset/spritesheet/simple/achievements
// name ="achievements"
// assets = list(
// "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',
// )
// /datum/asset/spritesheet/simple/pills
// name ="pills"
// assets = list(
// "pill1" = 'icons/UI_Icons/Pills/pill1.png',
// "pill2" = 'icons/UI_Icons/Pills/pill2.png',
// "pill3" = 'icons/UI_Icons/Pills/pill3.png',
// "pill4" = 'icons/UI_Icons/Pills/pill4.png',
// "pill5" = 'icons/UI_Icons/Pills/pill5.png',
// "pill6" = 'icons/UI_Icons/Pills/pill6.png',
// "pill7" = 'icons/UI_Icons/Pills/pill7.png',
// "pill8" = 'icons/UI_Icons/Pills/pill8.png',
// "pill9" = 'icons/UI_Icons/Pills/pill9.png',
// "pill10" = 'icons/UI_Icons/Pills/pill10.png',
// "pill11" = 'icons/UI_Icons/Pills/pill11.png',
// "pill12" = 'icons/UI_Icons/Pills/pill12.png',
// "pill13" = 'icons/UI_Icons/Pills/pill13.png',
// "pill14" = 'icons/UI_Icons/Pills/pill14.png',
// "pill15" = 'icons/UI_Icons/Pills/pill15.png',
// "pill16" = 'icons/UI_Icons/Pills/pill16.png',
// "pill17" = 'icons/UI_Icons/Pills/pill17.png',
// "pill18" = 'icons/UI_Icons/Pills/pill18.png',
// "pill19" = 'icons/UI_Icons/Pills/pill19.png',
// "pill20" = 'icons/UI_Icons/Pills/pill20.png',
// "pill21" = 'icons/UI_Icons/Pills/pill21.png',
// "pill22" = 'icons/UI_Icons/Pills/pill22.png',
// )
// //this exists purely to avoid meta by pre-loading all language icons.
// /datum/asset/language/register()
// for(var/path in typesof(/datum/language))
// set waitfor = FALSE
// var/datum/language/L = new path ()
// L.get_icon()
/datum/asset/spritesheet/pipes
name = "pipes"
/datum/asset/spritesheet/pipes/register()
for(var/each in list('icons/obj/pipe-item.dmi', 'icons/obj/pipes/disposal.dmi'))
InsertAll("", each, global.alldirs)
..()
// // Representative icons for each research design
// /datum/asset/spritesheet/research_designs
// name = "design"
// /datum/asset/spritesheet/research_designs/register()
// for (var/path in subtypesof(/datum/design))
// var/datum/design/D = path
// var/icon_file
// var/icon_state
// var/icon/I
// if(initial(D.research_icon) && initial(D.research_icon_state)) //If the design has an icon replacement skip the rest
// icon_file = initial(D.research_icon)
// icon_state = initial(D.research_icon_state)
// if(!(icon_state in icon_states(icon_file)))
// warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
// continue
// I = icon(icon_file, icon_state, SOUTH)
// else
// // construct the icon and slap it into the resource cache
// var/atom/item = initial(D.build_path)
// if (!ispath(item, /atom))
// // biogenerator outputs to beakers by default
// if (initial(D.build_type) & BIOGENERATOR)
// item = /obj/item/reagent_containers/glass/beaker/large
// else
// continue // shouldn't happen, but just in case
// // circuit boards become their resulting machines or computers
// if (ispath(item, /obj/item/circuitboard))
// var/obj/item/circuitboard/C = item
// var/machine = initial(C.build_path)
// if (machine)
// item = machine
// icon_file = initial(item.icon)
// icon_state = initial(item.icon_state)
// if(!(icon_state in icon_states(icon_file)))
// warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
// continue
// I = icon(icon_file, icon_state, SOUTH)
// // computers (and snowflakes) get their screen and keyboard sprites
// if (ispath(item, /obj/machinery/computer) || ispath(item, /obj/machinery/power/solar_control))
// var/obj/machinery/computer/C = item
// var/screen = initial(C.icon_screen)
// var/keyboard = initial(C.icon_keyboard)
// var/all_states = icon_states(icon_file)
// if (screen && (screen in all_states))
// I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY)
// if (keyboard && (keyboard in all_states))
// I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY)
// Insert(initial(D.id), I)
// return ..()
// /datum/asset/spritesheet/vending
// name = "vending"
// /datum/asset/spritesheet/vending/register()
// for (var/k in GLOB.vending_products)
// var/atom/item = k
// if (!ispath(item, /atom))
// continue
// var/icon_file = initial(item.icon)
// var/icon_state = initial(item.icon_state)
// var/icon/I
// var/icon_states_list = icon_states(icon_file)
// if(icon_state in icon_states_list)
// I = icon(icon_file, icon_state, SOUTH)
// var/c = initial(item.color)
// if (!isnull(c) && c != "#FFFFFF")
// I.Blend(c, ICON_MULTIPLY)
// else
// var/icon_states_string
// for (var/an_icon_state in icon_states_list)
// if (!icon_states_string)
// icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])"
// else
// icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])"
// stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]")
// I = icon('icons/turf/floors.dmi', "", SOUTH)
// var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-")
// Insert(imgid, I)
// return ..()
// /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'
// )
// /datum/asset/simple/orbit
// assets = list(
// "ghost.png" = 'html/ghost.png'
// )
// /datum/asset/simple/vv
// assets = list(
// "view_variables.css" = 'html/admin/view_variables.css'
// )
// /datum/asset/spritesheet/sheetmaterials
// name = "sheetmaterials"
// /datum/asset/spritesheet/sheetmaterials/register()
// InsertAll("", 'icons/obj/stack_objects.dmi')
// // Special case to handle Bluespace Crystals
// Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal")
// ..()
/datum/asset/nanoui
var/list/common = list()
var/list/common_dirs = list(
"nano/css/",
"nano/images/",
"nano/images/modular_computers/",
"nano/js/"
)
var/list/template_dirs = list(
"nano/templates/"
)
/datum/asset/nanoui/register()
// Crawl the directories to find files.
for(var/path in common_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // Ignore directories.
if(fexists(path + filename))
common[filename] = fcopy_rsc(path + filename)
register_asset(filename, common[filename])
// Combine all templates into a single bundle.
var/list/template_data = list()
for(var/path in template_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename) - 4) == ".tmpl") // Ignore directories.
template_data[filename] = file2text(path + filename)
var/template_bundle = "function nanouiTemplateBundle(){return [json_encode(template_data)];}"
var/fname = "data/nano_templates_bundle.js"
fdel(fname)
text2file(template_bundle, fname)
register_asset("nano_templates_bundle.js", fcopy_rsc(fname))
fdel(fname)
/datum/asset/nanoui/send(client)
send_asset_list(client, common)

View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
</head>
<body>
<script>
//this is used over window.location because window.location has a character limit in IE.
function sendbyond(text) {
var xhr = new XMLHttpRequest();
xhr.open('GET', '?'+text, true);
xhr.send(null);
}
var xhr = new XMLHttpRequest();
xhr.open('GET', 'asset_data.json', true);
xhr.responseType = 'text';
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
var status = xhr.status;
if (status >= 200 && status < 400) {
sendbyond('asset_cache_preload_data=' + encodeURIComponent(xhr.responseText));
}
}
};
xhr.send(null);
</script>
</body>
</html>