diff --git a/code/__DEFINES/qdel.dm b/code/__DEFINES/qdel.dm index 2028f45afa8..b17fbbe3d1a 100644 --- a/code/__DEFINES/qdel.dm +++ b/code/__DEFINES/qdel.dm @@ -39,7 +39,7 @@ // Defines for the time an item has to get its reference cleaned before it fails the queue and moves to the next. #define GC_FILTER_QUEUE 1 SECONDS -#define GC_CHECK_QUEUE 5 MINUTES +#define GC_CHECK_QUEUE 30 SECONDS // Reduced from 5 MINUTES for long-running rounds #define GC_DEL_QUEUE 10 SECONDS diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 4a139c2e562..188e8b67e1b 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -163,7 +163,7 @@ #define FIRE_PRIORITY_VIS 10 #define FIRE_PRIORITY_AMBIENCE 10 #define FIRE_PRIORITY_MISSIONS 10 -#define FIRE_PRIORITY_GARBAGE 15 +#define FIRE_PRIORITY_GARBAGE 10 // Increased from 15 for better performance in long rounds #define FIRE_PRIORITY_WET_FLOORS 20 #define FIRE_PRIORITY_AIR 20 #define FIRE_PRIORITY_NPC 20 diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index 1bb1d185c84..102b9fc864b 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -24,7 +24,7 @@ By using these methods of finding references, you can make your life far, far ea SUBSYSTEM_DEF(garbage) name = "Garbage" priority = FIRE_PRIORITY_GARBAGE - wait = 2 SECONDS + wait = 1 SECONDS // Increased frequency from 2 SECONDS for better throughput flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY init_order = INIT_ORDER_GARBAGE diff --git a/code/controllers/subsystem/idlenpcpool.dm b/code/controllers/subsystem/idlenpcpool.dm index 5c8bb49ab76..be05c808659 100644 --- a/code/controllers/subsystem/idlenpcpool.dm +++ b/code/controllers/subsystem/idlenpcpool.dm @@ -2,7 +2,7 @@ SUBSYSTEM_DEF(idlenpcpool) name = "Idling NPC Pool" flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT priority = FIRE_PRIORITY_IDLE_NPC - wait = 60 + wait = 30 // Reduced from 60 to check more frequently for player presence runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME var/list/currentrun = list() @@ -23,7 +23,9 @@ SUBSYSTEM_DEF(idlenpcpool) if (!resumed) var/list/idlelist = GLOB.simple_animals[AI_IDLE] - src.currentrun = idlelist.Copy() + var/list/zlist = GLOB.simple_animals[AI_Z_OFF] + // Process both idle and z-off mobs + src.currentrun = idlelist.Copy() + zlist.Copy() //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun @@ -33,12 +35,19 @@ SUBSYSTEM_DEF(idlenpcpool) --currentrun.len if (!SA) GLOB.simple_animals[AI_IDLE] -= SA + GLOB.simple_animals[AI_Z_OFF] -= SA continue if(!SA.ckey) - if(SA.stat != DEAD) - SA.handle_automated_movement() - if(SA.stat != DEAD) - SA.check_should_sleep() + // For AI_Z_OFF mobs, only check if they should wake up, don't move them + if(SA.AIStatus == AI_Z_OFF) + if(SA.stat != DEAD) + SA.check_should_sleep() + else + // For AI_IDLE mobs, do normal processing + if(SA.stat != DEAD) + SA.handle_automated_movement() + if(SA.stat != DEAD) + SA.check_should_sleep() if (MC_TICK_CHECK) return diff --git a/code/controllers/subsystem/machines.dm b/code/controllers/subsystem/machines.dm index ee0f4c9b1f2..60f547c6c48 100644 --- a/code/controllers/subsystem/machines.dm +++ b/code/controllers/subsystem/machines.dm @@ -6,6 +6,8 @@ SUBSYSTEM_DEF(machines) var/list/processing = list() var/list/currentrun = list() var/list/powernets = list() + /// Track how many machines we skipped due to empty virtual z-levels + var/skipped_machines = 0 /datum/controller/subsystem/machines/Initialize() makepowernets() @@ -31,7 +33,7 @@ SUBSYSTEM_DEF(machines) propagate_network(PC,PC.powernet) /datum/controller/subsystem/machines/stat_entry(msg) - msg = "M:[length(processing)]|PN:[length(powernets)]" + msg = "M:[length(processing)]|PN:[length(powernets)]|S:[skipped_machines]" return ..() @@ -40,6 +42,7 @@ SUBSYSTEM_DEF(machines) for(var/datum/powernet/Powernet in powernets) Powernet.reset() //reset the power state. src.currentrun = processing.Copy() + skipped_machines = 0 //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun @@ -47,10 +50,37 @@ SUBSYSTEM_DEF(machines) while(currentrun.len) var/obj/machinery/thing = currentrun[currentrun.len] currentrun.len-- - if(QDELETED(thing) || thing.process(wait * 0.1) == PROCESS_KILL) + + if(QDELETED(thing)) + processing -= thing + if (MC_TICK_CHECK) + return + continue + + // Skip machines on virtual z-levels with no players present + // Exceptions: + // 1. Critical machines (SM, PA, telecomms) always process + // 2. Machines in outpost areas always process (player hubs) + // 3. Machines in ship areas always process (player-owned vessels) + if(!thing.critical_machine) + var/area/machine_area = get_area(thing) + // Check if it's an outpost or ship area - these always process + if(!istype(machine_area, /area/outpost) && !istype(machine_area, /area/ship)) + var/thing_vz = thing.virtual_z() + if(thing_vz) + var/players_on_vz = LAZYACCESS(SSmobs.players_by_virtual_z, "[thing_vz]") + if(!length(players_on_vz)) + skipped_machines++ + if (MC_TICK_CHECK) + return + continue + + // Process the machine + if(thing.process(wait * 0.1) == PROCESS_KILL) processing -= thing if (!QDELETED(thing)) thing.datum_flags &= ~DF_ISPROCESSING + if (MC_TICK_CHECK) return diff --git a/code/controllers/subsystem/npcpool.dm b/code/controllers/subsystem/npcpool.dm index 9ccc6bda58d..de319433b9f 100644 --- a/code/controllers/subsystem/npcpool.dm +++ b/code/controllers/subsystem/npcpool.dm @@ -36,6 +36,10 @@ SUBSYSTEM_DEF(npcpool) if(QDELETED(SA)) continue + // Skip AI_Z_OFF mobs - they're on virtual z-levels with no players + if(SA.AIStatus == AI_Z_OFF) + continue + if(!SA.ckey && !SA.notransform) if(SA.stat != DEAD) SA.handle_automated_movement() diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm index 9634040582e..8a019edbc58 100644 --- a/code/modules/mob/living/living_movement.dm +++ b/code/modules/mob/living/living_movement.dm @@ -13,6 +13,11 @@ return TRUE if(ismob(mover) && (mover in buckled_mobs)) return TRUE + //Allow squeezing by on grab intent + if(iscarbon(mover)) + var/mob/living/carbon/C = mover + if(C.a_intent == INTENT_GRAB) + return TRUE return !mover.density || body_position == LYING_DOWN /mob/living/toggle_move_intent() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index e90b4a618fa..460c44296f6 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -232,6 +232,10 @@ /mob/living/simple_animal/proc/handle_automated_action() set waitfor = FALSE + // Periodically check if we should sleep (for non-hostile mobs) + // Hostile mobs override this and do their own checks + if(prob(10)) // 10% chance per action to check sleep state + check_should_sleep() return /mob/living/simple_animal/proc/handle_automated_movement() @@ -658,17 +662,39 @@ LAZYREMOVEASSOC(SSidlenpcpool.idle_mobs_by_virtual_level, "[virt_z]", src) /mob/living/simple_animal/proc/check_should_sleep() + // Don't sleep if being pulled or explicitly flagged to stay awake if (pulledby || shouldwakeup) toggle_ai(AI_ON) return + // Don't sleep if we're player-controlled + if(ckey) + return + var/virt_z = virtual_z() + if(!virt_z) + return + var/players_on_virtual_z = 0 - if(virt_z) - players_on_virtual_z = LAZYACCESS(SSmobs.players_by_virtual_z, "[virt_z]") - if(!length(players_on_virtual_z)) + players_on_virtual_z = LAZYACCESS(SSmobs.players_by_virtual_z, "[virt_z]") + + // If no players on this virtual z-level, sleep + if(!length(players_on_virtual_z)) + if(AIStatus != AI_Z_OFF) toggle_ai(AI_Z_OFF) - else if(AIStatus == AI_Z_OFF) + // If there are players and we're asleep, wake up + else if(AIStatus == AI_Z_OFF) + // Check if any players are actually close enough to matter + var/should_wake = FALSE + var/turf/our_turf = get_turf(src) + if(our_turf) + for(var/mob/living/player_mob in players_on_virtual_z) + // Wake up if a player is within reasonable distance + if(get_dist(our_turf, get_turf(player_mob)) <= MAX_SIMPLEMOB_WAKEUP_RANGE * 3) + should_wake = TRUE + break + + if(should_wake) toggle_ai(AI_ON) /mob/living/simple_animal/adjustHealth(amount, updating_health = TRUE, forced = FALSE)