# Shutdown-Script for Don't Starve Together Dedicated Server

I have written my first LUA-Script/Function to shut down the Dedicated Server for Don't Starve Together.
I wanted to shut down the server in 2 minutes and inform everyone on the server that the server is shutting down.
The function os.execute is nil in the dedicated server console, so I can't use os.execute("sleep " .. seconds).

Can I improve something on this script? Is it best practice?

function sleep(seconds)
local t = os.time()
local diff = 0
while diff < seconds do
diff = os.difftime(os.time(), t)
end
end

local steps = {120,60,30,10,5,4,3,2,1}
local n = table.getn(steps)
for i=1,n-1,1 do
TheNet:SystemMessage("The server shuts down in " .. steps[i] .. " seconds")
sleep(steps[i] - steps[i+1])
end
TheNet:SystemMessage("The server shuts down in " .. steps[n] .. " seconds")
sleep(steps[n])
TheNet:SystemMessage("The server is shutting down now")
c_shutdown(true)


Link to the server command list for Don't Starve.

• TheNet:SystemMessage prints the message into the chat
• c_shutdown(true) shutdown the server and persist the world
• I think is correct. Some nit suggestions are: 1) in the for loop, by default increase is '+1' so it's not necessary to type it ('for i=1,n-1 do' works too) 2) instead of 'table.getn(steps)' could simply write '#steps' Dec 17 '17 at 14:20

1. table.getn has been deprecated for more than 2 years now.
2. Why iterate only until n-1?
3. I'd prefer using the string.format over plain concatenation. This is just a personal preference, as the strings are easier to read that way.
4. Although you do not need to pass true to the c_shutdown, do mention in a comment what it does. Maintaining comments is a nice way to recognise engine specific hard-bound parameters; without having to refer the docs again.
5. Iterate over the table using ipairs

Rewritten, the code would be:

local function sleep(seconds)
local diff, t = 0, os.time()
while diff < seconds do
diff = os.difftime(os.time(), t)
end
end

local steps = {
120, 60, 30,
10, 5, 4, 3,
2, 1
}
local notice = "The server shuts down in %d seconds"

for _, secs in ipairs(steps) do
TheNet:SystemMessage(notice:format(secs))
sleep(secs)
end
TheNet:SystemMessage("The server is shutting down now")
c_shutdown(true)  -- true parameter implies that the game will be saved

• 1. ok 2. only until n-1, because: steps[i+1] 3. cool thing 4. ok 5. this ipairs strategy is not so clear for me. the _ stands for the key and this isn't used. Isn't there anything like foreach? Dec 21 '17 at 7:50
• @Shinigami ipairs is the same as foreach. I am not using _ because we are not interested in the index of each value. If you want, you can replace secs with steps[_]. foreach loops, AFAIK, also iterate over key => value pairs, and both values are returned in the generators. Dec 21 '17 at 9:47
function sleep(seconds)
local t = os.time()
local diff = 0
while diff < seconds do
diff = os.difftime(os.time(), t)
end
end


Correct me, but as far as I can see, that's a busy sleep, which might also be called "let's see how fast the CPU can go" sleep.

You need a "native" sleep function, something that is being woken up by the OS as to not make the CPU spin, or any other sort of callback after a certain amount of time.

local t = os.time()


Do not shorten variable names just because you can, it makes the code harder to read and harder to maintain.

local steps = {120,60,30,10,5,4,3,2,1}


You could also sleep for half the amount of time, like this:

local timeUntilShutdownInSeconds = 120;

while timeUntilShutdownInSeconds >= 1 do
-- Do Something
timeUntilShutdownInSeconds = timeUntilShutdownInSeconds / 2
sleep(timeUntilShutdownInSeconds)
end
$$$$
`