ID:1583369
 
(See the best response by Kumorii.)
Code:
RegenHandler
parent_type = /CombatPhysics

var/CombatMechanics/_src
var/const/TICK_TIME = 10
var
health_r = 5
stamina_r = 10
spirit_r = 5
oxygen_r = 10
tmp/obj/DivingHud/Respiration/oxygen

var{health_loss = 0;stamina_loss = 0;spirit_loss = 0;oxygen_loss = 0}
var{h_once = FALSE;s_once=FALSE;sp_once=FALSE;o_once=FALSE}

New(__src)
if(!__src)return 0
_src=__src
// init()
..()

init()
.=..()
spawn Regeneration()

proc
Regeneration()
while(_src && _src.mob && _src.mob.loc)

spawn(-1)
stamRegen()
healthRegen()
spiritRegen()
if(_src.mob.Race != "Fishman" && _src.mob.client)
oxygenRegen()

if(_src.Status.Stunned)
_src.Status.Stunned = max(0, _src.Status.Stunned - (TICK_TIME * _src.TICK_TIME))

sleep((TICK_TIME * _src.TICK_TIME) + world.tick_lag)

stamRegen()
if(_src.Stamina>=_src.MaxStamina) return 0
var/FastRecoveryPassive = _src.mob.getPassive("Fast Recovery")
_src.Stamina = max(0, _src.Stamina + (stamina_loss ? -(stamina_loss) : (FastRecoveryPassive ? stamina_r * 1.4 : stamina_r)))
if(s_once){s_once=FALSE;stamina_loss=0}

healthRegen()
if(_src.Health>=_src.MaxHealth)return 0
_src.Health = max(0, _src.Health + (health_loss ? -(health_loss) : health_r))
if(h_once){h_once=FALSE;health_loss=0}

spiritRegen()

oxygenRegen()
var dtime = _src.getMaxDivingTime()
if(!_src.mob.Diving && _src.mob.Dive < dtime)
_src.mob.Dive = min(dtime, _src.mob.Dive + (oxygen_loss ? -(oxygen_loss) : (2.5/oxygen_r)))
if(o_once){o_once=FALSE;oxygen_loss=0}
if(_src.mob.Dive >= dtime)
if(oxygen)
oxygen.Del(_src.mob.client)
else
if(!oxygen) oxygen = new(_src.mob.client)
oxygen.icon_state = "[max(0,round(_src.mob.Dive))]"

else if(_src.mob.Diving)
if(!oxygen)oxygen = new(_src.mob.client)
if(oxygen_loss)
_src.mob.Dive = max(0, (_src.mob.Dive - (oxygen_loss - 1)))
if(o_once){o_once=FALSE;oxygen_loss=0}

if(!_src.mob.Dive--)
_src.mob.z--
_src.mob.Diving = 0
_src.mob.overlays-='Bubbles.dmi'
oxygen.Del(_src.mob.client)
return
oxygen.icon_state = "[max(round(_src.mob.Dive),0)]"

if(debug)debug.Trace("RegenHandler/oxygenRegen():\
(Diving:
[_src.mob.Diving] | oxygen: [oxygen] | Dive: [_src.mob.Dive] abs-[round(_src.mob.Dive)])")


Problem description:

This code seems to generate a crash when I host the game with this module enabled.
It always worked perfect, some of the latter changes must've affected it, for some reason.
Maybe it is just me being stupid :)
You are using spawn in a loop.

Aside from that, I would personally only regenerate the mob when it needs to be regenerated. I could be wrong but it looks like the mob is regenerating all the time from the looks of your snippet.
Yeah you are very correct.

Actually spawn(-1) makes the spawned code to execute immediately before proceeding, as stated in the DM Reference, so I thought it wouldn't affect the loop in any way, I must do some more research to get this crash gone.

Apparently whenever I enable the Regeneration module on my source, the game suddenly crashes after ~3 minutes.
In response to Fushimi
Did you try removing the spawn? And if you did, what were the results? I'm fairly sure that is what the issue is. I don't see anything else that would lead to that in your snippet.
I did this optimization;

    proc
Regeneration()
isRegenerating = TRUE
while(_src && _src.mob && _src.mob.loc && needsRegen())
stamRegen()
healthRegen()
spiritRegen()
if(_src.mob.Race != "Fishman" && _src.mob.client)
oxygenRegen()

if(_src.Status.Stunned)
_src.Status.Stunned = max(0, _src.Status.Stunned - (TICK_TIME * _src.TICK_TIME))

sleep((TICK_TIME * _src.TICK_TIME) + world.tick_lag)
isRegenerating = FALSE

needsRegen()
. = (_src.Stamina >= _src.MaxStamina || _src.Health >= _src.MaxHealth || _src.mob.Diving ||!_src.mob.Diving && _src.mob.Dive < _src.getMaxDivingTime())
if(. && !isRegenerating)
spawn Regeneration()


I still need to test this in order to find if a crash happens.
Best response
Remove the spawn. From what I can tell, the loop is finishing before the regen procs which is stacking a lot of procs over time. I just skimmed, though. I'd suggest looking into a different approach that's a little more resource friendly.


EDIT: Beat me to it, lol.
This is the whole method if anyone is interested, it appears to be stable now, I removed the spawn and some unneeded checks.

RegenHandler
parent_type = /CombatPhysics

var/CombatMechanics/_src
var/const/TICK_TIME = 10
var
health_r = 5
stamina_r = 10
spirit_r = 5
oxygen_r = 10
tmp/obj/DivingHud/Respiration/oxygen
tmp/isRegenerating = FALSE

var{health_loss = 0;stamina_loss = 0;spirit_loss = 0;oxygen_loss = 0}
var{h_once = FALSE;s_once=FALSE;sp_once=FALSE;o_once=FALSE}

New(__src)
if(!__src)return 0
_src=__src
init()
..()

init()
.=..()
spawn Regeneration()

proc
Regeneration()
isRegenerating = TRUE
while(_src && _src.mob && _src.mob.loc && needsRegen())
stamRegen()
healthRegen()
spiritRegen()
if(_src.mob.Race != "Fishman" && _src.mob.client)
oxygenRegen()

if(_src.Status.Stunned)
_src.Status.Stunned = max(0, _src.Status.Stunned - (TICK_TIME * _src.TICK_TIME))

sleep((TICK_TIME * _src.TICK_TIME) + world.tick_lag)
isRegenerating = FALSE

needsRegen()
. = (_src.Stamina >= _src.MaxStamina || _src.Health >= _src.MaxHealth || _src.mob.Diving ||!_src.mob.Diving && _src.mob.Dive < _src.getMaxDivingTime())
if(. && !isRegenerating)
spawn Regeneration()

stamRegen()
var/FastRecoveryPassive = _src.mob.getPassive("Fast Recovery")
_src.Stamina = max(0, _src.Stamina + (stamina_loss ? -(stamina_loss) : (FastRecoveryPassive ? stamina_r * 1.4 : stamina_r)))
if(s_once){s_once=FALSE;stamina_loss=0}

healthRegen()
_src.Health = max(0, _src.Health + (health_loss ? -(health_loss) : health_r))
if(h_once){h_once=FALSE;health_loss=0}

spiritRegen()

oxygenRegen()
if(!needsRegen())return FALSE //Avoids an uneeded call to the rest of the proc.
// Also serves as initialization for the Regen proc when you start Diving.

var dtime = _src.getMaxDivingTime()
if(!_src.mob.Diving && _src.mob.Dive < dtime)
_src.mob.Dive = min(dtime, _src.mob.Dive + (oxygen_loss ? -(oxygen_loss) : (2.5/oxygen_r)))
if(o_once){o_once=FALSE;oxygen_loss=0}
if(_src.mob.Dive >= dtime)
if(oxygen)
oxygen.Del(_src.mob.client)
else
if(!oxygen) oxygen = new(_src.mob.client)
oxygen.icon_state = "[max(0,round(_src.mob.Dive))]"

else if(_src.mob.Diving)
if(!oxygen)oxygen = new(_src.mob.client)
if(oxygen_loss)
_src.mob.Dive = max(0, (_src.mob.Dive - (oxygen_loss - 1)))
if(o_once){o_once=FALSE;oxygen_loss=0}

if(!_src.mob.Dive--)
_src.mob.z--
_src.mob.Diving = 0
_src.mob.overlays-='Bubbles.dmi'
oxygen.Del(_src.mob.client)
return
oxygen.icon_state = "[max(round(_src.mob.Dive),0)]"

if(debug)debug.Trace("RegenHandler/oxygenRegen():\
(Diving:
[_src.mob.Diving] | oxygen: [oxygen] | Dive: [_src.mob.Dive] abs-[round(_src.mob.Dive)])")


Kumorii: What would be your approach?