Lua Error - Infinite Loop on Server Quit

Ok, I have taken up the task of adding to the Fairy Network Lua Entity I worked on 2 years ago.

I’ve a bit of a problem though.

Players on my server complained about how they hated the fact that when their fairy got accidentally deleted, or eaten by a stargate, that they would need to re-join the server to get the fairy to respawn - they are disabled from the spawn menu.

Anyhow…
To remedy this, I added a bit of code to the onRemove event of the entity, if the fairy was removed, or destroyed, without a specific variable being set, then it would trigger the fairy to spawn again. So another words, the fairy cannot be removed, unless specifically asked to leave via chat command.

Anyhow… I’ve encountered a side effect.

Apparently, when the server is exited, via an ‘exit’ command, while players are logged in, all the players entities or props etc, get destroyed or something before the server quits, this however, interacts with my fairy safeguard function, triggering an infinite loop.

1 - Ask server to exit
2 - Tries to destroy props etc
3 - Destroys fairy
4 - No variable set on fairy -
5 - Recreates the fairy
6 - Server is still trying to quit
7 - Destroys fairy
8 - No Variable set on fairy -
9 - Recreates fairy…

This process continues indefinitly

I was wondering if anyone knows how to create a global variable that I can set on the Server, that can be set on the Shutdown hook, that my Fairy Spawn function could then check for, and decide whether or not to re-spawn the fairy?

Im more a C Sharp type of guy, so im not that up to date with how to declare global variables or how to create variables that other systems can access.

I would say use another command than quit or exit, like exit2 then hook it on the server, and put a special variable on, then check on the fairy and dont respawn if it is true.

[lua]hook.Add(“ShutDown” , “SDKASDA” , function() – loop through all ents and set the variable and remove them end )[/lua]

I was thinking to use that, but I got no Idea when this gets called, and the fact its description is this: called just before the Lua enviroment is closed, and that the ent is still continuously spawned means that the Lua env is still not removed.

Which is why you remove the entities before the server fully shuts down.

Try it, it’ll either work or not work.



function FairyExit()
 fairies = ents.FindByClass("gmod_fairy")
 for k,fairy in pairs(fairies) do
  fairy.IsLeaving = true
 end
 exit
end
concommand.Add( "Fairy_Exit",FairyExit )
 


This is what im thinking, but I think I remember that the exit command along with some others, are blocked. Can anyone confirm?

[editline]11:54PM[/editline]

tried this too - doesnt work either…



 
function FairyExit()
 fairies = ents.FindByClass("gmod_fairy")
 for k,fairy in pairs(fairies) do
  fairy.IsLeaving = true
 end
 
end

hook.Add( "ShutDown", "fairy_shutingdown", FairyExit )
 


-derp-



function FairyExit()
 fairies = ents.FindByClass("gmod_fairy")
 for k,fairy in pairs(fairies) do
  fairy.IsLeaving = true
 end
 
end

hook.Add( "Shutdown", "fairy_shutingdown", FairyExit )


Tried putting this in the server autorun for the fairy addon im making. Im still getting infinite loops.

This is the spawn function, which is getting fired



function ENT:SpawnFunction(Ply, Trace)
 if not (Trace.Hit) then return end
 local Fairy = SpawnFairy(Ply, Trace.HitPos + Trace.HitNormal * 4)
 return Fairy
end


This is the onRemove function for the fairy



function ENT:OnRemove()
 
 local Index = self.Entity:EntIndex()
 --
 FairyNumber = 0
 Fairies[Index] = nil
 
 if (ValidEntity(self.Entity.Player)) then
  -- Player is still on the server
  local PlyIndex = self.Entity.Player:EntIndex()
  Fairies[PlyIndex].Num = Fairies[PlyIndex].Num - 1
  
  local Num = 0
  for k,v in pairs(Fairies[PlyIndex].Fairies) do
   local Ent = ents.GetByIndex(v)
   
   if (Ent) and (Ent:IsValid()) then
    Num = Num + 1
    Ent.Num = Num
   else
    table.remove(Fairies[PlyIndex].Fairies, v)
   end
  end
        if (self.Entity.IsLeaving != true) then
  SpawnFairy(self.Entity.Player, self.Entity.Player:GetShootPos())
 end
 else
  -- The player left or something, doesn't exist anyway
  --Fairies[PlyIndex] = nil
 end
end


Its this line in the onRemove which is firing the infinite loop, I think.



if (self.Entity.IsLeaving != true) then
  SpawnFairy(self.Entity.Player, self.Entity.Player:GetShootPos())
 end


I thought that by hooking into the shutdown hook, with a function to set the boolean to be true, for all fairies currently existing, I could get around it. But that doesnt seem to have worked.

Is it possible to set variables on the server itself?
Eg - Convars?

How about just re-enable spawning them if the fairy is gone, rather than directly spawning another straight away?

Because, its sandbox, and alot of people like to use the z key for undo.

I’d prefer to have the fairies unaffected by undo.

At the minute, it works fine, except for the infinite loop error, its a small inconvenience, Just means I have to close the server via process kill.

I may be talking out of my ass here, but isn’t there a way to just remove the undo function for the fairy anyway?

It can’t?

Just remove the undo.AddEntity?

Also I wouldn’t mind if we could see the erroring line when an infinite loop happens, just a suggestion to Garry.

The thing with infinite loops in code, is that the code doesnt always know when an infinite loop is occuring. The engine/code might think that there is some potential change in circumstance, which will make the loop eventually break.

In my case, its looping because of logic. Its doing what I’ve instructed it to do, however its just a case of me needing to set a variable to be the correct value when the server exits.

In regards to allowing players to spawn the fairies at their own convenience, Im kinda wanting the fairies to be a sort of recommended companion, where they will appear by default, and only leave when instructed to. Kind of Roleplay-ish I know, but im happy with it this way.

I just would like to see the file and line number where it triggered the infinite loop protection since on a “production” server with all scripts like wiremod and such it’s a pain in the a** to find out where the loop happens. This has happened to me once or twice and I couldn’t resolve it.
I think it is possible to find out the line number without affecting performance, I am not fully sure.
Or if the infinite loop protection could somehow generate lua errors so at least hooks would break and infinite loops on think/tick hooks couldn’t sabotage the server to death.

Well, one can always hope something could be done. This isn’t anything major and clear out your damn lua files does almost always work. Finding out where it really happens is another thing.