Profiles
A profile decides which parts of a schema a build compiles. Marking a statement with @profile
compiles it only when that profile is active. This keeps debug tooling out of the game you ship
without keeping a second schema file.
-- Validate writes while developing; trust your own code in the shipped game.@profile("dev")option WriteValidations = true
-- A debug remote that must never reach a live server.@profile("dev")event GiveMoney { From: Client, Type: Reliable, Call: SingleSync, Data: u32}
event Ping { From: Server, Type: Reliable, Call: SingleSync, Data: u8}A release build of this schema compiles Ping alone, with WriteValidations off. A dev build
compiles both events, with WriteValidations on.
Why it matters for the server: every event a client can send is surface a client can reach. A debug remote left in a shipped schema is a remote any exploiter can call, rate limited or not. A remote that is not compiled does not exist.
There are four profiles: dev, debug, test and release. A statement without @profile is
compiled under every one of them.
Choosing a profile
Section titled “Choosing a profile”On the command line, pass --profile (or -p):
blinkblox net --profile devIn the Studio plugin, set a string attribute named Profile, with one of the four names as its
value, on the schema’s file in ServerStorage.BLINK_CONFIGURATION_FILES. See the
Studio plugin page.
What can be marked
Section titled “What can be marked”@profile goes in front of a type (type, struct, enum, map, set), an event, a
function, a scope, an import or an option. Put it on its own line or on the same line as the
statement; either works.
Everything inside a marked scope or import follows it. A statement inside is compiled only if its scope is. Marking a statement inside an excluded scope with the active profile does not bring it back.
@profile("dev")scope Debug { event Teleport { From: Client, Type: Reliable, Call: SingleSync, Data: vector }
event Kill { From: Client, Type: Reliable, Call: SingleSync, Data: u8 }}An excluded import is still read. A statement that is left out is still parsed and its names
still registered, so the file an excluded import names must exist and must parse. What exclusion
does is keep the declarations out of the generated modules.
-
A compiled declaration cannot use an excluded one. If
Pingis compiled and uses a type markeddev, areleasebuild is refused withE3027rather than quietly carrying the type into the build. Mark both, or neither:Refused under release: Ping uses a dev-only type @profile("dev")struct Money {Amount: u32,}event Ping {From: Server,Type: Reliable,Call: SingleSync,Data: Money}The reverse is fine: a declaration marked
devmay use anything that is always compiled. -
Names stay unique across profiles. Two declarations with the same name are a duplicate, even under different profiles. You cannot declare
GiveMoneyonce fordevand again, differently, forrelease. -
An option may be set once per profile, and once without one.
@profile("dev")and@profile("release")may each setMaxPacketSize. Setting it both with and without a profile is refused under every profile, so a schema is valid in all builds or in none:Refused: set with and without a profile option MaxPacketSize = 4096@profile("dev")option MaxPacketSize = 1024event Ping {From: Server,Type: Reliable,Call: SingleSync,Data: u8} -
A statement takes one profile. Two
@profileattributes on the same statement are refused (E3028). To compile a statement under two profiles but not the others, there is no syntax; leave it unmarked, or declare it under one. -
A misspelt profile is an error (
E3026), not a statement that silently never compiles. The attribute’s name is checked too:@profileis the only one, and anything else isE3025. -
An attribute needs a statement after it. One at the end of a file, or in front of a closing brace, is refused (
E3028).
The client and the server
Section titled “The client and the server”A single compile writes the client and the server module from the same profile, so they always
agree. They only disagree if you mix modules from two builds – a dev client with a release
server. Their schema signatures then differ, and the
client module raises when it is required, rather than decoding one event as another.
A schema with no @profile anywhere has the same signature under every profile, so the flag only
matters where the schema uses it.
