Skip to content
This repository has been archived by the owner on Sep 8, 2022. It is now read-only.

[MIRROR] icon2html optimizations #1442

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions code/__DEFINES/flags.dm
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define ADMIN_SPAWNED_1 (1<<15) //! was this spawned by an admin? used for stat tracking stuff.
#define PREVENT_CONTENTS_EXPLOSION_1 (1<<16)
#define UNPAINTABLE_1 (1<<17)
<<<<<<< HEAD
=======
#define HTML_USE_INITAL_ICON_1 (1<<18) //! Should we use the initial icon for display? Mostly used by overlay only objects
/// Does the supermatter skip over this atom?
#define SUPERMATTER_IGNORES_1 (1 << 18) //set this to 18 because tg has some other flags appearantly too if that gets ever ported fix this !!!!
>>>>>>> 000e1cd18a... icon2html optimizations (#7610)

/// If the thing can reflect light (lasers/energy)
#define RICOCHET_SHINY (1<<0)
Expand Down
7 changes: 4 additions & 3 deletions code/__HELPERS/icon_smoothing.dm
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@

//generic (by snowflake) tile smoothing code; smooth your icons with this!
/**
/**
Each tile is divided in 4 corners, each corner has an appearance associated to it; the tile is then overlayed by these 4 appearances. To use this, just set your atom's 'smooth' var to 1. If your atom can be moved/unanchored, set its 'can_be_unanchored' var to 1. If you don't want your atom's icon to smooth with anything but atoms of the same type, set the list 'canSmoothWith' to null; Otherwise, put all types you want the atom icon to smooth with in 'canSmoothWith' INCLUDING THE TYPE OF THE ATOM ITSELF.

Each atom has its own icon file with all the possible corner states. See 'smooth_wall.dmi' for a template.

### DIAGONAL SMOOTHING INSTRUCTIONS

To make your atom smooth diagonally you need all the proper icon states (see 'smooth_wall.dmi' for a template) and to add the 'SMOOTH_DIAGONAL' flag to the atom's smooth var (in addition to either SMOOTH_TRUE or SMOOTH_MORE).

For turfs, what appears under the diagonal corners depends on the turf that was in the same position previously: if you make a wall on a plating floor, you will see plating under the diagonal wall corner, if it was space, you will see space.

If you wish to map a diagonal wall corner with a fixed underlay, you must configure the turf's 'fixed_underlay' list var, like so:

```
fixed_underlay = list("icon"='icon_file.dmi', "icon_state"="iconstatename")
```
Expand Down Expand Up @@ -112,6 +112,7 @@
if(!A || !A.smooth)
return
A.smooth &= ~SMOOTH_QUEUED
A.flags_1 |= HTML_USE_INITAL_ICON_1
if (!A.z)
return
if(QDELETED(A))
Expand Down
145 changes: 137 additions & 8 deletions code/__HELPERS/icons.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1158,8 +1158,24 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0
alpha += 25
obj_flags &= ~FROZEN

<<<<<<< HEAD
/// Save file used in icon2base64. Used for converting icons to base64.
GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of icons for the browser output
=======
/// generates a filename for a given asset.
/// like generate_asset_name(), except returns the rsc reference and the rsc file hash as well as the asset name (sans extension)
/// used so that certain asset files dont have to be hashed twice
/proc/generate_and_hash_rsc_file(file, dmi_file_path)
var/rsc_ref = fcopy_rsc(file)
var/hash
//if we have a valid dmi file path we can trust md5'ing the rsc file because we know it doesnt have the bug described in http://www.byond.com/forum/post/2611357
if(dmi_file_path)
hash = md5(rsc_ref)
else //otherwise, we need to do the expensive fcopy() workaround
hash = md5asfile(rsc_ref)

return list(rsc_ref, hash, "asset.[hash]")
>>>>>>> 000e1cd18a... icon2html optimizations (#7610)

/// Generate a filename for this asset
/// The same asset will always lead to the same asset name
Expand All @@ -1180,12 +1196,90 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico
var/list/partial = splittext(iconData, "{")
return replacetext(copytext_char(partial[2], 3, -5), "\n", "")

<<<<<<< HEAD
/proc/icon2html(thing, target, icon_state, dir, frame = 1, moving = FALSE)
=======
///given a text string, returns whether it is a valid dmi icons folder path
/proc/is_valid_dmi_file(icon_path)
if(!istext(icon_path) || !length(icon_path))
return FALSE

var/is_in_icon_folder = findtextEx(icon_path, "icons/")
var/is_dmi_file = findtextEx(icon_path, ".dmi")

if(is_in_icon_folder && is_dmi_file)
return TRUE
return FALSE

/// given an icon object, dmi file path, or atom/image/mutable_appearance, attempts to find and return an associated dmi file path.
/// a weird quirk about dm is that /icon objects represent both compile-time or dynamic icons in the rsc,
/// but stringifying rsc references returns a dmi file path
/// ONLY if that icon represents a completely unchanged dmi file from when the game was compiled.
/// so if the given object is associated with an icon that was in the rsc when the game was compiled, this returns a path. otherwise it returns ""
/proc/get_icon_dmi_path(icon/icon)
/// the dmi file path we attempt to return if the given object argument is associated with a stringifiable icon
/// if successful, this looks like "icons/path/to/dmi_file.dmi"
var/icon_path = ""

if(isatom(icon) || istype(icon, /image) || istype(icon, /mutable_appearance))
var/atom/atom_icon = icon
icon = atom_icon.icon
//atom icons compiled in from 'icons/path/to/dmi_file.dmi' are weird and not really icon objects that you generate with icon().
//if theyre unchanged dmi's then they're stringifiable to "icons/path/to/dmi_file.dmi"

if(isicon(icon) && isfile(icon))
//icons compiled in from 'icons/path/to/dmi_file.dmi' at compile time are weird and arent really /icon objects,
///but they pass both isicon() and isfile() checks. theyre the easiest case since stringifying them gives us the path we want
var/icon_ref = "\ref[icon]"
var/locate_icon_string = "[locate(icon_ref)]"

icon_path = locate_icon_string

else if(isicon(icon) && "[icon]" == "/icon")
// icon objects generated from icon() at runtime are icons, but they ARENT files themselves, they represent icon files.
// if the files they represent are compile time dmi files in the rsc, then
// the rsc reference returned by fcopy_rsc() will be stringifiable to "icons/path/to/dmi_file.dmi"
var/rsc_ref = fcopy_rsc(icon)

var/icon_ref = "\ref[rsc_ref]"

var/icon_path_string = "[locate(icon_ref)]"

icon_path = icon_path_string

else if(istext(icon))
var/rsc_ref = fcopy_rsc(icon)
//if its the text path of an existing dmi file, the rsc reference returned by fcopy_rsc() will be stringifiable to a dmi path

var/rsc_ref_ref = "\ref[rsc_ref]"
var/rsc_ref_string = "[locate(rsc_ref_ref)]"

icon_path = rsc_ref_string

if(is_valid_dmi_file(icon_path))
return icon_path

return FALSE

/**
* generate an asset for the given icon or the icon of the given appearance for [thing], and send it to any clients in target.
* Arguments:
* * thing - either a /icon object, or an object that has an appearance (atom, image, mutable_appearance).
* * target - either a reference to or a list of references to /client's or mobs with clients
* * icon_state - string to force a particular icon_state for the icon to be used
* * dir - dir number to force a particular direction for the icon to be used
* * frame - what frame of the icon_state's animation for the icon being used
* * moving - whether or not to use a moving state for the given icon
* * sourceonly - if TRUE, only generate the asset and send back the asset url, instead of tags that display the icon to players
* * extra_clases - string of extra css classes to use when returning the icon string
*/
/proc/icon2html(atom/thing, client/target, icon_state, dir = SOUTH, frame = 1, moving = FALSE, sourceonly = FALSE)
>>>>>>> 000e1cd18a... icon2html optimizations (#7610)
if (!thing)
return

var/key
var/icon/I = thing
var/icon/icon2collapse = thing
if (!target)
return
if (target == world)
Expand All @@ -1196,38 +1290,73 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico
targets = list(target)
else
targets = target
if (!targets.len)
return
if (!isicon(I))
if(!length(targets))
return

//check if the given object is associated with a dmi file in the icons folder. if it is then we dont need to do a lot of work
//for asset generation to get around byond limitations
var/icon_path = get_icon_dmi_path(thing)
if (!isicon(icon2collapse))
if (isfile(thing)) //special snowflake
var/name = SANITIZE_FILENAME("[generate_asset_name(thing)].png")
SSassets.transport.register_asset(name, thing)
for (var/thing2 in targets)
SSassets.transport.send_assets(thing2, name)
return "<img class='icon icon-misc' src='[SSassets.transport.get_asset_url(name)]'>"
<<<<<<< HEAD
var/atom/A = thing
if (isnull(dir))
dir = A.dir
if (isnull(icon_state))
icon_state = A.icon_state
I = A.icon
=======

//its either an atom, image, or mutable_appearance, we want its icon var
icon2collapse = thing.icon
if (isnull(icon_state))
icon_state = thing.icon_state

if (isnull(icon_state) || thing.flags_1 & HTML_USE_INITAL_ICON_1)
icon_state = initial(thing.icon_state)
if (isnull(dir))
dir = initial(thing.dir)

if (isnull(dir))
dir = thing.dir

>>>>>>> 000e1cd18a... icon2html optimizations (#7610)
if (ishuman(thing)) // Shitty workaround for a BYOND issue.
var/icon/temp = I
I = icon()
I.Insert(temp, dir = SOUTH)
var/icon/temp = icon2collapse
icon2collapse = icon()
icon2collapse.Insert(temp, dir = SOUTH)
dir = SOUTH
else
if (isnull(dir))
dir = SOUTH
if (isnull(icon_state))
icon_state = ""

I = icon(I, icon_state, dir, frame, moving)
icon2collapse = icon(icon2collapse, icon_state, dir, frame, moving)

var/list/name_and_ref = generate_and_hash_rsc_file(icon2collapse, icon_path)//pretend that tuples exist

var/rsc_ref = name_and_ref[1] //weird object thats not even readable to the debugger, represents a reference to the icons rsc entry
var/file_hash = name_and_ref[2]
key = "[name_and_ref[3]].png"

<<<<<<< HEAD
key = "[generate_asset_name(I)].png"
SSassets.transport.register_asset(key, I)
for (var/thing2 in targets)
SSassets.transport.send_assets(thing2, key)
=======
SSassets.transport.register_asset(key, rsc_ref, file_hash, icon_path)
for (var/client_target in targets)
SSassets.transport.send_assets(client_target, key)
if(sourceonly)
return SSassets.transport.get_asset_url(key)
>>>>>>> 000e1cd18a... icon2html optimizations (#7610)
return "<img class='icon icon-[icon_state]' src='[SSassets.transport.get_asset_url(key)]'>"

/proc/icon2base64html(thing)
Expand Down
28 changes: 28 additions & 0 deletions code/game/machinery/doors/airlock.dm
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
normalspeed = 1
explosion_block = 1
hud_possible = list(DIAG_AIRLOCK_HUD)
flags_1 = PREVENT_CLICK_UNDER_1 & HTML_USE_INITAL_ICON_1
var/allow_repaint = TRUE //Set to FALSE if the airlock should not be allowed to be repainted.

FASTDMM_PROP(\
Expand Down Expand Up @@ -1071,6 +1072,33 @@
user.visible_message("<span class='notice'>[user] pins [C] to [src].</span>", "<span class='notice'>You pin [C] to [src].</span>")
note = C
update_icon()
<<<<<<< HEAD
=======
else if(HAS_TRAIT(C, TRAIT_DOOR_PRYER) && user.a_intent != INTENT_HARM)
if(isElectrified() && C?.siemens_coefficient)
shock(user,100)

if(locked)
to_chat(user, "<span class='warning'>The bolts are down, it won't budge!</span>")
return

if(welded)
to_chat(user, "<span class='warning'>It's welded, it won't budge!</span>")
return

var/time_to_open = 5
if(hasPower() && !prying_so_hard && density)
time_to_open = 50
playsound(src, 'sound/machines/airlock_alien_prying.ogg', 100, TRUE)
prying_so_hard = TRUE
to_chat(user, "<span class='warning'>You begin prying open the airlock...</span>")
if(do_after(user, time_to_open, TRUE, src))
if(!open(2) && density)
to_chat(user, "<span class='warning'>Despite your attempts, [src] refuses to open.</span>")
prying_so_hard = FALSE
if(!hasPower())
INVOKE_ASYNC(src, (density ? .proc/open : .proc/close), 2)
>>>>>>> 000e1cd18a... icon2html optimizations (#7610)
else
return ..()

Expand Down
18 changes: 16 additions & 2 deletions code/modules/asset_cache/asset_cache_item.dm
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
* An internal datum containing info on items in the asset cache. Mainly used to cache md5 info for speed.
*/
/datum/asset_cache_item
/// the name of this asset item, becomes the key in SSassets.cache list
var/name
/// md5() of the file this asset item represents.
var/hash
/// the file this asset represents
var/resource
/// our file extension e.g. .png, .gif, etc
var/ext = ""
/// Should this file alsobut be sent via the legacy browse_rsc system
/// when cdn transports are enabled?
Expand All @@ -21,10 +25,20 @@
/// TRUE for keeping local asset names when browse_rsc backend is used
var/keep_local_name = FALSE

/datum/asset_cache_item/New(name, file)
///pass in a valid file_hash if you have one to save it from needing to do it again.
///pass in a valid dmi file path string e.g. "icons/path/to/dmi_file.dmi" to make generating the hash less expensive
/datum/asset_cache_item/New(name, file, file_hash, dmi_file_path)
if (!isfile(file))
file = fcopy_rsc(file)
hash = md5(file)

hash = file_hash

//the given file is directly from a dmi file and is thus in the rsc already, we know that its file_hash will be correct
if(!hash)
if(dmi_file_path)
hash = md5(file)
else
hash = md5asfile(file) //icons sent to the rsc md5 incorrectly when theyre given incorrect data
if (!hash)
hash = md5(fcopy_rsc(file))
if (!hash)
Expand Down
20 changes: 13 additions & 7 deletions code/modules/asset_cache/transports/asset_transport.dm
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,21 @@
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)
/**
* Register a browser asset with the asset cache system.
* returns a /datum/asset_cache_item.
* mutiple calls to register the same asset under the same asset_name return the same datum.
*
* Arguments:
* * asset_name - the identifier of the asset.
* * asset - the actual asset file (or an asset_cache_item datum).
* * file_hash - optional, a hash of the contents of the asset files contents. used so asset_cache_item doesnt have to hash it again
* * dmi_file_path - optional, means that the given asset is from the rsc and thus we dont need to do some expensive operations
*/
/datum/asset_transport/proc/register_asset(asset_name, asset, file_hash, dmi_file_path)
var/datum/asset_cache_item/ACI = asset
if (!istype(ACI))
ACI = new(asset_name, asset)
ACI = new(asset_name, asset, file_hash, dmi_file_path)
if (!ACI || !ACI.hash)
CRASH("ERROR: Invalid asset: [asset_name]:[asset]:[ACI]")
if (SSassets.cache[asset_name])
Expand Down