Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

overlay limbs for improved client performance #4290

Merged
merged 12 commits into from
Sep 4, 2023
15 changes: 8 additions & 7 deletions code/__DEFINES/human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,15 @@
#define ORDER_FOCUS_MAX_LEVEL 50

//Human Overlays Indexes used in update_icons/////////
#define UNDERWEAR_LAYER 41
#define UNDERSHIRT_LAYER 40
#define MUTANTRACE_LAYER 39
#define BODYPARTS_LAYER 42
#define DAMAGE_LAYER 41

/// For use by Hunter Flay
#define FLAY_LAYER 38
#define UNDERWEAR_LAYER 40
#define UNDERSHIRT_LAYER 39
#define MUTANTRACE_LAYER 38

#define DAMAGE_LAYER 37
/// For use by Hunter Flay
#define FLAY_LAYER 37
#define UNIFORM_LAYER 36

/// bs12 specific. this hack is probably gonna come back to haunt me
Expand Down Expand Up @@ -176,7 +177,7 @@
/// If you're hit by an acid DoT
#define EFFECTS_LAYER 1

#define TOTAL_LAYERS 41
#define TOTAL_LAYERS 42
//////////////////////////////////

//Synthetic Defines
Expand Down
6 changes: 6 additions & 0 deletions code/modules/mob/living/carbon/human/human_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@
///list of weakrefs of recently dropped objects
var/list/remembered_dropped_objects = list()

/// associated list of body part zone -> currently active limb key
var/list/icon_render_keys = list()

/// static associated list of limb key -> image to avoid unnecessary overlay generation
var/static/list/icon_render_image_cache = list()

/client/var/cached_human_playtime

/client/proc/get_total_human_playtime(skip_cache = FALSE)
Expand Down
58 changes: 47 additions & 11 deletions code/modules/mob/living/carbon/human/update_icons.dm
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,14 @@ There are several things that need to be remembered:

*/

/mob/living/carbon/human/apply_overlay(cache_index)
var/image/images = overlays_standing[cache_index]

if(!images)
return

/mob/living/carbon/human/apply_overlay(cache_index)
var/image/I = overlays_standing[cache_index]
if(I)
I.appearance_flags |= RESET_COLOR
SEND_SIGNAL(src, COMSIG_HUMAN_OVERLAY_APPLIED, cache_index, I)
overlays += I
SEND_SIGNAL(src, COMSIG_HUMAN_OVERLAY_APPLIED, cache_index, images)
overlays += images

/mob/living/carbon/human/remove_overlay(cache_index)
if(overlays_standing[cache_index])
Expand Down Expand Up @@ -132,10 +132,32 @@ There are several things that need to be remembered:
//BASE MOB SPRITE
/mob/living/carbon/human/proc/update_body()
appearance_flags |= KEEP_TOGETHER // sanity
vis_contents.Cut()
for(var/obj/limb/part in limbs)
vis_contents += part
part.update_icon(TRUE)

update_damage_overlays()

var/list/needs_update = list()
for(var/obj/limb/part as anything in limbs)
part.update_limb()

var/old_key = icon_render_keys?[part.icon_name]
icon_render_keys[part.icon_name] = part.get_limb_icon_key()
if(icon_render_keys[part.icon_name] == old_key)
continue

needs_update += part

var/list/new_limbs = list()
for(var/obj/limb/part as anything in limbs)
if(part in needs_update)
var/bodypart_icon = part.get_limb_icon()
new_limbs += bodypart_icon
icon_render_image_cache[icon_render_keys[part.icon_name]] = bodypart_icon
else
new_limbs += icon_render_image_cache[icon_render_keys[part.icon_name]]

remove_overlay(BODYPARTS_LAYER)
overlays_standing[BODYPARTS_LAYER] = new_limbs
apply_overlay(BODYPARTS_LAYER)

if(species.flags & HAS_UNDERWEAR)
//Underwear
Expand All @@ -154,6 +176,21 @@ There are several things that need to be remembered:
overlays_standing[UNDERSHIRT_LAYER] = undershirt_icon
apply_overlay(UNDERSHIRT_LAYER)

/// Recalculates and reapplies damage overlays to every limb
/mob/living/carbon/human/proc/update_damage_overlays()
remove_overlay(DAMAGE_LAYER)

var/list/damage_overlays = list()
for(var/obj/limb/part as anything in limbs)
if(part.status & LIMB_DESTROYED)
continue

damage_overlays += part.get_damage_overlays()

overlays_standing[DAMAGE_LAYER] = damage_overlays

apply_overlay(DAMAGE_LAYER)

/mob/living/carbon/human/proc/remove_underwear() // :flushed: - geeves
remove_overlay(UNDERSHIRT_LAYER)
remove_overlay(UNDERWEAR_LAYER)
Expand Down Expand Up @@ -739,7 +776,6 @@ Applied by gun suicide and high impact bullet executions, removed by rejuvenate,

//Human Overlays Indexes/////////
#undef MUTANTRACE_LAYER
#undef DAMAGE_LAYER
#undef UNIFORM_LAYER
#undef TAIL_LAYER
#undef ID_LAYER
Expand Down
182 changes: 111 additions & 71 deletions code/modules/organs/limbs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@
var/status = LIMB_ORGANIC
var/processing = FALSE

/// ethnicity of the owner, used for limb appearance, set in [/obj/limb/proc/update_limb()]
var/ethnicity = "western"

/// body type of the owner, used for limb appearance, set in [/obj/limb/proc/update_limb()]
var/body_type = "mesomorphic"

/// species of the owner, used for limb appearance, set in [/obj/limb/proc/update_limb()]
var/datum/species/species

/// defines which sprite the limb should use if dimorphic, set in [/obj/limb/proc/update_limb()]
var/limb_gender = MALE


/obj/limb/Initialize(mapload, obj/limb/P, mob/mob_owner)
. = ..()
if(P)
Expand All @@ -81,12 +94,10 @@
if(mob_owner)
owner = mob_owner

wound_overlay = image('icons/mob/humans/dam_human.dmi', "grayscale_0")
wound_overlay.blend_mode = BLEND_INSET_OVERLAY
wound_overlay = image('icons/mob/humans/dam_human.dmi', "grayscale_0", -DAMAGE_LAYER)
wound_overlay.color = owner?.species.blood_color

burn_overlay = image('icons/mob/humans/dam_human.dmi', "burn_0")
burn_overlay.blend_mode = BLEND_INSET_OVERLAY
burn_overlay = image('icons/mob/humans/dam_human.dmi', "burn_0", -DAMAGE_LAYER)

if(owner)
forceMove(owner)
Expand Down Expand Up @@ -361,7 +372,7 @@

SEND_SIGNAL(src, COMSIG_LIMB_TAKEN_DAMAGE, is_ff, previous_brute, previous_burn)
owner.updatehealth()
update_icon()
owner.update_damage_overlays()
start_processing()

///Special delimbs for different limbs
Expand Down Expand Up @@ -651,7 +662,7 @@ This function completely restores a damaged organ to perfect condition.

// sync the organ's damage with its wounds
update_damages()
update_icon()
owner.update_damage_overlays()
if(wound_disappeared)
owner.update_med_icon()
remove_wound_bleeding()
Expand All @@ -670,74 +681,70 @@ This function completely restores a damaged organ to perfect condition.

number_wounds += W.amount

/obj/limb/update_icon(forced = FALSE)
if(parent && parent.status & LIMB_DESTROYED)
overlays.Cut()
icon_state = ""
return
/// updates the various internal variables of the limb from the owner
/obj/limb/proc/update_limb()
SHOULD_CALL_PARENT(TRUE)

if(status & LIMB_DESTROYED)
if(forced)
overlays.Cut()
if(has_stump_icon && !(status & LIMB_AMPUTATED))
icon = 'icons/mob/humans/dam_human.dmi'
icon_state = "stump_[icon_name]_bone"
var/image/blood_overlay = new('icons/mob/humans/dam_human.dmi', "stump_[icon_name]_blood")
blood_overlay.color = owner.species.blood_color
overlays += blood_overlay
else
icon_state = ""
return
var/datum/ethnicity/owner_ethnicity = GLOB.ethnicities_list[owner.ethnicity]

var/race_icon = owner.species.icobase
if(owner_ethnicity)
ethnicity = owner_ethnicity.icon_name
else
ethnicity = "western"

if ((status & LIMB_ROBOT) && !(owner.species && owner.species.flags & IS_SYNTHETIC))
overlays.Cut()
icon = 'icons/mob/robotic.dmi'
icon_state = "[icon_name]"
return
var/datum/body_type/owner_body_type = GLOB.body_types_list[owner.body_type]

var/datum/ethnicity/E = GLOB.ethnicities_list[owner.ethnicity]
var/datum/body_type/B = GLOB.body_types_list[owner.body_type]
if(owner_body_type)
body_type = owner_body_type.icon_name
else
body_type = "mesomorphic"

var/e_icon
var/b_icon
if(isspeciesyautja(owner))
ethnicity = owner.ethnicity
body_type = owner.body_type

if (!E)
e_icon = "western"
else
e_icon = E.icon_name
species = owner.species
limb_gender = owner.gender

if (!B)
b_icon = "mesomorphic"
else
b_icon = B.icon_name
/// generates a list of overlays that should be applied to the owner
/obj/limb/proc/get_limb_icon()
SHOULD_CALL_PARENT(TRUE)
RETURN_TYPE(/list)

if(isspeciesyautja(owner))
e_icon = owner.ethnicity
b_icon = owner.body_type
icon_state = ""

icon = race_icon
icon_state = "[get_limb_icon_name(owner.species, b_icon, owner.gender, icon_name, e_icon)]"
wound_overlay.color = owner.species.blood_color
. = list()

var/n_is = damage_state_text()
if (forced || n_is != damage_state)
overlays.Cut()
damage_state = n_is
update_overlays()
if(parent?.status & LIMB_DESTROYED)
return

if(status & LIMB_DESTROYED)
if(has_stump_icon && !(status & LIMB_AMPUTATED))
. += image('icons/mob/humans/dam_human.dmi', "stump_[icon_name]_blood", -DAMAGE_LAYER)
return

/obj/limb/proc/update_overlays()
var/brutestate = copytext(damage_state, 1, 2)
var/burnstate = copytext(damage_state, 2)
if(brutestate != "0")
wound_overlay.icon_state = "grayscale_[brutestate]"
overlays += wound_overlay
var/image/limb = image(layer = -BODYPARTS_LAYER)

if(burnstate != "0")
burn_overlay.icon_state = "burn_[burnstate]"
overlays += burn_overlay
var/race_icon = species.icobase

if ((status & LIMB_ROBOT) && !(owner.species && owner.species.flags & IS_SYNTHETIC))
limb.icon = 'icons/mob/robotic.dmi'
limb.icon_state = "[icon_name]"
. += limb
return

limb.icon = race_icon
limb.icon_state = "[get_limb_icon_name(species, body_type, limb_gender, icon_name, ethnicity)]"

. += limb

return

/// generates a key for the purpose of caching the icon to avoid duplicate generations
/obj/limb/proc/get_limb_icon_key()
SHOULD_CALL_PARENT(TRUE)

return "[species.name]-[body_type]-[limb_gender]-[icon_name]-[ethnicity]-[status]"

// new damage icon system
// returns just the brute/burn damage code
Expand Down Expand Up @@ -774,7 +781,7 @@ This function completely restores a damaged organ to perfect condition.
//Recursive setting of self and all child organs to amputated
/obj/limb/proc/setAmputatedTree()
status |= LIMB_AMPUTATED
update_icon(TRUE)
owner.update_body()
for(var/obj/limb/O as anything in children)
O.setAmputatedTree()

Expand Down Expand Up @@ -1140,7 +1147,7 @@ treat_grafted var tells it to apply to grafted but unsalved wounds, for burn kit
for(var/obj/limb/T as anything in children)
T.robotize(uncalibrated = uncalibrated, synth_skin = synth_skin)

update_icon(TRUE)
owner.update_body(TRUE)

/obj/limb/proc/calibrate_prosthesis()
status &= ~LIMB_UNCALIBRATED_PROSTHETIC
Expand Down Expand Up @@ -1243,6 +1250,20 @@ treat_grafted var tells it to apply to grafted but unsalved wounds, for burn kit
owner.incision_depths[name] = SURGERY_DEPTH_SURFACE
owner.active_surgeries[name] = null

/obj/limb/proc/get_damage_overlays()
. = list()

damage_state = damage_state_text()
var/brutestate = copytext(damage_state, 1, 2)
if(brutestate != "0")
wound_overlay.icon_state = "grayscale_[icon_name]_[brutestate]"
. += wound_overlay

var/burnstate = copytext(damage_state, 2)
if(burnstate != "0")
burn_overlay.icon_state = "burn_[icon_name]_[burnstate]"
. += wound_overlay

/*
LIMB TYPES
*/
Expand Down Expand Up @@ -1389,17 +1410,36 @@ treat_grafted var tells it to apply to grafted but unsalved wounds, for burn kit
bandage_icon_amount = 4
var/disfigured = 0 //whether the head is disfigured.

///Specifically, damage overlays. Severed limb gore effects are applied elsewhere.
/obj/limb/head/update_overlays()
..()
var/eyes_r
var/eyes_g
var/eyes_b

var/lip_style

/obj/limb/head/update_limb()
. = ..()

eyes_r = owner.r_eyes
eyes_g = owner.g_eyes
eyes_b = owner.b_eyes

var/image/eyes = new/image('icons/mob/humans/onmob/human_face.dmi', owner.species.eyes)
lip_style = owner.lip_style

/obj/limb/head/get_limb_icon()
. = ..()

var/image/eyes = image('icons/mob/humans/onmob/human_face.dmi', species.eyes, layer = -BODYPARTS_LAYER)
eyes.color = list(null, null, null, null, rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes))
overlays += eyes
. += eyes

if(lip_style && (species && species.flags & HAS_LIPS))
var/image/lips = image('icons/mob/humans/onmob/human_face.dmi', "paint_[lip_style]", layer = -BODYPARTS_LAYER)
. += lips

/obj/limb/head/get_limb_icon_key()
. = ..()

if(owner.lip_style && (owner.species && owner.species.flags & HAS_LIPS))
var/icon/lips = new /icon('icons/mob/humans/onmob/human_face.dmi', "paint_[owner.lip_style]")
overlays += lips
return "[.]-[eyes_r]-[eyes_g]-[eyes_b]-[lip_style]"

/obj/limb/head/take_damage(brute, burn, sharp, edge, used_weapon = null,\
list/forbidden_limbs = list(), no_limb_loss,\
Expand Down
Binary file modified icons/mob/humans/dam_human.dmi
Binary file not shown.