mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 10:11:09 +00:00
* Ventcrawling improvements, performance and visual (#66709) * Initial pipecrawl work Ok so pipecrawl images were updating EVERY TIME YOU MOVED This was not good mojo What I've done here is twofold First, I ensured pipecrawl updates only when the net changes. This breaks the current implementation, but I intend on fixing that Second, I moved our method of getting pipes to the spatial grid This isn't that great at the moment, but I intend on adding support for tracking entered/exited cells, which should make this much better * Much faster pipecrawling processing, niceties Adds a concept called a cell tracker datum. It manages a list of cells a passed in bound is "inside", and when queried will return a list of new cells, and old cells. Because we only really care about maintaining an absolute window of "CELLS WE ARE IN" and less about always removing cells we're not in, we can manage a second window to prevent moving up and down on a cell line causing a ton of updates. Uses this concept to optimize pipecrawling significantly, from 3ms per call before to roughly 0.03ms per call. Also moves pipecrawl images to their own plane, so they don't overlap ui elements * Pipecrawling effects niceties, direction help You can now move in more then one direction when pipecrawling This works as expected, if you hold up and left, move up for a while, and come to a fork, you'll go left Added some effects to pipecrawling. It'll darken the lighting plane slightly, so you get a nice effect instead of just fullbright. Also added a color matrix and drop shadow to the pipe images, this way they stand out a bit more. You now glide between pipe moves, rather then moving instantly. This doesn't effect your actual move rate, but it no longer feels jittery with say, 60fps * Bounds * Fixes runtimes, cache something somethign sonic speed * Reworks how being interested in the spatial grid is tracked Rather then checking multiple variables on the atom to consider, we instead check for the existence of a string key. This key is used by a list on the spatial grid subsystem to retrive a cached list of all of the atoms "types" Doing this requires doing a bit of extra work in important_recursive_contents code, but it allows us to separate being a part of the spatial grid from using important recursive contents, which is very nice. As a consequence, I've had to unroll some lazylist macros in important recursive contents logic. It's not ""that"" bad but it's not great either. Oh and this adds a slight cost to enter/exit cell, but it's minimal. Basically, rather then checking for different features of a grid member, we just iterate the list their string key points to. Very handy So there's an added cost of a list copy and all, but we save the headache of more types technically increasing the cost of addition/removal. I also made adding/removing from the grid into one "pulbic" proc rather then two different ones for each operation, because it was starting to get silly * waaa waa it doesn't compile * chord -> coord * Ensures important_recursive_contents is actually emptied on removal * Removes soul * Kyler's review Co-authored-by: Kylerace <kylerlumpkin1@ gmail.com> * Kyler's review 2 Co-authored-by: Kylerace <kylerlumpkin1@ gmail.com> * Kyler's review 3 Moves some procs around, improves some documentation, catches a few small issues Co-authored-by: Kylerace <kylerlumpkin1@ gmail.com> * Ventcrawling improvements, performance and visual Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: Kylerace <kylerlumpkin1@ gmail.com>
100 lines
4.7 KiB
Plaintext
100 lines
4.7 KiB
Plaintext
/**
|
|
* Spatial gridmap, cell tracking
|
|
*
|
|
* This datum exists to make the large, repeated "everything in some range" pattern faster
|
|
* Rather then just refreshing against everything, we track all the cells in range of the passed in "window"
|
|
* This lets us do entered/left logic, and make ordinarially quite expensive logic much cheaper
|
|
*
|
|
* Note: This system should not be used for things who have strict requirements about what is NOT in their processed entries
|
|
* It should instead only be used for logic that only really cares about limiting how much gets "entered" in any one call
|
|
* Because we apply this limitation, we can do things to make our code much less prone to unneeded work
|
|
*/
|
|
/datum/cell_tracker
|
|
var/list/datum/spatial_grid_cell/member_cells = list()
|
|
// Inner window
|
|
// If a cell is inside this space, it will be entered into our membership list
|
|
/// The height (y radius) of our inner window
|
|
var/inner_window_x_radius
|
|
/// The width (x radius) of our inner window
|
|
var/inner_window_y_radius
|
|
|
|
// Outer window
|
|
// If a cell is outside this space, it will be removed from our memebership list
|
|
// This effectively applies a grace window, to prevent moving back and forth across a border line causing issues
|
|
/// The height (y radius) of our outer window
|
|
var/outer_window_x_radius
|
|
/// The width (x radius) of our outer window
|
|
var/outer_window_y_radius
|
|
|
|
/// Accepts a width and height to use for this tracker
|
|
/// Also accepts the ratio to use between inner and outer window. Optional, defaults to 2
|
|
/datum/cell_tracker/New(width, height, inner_outer_ratio)
|
|
set_bounds(width, height, inner_outer_ratio)
|
|
return ..()
|
|
|
|
/datum/cell_tracker/Destroy(force)
|
|
stack_trace("Attempted to delete a cell tracker. They don't hold any refs outside of cells, what are you doing")
|
|
if(!force)
|
|
return QDEL_HINT_LETMELIVE
|
|
member_cells.Cut()
|
|
return ..()
|
|
|
|
/// Takes a width and height, and uses them to set the inner window, and interpolate the outer window
|
|
/datum/cell_tracker/proc/set_bounds(width = 0, height = 0, ratio = 2)
|
|
// We want to store these as radii, rather then width and height, since that's convineient for spatial grid code
|
|
var/x_radius = CEILING(width, 2)
|
|
var/y_radius = CEILING(height, 2)
|
|
inner_window_x_radius = x_radius
|
|
inner_window_y_radius = y_radius
|
|
|
|
outer_window_x_radius = x_radius * ratio
|
|
outer_window_y_radius = y_radius * ratio
|
|
|
|
/// Returns a list of newly and formerly joined spatial grid managed objects of type [type] in the form list(new, old)
|
|
/// Takes the center of our window as input
|
|
/datum/cell_tracker/proc/recalculate_type_members(turf/center, type)
|
|
var/list/new_and_old = recalculate_cells(center)
|
|
|
|
var/list/new_members = list()
|
|
var/list/former_members = list()
|
|
/// Pull out all the new and old memebers we want
|
|
switch(type)
|
|
if(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS)
|
|
for(var/datum/spatial_grid_cell/cell as anything in new_and_old[1])
|
|
new_members += cell.client_contents
|
|
for(var/datum/spatial_grid_cell/cell as anything in new_and_old[2])
|
|
former_members += cell.client_contents
|
|
if(SPATIAL_GRID_CONTENTS_TYPE_HEARING)
|
|
for(var/datum/spatial_grid_cell/cell as anything in new_and_old[1])
|
|
new_members += cell.hearing_contents
|
|
for(var/datum/spatial_grid_cell/cell as anything in new_and_old[2])
|
|
former_members += cell.hearing_contents
|
|
if(SPATIAL_GRID_CONTENTS_TYPE_ATMOS)
|
|
for(var/datum/spatial_grid_cell/cell as anything in new_and_old[1])
|
|
new_members += cell.atmos_contents
|
|
for(var/datum/spatial_grid_cell/cell as anything in new_and_old[2])
|
|
former_members += cell.atmos_contents
|
|
|
|
return list(new_members, former_members)
|
|
|
|
/// Recalculates our member list, returns a list in the form list(new members, old members) for reaction
|
|
/// Accepts the turf to use as our "center"
|
|
/datum/cell_tracker/proc/recalculate_cells(turf/center)
|
|
if(!center)
|
|
CRASH("/datum/cell_tracker had an invalid location on refresh, ya done fucked")
|
|
// This is a mild waste of cpu time. Consider optimizing by adding a new helper function to get just the space between two bounds
|
|
// Assuming it ever becomes a real problem
|
|
var/list/datum/spatial_grid_cell/inner_window = SSspatial_grid.get_cells_in_bounds(center, inner_window_x_radius, inner_window_y_radius)
|
|
var/list/datum/spatial_grid_cell/outer_window = SSspatial_grid.get_cells_in_bounds(center, outer_window_x_radius, outer_window_y_radius)
|
|
|
|
var/list/datum/spatial_grid_cell/new_cells = inner_window - member_cells
|
|
// The outer window may contain cells we don't actually have, so we do it like this
|
|
var/list/datum/spatial_grid_cell/old_cells = member_cells - outer_window
|
|
|
|
// This whole thing is a naive implementation,
|
|
// if it turns out to be expensive because of all the list operations I'll look closer at it
|
|
member_cells -= old_cells
|
|
member_cells += new_cells
|
|
|
|
return list(new_cells, old_cells)
|