diff --git a/aurorastation.dme b/aurorastation.dme index 6225f16ea0b..ad9aa7c3731 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -140,7 +140,9 @@ #include "code\__DEFINES\dcs\signals\signals_spatial_grid.dm" #include "code\__DEFINES\dcs\signals\signals_subsystem.dm" #include "code\__DEFINES\dcs\signals\signals_atom\signals_atom_main.dm" +#include "code\__DEFINES\dcs\signals\signals_atom\signals_atom_movable.dm" #include "code\__DEFINES\dcs\signals\signals_atom\signals_atom_x_act.dm" +#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_main.dm" #include "code\__HELPERS\_global_objects.dm" #include "code\__HELPERS\_lists.dm" #include "code\__HELPERS\_string_lists.dm" diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm new file mode 100644 index 00000000000..ed9a684578a --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm @@ -0,0 +1,7 @@ +// Atom movable signals. Format: +// When the signal is called: (signal arguments) +// All signals send the source datum of the signal as the first argument + +///from base of atom/movable/Moved(): (/atom) +#define COMSIG_MOVABLE_PRE_MOVE "movable_pre_move" + #define COMPONENT_MOVABLE_BLOCK_PRE_MOVE (1<<0) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm new file mode 100644 index 00000000000..a4d09cc7e91 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm @@ -0,0 +1,4 @@ +/// From base of /client/Move(): (list/move_args) +#define COMSIG_MOB_CLIENT_PRE_LIVING_MOVE "mob_client_pre_living_move" + /// Should we stop the current living movement attempt + #define COMSIG_MOB_CLIENT_BLOCK_PRE_LIVING_MOVE COMPONENT_MOVABLE_BLOCK_PRE_MOVE diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 7793f3ab1b9..3930643f195 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -372,31 +372,6 @@ Moved(old_loc, TRUE) return TRUE -/atom/movable/Move() - var/old_loc = loc - . = ..() - if (.) - // Events. - if (GLOB.moved_event.global_listeners[src]) - GLOB.moved_event.raise_event(src, old_loc, loc) - - // Lighting. - if (light_sources) - var/datum/light_source/L - var/thing - for (thing in light_sources) - L = thing - L.source_atom.update_light() - - // Openturf. - if (bound_overlay) - // The overlay will handle cleaning itself up on non-openspace turfs. - bound_overlay.forceMove(get_step(src, UP)) - if (bound_overlay.dir != dir) - bound_overlay.set_dir(dir) - - Moved(old_loc, FALSE) - /atom/movable/proc/Moved(atom/old_loc, forced) SHOULD_CALL_PARENT(TRUE) SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, old_loc, forced) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index c7b34dd7754..abb7ef61209 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -218,6 +218,7 @@ var/list/admin_verbs_debug = list( /client/proc/cmd_display_del_log, /client/proc/cmd_display_harddel_log, /client/proc/cmd_display_init_log, + /client/proc/cmd_generate_lag, /client/proc/cmd_ss_panic, /client/proc/reset_openturf, /datum/admins/proc/capture_map, @@ -390,6 +391,7 @@ var/list/admin_verbs_hideable = list( /client/proc/cmd_display_harddel_log, /datum/admins/proc/ccannoucment, /client/proc/cmd_display_init_log, + /client/proc/cmd_generate_lag, /client/proc/getruntimelog, /client/proc/toggledebuglogs, /client/proc/getserverlog, @@ -476,6 +478,7 @@ var/list/admin_verbs_dev = list( //will need to be altered - Ryan784 /client/proc/cmd_display_del_log, /client/proc/cmd_display_harddel_log, /client/proc/cmd_display_init_log, + /client/proc/cmd_generate_lag, /client/proc/create_poll, //Allows to create polls /client/proc/profiler_start, /client/proc/rustg_send_udp diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 94467981545..0ee2097b981 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -517,3 +517,25 @@ // Clear the user's cache so they get resent. usr.client.sent_assets = list() + +/** + * Used to generate lag and load the MC to test how things work under live server stress + */ +/client/proc/cmd_generate_lag() + set name = "Generate Lag" + set category = "Debug" + set desc = "Generate lag, to be used for LOCAL TESTS ONLY" + + var/mollyguard = tgui_alert(src, "This is to be used only on local instances, DO NOT USE IT ON LIVE, YOU CANNOT UNDO THIS, do you understand?", "Molly Guard", list("No", "Yes")) + + if(mollyguard != "Yes") + return + + var/tick_offenses = tgui_input_number(src, "Tick usage offset from 100?", "Tick Offset", 0, min_value = -100, round_value=TRUE) + var/jitter = tgui_input_number(src, "What jitter should be applied?", "Jitter", 0, min_value = 0, round_value=TRUE) + + while(TRUE) + var/jitter_this_run = rand(0, jitter) + for(var/atom/an_atom in world) + if(world.tick_usage > (100+(tick_offenses+jitter_this_run))) + stoplag() diff --git a/code/modules/mob/abstract/freelook/update_triggers.dm b/code/modules/mob/abstract/freelook/update_triggers.dm index 3fe1176a76b..a2e91b60b1b 100644 --- a/code/modules/mob/abstract/freelook/update_triggers.dm +++ b/code/modules/mob/abstract/freelook/update_triggers.dm @@ -15,11 +15,6 @@ if(.) updateVisibility(src, FALSE) -/atom/movable/Move() - . = ..() - if(opacity && .) - updateVisibility(src) - /atom/movable/forceMove() . = ..() if(opacity && .) diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index ae172ad8e52..e7ab4c101bf 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -132,6 +132,11 @@ //This proc should never be overridden elsewhere at /atom/movable to keep directions sane. /atom/movable/Move(newloc, direct) + if(SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_MOVE, newloc) & COMPONENT_MOVABLE_BLOCK_PRE_MOVE) + return + + var/old_loc = loc + if (direct & (direct - 1)) if (direct & 1) if (direct & 4) @@ -167,6 +172,38 @@ var/olddir = dir //we can't override this without sacrificing the rest of movable/New() . = ..() + + if(.) + // Events. + if(GLOB.moved_event.global_listeners[src]) + GLOB.moved_event.raise_event(src, old_loc, loc) + + // Lighting. + if(light_sources) + var/datum/light_source/L + var/thing + for(thing in light_sources) + L = thing + L.source_atom.update_light() + + // Openturf. + if(bound_overlay) + // The overlay will handle cleaning itself up on non-openspace turfs. + bound_overlay.forceMove(get_step(src, UP)) + if(bound_overlay.dir != dir) + bound_overlay.set_dir(dir) + + if(opacity) + updateVisibility(src) + + //Mimics + if(bound_overlay) + bound_overlay.forceMove(get_step(src, UP)) + if(bound_overlay.dir != dir) + bound_overlay.set_dir(dir) + + Moved(old_loc, FALSE) + if(direct != olddir) dir = olddir set_dir(direct) @@ -187,7 +224,17 @@ return -/client/Move(n, direct) +/** + * Move a client in a direction + * + * This is called when a client tries to move, usually it dispatches the moving request to the mob it's controlling + */ +/client/Move(new_loc, direct) + if(world.time < move_delay) //do not move anything ahead of this check please + return FALSE + + var/old_move_delay = move_delay + if(!mob) return // Moved here to avoid nullrefs below @@ -201,27 +248,21 @@ if(moving || world.time < move_delay) return 0 - //This compensates for the inaccuracy of move ticks - //Whenever world.time overshoots the movedelay, due to it only ticking once per decisecond - //The overshoot value is subtracted from our next delay, farther down where move delay is set. - //This doesn't entirely remove the problem, but it keeps travel times accurate to within 0.1 seconds - //Over an infinite distance, and prevents the inaccuracy from compounding. Thus making it basically a non-issue - var/leftover = world.time - move_delay - if (leftover > 1) - leftover = 0 - if(mob.stat == DEAD && isliving(mob)) mob.ghostize() return // handle possible Eye movement if(mob.eyeobj) - return mob.EyeMove(n,direct) + return mob.EyeMove(new_loc,direct) if(mob.transforming) return //This is sota the goto stop mobs from moving var if(isliving(mob)) + if(SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_PRE_LIVING_MOVE, new_loc, direct) & COMSIG_MOB_CLIENT_BLOCK_PRE_LIVING_MOVE) + return FALSE + var/mob/living/L = mob if(L.incorporeal_move && isturf(mob.loc))//Move though walls Process_Incorpmove(direct, mob) @@ -275,22 +316,29 @@ if(M.pulling == mob) if(!M.restrained() && M.stat == 0 && M.canmove && mob.Adjacent(M)) to_chat(src, SPAN_NOTICE("You're restrained! You can't move!")) - return 0 + return FALSE else M.stop_pulling() if(mob.pinned.len) to_chat(src, SPAN_WARNING("You're pinned to a wall by [mob.pinned[1]]!")) move_delay = world.time + 1 SECOND // prevent spam - return 0 + return FALSE - move_delay = world.time - leftover//set move delay + //If the move was recent, count using old_move_delay + //We want fractional behavior and all + if(old_move_delay + world.tick_lag > world.time) + //Yes this makes smooth movement stutter if add_delay is too fractional + //Yes this is better then the alternative + move_delay = old_move_delay + else + move_delay = world.time - if (mob.buckled_to) + if(mob.buckled_to) if(istype(mob.buckled_to, /obj/vehicle)) //manually set move_delay for vehicles so we don't inherit any mob movement penalties //specific vehicle move delays are set in code\modules\vehicles\vehicle.dm - move_delay = world.time + move_delay = (old_move_delay + world.tick_lag > world.time) ? old_move_delay : world.time //drunk driving if(mob.confused && prob(25)) direct = pick(GLOB.cardinal) @@ -366,7 +414,7 @@ if(mob.confused && prob(25) && mob.m_intent == M_RUN) step(mob, pick(GLOB.cardinal)) else - . = mob.SelfMove(n, direct) + . = mob.SelfMove(new_loc, direct) for (var/obj/item/grab/G in list(mob:l_hand, mob:r_hand)) if (G.state == GRAB_NECK) diff --git a/code/modules/multiz/zmimic/mimic_movable.dm b/code/modules/multiz/zmimic/mimic_movable.dm index 471bc0593df..51f718c108f 100644 --- a/code/modules/multiz/zmimic/mimic_movable.dm +++ b/code/modules/multiz/zmimic/mimic_movable.dm @@ -15,13 +15,6 @@ else // Not a turf, so we need to destroy immediately instead of waiting for the destruction timer to proc. qdel(bound_overlay) -/atom/movable/Move() - . = ..() - if (. && bound_overlay) - bound_overlay.forceMove(get_step(src, UP)) - if (bound_overlay.dir != dir) - bound_overlay.set_dir(dir) - /atom/movable/set_dir(ndir) . = ..() if (. && bound_overlay) diff --git a/html/changelogs/fluffyghost-movementlagcompensator.yml b/html/changelogs/fluffyghost-movementlagcompensator.yml new file mode 100644 index 00000000000..c8140522301 --- /dev/null +++ b/html/changelogs/fluffyghost-movementlagcompensator.yml @@ -0,0 +1,45 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +# admin +# backend +# security +# refactor +################################# + +# Your name. +author: FluffyGhost + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - backend: "Updated how the movement delay for cliented mob is calculated, which should help smooth out movement delays when the MC is loaded. Hopefully." + - backend: "Living mob movements now emit a signal that can be intercepted and replied to block said movement." + - backend: "Added a lag generator for local tests to simulate the MC being loaded, FOR LOCAL TEST IS THE KEYWORD HERE." + - backend: "Consolidated atom/movable/Move in a single proc." + - backend: "Added a signal for atom/movable/Move that can be intercepted and replied to block said movement."