Skip to content

Commit

Permalink
Revert "Glide size is now determined by cpu usage. (Monkestation#4146)…
Browse files Browse the repository at this point in the history
…" (Monkestation#4820)

This reverts commit f610110.
  • Loading branch information
dwasint authored Jan 12, 2025
1 parent c861bd5 commit 5b2d74f
Show file tree
Hide file tree
Showing 14 changed files with 28 additions and 320 deletions.
6 changes: 1 addition & 5 deletions code/__DEFINES/movement.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,14 @@

/// Compensating for time dilation
GLOBAL_VAR_INIT(glide_size_multiplier, 1.0)
/// The error motivating our existing multiplier
GLOBAL_VAR_INIT(glide_size_multi_error, 0)

///Broken down, here's what this does:
/// divides the world icon_size (32) by delay divided by ticklag to get the number of pixels something should be moving each tick.
/// The division result is given a min value of 1 to prevent obscenely slow glide sizes from being set
/// Then that's multiplied by the global glide size multiplier. 1.25 by default feels pretty close to spot on. This is just to try to get byond to behave.
/// The whole result is then clamped to within the range above.
/// Not very readable but it works
#define DELAY_TO_GLIDE_SIZE(delay) DISTANCE_BOUND_DELAY_TO_GLIDE_SIZE(world.icon_size, delay)

#define DISTANCE_BOUND_DELAY_TO_GLIDE_SIZE(distance, delay) (clamp((((distance) / max((delay) / world.tick_lag, 1)) * GLOB.glide_size_multiplier), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE))
#define DELAY_TO_GLIDE_SIZE(delay) (clamp(((world.icon_size / max((delay) / world.tick_lag, 1)) * GLOB.glide_size_multiplier), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE))

///Similar to DELAY_TO_GLIDE_SIZE, except without the clamping, and it supports piping in an unrelated scalar
#define MOVEMENT_ADJUSTED_GLIDE_SIZE(delay, movement_disparity) (world.icon_size / ((delay) / world.tick_lag) * movement_disparity * GLOB.glide_size_multiplier)
Expand Down
2 changes: 1 addition & 1 deletion code/__DEFINES/perf_test.dm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// Macro that takes a tick usage to target, and proceses until we hit it
/// This lets us simulate generic load as we'd like, to make testing for overtime easier
#define CONSUME_UNTIL(target_usage) \
while(TICK_USAGE < (target_usage)) {\
while(TICK_USAGE < target_usage) {\
var/_knockonwood_x = 0;\
_knockonwood_x += 20;\
}
Expand Down
94 changes: 0 additions & 94 deletions code/controllers/master.dm
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ GLOBAL_REAL(Master, /datum/controller/master)
///used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits
var/static/current_ticklimit = TICK_LIMIT_RUNNING

var/spike_cpu = 0
var/sustain_chance = 100
var/sustain_cpu = 0

/datum/controller/master/New()
// Ensure usr is null, to prevent any potential weirdness resulting from the MC having a usr if it's manually restarted.
usr = null
Expand Down Expand Up @@ -467,8 +463,6 @@ GLOBAL_REAL(Master, /datum/controller/master)
tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag)))
var/starting_tick_usage = TICK_USAGE

update_glide_size()

if (init_stage != init_stage_completed)
return MC_LOOP_RTN_NEWSTAGES
if (processing <= 0)
Expand Down Expand Up @@ -833,91 +827,3 @@ GLOBAL_REAL(Master, /datum/controller/master)
for (var/thing in subsystems)
var/datum/controller/subsystem/SS = thing
SS.OnConfigLoad()

/world/Tick()
unroll_cpu_value()
if(Master.sustain_cpu && prob(Master.sustain_chance))
// avoids byond sleeping the loop and causing the MC to infinistall
CONSUME_UNTIL(min(Master.sustain_cpu, 10000))

if(Master.spike_cpu)
CONSUME_UNTIL(min(Master.spike_cpu, 10000))
Master.spike_cpu = 0


#define CPU_SIZE 20
#define WINDOW_SIZE 16
GLOBAL_LIST_INIT(cpu_values, new /list(CPU_SIZE))
GLOBAL_LIST_INIT(avg_cpu_values, new /list(CPU_SIZE))
GLOBAL_VAR_INIT(cpu_index, 1)
GLOBAL_VAR_INIT(last_cpu_update, -1)

/// Inserts our current world.cpu value into our rolling lists
/// Its job is to pull the actual usage last tick instead of the moving average
/world/proc/unroll_cpu_value()
if(GLOB.last_cpu_update == world.time)
return
GLOB.last_cpu_update = world.time
var/avg_cpu = world.cpu
var/list/cpu_values = GLOB.cpu_values
var/cpu_index = GLOB.cpu_index

// We need to hook into the INSTANT we start our moving average so we can reconstruct gained/lost cpu values
var/lost_value = 0
lost_value = cpu_values[WRAP(cpu_index - WINDOW_SIZE, 1, CPU_SIZE + 1)]

// avg = (A + B + C + D) / 4
// old_avg = (A + B + C) / 3
// (avg * 4 - old_avg * 3) roughly = D
// avg = (B + C + D) / 3
// old_avg = (A + B + C) / 3
// (avg * 4 - old_avg * 3) roughly = D - A
// so if we aren't moving we need to add the value we are losing
// We're trying to do this with as few ops as possible mind
// soooo
// C = (avg * 3 - old_avg * 3) + A

var/last_avg_cpu = GLOB.avg_cpu_values[WRAP(cpu_index - 1, 1, CPU_SIZE + 1)]
var/real_cpu = (avg_cpu *WINDOW_SIZE - last_avg_cpu * WINDOW_SIZE) + lost_value

// cache for sonic speed
cpu_values[cpu_index] = real_cpu
GLOB.avg_cpu_values[cpu_index] = avg_cpu
GLOB.cpu_index = WRAP(cpu_index + 1, 1, CPU_SIZE + 1)


/proc/update_glide_size()
world.unroll_cpu_value()
var/list/cpu_values = GLOB.cpu_values
var/sum = 0
var/non_zero = 0
for(var/value in cpu_values)
sum += max(value, 100)
if(value != 0)
non_zero += 1

var/first_average = non_zero ? sum / non_zero : 1
var/trimmed_sum = 0
var/used = 0
for(var/value in cpu_values)
if(!value)
continue
// If we deviate more then 60% away from the average, skip it
if(abs(1 - (max(value, 100) / first_average)) <= 0.3)
trimmed_sum += max(value, 100)
used += 1

var/final_average = trimmed_sum ? trimmed_sum / used : first_average
GLOB.glide_size_multiplier = min(100 / final_average, 1)
GLOB.glide_size_multi_error = max((final_average - 100) / 100 * world.tick_lag, 0)

/// Gets the cpu value we finished the last tick with (since the index reads a step ahead)
var/last_cpu = cpu_values[WRAP(GLOB.cpu_index - 1, 1, CPU_SIZE + 1)]
var/error = max((last_cpu - 100) / 100 * world.tick_lag, 0)

for(var/atom/movable/trouble as anything in GLOB.gliding_atoms)
if(world.time >= trouble.glide_stopping_time || QDELETED(trouble))
GLOB.gliding_atoms -= trouble
trouble.glide_tracking = FALSE
continue
trouble.account_for_glide_error(error)
7 changes: 2 additions & 5 deletions code/controllers/subsystem.dm
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@

//Do not blindly add vars here to the bottom, put it where it goes above
//If your var only has two values, put it in as a flag.
var/consume_most_allocation = FALSE


//Do not override
///datum/controller/subsystem/New()
Expand All @@ -133,10 +133,7 @@
tick_allocation_avg = MC_AVERAGE(tick_allocation_avg, tick_allocation_last)

. = SS_SLEEPING
if(consume_most_allocation)
CONSUME_UNTIL(Master.current_ticklimit * 0.8)
else
fire(resumed)
fire(resumed)
. = state
if (state == SS_SLEEPING)
slept_count++
Expand Down
3 changes: 0 additions & 3 deletions code/controllers/subsystem/input.dm
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ VERB_MANAGER_SUBSYSTEM_DEF(input)
///running average of the amount of real time clicks take to truly execute after the command is originally sent to the server.
///if a click isnt delayed at all then it counts as 0 deciseconds.
var/average_click_delay = 0
var/list/moving_mobs = list()

/datum/controller/subsystem/verb_manager/input/Initialize()
setup_default_macro_sets()
Expand Down Expand Up @@ -72,8 +71,6 @@ VERB_MANAGER_SUBSYSTEM_DEF(input)
var/moves_this_run = 0
for(var/mob/user in GLOB.keyloop_list)
moves_this_run += user.focus?.keyLoop(user.client)//only increments if a player moves due to their own input
for(var/mob/moving in SSinput.moving_mobs)
moves_this_run += moving.keyLoop(gondor_calls_for_aid = TRUE)

movements_per_second = MC_AVG_SECONDS(movements_per_second, moves_this_run, wait TICKS)

Expand Down
1 change: 1 addition & 0 deletions code/controllers/subsystem/time_track.dm
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ SUBSYSTEM_DEF(time_track)
time_dilation_avg_fast = MC_AVERAGE_FAST(time_dilation_avg_fast, time_dilation_current)
time_dilation_avg = MC_AVERAGE(time_dilation_avg, time_dilation_avg_fast)
time_dilation_avg_slow = MC_AVERAGE_SLOW(time_dilation_avg_slow, time_dilation_avg)
GLOB.glide_size_multiplier = (current_byondtime - last_tick_byond_time) / (current_realtime - last_tick_realtime)
else
first_run = FALSE
last_tick_realtime = current_realtime
Expand Down
2 changes: 1 addition & 1 deletion code/datums/components/scope.dm
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
stop_zooming(user_mob)
return
tracker.calculate_params()
if(!user_client.intended_direction)
if(!length(user_client.keys_held & user_client.movement_keys))
user_mob.face_atom(tracker.given_turf)
animate(user_client, world.tick_lag, pixel_x = tracker.given_x, pixel_y = tracker.given_y)

Expand Down
71 changes: 5 additions & 66 deletions code/game/atoms_movable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -119,23 +119,6 @@
///can we grab this object?
var/cant_grab = FALSE

/// The world.time we started our last glide
var/last_glide_start = 0
/// The ammount of unaccounted accumulated error between our glide visuals and the world tickrate
var/accumulated_glide_error = 0
/// The amount of banked (accounted for) error between our visual and world glide rates
var/banked_glide_error = 0
/// The amount of error accounted for in the initial delay of our glide (based off GLOB.glide_size_multiplier)
var/built_in_glide_error = 0
/// The world.time at which we assume our next glide will end
var/glide_stopping_time = 0
/// We are currently tracking our glide animation
var/glide_tracking = FALSE
/// If we should use glide correction
var/use_correction = FALSE
var/mutable_appearance/glide_text
var/debug_glide = FALSE

/mutable_appearance/emissive_blocker

/mutable_appearance/emissive_blocker/New()
Expand Down Expand Up @@ -606,59 +589,15 @@
if(!only_pulling && pulledby && moving_diagonally != FIRST_DIAG_STEP && (get_dist(src, pulledby) > 1 || z != pulledby.z)) //separated from our puller and not in the middle of a diagonal move.
pulledby.stop_pulling()

GLOBAL_LIST_EMPTY(gliding_atoms)

/atom/movable/proc/set_glide_size(target = 8, mid_move = FALSE)
/atom/movable/proc/set_glide_size(target = 8, recursed = FALSE)
if (HAS_TRAIT(src, TRAIT_NO_GLIDE))
return
SEND_SIGNAL(src, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, target)
glide_size = target
// If we're mid move don't reset ourselves yeah?
if(!mid_move || !glide_tracking)
last_glide_start = world.time
glide_stopping_time = world.time + (world.icon_size / target) * world.tick_lag
accumulated_glide_error = 0
banked_glide_error = 0
built_in_glide_error = GLOB.glide_size_multi_error
update_glide_text()
if(!glide_tracking && use_correction)
GLOB.gliding_atoms += src
glide_tracking = TRUE

for(var/mob/buckled_mob as anything in buckled_mobs)
buckled_mob.set_glide_size(target, mid_move = mid_move)

/atom/movable/proc/update_glide_text()
if(!debug_glide)
return
cut_overlay(glide_text)
glide_text = mutable_appearance(offset_spokesman = src, plane = ABOVE_LIGHTING_PLANE)
glide_text.maptext = "GS: [glide_size]ppt\nMulti: [GLOB.glide_size_multiplier * 100]% \nBIE: [built_in_glide_error]ds \nErr: [accumulated_glide_error]ds"
glide_text.maptext_width = 500
glide_text.maptext_height = 500
glide_text.maptext_y = 32
add_overlay(glide_text)

/atom/movable/proc/account_for_glide_error(error)
// Intentionally can go negative to handle being overoptimistic about glide rates
accumulated_glide_error += error - built_in_glide_error
if(abs(accumulated_glide_error) < world.tick_lag * 0.5)
update_glide_text()
return
// we're trying to account for random spikes in error while gliding
// So we're gonna use the known GAME tick we want to stop at,
// alongside how much time has visually past to work out
// exactly how fast we need to move to make up that distance
var/game_time_spent = (world.time - last_glide_start)
var/visual_time_spent = game_time_spent + accumulated_glide_error + built_in_glide_error * game_time_spent
var/distance_covered = glide_size * visual_time_spent
var/distance_remaining = world.icon_size - distance_covered
var/game_time_remaining = (glide_stopping_time - world.time)
built_in_glide_error += accumulated_glide_error / game_time_remaining
accumulated_glide_error = 0
set_glide_size(clamp((((distance_remaining) / max((game_time_remaining) / world.tick_lag, 1))), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE), mid_move = TRUE)

update_glide_text()

if(!recursed)
for(var/mob/buckled_mob as anything in buckled_mobs)
buckled_mob.set_glide_size(target, TRUE)

/**
* meant for movement with zero side effects. only use for objects that are supposed to move "invisibly" (like camera mobs or ghosts)
Expand Down
3 changes: 0 additions & 3 deletions code/modules/client/client_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,6 @@
var/list/keys_held = list()
/// A buffer for combinations such of modifiers + keys (ex: CtrlD, AltE, ShiftT). Format: `"key"` -> `"combo"` (ex: `"D"` -> `"CtrlD"`)
var/list/key_combos_held = list()
a/// The direction we WANT to move, based off our keybinds
/// Will be udpated to be the actual direction later on
var/intended_direction = NONE
/*
** These next two vars are to apply movement for keypresses and releases made while move delayed.
** Because discarding that input makes the game less responsive.
Expand Down
1 change: 0 additions & 1 deletion code/modules/client/client_procs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1184,7 +1184,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
winset(src, "default-[REF(key)]", "parent=default;name=[key];command=[msay]")
else
winset(src, "default-[REF(key)]", "parent=default;name=[key];command=")
calculate_move_dir()

/client/proc/change_view(new_size)
if (isnull(new_size))
Expand Down
40 changes: 11 additions & 29 deletions code/modules/keybindings/bindings_atom.dm
Original file line number Diff line number Diff line change
@@ -1,46 +1,28 @@
// You might be wondering why this isn't client level. If focus is null, we don't want you to move.
// Only way to do that is to tie the behavior into the focus's keyLoop().

/atom/movable/keyLoop(client/user, gondor_calls_for_aid = FALSE)
// Clients don't go null randomly. They do go null unexpectedly though, when they're poked in particular ways
// keyLoop is called by a for loop over mobs. We're guarenteed that all the mobs have clients at the START
// But the move of one mob might poke the client of another, so we do this
if(gondor_calls_for_aid)
user = src
if(!user)
return FALSE
var/movement_dir = user.intended_direction | user.next_move_dir_add
// If we're not movin anywhere, we aren't movin anywhere
// Safe because nothing adds to movement_dir after this moment
if(!movement_dir)
return FALSE
if(user.next_move_dir_sub)
/atom/movable/keyLoop(client/user)
var/movement_dir = NONE
for(var/_key in user?.keys_held)
movement_dir = movement_dir | user.movement_keys[_key]
if(user?.next_move_dir_add)
movement_dir |= user.next_move_dir_add
if(user?.next_move_dir_sub)
movement_dir &= ~user.next_move_dir_sub
// Sanity checks in case you hold left and right and up to make sure you only go up
if((movement_dir & NORTH) && (movement_dir & SOUTH))
movement_dir &= ~(NORTH|SOUTH)
if((movement_dir & EAST) && (movement_dir & WEST))
movement_dir &= ~(EAST|WEST)

if(!gondor_calls_for_aid && user.dir != NORTH && movement_dir) //If we're not moving, don't compensate, as byond will auto-fill dir otherwise
if(user && movement_dir) //If we're not moving, don't compensate, as byond will auto-fill dir otherwise
movement_dir = turn(movement_dir, -dir2angle(user.dir)) //By doing this we ensure that our input direction is offset by the client (camera) direction

//turn without moving while using the movement lock key, unless something wants to ignore it and move anyway
if(user.movement_locked && !(SEND_SIGNAL(src, COMSIG_MOVABLE_KEYBIND_FACE_DIR, movement_dir) & COMSIG_IGNORE_MOVEMENT_LOCK))
if(user?.movement_locked && !(SEND_SIGNAL(src, COMSIG_MOVABLE_KEYBIND_FACE_DIR, movement_dir) & COMSIG_IGNORE_MOVEMENT_LOCK))
keybind_face_direction(movement_dir)
else if(gondor_calls_for_aid)
var/mob/mob_src = src
mob_src.bullshit_hell(get_step(src, movement_dir), movement_dir)
return !!movement_dir
// Null check cause of the signal above
else if(user)
user.Move(get_step(src, movement_dir), movement_dir)
else
user?.Move(get_step(src, movement_dir), movement_dir)
return !!movement_dir //true if there was actually any player input

return FALSE

/client/proc/calculate_move_dir()
var/movement_dir = NONE
for(var/_key in keys_held)
movement_dir |= movement_keys[_key]
intended_direction = movement_dir
14 changes: 6 additions & 8 deletions code/modules/keybindings/bindings_client.dm
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,9 @@

//the time a key was pressed isn't actually used anywhere (as of 2019-9-10) but this allows easier access usage/checking
keys_held[_key] = world.time
var/movement = movement_keys[_key]
if(movement)
calculate_move_dir()
if(!movement_locked && !(next_move_dir_sub & movement))
if(!movement_locked)
var/movement = movement_keys[_key]
if(!(next_move_dir_sub & movement))
next_move_dir_add |= movement

// Client-level keybindings are ones anyone should be able to do at any time
Expand Down Expand Up @@ -95,10 +94,9 @@

keys_held -= _key

var/movement = movement_keys[_key]
if(movement)
calculate_move_dir()
if(!movement_locked && !(next_move_dir_add & movement))
if(!movement_locked)
var/movement = movement_keys[_key]
if(!(next_move_dir_add & movement))
next_move_dir_sub |= movement

// We don't do full key for release, because for mod keys you
Expand Down
1 change: 0 additions & 1 deletion code/modules/mob/mob_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
see_in_dark = 1e6
// A list of factions that this mob is currently in, for hostile mob targeting, amongst other things
faction = list(FACTION_NEUTRAL)
use_correction = TRUE
/// The current client inhabiting this mob. Managed by login/logout
/// This exists so we can do cleanup in logout for occasions where a client was transfere rather then destroyed
/// We need to do this because the mob on logout never actually has a reference to client
Expand Down
Loading

0 comments on commit 5b2d74f

Please sign in to comment.