Start order
Say which start runs first with function Start() after Wallet.Start, and shot check checks the order of the calls in the start script.
What it is
A game starts its systems from a script, one call per line (Init/Server.shot: Wallet.Start(), Market.Start(), ...). When one Start uses what another Start sets up, swapping their two lines breaks the game at run time, often without an error: a list copied empty, a handler that runs before the state it needs exists. A clause on the Start's own header line declares that order where its reader sees it:
function Start() after Wallet.Start {it prices gems with the rates Wallet loads}shot check then finds the scripts that call the Start and checks the order of the calls. It costs nothing at run time: the clause is not code and is left out of the compiled Luau.
The whole syntax
Market/Market.shot
types script.Parent.Types
use @shot.Wallet
local prices : {[string] : number} = {}
rootdoc {
The shop's prices in coins.
}
module Market = {
doc { Opens the shop }
function Start() after Wallet.Start {it prices gems with the rates Wallet loads}
prices.gem_pack = 5 * (Wallet.Rates().Gems or 0)
end
}Wallet/Wallet.shot
types script.Parent.Types
local Players = game:GetService("Players")
local rates : {[string] : number} = {}
local coins : {[Player] : number} = {}
rootdoc {
Every player's coins, and what a gem is worth in coins.
}
module Wallet = {
doc { Loads the exchange rates and gives every player who joins a wallet }
function Start() before Prizes.Start {Prizes pays a join prize into the wallet this makes}
rates.Gems = 10
Players.PlayerAdded:Connect(function(player : Player)
coins[player] = 0
end)
end
doc { The exchange rates, currency to coins }
function Rates() : {[string] : number}
return table.clone(rates)
end
doc { Adds coins to a player's wallet }
function Give(player : Player, amount : number)
coins[player] = (coins[player] or 0) + amount
end
}Init/Server.shot
@server enabled
use Wallet
use Market
use Prizes
Wallet.Start()
Market.Start()
Prizes.Start()after X: X's call must come above this function's call in the script that calls both.before Y: Y's call must come below it.- The clause states what the Start needs, not a rule to keep: a change that needs another order removes that need, then drops the clause (the error's last fix).
- Write each name as the start script calls it (
Wallet.Start,Economy.Server.Start,ProfileStore.Start), not as a path. Several names take commas:after Wallet.Start, Bank.Start.afterandbeforecan both appear on one line. - A reason in braces may follow a name:
{it prices gems with the rates Wallet loads}. Say what breaks at run time if the order is lost; the error quotes it. It stays on the header line. - The clause goes on the header line of a module function (or a class method) after its parameters and return type. The function is usually Start, but any function a script calls on its own line can declare one.
- Declare an order only when it is true: you swapped the two calls and something changed. Put it on the side that breaks (Market needs Wallet first: Market says
after Wallet.Start; Wallet's handler must run first: Wallet saysbefore Prizes.Start).
What is checked
- The scripts that call the declaring function are found wherever they are (any
@serveror@clientscript, not only Init), and in each the declared names are looked up among the calls that start a line, by the text before the parentheses. - The order of the two calls' lines. A wrong order is an error at the call that must move. When the declaration has a reason, the error also says how to keep the order a change asks for: make the Start that runs first do that work without the other (when it is first needed, not at start), then drop the clause.
- A declared name no script calls is an error with the nearest call; a declaring function no script calls is an error, since its order can't be checked.
- Two declarations that can't both hold (Market
after Wallet.Startand Walletafter Market.Start) are one error naming both.
What it doesn't check
- Couplings nobody declared.
shot checkdoesn't look for them: find them by reading what each Start reads that another Start sets up, and prove each by swapping the two calls on a copy and running the scenarios. - Calls that aren't on a line of their own (inside an if, a function or a loop are still lines of their own;
print(Wallet.Start())is not), and starts called from two different scripts: two scripts have no order between them, so that declaration is an error. - Longer cycles (A after B, B after C, C after A): each declaration is checked against the lines, so one of them is reported as a wrong order.
Errors
Init/Server.shot:7:1 Market.Start() runs before Wallet.Start() (line 8), but Market.Start must run after it (Market/Market.shot:12: after Wallet.Start {it prices gems with the rates Wallet loads}): move this line below line 8; or, to keep this order, make Market.Start do that without Wallet.Start (when it is first needed, not at start), then drop after Wallet.Start there; or if Market no longer needs that order, drop after Wallet.Start there
Init/Server.shot:8:1 Wallet.Start() runs after Prizes.Start() (line 7), but Wallet.Start must run before it (Wallet/Wallet.shot:13: before Prizes.Start {Prizes pays a join prize into the wallet this makes}): move this line above line 7; or, to keep this order, make Prizes.Start do that without Wallet.Start (when it is first needed, not at start), then drop before Prizes.Start there; or if Wallet no longer needs that order, drop before Prizes.Start there
Market/Market.shot:12:25 after Walet.Start {it prices gems with the rates Wallet loads}: no script calls Walet.Start() (nearest: Wallet.Start): write the name as Init/Server.shot calls it
Wallet/Wallet.shot:13:25 after Market.Start and Market/Market.shot:12's after Wallet.Start {it prices gems with the rates Wallet loads} can't both hold: each wants its Start first. Keep the one that is still true and drop the other
Market/Market.shot:12:25 no script calls Start of Market/Market.shot, so its after can't be checked: call it from the script that starts the game (Init/Server.shot), or drop the clause
Market/Market.shot:12:19 a comma goes between two names: after Wallet.Start, Bank.Start