mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-13 08:04:22 +01:00
Unit Test rework & Master/Ticker update (#17912)
* Unit Test rework & Master/Ticker update * Fixes and working unit testing * Fixes * Test fixes and FA update * Fixed runtimes * Radio subsystem * move that glob wherever later * ident * CIBUILDING compile option * Fixed runtimes * Some changes to the workflow * CI Split * More split * Pathing * Linters and Annotators * ci dir fix * Missing undef fixed * Enable grep checks * More test conversions * More split * Correct file * Removes unneeded inputs * oop * More dependency changes * More conversions * Conversion fixes * Fixes * Some assert fixes * Corrects start gate * Converted some README.dms to README.mds * Removes duplicate proc * Removes unused defines * Example configs * fix dll access viol by double calling * Post-rebase fixes * Cleans up names global list * Undef restart counter * More code/game/ cleanup * Statpanel update * Skybox * add * Fix ticker * Roundend fix * Persistence dependency update * Reordering * Reordering * Reordering * Initstage fix * . * . * Reorder * Reorder * Circle * Mobs * Air * Test fix * CI Script Fix * Configs * More ticker stuff * This is now in 'reboot world' * Restart world announcements * no glob in PreInit * to define * Update * Removed old include * Make this file normal again * moved * test * shared unit testing objects * Updates batched_spritesheets and universal_icon * . * job data debug * rm that * init order * show us * . * i wonder * . * . * urg * do we not have a job ID? * . * rm sleep for now * updated rust-g linux binaries * binaries update 2 * binaries update 3 * testing something * change that * test something * . * . * . * locavar * test * move that * . * debug * don't run this test * strack trace it * cleaner * . * . * cras again * also comment this out * return to official rust g * Update robot_icons.dm * monitor the generation * . --------- Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
@@ -1,107 +1,90 @@
|
||||
GLOBAL_LIST_EMPTY(robot_sprite_sheets)
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons
|
||||
_abstract = /datum/asset/spritesheet_batched/robot_icons
|
||||
name = "robot_icons"
|
||||
fully_generated = TRUE
|
||||
var/module_type
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/standard
|
||||
name = "robot_icons_standard"
|
||||
fully_generated = FALSE
|
||||
module_type = "Standard"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/service
|
||||
name = "robot_icons_service"
|
||||
fully_generated = FALSE
|
||||
module_type = "Service"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/clerical
|
||||
name = "robot_icons_clerical"
|
||||
fully_generated = FALSE
|
||||
module_type = "Clerical"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/clown
|
||||
name = "robot_icons_clown"
|
||||
fully_generated = FALSE
|
||||
module_type = "Clown"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/command
|
||||
name = "robot_icons_command"
|
||||
fully_generated = FALSE
|
||||
module_type = "Command"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/research
|
||||
name = "robot_icons_research"
|
||||
fully_generated = FALSE
|
||||
module_type = "Research"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/miner
|
||||
name = "robot_icons_miner"
|
||||
fully_generated = FALSE
|
||||
module_type = "Miner"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/crisis
|
||||
name = "robot_icons_crisis"
|
||||
fully_generated = FALSE
|
||||
module_type = "Crisis"
|
||||
|
||||
/* Modul not in use
|
||||
/datum/asset/spritesheet_batched/robot_icons/surgeon
|
||||
name = "robot_icons_surgeon"
|
||||
module_type = "Surgeon"
|
||||
*/
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/security
|
||||
name = "robot_icons_security"
|
||||
fully_generated = FALSE
|
||||
module_type = "Security"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/combat
|
||||
name = "robot_icons_combat"
|
||||
fully_generated = FALSE
|
||||
module_type = "Combat"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/exploration
|
||||
name = "robot_icons_exploration"
|
||||
fully_generated = FALSE
|
||||
module_type = "Exploration"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/engineering
|
||||
name = "robot_icons_engineering"
|
||||
fully_generated = FALSE
|
||||
module_type = "Engineering"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/janitor
|
||||
name = "robot_icons_janitor"
|
||||
fully_generated = FALSE
|
||||
module_type = "Janitor"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/gravekeeper
|
||||
name = "robot_icons_gravekeeper"
|
||||
fully_generated = FALSE
|
||||
module_type = "Gravekeeper"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/lost
|
||||
name = "robot_icons_lost"
|
||||
fully_generated = FALSE
|
||||
module_type = "Lost"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/protector
|
||||
name = "robot_icons_protector"
|
||||
fully_generated = FALSE
|
||||
module_type = "Protector"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/mechanist
|
||||
name = "robot_icons_mechanist"
|
||||
fully_generated = FALSE
|
||||
module_type = "Mechanist"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/combat_medic
|
||||
name = "robot_icons_combat_medic"
|
||||
fully_generated = FALSE
|
||||
module_type = "Combat Medic"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/ninja
|
||||
name = "robot_icons_ninja"
|
||||
fully_generated = FALSE
|
||||
module_type = "Ninja"
|
||||
|
||||
/datum/asset/spritesheet_batched/robot_icons/create_spritesheets()
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
var/load_immediately = FALSE
|
||||
/// If we should avoid propogating 'invalid dir' errors from rust-g. Because sometimes, you just don't know what dirs are valid.
|
||||
var/ignore_dir_errors = FALSE
|
||||
/// Avoid propogating 'Could not find associated icon state' errors because we know our input data fucking sucks
|
||||
var/ignore_associated_icon_state_errors = FALSE
|
||||
|
||||
/// Forces use of the smart cache. This is for unit tests, please respect the config <3
|
||||
var/force_cache = FALSE
|
||||
@@ -48,6 +46,7 @@
|
||||
var/cache_dmi_hashes_json = null
|
||||
/// Used to prevent async cache refresh jobs from looping on failure.
|
||||
var/cache_result = null
|
||||
var/getting_genned = FALSE
|
||||
|
||||
/datum/asset/spritesheet_batched/proc/should_load_immediately()
|
||||
#ifdef DO_NOT_DEFER_ASSETS
|
||||
@@ -78,7 +77,7 @@
|
||||
if(cached_rustg_version != rustg_version)
|
||||
log_asset("Invalidated cache for spritesheet_[name] due to rustg updating from [cached_rustg_version] to [rustg_version].")
|
||||
return CACHE_INVALID
|
||||
// Invalidate cache if the DM version changes
|
||||
// Invalidate cache if the DM version changes
|
||||
var/cached_dm_version = cache_json["dm_version"]
|
||||
if(isnull(cached_dm_version))
|
||||
log_asset("Cache for spritesheet_[name] did not contain a dm_version!")
|
||||
@@ -108,8 +107,8 @@
|
||||
if (data_out == RUSTG_JOB_ERROR)
|
||||
CRASH("Spritesheet [name] cache JOB PANIC")
|
||||
else if(!findtext(data_out, "{", 1, 2))
|
||||
rustg_file_write(cache_data, "[GLOB.log_directory]-spritesheet_cache_debug.[name].json")
|
||||
rustg_file_write(entries_json, "[GLOB.log_directory]-spritesheet_debug_[name].json")
|
||||
rustg_file_write(cache_data, "[GLOB.log_directory]/spritesheet_cache_debug.[name].json")
|
||||
rustg_file_write(entries_json, "[GLOB.log_directory]/spritesheet_debug_[name].json")
|
||||
CRASH("Spritesheet [name] cache check UNKNOWN ERROR: [data_out]")
|
||||
var/result = json_decode(data_out)
|
||||
var/fail = result["fail_reason"]
|
||||
@@ -127,6 +126,8 @@
|
||||
/datum/asset/spritesheet_batched/proc/insert_icon(sprite_name, datum/universal_icon/entry)
|
||||
if(!istext(sprite_name) || !length(sprite_name))
|
||||
CRASH("Invalid sprite_name \"[sprite_name]\" given to insert_icon()! Providing non-strings will break icon generation.")
|
||||
if(!istype(entry))
|
||||
CRASH("Invalid type provided to insert_icon()! Value: [entry] (type: [entry?.type])")
|
||||
entries[sprite_name] = entry.to_list()
|
||||
|
||||
/datum/asset/spritesheet_batched/register()
|
||||
@@ -148,7 +149,6 @@
|
||||
|
||||
/// Call insert_icon or insert_all_icons here, building a spritesheet!
|
||||
/datum/asset/spritesheet_batched/proc/create_spritesheets()
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
CRASH("create_spritesheets() not implemented for [type]!")
|
||||
|
||||
/datum/asset/spritesheet_batched/proc/insert_all_icons(prefix, icon/I, list/directions, prefix_with_dirs = TRUE)
|
||||
@@ -159,8 +159,6 @@
|
||||
directions = list(SOUTH)
|
||||
|
||||
for (var/icon_state_name in icon_states(I))
|
||||
if(icon_state_name == "")
|
||||
icon_state_name = "byond-default"
|
||||
for (var/direction in directions)
|
||||
var/prefix2 = (directions.len > 1 && prefix_with_dirs) ? "[dir2text(direction)]-" : ""
|
||||
insert_icon("[prefix][prefix2][icon_state_name]", uni_icon(I, icon_state_name, direction))
|
||||
@@ -171,6 +169,8 @@
|
||||
if(!length(entries))
|
||||
CRASH("Spritesheet [name] ([type]) is empty! What are you doing?")
|
||||
|
||||
if(getting_genned)
|
||||
stack_trace("Spritesheet batching has been called twice. This is illegal!")
|
||||
if(isnull(entries_json))
|
||||
entries_json = json_encode(entries)
|
||||
|
||||
@@ -192,15 +192,16 @@
|
||||
var/data_out
|
||||
if(yield || !isnull(job_id))
|
||||
if(isnull(job_id))
|
||||
getting_genned = TRUE
|
||||
job_id = rustg_iconforge_generate_async("data/spritesheets/", name, entries_json, do_cache, FALSE, TRUE)
|
||||
UNTIL((data_out = rustg_iconforge_check(job_id)) != RUSTG_JOB_NO_RESULTS_YET)
|
||||
getting_genned = FALSE
|
||||
else
|
||||
//rustg_file_write(entries_json, "fuckoff.json")
|
||||
data_out = rustg_iconforge_generate("data/spritesheets/", name, entries_json, do_cache, FALSE, TRUE)
|
||||
if (data_out == RUSTG_JOB_ERROR)
|
||||
CRASH("Spritesheet [name] JOB PANIC")
|
||||
else if(!findtext(data_out, "{", 1, 2))
|
||||
rustg_file_write(entries_json, "[GLOB.log_directory]-spritesheet_debug_[name].json")
|
||||
rustg_file_write(entries_json, "[GLOB.log_directory]/spritesheet_debug_[name].json")
|
||||
CRASH("Spritesheet [name] UNKNOWN ERROR: [data_out]")
|
||||
var/data = json_decode(data_out)
|
||||
sizes = data["sizes"]
|
||||
@@ -209,30 +210,31 @@
|
||||
var/dmi_hashes = data["dmi_hashes"] // this only contains values if do_cache is TRUE.
|
||||
|
||||
for(var/size_id in sizes)
|
||||
var/file_path = "data/spritesheets/[name]_[size_id].png"
|
||||
var/file_hash = rustg_hash_file("md5", file_path)
|
||||
SSassets.transport.register_asset("[name]_[size_id].png", fcopy_rsc(file_path), file_hash)
|
||||
var/res_name = "spritesheet_[name].css"
|
||||
var/fname = "data/spritesheets/[res_name]"
|
||||
var/png_name = "[name]_[size_id].png"
|
||||
var/file_directory = "data/spritesheets/[png_name]"
|
||||
var/file_hash = rustg_hash_file(RUSTG_HASH_MD5, file_directory)
|
||||
SSassets.transport.register_asset(png_name, fcopy_rsc(file_directory), file_hash)
|
||||
if(CONFIG_GET(flag/save_spritesheets))
|
||||
save_to_logs(file_name = png_name, file_location = file_directory)
|
||||
var/css_name = "spritesheet_[name].css"
|
||||
var/file_directory = "data/spritesheets/[css_name]"
|
||||
|
||||
fdel(fname)
|
||||
fdel(file_directory)
|
||||
var/css = generate_css()
|
||||
rustg_file_write(css, fname)
|
||||
var/css_hash = rustg_hash_string("md5", css)
|
||||
SSassets.transport.register_asset(res_name, fcopy_rsc(fname), file_hash=css_hash)
|
||||
rustg_file_write(css, file_directory)
|
||||
var/css_hash = rustg_hash_string(RUSTG_HASH_MD5, css)
|
||||
SSassets.transport.register_asset(css_name, fcopy_rsc(file_directory), file_hash=css_hash)
|
||||
|
||||
if(CONFIG_GET(flag/save_spritesheets))
|
||||
save_to_logs(file_name = css_name, file_location = file_directory)
|
||||
|
||||
if (do_cache)
|
||||
write_cache_meta(input_hash, dmi_hashes)
|
||||
fully_generated = TRUE
|
||||
// If we were ever in there, remove ourselves
|
||||
SSasset_loading.dequeue_asset(src)
|
||||
if(data["error"])
|
||||
var/err = data["error"]
|
||||
if(ignore_dir_errors && findtext(err, "is not in the set of valid dirs"))
|
||||
return
|
||||
if(ignore_associated_icon_state_errors && findtext(err, "Could not find associated icon state"))
|
||||
return
|
||||
CRASH("Error during spritesheet generation for [name]: [err]")
|
||||
if(data["error"] && !(ignore_dir_errors && findtext(data["error"], "is not in the set of valid dirs")))
|
||||
CRASH("Error during spritesheet generation for [name]: [data["error"]]")
|
||||
|
||||
/datum/asset/spritesheet_batched/queued_generation()
|
||||
realize_spritesheets(yield = TRUE)
|
||||
@@ -266,7 +268,7 @@
|
||||
var/size_split = splittext(size_id, "x")
|
||||
var/width = text2num(size_split[1])
|
||||
var/height = text2num(size_split[2])
|
||||
out += ".[name][size_id]{display:inline-block;width:[width]px;height:[height]px;background-image:url('[get_background_url("[name]_[size_id].png")]');background-repeat: no-repeat;}"
|
||||
out += ".[name][size_id]{display:inline-block;width:[width]px;height:[height]px;background-image:url('[get_background_url("[name]_[size_id].png")]');background-repeat:no-repeat;}"
|
||||
|
||||
for (var/sprite_id in sprites)
|
||||
var/sprite = sprites[sprite_id]
|
||||
@@ -286,7 +288,8 @@
|
||||
if(!CONFIG_GET(flag/smart_cache_assets) && !force_cache)
|
||||
return FALSE
|
||||
// this is already guaranteed to exist.
|
||||
var/css_fname = "data/spritesheets/spritesheet_[name].css"
|
||||
var/css_name = "spritesheet_[name].css"
|
||||
var/css_file_directory = "data/spritesheets/[css_name]"
|
||||
|
||||
// sizes gets filled during should_refresh()
|
||||
for(var/size_id in sizes)
|
||||
@@ -294,13 +297,16 @@
|
||||
if(!fexists(fname))
|
||||
return FALSE
|
||||
|
||||
var/css_hash = rustg_hash_file("md5", css_fname)
|
||||
SSassets.transport.register_asset("spritesheet_[name].css", fcopy_rsc(css_fname), file_hash=css_hash)
|
||||
var/css_hash = rustg_hash_file(RUSTG_HASH_MD5, css_file_directory)
|
||||
SSassets.transport.register_asset(css_name, fcopy_rsc(css_file_directory), file_hash=css_hash)
|
||||
for(var/size_id in sizes)
|
||||
var/fname = "data/spritesheets/[name]_[size_id].png"
|
||||
var/hash = rustg_hash_file("md5", fname)
|
||||
var/hash = rustg_hash_file(RUSTG_HASH_MD5, fname)
|
||||
SSassets.transport.register_asset("[name]_[size_id].png", fcopy_rsc(fname), file_hash=hash)
|
||||
|
||||
if(CONFIG_GET(flag/save_spritesheets))
|
||||
save_to_logs(file_name = css_name, file_location = css_file_directory)
|
||||
|
||||
return TRUE
|
||||
|
||||
/// Returns the URL to put in the background:url of the CSS asset
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
|
||||
/// Don't instantiate these yourself, use uni_icon.
|
||||
/datum/universal_icon/New(icon/icon_file, icon_state="", dir=null, frame=null, datum/icon_transformer/transform=null, color=null)
|
||||
#ifdef UNIT_TEST
|
||||
#ifdef UNIT_TESTS
|
||||
// This check is kinda slow and shouldn't fail unless a developer makes a mistake. So it'll get caught in unit tests.
|
||||
if(!isicon(icon_file) || !isfile(icon_file) || "[icon_file]" == "/icon")
|
||||
if(!isicon(icon_file) || !isfile(icon_file) || "[icon_file]" == "/icon" || !length("[icon_file]"))
|
||||
// bad! use 'icons/path_to_dmi.dmi' format only
|
||||
CRASH("FATAL: universal_icon was provided icon_file: [icon_file] - icons provided to batched spritesheets MUST be DMI files, they cannot be /image, /icon, or other runtime generated icons.")
|
||||
#endif
|
||||
@@ -44,10 +44,10 @@
|
||||
transform.blend_color(color, blend_mode)
|
||||
return src
|
||||
|
||||
/datum/universal_icon/proc/blend_icon(datum/universal_icon/icon_object, blend_mode)
|
||||
/datum/universal_icon/proc/blend_icon(datum/universal_icon/icon_object, blend_mode, x=1, y=1)
|
||||
if(!transform)
|
||||
transform = new
|
||||
transform.blend_icon(icon_object, blend_mode)
|
||||
transform.blend_icon(icon_object, blend_mode, x, y)
|
||||
return src
|
||||
|
||||
/datum/universal_icon/proc/scale(width, height)
|
||||
@@ -62,14 +62,116 @@
|
||||
transform.crop(x1, y1, x2, y2)
|
||||
return src
|
||||
|
||||
/// Internally performs a crop.
|
||||
/datum/universal_icon/proc/shift(dir, amount, icon_width, icon_height)
|
||||
/datum/universal_icon/proc/flip(dir)
|
||||
if(!transform)
|
||||
transform = new
|
||||
var/list/offsets = dir2offset(dir)
|
||||
var/shift_x = -offsets[1] * amount
|
||||
var/shift_y = -offsets[2] * amount
|
||||
transform.crop(1 + shift_x, 1 + shift_y, icon_width + shift_x, icon_height + shift_y)
|
||||
transform.flip(dir)
|
||||
return src
|
||||
|
||||
/datum/universal_icon/proc/rotate(angle)
|
||||
if(!transform)
|
||||
transform = new
|
||||
transform.rotate(angle)
|
||||
return src
|
||||
|
||||
/datum/universal_icon/proc/shift(dir, offset, wrap=0)
|
||||
if(!transform)
|
||||
transform = new
|
||||
transform.shift(dir, offset, wrap)
|
||||
return src
|
||||
|
||||
/datum/universal_icon/proc/swap_color(src_color, dst_color)
|
||||
if(!transform)
|
||||
transform = new
|
||||
transform.swap_color(src_color, dst_color)
|
||||
return src
|
||||
|
||||
/datum/universal_icon/proc/draw_box(color, x1, y1, x2=x1, y2=y1)
|
||||
if(!transform)
|
||||
transform = new
|
||||
transform.draw_box(color, x1, y1, x2, y2)
|
||||
return src
|
||||
|
||||
/datum/universal_icon/proc/map_colors_inferred(list/color_args)
|
||||
var/num_args = length(color_args)
|
||||
if(num_args <= 20 || num_args >= 16)
|
||||
src.map_colors_rgba(arglist(color_args))
|
||||
else if(num_args <= 12 || num_args >= 9)
|
||||
src.map_colors_rgb(arglist(color_args))
|
||||
else if(num_args == 5)
|
||||
src.map_colors_rgba_hex(arglist(color_args))
|
||||
else if(num_args == 4)
|
||||
// is there alpha in the hex?
|
||||
if(length(color_args[3]) == 7 || length(color_args[3]) == 4)
|
||||
src.map_colors_rgb_hex(arglist(color_args))
|
||||
else
|
||||
src.map_colors_rgba_hex(arglist(color_args))
|
||||
else if(num_args == 3)
|
||||
src.map_colors_rgb_hex(arglist(color_args))
|
||||
|
||||
/datum/universal_icon/proc/map_colors_rgba(rr, rg, rb, ra, gr, gg, gb, ga, br, bg, bb, ba, ar, ag, ab, aa, r0=0, g0=0, b0=0, a0=0)
|
||||
if(!transform)
|
||||
transform = new
|
||||
transform.map_colors(rr, rg, rb, ra, gr, gg, gb, ga, br, bg, bb, ba, ar, ag, ab, aa, r0, g0, b0, a0)
|
||||
return src
|
||||
|
||||
/datum/universal_icon/proc/map_colors_rgb(rr, rg, rb, gr, gg, gb, br, bg, bb, r0=0, g0=0, b0=0)
|
||||
if(!transform)
|
||||
transform = new
|
||||
transform.map_colors(rr, rg, rb, 0, gr, gg, gb, 0, br, bg, bb, 0, 0, 0, 0, 1, r0, g0, b0, 0)
|
||||
return src
|
||||
|
||||
/datum/universal_icon/proc/map_colors_rgb_hex(r_rgb, g_rgb, b_rgb, rgb0=rgb(0,0,0))
|
||||
if(!transform)
|
||||
transform = new
|
||||
var/rr = hex2num(copytext(r_rgb, 2, 4)) / 255
|
||||
var/rg = hex2num(copytext(r_rgb, 4, 6)) / 255
|
||||
var/rb = hex2num(copytext(r_rgb, 6, 8)) / 255
|
||||
|
||||
var/gr = hex2num(copytext(g_rgb, 2, 4)) / 255
|
||||
var/gg = hex2num(copytext(g_rgb, 4, 6)) / 255
|
||||
var/gb = hex2num(copytext(g_rgb, 6, 8)) / 255
|
||||
|
||||
var/br = hex2num(copytext(b_rgb, 2, 4)) / 255
|
||||
var/bg = hex2num(copytext(b_rgb, 4, 6)) / 255
|
||||
var/bb = hex2num(copytext(b_rgb, 6, 8)) / 255
|
||||
|
||||
var/r0 = hex2num(copytext(rgb0, 2, 4)) / 255
|
||||
var/b0 = hex2num(copytext(rgb0, 4, 6)) / 255
|
||||
var/g0 = hex2num(copytext(rgb0, 6, 8)) / 255
|
||||
|
||||
transform.map_colors(rr, rg, rb, 0, gr, gg, gb, 0, br, bg, bb, 0, 0, 0, 0, 1, r0, b0, g0, 0)
|
||||
return src
|
||||
|
||||
/datum/universal_icon/proc/map_colors_rgba_hex(r_rgba, g_rgba, b_rgba, a_rgba, rgba0="#00000000")
|
||||
if(!transform)
|
||||
transform = new
|
||||
var/rr = hex2num(copytext(r_rgba, 2, 4)) / 255
|
||||
var/rg = hex2num(copytext(r_rgba, 4, 6)) / 255
|
||||
var/rb = hex2num(copytext(r_rgba, 6, 8)) / 255
|
||||
var/ra = hex2num(copytext(r_rgba, 8, 10)) / 255
|
||||
|
||||
var/gr = hex2num(copytext(g_rgba, 2, 4)) / 255
|
||||
var/gg = hex2num(copytext(g_rgba, 4, 6)) / 255
|
||||
var/gb = hex2num(copytext(g_rgba, 6, 8)) / 255
|
||||
var/ga = hex2num(copytext(g_rgba, 8, 10)) / 255
|
||||
|
||||
var/br = hex2num(copytext(b_rgba, 2, 4)) / 255
|
||||
var/bg = hex2num(copytext(b_rgba, 4, 6)) / 255
|
||||
var/bb = hex2num(copytext(b_rgba, 6, 8)) / 255
|
||||
var/ba = hex2num(copytext(b_rgba, 8, 10)) / 255
|
||||
|
||||
var/ar = hex2num(copytext(a_rgba, 2, 4)) / 255
|
||||
var/ag = hex2num(copytext(a_rgba, 4, 6)) / 255
|
||||
var/ab = hex2num(copytext(a_rgba, 6, 8)) / 255
|
||||
var/aa = hex2num(copytext(a_rgba, 8, 10)) / 255
|
||||
|
||||
var/r0 = hex2num(copytext(rgba0, 2, 4)) / 255
|
||||
var/b0 = hex2num(copytext(rgba0, 4, 6)) / 255
|
||||
var/g0 = hex2num(copytext(rgba0, 6, 8)) / 255
|
||||
var/a0 = hex2num(copytext(rgba0, 8, 10)) / 255
|
||||
|
||||
transform.map_colors(rr, rg, rb, ra, gr, gg, gb, ga, br, bg, bb, ba, ar, ag, ab, aa, r0, b0, g0, a0)
|
||||
return src
|
||||
|
||||
/// Internally performs a color blend.
|
||||
@@ -118,11 +220,29 @@
|
||||
if(!istype(icon_object))
|
||||
stack_trace("Invalid icon found in icon transformer during apply()! [icon_object]")
|
||||
continue
|
||||
target.Blend(icon_object.to_icon(), transform["blend_mode"])
|
||||
target.Blend(icon_object.to_icon(), transform["blend_mode"], transform["x"], transform["y"])
|
||||
if(RUSTG_ICONFORGE_SCALE)
|
||||
target.Scale(transform["width"], transform["height"])
|
||||
if(RUSTG_ICONFORGE_CROP)
|
||||
target.Crop(transform["x1"], transform["y1"], transform["x2"], transform["y2"])
|
||||
if(RUSTG_ICONFORGE_MAP_COLORS)
|
||||
target.MapColors(
|
||||
transform["rr"], transform["rg"], transform["rb"], transform["ra"],
|
||||
transform["gr"], transform["gg"], transform["gb"], transform["ga"],
|
||||
transform["br"], transform["bg"], transform["bb"], transform["ba"],
|
||||
transform["ar"], transform["ag"], transform["ab"], transform["aa"],
|
||||
transform["r0"], transform["g0"], transform["b0"], transform["a0"],
|
||||
)
|
||||
if(RUSTG_ICONFORGE_FLIP)
|
||||
target.Flip(transform["dir"])
|
||||
if(RUSTG_ICONFORGE_TURN)
|
||||
target.Turn(transform["angle"])
|
||||
if(RUSTG_ICONFORGE_SHIFT)
|
||||
target.Shift(transform["dir"], transform["offset"], transform["wrap"])
|
||||
if(RUSTG_ICONFORGE_SWAP_COLOR)
|
||||
target.SwapColor(transform["src_color"], transform["dst_color"])
|
||||
if(RUSTG_ICONFORGE_DRAW_BOX)
|
||||
target.DrawBox(transform["color"], transform["x1"], transform["y1"], transform["x2"], transform["y2"])
|
||||
return target
|
||||
|
||||
/datum/icon_transformer/proc/copy()
|
||||
@@ -134,7 +254,7 @@
|
||||
return new_transformer
|
||||
|
||||
/datum/icon_transformer/proc/blend_color(color, blend_mode)
|
||||
#ifdef UNIT_TEST
|
||||
#ifdef UNIT_TESTS
|
||||
if(!istext(color))
|
||||
CRASH("Invalid color provided to blend_color: [color]")
|
||||
if(!isnum(blend_mode))
|
||||
@@ -142,28 +262,77 @@
|
||||
#endif
|
||||
transforms += list(list("type" = RUSTG_ICONFORGE_BLEND_COLOR, "color" = color, "blend_mode" = blend_mode))
|
||||
|
||||
/datum/icon_transformer/proc/blend_icon(datum/universal_icon/icon_object, blend_mode)
|
||||
#ifdef UNIT_TEST
|
||||
/datum/icon_transformer/proc/blend_icon(datum/universal_icon/icon_object, blend_mode, x=1, y=1)
|
||||
#ifdef UNIT_TESTS
|
||||
// icon_object's type is checked later in to_list
|
||||
if(!isnum(blend_mode))
|
||||
CRASH("Invalid blend_mode provided to blend_icon: [blend_mode]")
|
||||
if(!isnum(x))
|
||||
CRASH("Invalid x offset provided to blend_icon: [x]")
|
||||
if(!isnum(y))
|
||||
CRASH("Invalid y offset provided to blend_icon: [y]")
|
||||
#endif
|
||||
transforms += list(list("type" = RUSTG_ICONFORGE_BLEND_ICON, "icon" = icon_object, "blend_mode" = blend_mode))
|
||||
transforms += list(list("type" = RUSTG_ICONFORGE_BLEND_ICON, "icon" = icon_object, "blend_mode" = blend_mode, "x" = x, "y" = y))
|
||||
|
||||
/datum/icon_transformer/proc/scale(width, height)
|
||||
#ifdef UNIT_TEST
|
||||
#ifdef UNIT_TESTS
|
||||
if(!isnum(width) || !isnum(height))
|
||||
CRASH("Invalid arguments provided to scale: [width],[height]")
|
||||
#endif
|
||||
transforms += list(list("type" = RUSTG_ICONFORGE_SCALE, "width" = width, "height" = height))
|
||||
|
||||
/datum/icon_transformer/proc/crop(x1, y1, x2, y2)
|
||||
#ifdef UNIT_TEST
|
||||
#ifdef UNIT_TESTS
|
||||
if(!isnum(x1) || !isnum(y1) || !isnum(x2) || !isnum(y2))
|
||||
CRASH("Invalid arguments provided to crop: [x1],[y1],[x2],[y2]")
|
||||
#endif
|
||||
transforms += list(list("type" = RUSTG_ICONFORGE_CROP, "x1" = x1, "y1" = y1, "x2" = x2, "y2" = y2))
|
||||
|
||||
/datum/icon_transformer/proc/flip(dir)
|
||||
#ifdef UNIT_TESTS
|
||||
if(!isnum(dir))
|
||||
CRASH("Invalid arguments provided to flip: [dir]")
|
||||
#endif
|
||||
transforms += list(list("type" = RUSTG_ICONFORGE_FLIP, "dir" = dir))
|
||||
|
||||
/datum/icon_transformer/proc/rotate(angle)
|
||||
#ifdef UNIT_TESTS
|
||||
if(!isnum(angle))
|
||||
CRASH("Invalid arguments provided to rotate: [angle]")
|
||||
#endif
|
||||
transforms += list(list("type" = RUSTG_ICONFORGE_TURN, "angle" = angle))
|
||||
|
||||
/datum/icon_transformer/proc/shift(dir, offset, wrap=FALSE)
|
||||
#ifdef UNIT_TESTS
|
||||
if(!isnum(dir) || !isnum(offset) || (wrap != FALSE && wrap != TRUE))
|
||||
CRASH("Invalid arguments provided to shift: [dir],[offset],[wrap]")
|
||||
#endif
|
||||
transforms += list(list("type" = RUSTG_ICONFORGE_SHIFT, "dir" = dir, "offset" = offset, "wrap" = wrap))
|
||||
|
||||
/datum/icon_transformer/proc/swap_color(src_color, dst_color)
|
||||
#ifdef UNIT_TESTS
|
||||
if(!istext(src_color) || !istext(dst_color))
|
||||
CRASH("Invalid arguments provided to swap_color: [src_color],[dst_color]")
|
||||
#endif
|
||||
transforms += list(list("type" = RUSTG_ICONFORGE_SWAP_COLOR, "src_color" = src_color, "dst_color" = dst_color))
|
||||
|
||||
/datum/icon_transformer/proc/draw_box(color, x1, y1, x2=x1, y2=y1)
|
||||
#ifdef UNIT_TESTS
|
||||
if(!istext(color) || !isnum(x1) || !isnum(y1) || !isnum(x2) || !isnum(y2))
|
||||
CRASH("Invalid arguments provided to draw_box: [color],[x1],[y1],[x2],[y2]")
|
||||
#endif
|
||||
transforms += list(list("type" = RUSTG_ICONFORGE_DRAW_BOX, "color" = color, "x1" = x1, "y1" = y1, "x2" = x2, "y2" = y2))
|
||||
|
||||
/datum/icon_transformer/proc/map_colors(rr, rg, rb, ra, gr, gg, gb, ga, br, bg, bb, ba, ar, ag, ab, aa, r0=0, g0=0, b0=0, a0=0)
|
||||
transforms += list(list(
|
||||
"type" = RUSTG_ICONFORGE_MAP_COLORS,
|
||||
"rr" = rr, "rg" = rg, "rb" = rb, "ra" = ra,
|
||||
"gr" = gr, "gg" = gg, "gb" = gb, "ga" = ga,
|
||||
"br" = br, "bg" = bg, "bb" = bb, "ba" = ba,
|
||||
"ar" = ar, "ag" = ag, "ab" = ab, "aa" = aa,
|
||||
"r0" = r0, "g0" = g0, "b0" = b0, "a0" = a0,
|
||||
))
|
||||
|
||||
/// Recursively converts all contained [/datum/universal_icon]s and their associated [/datum/icon_transformer]s into list form so the transforms can be JSON encoded.
|
||||
/datum/icon_transformer/proc/to_list()
|
||||
RETURN_TYPE(/list)
|
||||
@@ -204,26 +373,240 @@
|
||||
return transform
|
||||
|
||||
/// Converts a GAGS item to a universal icon by generating blend operations.
|
||||
// /proc/gags_to_universal_icon(obj/item/path)
|
||||
// RETURN_TYPE(/datum/universal_icon)
|
||||
// if(!ispath(path, /obj/item) || !initial(path.greyscale_config) || !initial(path.greyscale_colors))
|
||||
// CRASH("gags_to_universal_icon() received an invalid path!")
|
||||
// var/datum/greyscale_config/config = initial(path.greyscale_config)
|
||||
// var/colors = initial(path.greyscale_colors)
|
||||
// var/datum/universal_icon/entry = SSgreyscale.GetColoredIconEntryByType(config, colors, initial(path.icon_state))
|
||||
// return entry
|
||||
/*
|
||||
/proc/gags_to_universal_icon(atom/path)
|
||||
RETURN_TYPE(/datum/universal_icon)
|
||||
if(!ispath(path, /atom) || !initial(path.greyscale_config) || !initial(path.greyscale_colors))
|
||||
CRASH("gags_to_universal_icon() received an invalid path of \"[path]\"!")
|
||||
var/datum/greyscale_config/config = initial(path.greyscale_config)
|
||||
var/colors = initial(path.greyscale_colors)
|
||||
var/datum/universal_icon/entry = SSgreyscale.GetColoredIconByTypeUniversalIcon(config, colors, path::post_init_icon_state || path::icon_state)
|
||||
return entry
|
||||
*/
|
||||
|
||||
/// Gets the relevant universal icon for an atom, when displayed in TGUI. (see: icon_state_preview)
|
||||
/// Supports GAGS items and colored items.
|
||||
/proc/get_display_icon_for(atom/A)
|
||||
if (!ispath(A, /atom))
|
||||
/proc/get_display_icon_for(atom/atom_path)
|
||||
if (!ispath(atom_path, /atom))
|
||||
return FALSE
|
||||
var/icon_file = initial(A.icon)
|
||||
var/icon_state = initial(A.icon_state)
|
||||
// if(ispath(A, /obj/item))
|
||||
// var/obj/item/I = A
|
||||
// if(initial(I.icon_state_preview))
|
||||
// icon_state = initial(I.icon_state_preview)
|
||||
// if(initial(I.greyscale_config) && initial(I.greyscale_colors))
|
||||
// return gags_to_universal_icon(I)
|
||||
return uni_icon(icon_file, icon_state, color=initial(A.color))
|
||||
var/icon_file = atom_path::icon
|
||||
var/icon_state = atom_path::icon_state
|
||||
/*
|
||||
if(atom_path::greyscale_config && atom_path::greyscale_colors)
|
||||
return gags_to_universal_icon(atom_path)
|
||||
if(ispath(atom_path, /obj))
|
||||
var/obj/obj_path = atom_path
|
||||
if(obj_path::icon_state_preview)
|
||||
icon_state = obj_path::icon_state_preview
|
||||
*/
|
||||
return uni_icon(icon_file, icon_state, color=atom_path::color)
|
||||
|
||||
/// getFlatIcon for [/datum/universal_icon]s
|
||||
/// Still fairly slow for complex appearances due to filesystem operations. Try to avoid using it
|
||||
/proc/get_flat_uni_icon(image/appearance, defdir, deficon, defstate, defblend, start = TRUE, parentcolor)
|
||||
// Loop through the underlays, then overlays, sorting them into the layers list
|
||||
#define PROCESS_OVERLAYS_OR_UNDERLAYS(flat, process, base_layer) \
|
||||
for (var/i in 1 to process.len) { \
|
||||
var/image/current = process[i]; \
|
||||
if (!current) { \
|
||||
continue; \
|
||||
} \
|
||||
if (current.plane != FLOAT_PLANE && current.plane != appearance.plane) { \
|
||||
continue; \
|
||||
} \
|
||||
var/current_layer = current.layer; \
|
||||
if (current_layer < 0) { \
|
||||
if (current_layer <= -1000) { \
|
||||
return flat; \
|
||||
} \
|
||||
current_layer = base_layer + appearance.layer + current_layer / 1000; \
|
||||
} \
|
||||
/* If we are using topdown rendering, chop that part off so things layer together as expected */ \
|
||||
if((current_layer >= TOPDOWN_LAYER && current_layer < EFFECTS_LAYER) || current_layer > TOPDOWN_LAYER + EFFECTS_LAYER) { \
|
||||
current_layer -= TOPDOWN_LAYER; \
|
||||
} \
|
||||
for (var/index_to_compare_to in 1 to layers.len) { \
|
||||
var/compare_to = layers[index_to_compare_to]; \
|
||||
if (current_layer < layers[compare_to]) { \
|
||||
layers.Insert(index_to_compare_to, current); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
layers[current] = current_layer; \
|
||||
}
|
||||
|
||||
var/datum/universal_icon/flat = uni_icon('icons/blanks/32x32.dmi', "nothing")
|
||||
|
||||
if(!appearance || appearance.alpha <= 0)
|
||||
return flat
|
||||
|
||||
if(start)
|
||||
if(!deficon)
|
||||
deficon = appearance.icon
|
||||
if(!defstate)
|
||||
defstate = appearance.icon_state
|
||||
if(!defblend)
|
||||
defblend = appearance.blend_mode
|
||||
|
||||
var/should_display = TRUE
|
||||
var/curicon = appearance.icon || deficon
|
||||
var/string_curicon = "[curicon]"
|
||||
var/curstate = appearance.icon_state || defstate
|
||||
// Filter out 'runtime' icons (server-generated RSC cache icons)
|
||||
// Write the icon to the filesystem so it can be used by iconforge
|
||||
if(!isfile(curicon) || !length(string_curicon))
|
||||
var/file_path_tmp = "tmp/uni_icon-tmp-[rand(1, 999)].dmi" // this filename is temporary.
|
||||
fcopy(curicon, file_path_tmp)
|
||||
var/file_hash = rustg_hash_file(RUSTG_HASH_MD5, file_path_tmp)
|
||||
// Use the hash as its new filename - this allows the uni_icon to be smart cached, because the filename will be consistent between runs if the content is the same
|
||||
var/file_path = "tmp/uni_icon-[file_hash].dmi"
|
||||
fcopy(file_path_tmp, file_path)
|
||||
fdel(file_path_tmp) // delete the old one
|
||||
curicon = file(file_path)
|
||||
|
||||
if(!icon_exists(curicon, curstate))
|
||||
if("" in icon_states_fast(curicon)) // BYOND defaulting functionality
|
||||
curstate = ""
|
||||
else
|
||||
should_display = FALSE
|
||||
|
||||
var/curdir = (!appearance.dir || appearance.dir == SOUTH) ? defdir : appearance.dir
|
||||
var/base_icon_dir //We'll use this to get the icon state to display if not null BUT NOT pass it to overlays as the dir we have
|
||||
|
||||
if(should_display)
|
||||
//Determines if there're directionals.
|
||||
if (curdir != SOUTH)
|
||||
// icon states either have 1, 4 or 8 dirs. We only have to check
|
||||
// one of NORTH, EAST or WEST to know that this isn't a 1-dir icon_state since they just have SOUTH.
|
||||
var/list/metadata = icon_metadata(curicon)
|
||||
if(islist(metadata))
|
||||
for(var/list/state_data as anything in metadata["states"])
|
||||
var/name = state_data["name"]
|
||||
if(name != curstate)
|
||||
continue
|
||||
var/dir_count = state_data["dirs"]
|
||||
if(dir_count == 1)
|
||||
base_icon_dir = SOUTH
|
||||
else if(!length(icon_states(icon(curicon, curstate, NORTH))))
|
||||
base_icon_dir = SOUTH
|
||||
|
||||
var/list/icon_dimensions = get_icon_dimensions(curicon)
|
||||
var/icon_width = icon_dimensions["width"]
|
||||
var/icon_height = icon_dimensions["height"]
|
||||
if(icon_width != 32 || icon_height != 32)
|
||||
flat.scale(icon_width, icon_height)
|
||||
|
||||
if(!base_icon_dir)
|
||||
base_icon_dir = curdir
|
||||
|
||||
var/curblend = appearance.blend_mode || defblend
|
||||
|
||||
|
||||
if(appearance.overlays.len || appearance.underlays.len)
|
||||
// Layers will be a sorted list of icons/overlays, based on the order in which they are displayed
|
||||
var/list/layers = list()
|
||||
var/image/copy
|
||||
if(should_display)
|
||||
// Add the atom's icon itself, without pixel_x/y offsets.
|
||||
copy = image(icon=curicon, icon_state=curstate, layer=appearance.layer, dir=base_icon_dir)
|
||||
copy.color = appearance.color
|
||||
copy.alpha = appearance.alpha
|
||||
copy.blend_mode = curblend
|
||||
layers[copy] = appearance.layer
|
||||
|
||||
PROCESS_OVERLAYS_OR_UNDERLAYS(flat, appearance.underlays, 0)
|
||||
PROCESS_OVERLAYS_OR_UNDERLAYS(flat, appearance.overlays, 1)
|
||||
|
||||
var/datum/universal_icon/add // Icon of overlay being added
|
||||
|
||||
var/list/flat_dimensions = get_icon_dimensions(flat)
|
||||
var/flatX1 = 1
|
||||
var/flatX2 = flat_dimensions["width"]
|
||||
var/flatY1 = 1
|
||||
var/flatY2 = flat_dimensions["height"]
|
||||
|
||||
var/addX1 = 0
|
||||
var/addX2 = 0
|
||||
var/addY1 = 0
|
||||
var/addY2 = 0
|
||||
|
||||
if(appearance.color)
|
||||
if(islist(appearance.color))
|
||||
flat.map_colors_inferred(appearance.color)
|
||||
else
|
||||
flat.blend_color(appearance.color, ICON_MULTIPLY)
|
||||
|
||||
if(parentcolor && !(appearance.appearance_flags & RESET_COLOR))
|
||||
if(islist(parentcolor))
|
||||
flat.map_colors_inferred(parentcolor)
|
||||
else
|
||||
flat.blend_color(parentcolor, ICON_MULTIPLY)
|
||||
|
||||
var/next_parentcolor = appearance.color || parentcolor
|
||||
|
||||
for(var/image/layer_image as anything in layers)
|
||||
if(layer_image.alpha == 0)
|
||||
continue
|
||||
|
||||
if(layer_image == copy && length("[layer_image.icon]")) // 'layer_image' is an /image based on the object being flattened, and isn't a 'runtime' icon.
|
||||
curblend = BLEND_OVERLAY
|
||||
add = uni_icon(layer_image.icon, layer_image.icon_state, base_icon_dir)
|
||||
if(appearance.color)
|
||||
if(islist(appearance.color))
|
||||
add.map_colors_inferred(appearance.color)
|
||||
else
|
||||
add.blend_color(appearance.color, ICON_MULTIPLY)
|
||||
else // 'layer_image' is an appearance object.
|
||||
add = get_flat_uni_icon(layer_image, curdir, curicon, curstate, curblend, FALSE, next_parentcolor)
|
||||
if(!add || !length(add.icon_file))
|
||||
continue
|
||||
|
||||
// Find the new dimensions of the flat icon to fit the added overlay
|
||||
var/list/add_dimensions = get_icon_dimensions(add)
|
||||
addX1 = min(flatX1, layer_image.pixel_x + layer_image.pixel_w + 1)
|
||||
addX2 = max(flatX2, layer_image.pixel_x + layer_image.pixel_w + add_dimensions["width"]) // assuming 32x32
|
||||
addY1 = min(flatY1, layer_image.pixel_y + layer_image.pixel_z + 1)
|
||||
addY2 = max(flatY2, layer_image.pixel_y + layer_image.pixel_z + add_dimensions["height"])
|
||||
|
||||
if (
|
||||
addX1 != flatX1 \
|
||||
&& addX2 != flatX2 \
|
||||
&& addY1 != flatY1 \
|
||||
&& addY2 != flatY2 \
|
||||
)
|
||||
// Resize the flattened icon so the new icon fits
|
||||
flat.crop(
|
||||
addX1 - flatX1 + 1,
|
||||
addY1 - flatY1 + 1,
|
||||
addX2 - flatX1 + 1,
|
||||
addY2 - flatY1 + 1
|
||||
)
|
||||
|
||||
flatX1 = addX1
|
||||
flatX2 = addY1
|
||||
flatY1 = addX2
|
||||
flatY2 = addY2
|
||||
|
||||
// Blend the overlay into the flattened icon
|
||||
flat.blend_icon(add, blendMode2iconMode(curblend), layer_image.pixel_x + layer_image.pixel_w + 2 - flatX1, layer_image.pixel_y + layer_image.pixel_z + 2 - flatY1)
|
||||
|
||||
if(appearance.alpha < 255)
|
||||
flat.blend_color(rgb(255, 255, 255, appearance.alpha), ICON_MULTIPLY)
|
||||
|
||||
return flat
|
||||
|
||||
else if(should_display) // There's no overlays.
|
||||
var/datum/universal_icon/final_icon = uni_icon(curicon, curstate, base_icon_dir)
|
||||
|
||||
if (appearance.alpha < 255)
|
||||
final_icon.blend_color(rgb(255,255,255, appearance.alpha), ICON_MULTIPLY)
|
||||
|
||||
if (appearance.color)
|
||||
if (islist(appearance.color))
|
||||
final_icon.map_colors_inferred(appearance.color)
|
||||
else
|
||||
final_icon.blend_color(appearance.color, ICON_MULTIPLY)
|
||||
|
||||
return final_icon
|
||||
|
||||
#undef PROCESS_OVERLAYS_OR_UNDERLAYS
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
/// 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 defined(UNIT_TEST)
|
||||
#if defined(UNIT_TESTS)
|
||||
return
|
||||
#endif
|
||||
if (!istype(client))
|
||||
|
||||
Reference in New Issue
Block a user