Step 11 of 14, updated

Start order: required, after and before

Mark a start function required and the game can't forget to call it. Say what it runs after or before, and shot check holds the start script to that order.

You'll learn required, after and before, and what the checker says when they break.

A start nobody calls

Bank.Start opens every wallet. Today a script that forgets the call runs with no error and no wallets:

struck ShotScript writes it for youhighlighted new in ShotScript
Luau todayBank (a ModuleScript, part)
-- Call once when the server starts,-- or nobody gets a wallet.function Bank.Start()	for _, player in Players:GetPlayers() do		Bank.Open(player)	end	Players.PlayerAdded:Connect(Bank.Open)end
ShotScriptWallet/Bank.shot (part)
doc { Opens a wallet for every player }required function Start()	local here = Players:GetPlayers()	for _, player in here do		module.Open(player)	end	Players.PlayerAdded:Connect(		module.Open)end
What it compiles toWallet/Bank.luau (part)
--[[$doc
	Opens a wallet for every player
]]
function Bank.Start()
	local here = Players:GetPlayers()
	for _, player in here do
		module.Open(player)
	end
	Players.PlayerAdded:Connect(
		module.Open)
end

Tip required leaves no trace in the Luau: it is a promise the checker keeps. On a class it goes on a static function, public required static Setup().

Take Bank.Start() out of Init/Server.shot (the first error comes from the order below):

$ shot check
./Stats/Stats.shot:11:26   before Bank.Start: no script calls Bank.Start() (nearest: Stats.Start): write the name as Init/Server.shot calls it
./Wallet/Bank.shot:44   required Bank.Start is never called: the game runs without it
2 errors in 2 files (16 files checked, 4.9 s)

One start before another

Bank.Start now opens wallets for players already in the server, and Bank.Open tells the game with a second Wallet event:

ShotScriptWallet/Types.shot (part)
-- A wallet was opened for a player
event WalletOpened(player : Player)
ShotScriptWallet/Bank.shot (part)
doc { Opens a wallet for the player }
function Open(player : Player)
	module.Wallets[player] = Wallet.new(0)
	module.Count += 1
	WalletOpened.Publish(player)
end

Stats counts those, so it must listen before Bank opens the first. The order goes on the header of the function that needs it:

Luau todayServer (a Script)
-- Stats before Bank: Stats counts the-- wallets Bank.Start opens.Stats.Start()Bank.Start()Shop.Server.Start()
ShotScriptStats/Stats.shot (part)
doc { Wallets opened so far }Opened : number = 0function Start() before Bank.Start	WalletOpened.Subscribe(function(		player : Player)		module.Opened += 1	end)	CoinsGiven.Subscribe(function(		player : Player,		amount : number,		reason : Reason)		module.Total += amount	end)end
What it compiles toStats/Stats.luau (part)
Stats.Opened = 0

function Stats.Start()
	WalletOpened.Subscribe(function(
		player : Player)
		module.Opened += 1
	end)
	CoinsGiven.Subscribe(function(
		player : Player,
		amount : number,
		reason : Reason)
		module.Total += amount
	end)
end

(Stats/Types.shot now reads import CoinsGiven, WalletOpened, Reason from Wallet.)

  • after X: X's call must come above this function's call in the script that calls both; before Y: below it. Both may sit on one line, and several names take commas.
  • Write each name as the start script calls it: Bank.Start, Shop.Server.Start.
  • The clause isn't code: it is left out of the compiled Luau.
  • Declare an order only when it is true, on the side that breaks: Stats misses the wallets, so Stats says before Bank.Start.

Checked

Swap the two calls in Init/Server.shot, Bank.Start() above Stats.Start():

$ shot check
./Init/Server.shot:8:1   Stats.Start() runs after Bank.Start() (line 7), but Stats.Start must run before it (Stats/Stats.shot:11: before Bank.Start): move this line above line 7, or if Stats no longer needs that order, drop before Bank.Start there
1 errors in 1 file (16 files checked, 2.6 s)

The order is real. A player already in the server when it starts:

LuauScenarios/Opened.luau
-- Opened: a player already in the server when it starts gets a wallet, and Stats counts it.
return function(world)
	local Stats = world.Server.Require("Stats")
	local ana = world:AddPlayer("Ana")
	world:Boot()
	world:AddPlayer("Bo")
	world:Step(0.1)
	world.Logf("Stats.Opened is %s", world.Fmt(Stats.Opened))
	assert(Stats.Opened == 2, "Ana, already here, and Bo")
end

Swapped, Ana is missed:

$ shot run Opened
==== Opened
[client:Ana print] client started
[client:Bo print] client started
Stats.Opened is 1
---- scenario error
  [scenario] Scenarios/Opened.luau:9: Ana, already here, and Bo
      Scenarios/Opened.luau:9

==== summary
  Opened         FAILED  (3 lines, 1 errors, 0.1s virtual)
0 of 1 scenario(s) passed

In the right order:

$ shot run Opened
==== Opened
[client:Ana print] client started
[client:Bo print] client started
Stats.Opened is 2

==== summary
  Opened         OK  (3 lines, 0 errors, 0.1s virtual)
1 of 1 scenario(s) passed
Try it

Give the clause a reason in braces, before Bank.Start {it counts the wallets Bank opens}, and swap the two lines again. The error now quotes your reason, and says how to keep the other order if you ever need it.