Merge pull request #2824 from tigercat2000/I_am_fucking_mental

/vg/ / -tg- asset_cache
This commit is contained in:
Fox McCloud
2015-12-13 01:29:34 -05:00
18 changed files with 314 additions and 150 deletions
+15
View File
@@ -1177,3 +1177,18 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
log_admin("[key_name(src)] has toggled [M.key]'s [blockname] block [state]!")
else
alert("Invalid mob")
/client/proc/reload_nanoui_resources()
set category = "Debug"
set name = "Reload NanoUI Resources"
set desc = "Force the client to redownload NanoUI Resources"
// Close open NanoUIs.
nanomanager.close_user_uis(usr)
// Re-load the assets.
var/datum/asset/assets = get_asset_datum(/datum/asset/nanoui)
assets.register()
// Clear the user's cache so they get resent.
usr.client.cache = list()
+2 -1
View File
@@ -138,7 +138,8 @@ var/list/admin_verbs_show_debug_verbs = list(
/client/proc/print_jobban_old,
/client/proc/print_jobban_old_filter,
/client/proc/forceEvent,
/client/proc/nanomapgen_DumpImage
/client/proc/nanomapgen_DumpImage,
/client/proc/reload_nanoui_resources
)
/client/proc/enable_debug_verbs()
+241
View File
@@ -0,0 +1,241 @@
/*
Asset cache quick users guide:
Make a datum at the bottom of this file with your assets for your thing.
The simple subsystem 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.
You can set verify to TRUE if you want send() to sleep until the client has the assets.
*/
// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping.
// This is doubled for the first asset, then added per asset after
#define ASSET_CACHE_SEND_TIMEOUT 7
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
//List of ALL assets for the above, format is list(filename = asset).
/var/global/list/asset_cache = list()
/client
var/list/cache = list() // List of all assets sent to this client by the asset cache.
var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
var/list/sending = list()
var/last_asset_job = 0 // Last job done.
//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(var/client/client, var/asset_name, var/verify = TRUE)
if(!istype(client))
if(ismob(client))
var/mob/M = client
if(M.client)
client = M.client
else
return 0
else
return 0
if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
return 0
client << browse_rsc(asset_cache[asset_name], asset_name)
if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip.
if (client)
client.cache += asset_name
return 1
if (!client)
return 0
client.sending |= asset_name
var/job = ++client.last_asset_job
client << browse({"
<script>
window.location.href="?asset_cache_confirm_arrival=[job]"
</script>
"}, "window=asset_cache_browser")
var/t = 0
var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
sleep(1) // Lock up the caller until this is received.
t++
if(client)
client.sending -= asset_name
client.cache |= asset_name
client.completed_asset_jobs -= job
return 1
//This proc blocks(sleeps) unless verify is set to false
/proc/send_asset_list(var/client/client, var/list/asset_list, var/verify = TRUE)
if(!istype(client))
if(ismob(client))
var/mob/M = client
if(M.client)
client = M.client
else
return 0
else
return 0
var/list/unreceived = asset_list - (client.cache + client.sending)
if(!unreceived || !unreceived.len)
return 0
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
client << "Sending Resources..."
for(var/asset in unreceived)
if (asset in asset_cache)
client << browse_rsc(asset_cache[asset], asset)
if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip.
if (client)
client.cache += unreceived
return 1
if (!client)
return 0
client.sending |= unreceived
var/job = ++client.last_asset_job
client << browse({"
<script>
window.location.href="?asset_cache_confirm_arrival=[job]"
</script>
"}, "window=asset_cache_browser")
var/t = 0
var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
sleep(1) // Lock up the caller until this is received.
t++
if(client)
client.sending -= unreceived
client.cache |= unreceived
client.completed_asset_jobs -= job
return 1
//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(var/client/client, var/list/files, var/register_asset = TRUE)
for(var/file in files)
if (!client)
break
if (register_asset)
register_asset(file,files[file])
send_asset(client,file)
sleep(-1) //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.
//if it's an icon or something be careful, you'll have to copy it before further use.
/proc/register_asset(var/asset_name, var/asset)
asset_cache[asset_name] = asset
//From here on out it's populating the asset cache.
/proc/populate_asset_cache()
for(var/type in typesof(/datum/asset) - list(/datum/asset, /datum/asset/simple))
var/datum/asset/A = new type()
A.register()
for(var/client/C in clients)
//doing this to a client too soon after they've connected can cause issues, also the proc we call sleeps
spawn(10)
getFilesSlow(C, asset_cache, FALSE)
//These datums are used to populate the asset cache, the proc "register()" does this.
//all of our asset datums, used for referring to these later
/var/global/list/asset_datums = list()
//get a assetdatum or make a new one
/proc/get_asset_datum(var/type)
if (!(type in asset_datums))
return new type()
return asset_datums[type]
/datum/asset/New()
asset_datums[type] = src
/datum/asset/proc/register()
return
/datum/asset/proc/send(client)
return
//If you don't need anything complicated.
/datum/asset/simple
var/assets = list()
var/verify = FALSE
/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,verify)
//DEFINITIONS FOR ASSET DATUMS START HERE.
/datum/asset/simple/paper
assets = list(
"large_stamp-clown.png" = 'icons/paper_icons/large_stamp-clown.png',
"large_stamp-deny.png" = 'icons/paper_icons/large_stamp-deny.png',
"large_stamp-ok.png" = 'icons/paper_icons/large_stamp-ok.png',
"large_stamp-hop.png" = 'icons/paper_icons/large_stamp-hop.png',
"large_stamp-cmo.png" = 'icons/paper_icons/large_stamp-cmo.png',
"large_stamp-ce.png" = 'icons/paper_icons/large_stamp-ce.png',
"large_stamp-hos.png" = 'icons/paper_icons/large_stamp-hos.png',
"large_stamp-rd.png" = 'icons/paper_icons/large_stamp-rd.png',
"large_stamp-cap.png" = 'icons/paper_icons/large_stamp-cap.png',
"large_stamp-qm.png" = 'icons/paper_icons/large_stamp-qm.png',
"large_stamp-law.png" = 'icons/paper_icons/large_stamp-law.png',
"large_stamp-cent.png" = 'icons/paper_icons/large_stamp-cent.png',
"large_stamp-syndicate.png" = 'icons/paper_icons/large_stamp-syndicate.png',
"talisman.png" = 'icons/paper_icons/talisman.png',
"ntlogo.png" = 'icons/paper_icons/ntlogo.png'
)
/datum/asset/nanoui
var/list/common = list()
var/list/common_dirs = list(
"nano/css/",
"nano/js/",
"nano/images/",
"nano/layouts/"
)
var/list/uncommon_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])
for (var/path in uncommon_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // Ignore directories.
if(fexists(path + filename))
register_asset(filename, fcopy_rsc(path + filename))
/datum/asset/nanoui/send(client, uncommon)
if(!islist(uncommon))
uncommon = list(uncommon)
send_asset_list(client, uncommon)
send_asset_list(client, common)
+9 -4
View File
@@ -35,6 +35,11 @@
#endif
if(href_list["asset_cache_confirm_arrival"])
//src << "ASSET JOB [href_list["asset_cache_confirm_arrival"]] ARRIVED."
var/job = text2num(href_list["asset_cache_confirm_arrival"])
completed_asset_jobs += job
return
//Reduces spamming of links by dropping calls that happen during the delay period
if(next_allowed_topic_time > world.time)
@@ -232,8 +237,6 @@
///////////
/client/New(TopicData)
TopicData = null //Prevent calls to client.Topic from connect
client_cache += src
client_cache[src] = list()
if(connection != "seeker") //Invalid connection type.
return null
@@ -310,6 +313,9 @@
screen += void
if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them.
src << "<span class='warning'>Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you.</span>"
//////////////
//DISCONNECT//
//////////////
@@ -415,8 +421,7 @@
'html/panels.css' // Used for styling certain panels, such as in the new player panel
)
// Send NanoUI resources to this client
spawn nanomanager.send_resources(src)
getFilesSlow(src, asset_cache, register_asset = FALSE)
//For debugging purposes
/client/proc/list_all_languages()
-84
View File
@@ -1,84 +0,0 @@
//We store a list of all clients, with a list of all file names that the client received.
/var/global/list/client_cache = list()
//List of ALL assets for the above, format is list(filename = asset).
/var/global/list/asset_cache = list()
//This proc sends the asset to the client, but only if it needs it.
/proc/send_asset(var/client/client, var/asset_name)
var/list/client_list = client_cache[client]
ASSERT(client_list)
if(asset_name in client_list)
return
//world << "sending a client the asset '[asset_name]'"
client << browse_rsc(asset_cache[asset_name], asset_name)
client_list += asset_name
/proc/send_asset_list(var/client/client, var/list/asset_list)
for(var/asset_name in asset_list)
send_asset(client, asset_name)
//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.
//if it's an icon or something be careful, you'll have to copy it before further use.
/proc/register_asset(var/asset_name, var/asset)
asset_cache |= asset_name
asset_cache[asset_name] = asset
//From here on out it's populating the asset cache.
/proc/populate_asset_cache()
for(var/type in typesof(/datum/asset) - list(/datum/asset, /datum/asset/simple))
var/datum/asset/A = new type()
A.register()
//These datums are used to populate the asset cache, the proc "register()" does this.
/datum/asset/proc/register()
return
//If you don't need anything complicated.
/datum/asset/simple
var/assets = list()
/datum/asset/simple/register()
for(var/asset_name in assets)
register_asset(asset_name, assets[asset_name])
//DEFINITIONS FOR ASSET DATUMS START HERE.
/datum/asset/simple/spider_os
assets = list(
"sos_1.png" = 'icons/spideros_icons/sos_1.png',
"sos_2.png" = 'icons/spideros_icons/sos_2.png',
"sos_3.png" = 'icons/spideros_icons/sos_3.png',
"sos_4.png" = 'icons/spideros_icons/sos_4.png',
"sos_5.png" = 'icons/spideros_icons/sos_5.png',
"sos_6.png" = 'icons/spideros_icons/sos_6.png',
"sos_7.png" = 'icons/spideros_icons/sos_7.png',
"sos_8.png" = 'icons/spideros_icons/sos_8.png',
"sos_9.png" = 'icons/spideros_icons/sos_9.png',
"sos_10.png" = 'icons/spideros_icons/sos_10.png',
"sos_11.png" = 'icons/spideros_icons/sos_11.png',
"sos_12.png" = 'icons/spideros_icons/sos_12.png',
"sos_13.png" = 'icons/spideros_icons/sos_13.png',
"sos_14.png" = 'icons/spideros_icons/sos_14.png'
)
/datum/asset/simple/paper
assets = list(
"large_stamp-clown.png" = 'icons/paper_icons/large_stamp-clown.png',
"large_stamp-deny.png" = 'icons/paper_icons/large_stamp-deny.png',
"large_stamp-ok.png" = 'icons/paper_icons/large_stamp-ok.png',
"large_stamp-hop.png" = 'icons/paper_icons/large_stamp-hop.png',
"large_stamp-cmo.png" = 'icons/paper_icons/large_stamp-cmo.png',
"large_stamp-ce.png" = 'icons/paper_icons/large_stamp-ce.png',
"large_stamp-hos.png" = 'icons/paper_icons/large_stamp-hos.png',
"large_stamp-rd.png" = 'icons/paper_icons/large_stamp-rd.png',
"large_stamp-cap.png" = 'icons/paper_icons/large_stamp-cap.png',
"large_stamp-qm.png" = 'icons/paper_icons/large_stamp-qm.png',
"large_stamp-law.png" = 'icons/paper_icons/large_stamp-law.png',
"large_stamp-cent.png" = 'icons/paper_icons/large_stamp-cent.png',
"large_stamp-syndicate.png" = 'icons/paper_icons/large_stamp-syndicate.png',
"talisman.png" = 'icons/paper_icons/talisman.png',
"ntlogo.png" = 'icons/paper_icons/ntlogo.png'
)
+3 -43
View File
@@ -5,32 +5,6 @@
var/open_uis[0]
// a list of current open /nanoui UIs, not grouped, for use in processing
var/list/processing_uis = list()
// a list of asset filenames which are to be sent to the client on user logon
var/list/asset_files = list()
/**
* Create a new nanomanager instance.
* This proc generates a list of assets which are to be sent to each client on connect
*
* @return /nanomanager new nanomanager object
*/
/datum/nanomanager/New()
var/list/nano_asset_dirs = list(\
"nano/css/",\
"nano/images/",\
"nano/js/",\
"nano/templates/"\
)
var/list/filenames = null
for (var/path in nano_asset_dirs)
filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // filenames which end in "/" are actually directories, which we want to ignore
if(fexists(path + filename))
asset_files.Add(fcopy_rsc(path + filename)) // add this file to asset_files for sending to clients when they connect
return
/**
* Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data
@@ -122,8 +96,8 @@
if(ui && ui.src_object && ui.user && ui.src_object.nano_host())
ui.close()
close_count++
return close_count
return close_count
/**
* Update /nanoui uis belonging to user
*
@@ -253,18 +227,4 @@
oldMob.open_uis.Cut()
return 1 // success
/**
* Sends all nano assets to the client
* This is called on user login
*
* @param client /client The user's client
*
* @return nothing
*/
/datum/nanomanager/proc/send_resources(client)
for(var/file in asset_files)
client << browse_rsc(file) // send the file to the client
return 1 // success
+3
View File
@@ -96,6 +96,9 @@ nanoui is used to open and update nano browser uis
add_common_assets()
var/datum/asset/assets = get_asset_datum(/datum/asset/nanoui)
assets.send(user, ntemplate_filename)
/**
* Use this proc to add assets which are common to (and required by) all nano uis
*
+3 -3
View File
@@ -16,10 +16,10 @@
if(!affecting) return//If no mob is wearing the suit. I almost forgot about this variable.
var/mob/living/carbon/human/U = affecting
var/display_to = U//Who do we want to display certain messages to?
if(U.client) // Send the spider OS images to the client
var/datum/asset/simple/S = new/datum/asset/simple/spider_os()
send_asset_list(U.client, S.assets)
var/datum/asset/simple/S = new/datum/asset/simple/spider_os() //no longer exists ;)
send_asset_list(U.client, S.assets)
var/dat = "<html><head><title>SpiderOS</title></head><body bgcolor=\"#3D5B43\" text=\"#DB2929\"><style>a, a:link, a:visited, a:active, a:hover { color: #DB2929; }img {border-style:none;}</style>"
dat += "<a href='byond://?src=\ref[src];choice=Refresh'><img src=sos_7.png> Refresh</a>"
+2 -4
View File
@@ -59,10 +59,8 @@
user << "<span class='notice'>You have to go closer if you want to read it.</span>"
/obj/item/weapon/paper/proc/show_content(var/mob/user, var/forceshow = 0, var/forcestars = 0, var/infolinks = 0, var/view = 1)
set src in oview(1)
if(user.client) // Send the paper images to the client
var/datum/asset/simple/S = new/datum/asset/simple/paper()
send_asset_list(user.client, S.assets)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/paper)
assets.send(user)
var/data
if((!user.say_understands(null, all_languages["Galactic Common"]) && !forceshow) || forcestars) //assuming all paper is written in common is better than hardcoded type checks