Prototype: instance scripts as dropped-in .csx - #2374
Draft
erwan-joly wants to merge 1 commit into
Draft
Conversation
A prototype of the authoring half, to judge before committing to a format. Instance content is not declarative. The vocabulary this game's instances have always used is thirteen triggers - OnDeath, OnTimeout, OnAreaEntry, OnLockerOpen and the rest - and about twenty-six actions: SummonMonster, SpawnPortal, SetMonsterLockers, StartClock, End. That is an event tree, and XML or YAML would each end up an invented DSL around it. Scripts drop into instances/ as .csx and are compiled on first entry, never at boot: Roslyn costs 1352ms to warm up and about 85ms a script afterwards, so compiling all hundred-odd at startup would be eleven seconds for nothing. Measured here, a cold load is 63ms and the second is 0ms. IInstanceRun is the whole design. The script only ever calls those verbs, so the engine behind it stays swappable - Jint or NLua would bind to the same interface without remodelling anything. Scripts are testable, which is the point of choosing csx over a scripting language: CsxInstanceScriptTests drives the dropped-in file against a recording run and asserts the exact sequence it asks for, including that a broken script fails at load rather than opening a door onto an empty room.
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueThanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft, to judge the authoring format before committing to one. Nothing here is wired into the server yet.
Why not a data format
Instance content is not declarative. The vocabulary these instances have always used is thirteen triggers —
OnDeath,OnTimeout,OnAreaEntry,OnLockerOpen,OnMapClean,OnFirstEnable… — and about twenty-six actions:SummonMonster,SpawnPortal,SetMonsterLockers,ChangePortalType,StartClock,RefreshRaidGoals,End.That is an event tree. YAML or XML around it becomes an invented DSL with conditionals and sequencing — the GitHub-Actions problem — and neither gives any checking of the VNums and enums this codebase leans on.
Why .csx rather than Lua or JS
Sandboxing is the only axis where a scripting language wins, and it only matters if packs come from someone other than you. Against that,
.csxgives type safety and IntelliSense over ~40 verbs, and — the part that decided it for me — scripts stay testable.Worth knowing before reaching for Lua: MoonSharp, the library most people pick, last shipped in 2016. NLua is alive but needs per-platform native binaries; Jint is alive and pure-managed, and remains the right choice if untrusted content ever becomes a requirement.
IInstanceRunis deliberately the only thing a script touches, so swapping engine is a binding change, not a redesign.The startup objection, measured and removed
Roslyn scripting costs 1352 ms to warm up and ~85 ms per script after. Compiling ~114 instances at boot would be about eleven seconds for no benefit.
So scripts compile on first entry and are cached. Measured in
CompilingIsPaidOnceThenCached: cold 63 ms, warm 0 ms. Invisible to the player who opens the door.What is here
IInstanceRun— the verbs. This is the actual design; the engine behind it is swappable.InstanceScript— a base so a script overrides only the triggers it uses, the way real definitions omit what they do not have.CsxInstanceScriptLoader— lazy, cached, and fails loudly at load with the compiler diagnostics rather than opening a door onto an empty room.instances/timespace-01.csx— a time-space in 47 lines: clock, three monsters behind a locker, portal unlocked on clear, boss, success.Tests
Six, driving the dropped-in file against a recording run and asserting the exact sequence of calls — including that a broken script throws at load. This is the argument for csx: instance content is testable with the same harness as everything else, which for wave and timer logic is worth more than sandboxing.
Open questions
wp/gpgeneration and the run lifecycle — none of which cares what format the definition came from.