Offset render relays for non-offsetting planes to match highest matching render plane (#84184)

## About The Pull Request

**Alternate title: "Fix blind people getting so blind they become deaf
when going down a flight of stairs"**

So 'bout half a week to a week ago I overheard a friend complaining
about blind people not seeing runechat on lower multi-z levels. Asked a
bit, apparently they'd reported this about half a year ago, and it's
still an issue.
So in my never-ending hubris I decided to just go and fix it!
Now, admittedly? I really _really_ do not get the rendering system we
use.
The simple options were right out: we can't allow the fullscreens plane
to be offset, as this causes issues with looking up/down, or disallow
runechat from being offset, which causes issues with runechat from other
levels.

After poking our very cool and smart rendering guy several times over
the course of the last week, this is what we got to:

### The technical bits

We simply make the rendering relays for non-offsetting plane masters
point to the highest rendering plane that matches the target.
We do this by offsetting the rendering relays in place, by adjusting
their plane and layer values to match the new offset, with a new
`offset_relays_in_place(new_offset)` proc called in
`/datum/plane_master_group/proc/transform_lower_turfs(...)`.
Importantly, we compare the current layer values to what they should've
been, so we don't accidentally override relays with custom-set layers.

This fixes our issue (as tested on wawastation):
<details>
  <summary>Images</summary>
  

![image](https://github.com/tgstation/tgstation/assets/42909981/c6a10e04-dd08-4642-bc4d-d99ae5004a40)

![image](https://github.com/tgstation/tgstation/assets/42909981/740dc894-7495-4c35-b729-ffcc539ca928)

![image](https://github.com/tgstation/tgstation/assets/42909981/986433a7-e66e-408a-8e77-1f1eb89cb67c)
  
</details>

## Why It's Good For The Game

Fixes #80376.
## Changelog
🆑
fix: You can see runechat above fullscreen overlays on lower multi-z
levels again. Rejoice, blind players. Please report any weird rendering
layering issues.
/🆑
This commit is contained in:
_0Steven
2024-07-11 10:05:07 +02:00
committed by GitHub
parent d3f6c15283
commit 5e753b6788
9 changed files with 75 additions and 24 deletions

View File

@@ -319,6 +319,15 @@
#define PLANE_CRITICAL_FUCKO_PARALLAX (PLANE_CRITICAL_DISPLAY|PLANE_CRITICAL_NO_RELAY|PLANE_CRITICAL_CUT_RENDER) #define PLANE_CRITICAL_FUCKO_PARALLAX (PLANE_CRITICAL_DISPLAY|PLANE_CRITICAL_NO_RELAY|PLANE_CRITICAL_CUT_RENDER)
//---------- Plane Master offsetting_flags -------------
// Describes how different plane masters behave regarding being offset
/// This plane master will not be offset itself, existing only once with an offset of 0
/// Mostly used for planes that really don't need to be duplicated, like the hud planes
#define BLOCKS_PLANE_OFFSETTING (1<<0)
/// This plane master will have its relays offset to match the highest rendering plane that matches the target
/// Required for making things like the blind fullscreen not render over runechat
#define OFFSET_RELAYS_MATCH_HIGHEST (1<<1)
/// A value of /datum/preference/numeric/multiz_performance that disables the option /// A value of /datum/preference/numeric/multiz_performance that disables the option
#define MULTIZ_PERFORMANCE_DISABLE -1 #define MULTIZ_PERFORMANCE_DISABLE -1
/// We expect at most 3 layers of multiz /// We expect at most 3 layers of multiz

View File

@@ -185,7 +185,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
for(var/group_key as anything in master_groups) for(var/group_key as anything in master_groups)
var/datum/plane_master_group/group = master_groups[group_key] var/datum/plane_master_group/group = master_groups[group_key]
group.transform_lower_turfs(src, current_plane_offset) group.build_planes_offset(src, current_plane_offset)
/datum/hud/proc/should_use_scale() /datum/hud/proc/should_use_scale()
return should_sight_scale(mymob.sight) return should_sight_scale(mymob.sight)
@@ -204,10 +204,9 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
current_plane_offset = new_offset current_plane_offset = new_offset
SEND_SIGNAL(src, COMSIG_HUD_OFFSET_CHANGED, old_offset, new_offset) SEND_SIGNAL(src, COMSIG_HUD_OFFSET_CHANGED, old_offset, new_offset)
if(should_use_scale()) for(var/group_key as anything in master_groups)
for(var/group_key as anything in master_groups) var/datum/plane_master_group/group = master_groups[group_key]
var/datum/plane_master_group/group = master_groups[group_key] group.build_planes_offset(src, new_offset)
group.transform_lower_turfs(src, new_offset)
/datum/hud/Destroy() /datum/hud/Destroy()
if(mymob.hud_used == src) if(mymob.hud_used == src)

View File

@@ -45,7 +45,7 @@
our_hud = viewing_hud our_hud = viewing_hud
our_hud.master_groups[key] = src our_hud.master_groups[key] = src
show_hud() show_hud()
transform_lower_turfs(our_hud, active_offset) build_planes_offset(our_hud, active_offset)
/// Hide the plane master from its current hud, fully clear it out /// Hide the plane master from its current hud, fully clear it out
/datum/plane_master_group/proc/orphan_hud() /datum/plane_master_group/proc/orphan_hud()
@@ -64,7 +64,7 @@
hide_hud() hide_hud()
rebuild_plane_masters() rebuild_plane_masters()
show_hud() show_hud()
transform_lower_turfs(our_hud, active_offset) build_planes_offset(our_hud, active_offset)
/// Regenerate our plane masters, this is useful if we don't have a mob but still want to rebuild. Such in the case of changing the screen_loc of relays /// Regenerate our plane masters, this is useful if we don't have a mob but still want to rebuild. Such in the case of changing the screen_loc of relays
/datum/plane_master_group/proc/rebuild_plane_masters() /datum/plane_master_group/proc/rebuild_plane_masters()
@@ -97,7 +97,7 @@
/datum/plane_master_group/proc/build_plane_masters(starting_offset, ending_offset) /datum/plane_master_group/proc/build_plane_masters(starting_offset, ending_offset)
for(var/atom/movable/screen/plane_master/mytype as anything in get_plane_types()) for(var/atom/movable/screen/plane_master/mytype as anything in get_plane_types())
for(var/plane_offset in starting_offset to ending_offset) for(var/plane_offset in starting_offset to ending_offset)
if(plane_offset != 0 && !initial(mytype.allows_offsetting)) if(plane_offset != 0 && (initial(mytype.offsetting_flags) & BLOCKS_PLANE_OFFSETTING))
continue continue
var/atom/movable/screen/plane_master/instance = new mytype(null, null, src, plane_offset) var/atom/movable/screen/plane_master/instance = new mytype(null, null, src, plane_offset)
plane_masters["[instance.plane]"] = instance plane_masters["[instance.plane]"] = instance
@@ -110,7 +110,7 @@
// It would be nice to setup parallaxing for stairs and things when doing this // It would be nice to setup parallaxing for stairs and things when doing this
// So they look nicer. if you can't it's all good, if you think you can sanely look at monster's work // So they look nicer. if you can't it's all good, if you think you can sanely look at monster's work
// It's hard, and potentially expensive. be careful // It's hard, and potentially expensive. be careful
/datum/plane_master_group/proc/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE) /datum/plane_master_group/proc/build_planes_offset(datum/hud/source, new_offset, use_scale = TRUE)
// Check if this feature is disabled for the client, in which case don't use scale. // Check if this feature is disabled for the client, in which case don't use scale.
var/mob/our_mob = our_hud?.mymob var/mob/our_mob = our_hud?.mymob
if(!our_mob?.client?.prefs?.read_preference(/datum/preference/toggle/multiz_parallax)) if(!our_mob?.client?.prefs?.read_preference(/datum/preference/toggle/multiz_parallax))
@@ -158,7 +158,11 @@
for(var/plane_key in plane_masters) for(var/plane_key in plane_masters)
var/atom/movable/screen/plane_master/plane = plane_masters[plane_key] var/atom/movable/screen/plane_master/plane = plane_masters[plane_key]
if(!plane.allows_offsetting) if(plane.offsetting_flags & BLOCKS_PLANE_OFFSETTING)
if(plane.offsetting_flags & OFFSET_RELAYS_MATCH_HIGHEST)
// Don't offset the plane, do offset where the relays point
// Required for making things like the blind fullscreen not render over runechat
plane.offset_relays_in_place(new_offset)
continue continue
var/visual_offset = plane.offset - new_offset var/visual_offset = plane.offset - new_offset
@@ -199,13 +203,13 @@
#undef MAX_CLIENT_BUILD_WITH_WORKING_SECONDARY_MAPS #undef MAX_CLIENT_BUILD_WITH_WORKING_SECONDARY_MAPS
/datum/plane_master_group/popup/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE) /datum/plane_master_group/popup/build_planes_offset(datum/hud/source, new_offset, use_scale = TRUE)
return ..(source, new_offset, FALSE) return ..(source, new_offset, FALSE)
/// Holds the main plane master /// Holds the main plane master
/datum/plane_master_group/main /datum/plane_master_group/main
/datum/plane_master_group/main/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE) /datum/plane_master_group/main/build_planes_offset(datum/hud/source, new_offset, use_scale = TRUE)
if(use_scale) if(use_scale)
return ..(source, new_offset, source.should_use_scale()) return ..(source, new_offset, source.should_use_scale())
return ..() return ..()

View File

@@ -20,9 +20,9 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master)
/// The plane master group we're a member of, our "home" /// The plane master group we're a member of, our "home"
var/datum/plane_master_group/home var/datum/plane_master_group/home
/// If our plane master allows for offsetting /// If our plane master has different offsetting logic
/// Mostly used for planes that really don't need to be duplicated, like the hud planes /// Possible flags are defined in [_DEFINES/layers.dm]
var/allows_offsetting = TRUE var/offsetting_flags = NONE
/// Our offset from our "true" plane, see below /// Our offset from our "true" plane, see below
var/offset var/offset
/// When rendering multiz, lower levels get their own set of plane masters /// When rendering multiz, lower levels get their own set of plane masters

View File

@@ -7,7 +7,7 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT mouse_opacity = MOUSE_OPACITY_TRANSPARENT
render_relay_planes = list() render_relay_planes = list()
// We do NOT allow offsetting, because there's no case where you would want to block only one layer, at least currently // We do NOT allow offsetting, because there's no case where you would want to block only one layer, at least currently
allows_offsetting = FALSE offsetting_flags = BLOCKS_PLANE_OFFSETTING
// We mark as multiz_scaled FALSE so transforms don't effect us, and we draw to the planes below us as if they were us. // We mark as multiz_scaled FALSE so transforms don't effect us, and we draw to the planes below us as if they were us.
// This is safe because we will ALWAYS be on the top z layer, so it DON'T MATTER // This is safe because we will ALWAYS be on the top z layer, so it DON'T MATTER
multiz_scaled = FALSE multiz_scaled = FALSE
@@ -368,7 +368,7 @@
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
render_relay_planes = list(RENDER_PLANE_NON_GAME) render_relay_planes = list(RENDER_PLANE_NON_GAME)
mouse_opacity = MOUSE_OPACITY_TRANSPARENT mouse_opacity = MOUSE_OPACITY_TRANSPARENT
allows_offsetting = FALSE offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST
/atom/movable/screen/plane_master/runechat /atom/movable/screen/plane_master/runechat
name = "Runechat" name = "Runechat"
@@ -397,7 +397,7 @@
plane = HUD_PLANE plane = HUD_PLANE
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
render_relay_planes = list(RENDER_PLANE_NON_GAME) render_relay_planes = list(RENDER_PLANE_NON_GAME)
allows_offsetting = FALSE offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST
/atom/movable/screen/plane_master/above_hud /atom/movable/screen/plane_master/above_hud
name = "Above HUD" name = "Above HUD"
@@ -405,7 +405,7 @@
plane = ABOVE_HUD_PLANE plane = ABOVE_HUD_PLANE
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
render_relay_planes = list(RENDER_PLANE_NON_GAME) render_relay_planes = list(RENDER_PLANE_NON_GAME)
allows_offsetting = FALSE offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST
/atom/movable/screen/plane_master/splashscreen /atom/movable/screen/plane_master/splashscreen
name = "Splashscreen" name = "Splashscreen"
@@ -413,7 +413,7 @@
plane = SPLASHSCREEN_PLANE plane = SPLASHSCREEN_PLANE
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
render_relay_planes = list(RENDER_PLANE_NON_GAME) render_relay_planes = list(RENDER_PLANE_NON_GAME)
allows_offsetting = FALSE offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST
/atom/movable/screen/plane_master/escape_menu /atom/movable/screen/plane_master/escape_menu
name = "Escape Menu" name = "Escape Menu"
@@ -421,4 +421,4 @@
plane = ESCAPE_MENU_PLANE plane = ESCAPE_MENU_PLANE
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
render_relay_planes = list(RENDER_PLANE_MASTER) render_relay_planes = list(RENDER_PLANE_MASTER)
allows_offsetting = FALSE offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST

View File

@@ -457,6 +457,8 @@
// That's what this is for // That's what this is for
if(show_to) if(show_to)
show_to.screen += relay show_to.screen += relay
if(offsetting_flags & OFFSET_RELAYS_MATCH_HIGHEST && home.our_hud)
offset_relay(relay, home.our_hud.current_plane_offset)
return relay return relay
/// Breaks a connection between this plane master, and the passed in place /// Breaks a connection between this plane master, and the passed in place
@@ -479,3 +481,40 @@
return relay return relay
return null return null
/**
* Offsets our relays in place using the given parameter by adjusting their plane and
* layer values, avoiding changing the layer for relays with custom-set layers.
*
* Used in [proc/build_planes_offset] to make the relays for non-offsetting planes
* match the highest rendering plane that matches the target, to avoid them rendering
* on the highest level above things that should be visible.
*
* Parameters:
* - new_offset: the offset we will adjust our relays to
*/
/atom/movable/screen/plane_master/proc/offset_relays_in_place(new_offset)
for(var/atom/movable/render_plane_relay/rpr in relays)
offset_relay(rpr, new_offset)
/**
* Offsets a given render relay using the given parameter by adjusting its plane and
* layer values, avoiding changing the layer if it has a custom-set layer.
*
* Parameters:
* - rpr: the render plane relay we will offset
* - new_offset: the offset we will adjust it by
*/
/atom/movable/screen/plane_master/proc/offset_relay(atom/movable/render_plane_relay/rpr, new_offset)
var/base_relay_plane = PLANE_TO_TRUE(rpr.plane)
var/old_offset = PLANE_TO_OFFSET(rpr.plane)
rpr.plane = GET_NEW_PLANE(base_relay_plane, new_offset)
var/old_offset_plane = real_plane - (PLANE_RANGE * old_offset)
var/old_layer = (old_offset_plane + abs(LOWEST_EVER_PLANE * 30))
if(rpr.layer != old_layer) // Avoid overriding custom-set layers
return
var/offset_plane = real_plane - (PLANE_RANGE * new_offset)
var/new_layer = (offset_plane + abs(LOWEST_EVER_PLANE * 30))
rpr.layer = new_layer

View File

@@ -890,7 +890,7 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away
var/offset_plane = GET_NEW_PLANE(plane_to_use, plane_offset) var/offset_plane = GET_NEW_PLANE(plane_to_use, plane_offset)
var/string_plane = "[offset_plane]" var/string_plane = "[offset_plane]"
if(!initial(master_type.allows_offsetting)) if(initial(master_type.offsetting_flags) & BLOCKS_PLANE_OFFSETTING)
plane_offset_blacklist[string_plane] = TRUE plane_offset_blacklist[string_plane] = TRUE
var/render_target = initial(master_type.render_target) var/render_target = initial(master_type.render_target)
if(!render_target) if(!render_target)

View File

@@ -13,4 +13,4 @@
for(var/group_key as anything in my_hud.master_groups) for(var/group_key as anything in my_hud.master_groups)
var/datum/plane_master_group/group = my_hud.master_groups[group_key] var/datum/plane_master_group/group = my_hud.master_groups[group_key]
group.transform_lower_turfs(my_hud, my_hud.current_plane_offset) group.build_planes_offset(my_hud, my_hud.current_plane_offset)

View File

@@ -18,4 +18,4 @@
for(var/group_key as anything in my_hud.master_groups) for(var/group_key as anything in my_hud.master_groups)
var/datum/plane_master_group/group = my_hud.master_groups[group_key] var/datum/plane_master_group/group = my_hud.master_groups[group_key]
group.transform_lower_turfs(my_hud, my_hud.current_plane_offset) group.build_planes_offset(my_hud, my_hud.current_plane_offset)