Server and client
Mark code server or client and shot check stops each side requiring the other's code, and one name can stand for a module with a version on each side.
A file is shared unless you mark it server or client. shot check reports a require that crosses sides the wrong way, and a split module or diffsource func lets code on either side reach its own version through one name.
Sides
Every file has a side:
class / module / func | both: shared, runs on server and client (the default) |
server class / module / func | server only |
client class / module / func | client only |
@server ... / @client ... script | the script's side |
split module, diffsource func | both |
What may require what:
both code | may require: both |
server code | may require: both, server |
client code | may require: both, client |
Breaking it is an error at the require: "client code requires server MarketServer (Market/
The common case: a shared class (plain class) that needs a server-only module gets "both code requires server ...". If the class only makes sense on the server, mark it: server class Till = { ... }.
Everything compiles into ReplicatedStorage.Shot, server files included: classes, modules and funcs as ordinary ModuleScripts. server and client only decide what may require what; nothing is hidden or moved.
Split module
One name for a client module and a server module, so code on both sides, like the two Init scripts, can require one thing.
Market/Market.shot
types script.Parent.Types
split module Market = {
Client -> script.Parent.MarketClient,
Server -> script.Parent.MarketServer
}Market/MarketClient.shot
types script.Parent.Types
client module MarketClient = {
function Open()
end
}Market/MarketServer.shot
types script.Parent.Types
server module MarketServer = {
function Start()
end
}Init/Client.shot
@client enabled
local Market = require(@shot.Market)
Market.Client.Open()- On the server,
Market.Serveris the server module andMarket.Clientis nil. On the client it is the other way round. - A split module named after its folder (Market/Market.shot) is the folder's entry point:
require(@shot.Market). - The type checker thinks both fields are always there. The nil side is caught only by ShotScript's own rule, in client and server files, when the module is held in a local made by
local Market = require(...): a client file usingMarket.Servergives "client code uses Market.Server". Shared (both) code is not checked; test the side first (RunService:IsServer()) before touching either field there. - Entries are separated by a comma. Both lines are needed ("split module Market has no Server -> line"), and each must point at a file ("split Market: nothing at Client -> script.
Parent. MarketClien").
Diffsource func
One name for a client func and a server func with the same signature. The value is the client func on the client and the server func on the server.
Utils/
types script.Parent.Types
diffsource func UniqueIdentifier = {
Client -> script.Parent.UIDClient,
Server -> script.Parent.UIDServer
}The two funcs, each in its own file: client func UIDClient() : string in UIDClient.shot and server func UIDServer() : string in UIDServer.shot.
Checked:
- both entries are funcs ("diffsource UniqueIdentifier: Client -> script.Parent.UIDClient is not a func"),
- the Client entry is a client (or both) func and the Server entry a server (or both) func ("diffsource UniqueIdentifier: Client -> UIDServer is a server func"),
- both have the same parameter and return types ("diffsource UniqueIdentifier: Client is () -> string but Server is () -> number").
