fix(gsc): correct the claim that no off-engine compiler exists
gsc-tool compiles GSC outside the engine and reproduces the engine's own diagnostics, so the skill's "no compiler, linter, or test harness worth the name" framing was wrong and sent the reader to load a map instead of running a 50ms check. §1 is now the gate: `--mode comp --game <title> --system pc --dry`, with the warning that `--mode parse` is syntax-only and accepts code the compiler rejects, and that `--game` takes the engine codename (h2 for MW2CR) rather than the marketing name. A clean compile proves the script loads, not that it works, so the "behaviour is unverified until the map runs" half is kept and sharpened. Also adds two §8 entries found the hard way: a local declared inside a block is not visible after it, and there are no file-scope constants. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6207de1a97
commit
e385e01993
2 files changed
+37
-12
No files matched your search
+36
-11
@@ -4,7 +4,7 @@ description: >-
|
||||
Use this skill when writing, reviewing, or debugging GSC (Game Script / Call of Duty script)
|
||||
or CSC — including entity-vs-level scope, threads and notify/wait semantics, endon/waittill
|
||||
discipline, undefined-value guards, the no-OOP/no-exceptions reality, asset precaching,
|
||||
per-frame cost, and the fact that GSC has no compiler, linter, or test harness worth the name.
|
||||
per-frame cost, block scoping, and compiling off-engine with gsc-tool.
|
||||
---
|
||||
|
||||
# GSC — Rules & Preferences
|
||||
@@ -13,10 +13,10 @@ Extends [`coding-dev.md`](skills-public/coding-dev.md). Everything there applies
|
||||
|
||||
GSC is the Call of Duty engine's own scripting language (`.gsc` server-side, `.csc`
|
||||
client-side). It is **not Lua, not JavaScript, and not C** despite resembling all three. It has
|
||||
no type system, no exceptions, no classes, no closures in most dialects, and — in a modded
|
||||
install — **no diagnostics beyond the in-game console**. That last fact drives most of what
|
||||
follows: the language will not tell you that you are wrong, so the code has to be written so
|
||||
that it cannot be.
|
||||
no type system, no exceptions, no classes, no closures in most dialects, and no test harness.
|
||||
It can be compiled off-engine (see §1), which catches syntax and scope errors — but nothing
|
||||
checks a type, a field that was never set, or a builtin that does not exist in the target title.
|
||||
So the code still has to be written so that it cannot be wrong.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Establish the dialect before writing anything.** IW3/IW4 (MW/MW2), IW5 (MW3), T5/T6 (Black
|
||||
@@ -27,18 +27,38 @@ that it cannot be.
|
||||
|
||||
---
|
||||
|
||||
## 1. There Is No Gate — Build One
|
||||
## 1. The Gate — `gsc-tool`, Then The Game
|
||||
|
||||
GSC has no `gsc -Wall`. What exists:
|
||||
**There is an off-engine GSC compiler: `gsc-tool`.** Reach for it first; it is
|
||||
easy to assume none exists and verify by loading a map instead.
|
||||
|
||||
```bash
|
||||
gsc-tool --mode comp --game <title> --system pc --dry path/to/script.gsc
|
||||
```
|
||||
|
||||
It exits non-zero and prints the engine's own diagnostic, e.g.
|
||||
`[ERROR]:compiler:script:97:25: local variable 'previous_count' not found`.
|
||||
|
||||
- **Use `--mode comp`, not `--mode parse`.** `parse` is syntax-only and happily
|
||||
accepts code the engine's compiler rejects, including the block-scope error
|
||||
above. `comp` with `--dry` writes nothing and does the real thing.
|
||||
- **`--game` must match the title**, and it is not the marketing name: MW2
|
||||
Campaign Remastered is `h2`, MWR is `h1`. The choices are `iw5 iw6 iw7 iw8
|
||||
iw9 s1 s2 s4 h1 h2 t6 t7 t8 t9 jup`. Wrong title, wrong builtin table.
|
||||
- Prebuilt binaries ship on its GitHub releases; there is no distro package.
|
||||
- Many mod trees already vendor it (Overlord has it under `deps/gsc-tool`).
|
||||
|
||||
What that still leaves:
|
||||
|
||||
| Check | How |
|
||||
| :--- | :--- |
|
||||
| **Syntax** | The engine's own compile at load. Read the console; a parse error names the file and line and then stops the whole script loading. |
|
||||
| **Syntax + semantics** | `gsc-tool --mode comp`. Put it in the build gate. |
|
||||
| **Builtin exists for this title** | `gsc-tool`'s own engine tables, e.g. `src/gsc/engine/h2_meth.cpp`. Grep before using a builtin you remember from another title. |
|
||||
| **Runtime errors** | In-game console / `developer 1`. Many mod loaders print a script stack trace. |
|
||||
| **Static lint** | Third-party only, and dialect-specific. Use one if it exists for the target title; otherwise there is none. |
|
||||
| **Tests** | None off-host. Behaviour is verified by playing the map. |
|
||||
|
||||
Therefore:
|
||||
So a compile is cheap and mandatory, and **behaviour is still unverified until
|
||||
the map runs.** Both halves matter:
|
||||
|
||||
- **`developer 1` (or the loader's equivalent) is mandatory during development.** Without it the
|
||||
engine suppresses script warnings and an undefined-value error looks like "the feature did
|
||||
@@ -48,7 +68,7 @@ Therefore:
|
||||
- **Instrument with `iprintln` / `iprintlnbold` / `println`** on the success *and* the failure
|
||||
path. A function that silently returns on a guard is indistinguishable from one that never ran.
|
||||
- **Say plainly in your report that GSC behaviour is unverified** unless you actually loaded the
|
||||
map and watched it. There is no test suite to hide behind.
|
||||
map and watched it. A clean `gsc-tool` compile proves the script loads, not that it works.
|
||||
|
||||
---
|
||||
|
||||
@@ -211,6 +231,11 @@ init()
|
||||
functions over reimplementing them. `maps\_utility` and `common_scripts\utility` already have
|
||||
flag, wait, and array helpers.
|
||||
- **`/* */` comments do not nest.** Commenting out a block that contains one breaks the file.
|
||||
- **A local declared inside a block is not visible after it.** Writing it in one `if` and reading
|
||||
it in a second does not compile — declare it unconditionally at function scope. Assigning
|
||||
`undefined` to an entity field unsets it, which is usually the right "restore nothing".
|
||||
- **No file-scope constants.** `MY_CONST = 0.2;` outside a function is not valid in most
|
||||
dialects; use a local at the point of use or a `level.` field set during init.
|
||||
- File and function size limits from the general rules apply, and matter more here than usual:
|
||||
there is no debugger worth the name, so a 300-line function is unanalysable.
|
||||
- **Delete dead code.** With no linter to flag it, commented-out GSC accumulates forever.
|
||||
|
||||
Reference in new issue
Block a user