Coming from KSP modding¶
If you have written parts or weapons for Kerbal Space Program, most of your instincts transfer and three of them will actively mislead you. This page is the translation, and the three that mislead are named first.
It maps concepts — PartModule, ConfigNode, ModuleManager, GameData — that anyone who has
modded that game already knows. No mod's source was consulted or copied; these are the parts of
KSP's own API that every part author has used.
The short version¶
| In KSP | Here |
|---|---|
GameData/<Mod>/ scanned at startup |
mods/KSArmory/, listed in the user directory's manifest.toml |
.cfg in ConfigNode format |
XML — KSArmoryAssets.xml, KSArmoryGameData.xml |
PART { } |
<Part> and <SubPart> |
MODULE { name = X } binding a PartModule |
nothing. See below. |
| module fields tuned per part | LauncherProfile / MunitionProfile / SensorProfile, declared in a file in a mod's KSArmory/ folder |
ModuleManager patching (@, %, :NEEDS) |
nothing; there is no patch layer |
model.mu |
.glb, in a shared mesh atlas |
PartResource / resource flow |
nothing; ammunition is counted by the mod |
KSP's own Debug.Log |
Ksa/Log.cs, writing Logs/KSArmory.log |
The three that will mislead you¶
1. There is no PartModule¶
This is the big one, and everything else in the architecture follows from it.
KSA has no way for a mod to register a behaviour that the engine then calls on a part. Its per-frame update lists are internal and are not reachable without patching the game. So the KSP reflex — write a class, name it in a config, let the game drive it — has no equivalent.
What this mod does instead: the part is inert structure with mass and a collider.
Ksa/LauncherPart.cs looks for it on a vehicle by part Id, and Ksa/WeaponSystem.cs runs the
behaviour from the mod's own frame hook. A part is a thing to find, not a thing that acts.
The consequence you will feel: behaviour is not per-part-instance by default. If you want two
launchers on one craft to behave differently, that is something you build, not something the
engine gives you. Sim/SystemConfig.cs and Ksa/WeaponSystems.cs are that machinery.
docs/BLOCKED-ON-KSA.md lists this and everything else the mod wants and cannot have, with the
engine reason for each. If RocketWerkz ever ship a module system, that file is where the change
starts.
2. Rounds are not physics objects¶
In KSP a missile is a vessel: it has parts, colliders, and the physics engine moves it.
Here a round is a number integrated by the mod, drawn as a subpart body. That is deliberate —
see the design notes in CLAUDE.md — and it buys sub-frame fuse accuracy and an inability to
corrupt a save. Terrain collision is then something a round opts into rather than something it
gets: MunitionProfile.HitsTerrain costs a height-map sample per round per frame, so a bomb is
stopped by the ground and a cannon shell passes through a hill.
So: do not look for a rigidbody, and do not expect OnCollisionEnter. Guidance lives in
Sim/Interceptor.cs, is pure maths, and is tested headlessly with no game running at all.
3. Everything is in a heliocentric frame, and it is moving at 29.8 km/s¶
KSP gives you one origin that is, for practical purposes, still. KSA does not.
Positions are in the ecliptic frame. Earth is travelling at about 29.8 km/s through it, so a one-frame error in which instant two positions were sampled at is not a rounding error — it is ~500 m at 60 fps. It surfaces as a jitter, a constant offset, a guidance error or a drift, which are four disguises for one mistake.
Read docs/FRAMES-AND-EPOCHS.md before touching rounds, drawing or timing. It is not general
advice; it is the engine's actual contract, the rules that follow from it, and how to tell the
four failure shapes apart.
What is the same¶
- Parts are declared as data and reference assets by Id. The XML is stricter than
ConfigNode, but the shape is familiar: declare a mesh, declare a material, declare a part that uses them. - Art is separate from behaviour.
tools/model/generates the vehicle from a Blender script; nothing in the simulation names it. - A weapon system is data plus art. No fire-control, guidance or drive code names the Pantsir.
It is named in
src/KSArmory/KSArmory/Pantsir.xml, one of the mod's own definitions files, which is meant to.
Adding a weapon¶
In KSP this is a .cfg and a model, with no compiler. Here it is five steps, and step three is the
only one that can still want a rebuild:
- Model it. Copy
tools/model/pantsir.py, keep the group and pivot conventions, export into the same atlas.tools/model/checkmesh.pyfails the build on the two defects that are only visible in game. - Declare the part. A
<SubPart>per moving assembly plus a<Part>inKSArmoryAssets.xml, and a<PartGameData>with colliders and mass. - Define it. A
<Launcher>in a file insrc/KSArmory/KSArmory/, naming the<Munition>and<Sensor>it uses, with the geometrytools/model/build.shprints. It goes through the reader a third-party pack uses. - Teach the validator.
tools/validate-parts.pycompares the profile's geometry againstmuzzles.json, and it is scoped per launcher — a new one gets no check until you add it. The generator emitting those numbers and the profile holding them are the same numbers in two files, and geometry duplicated across a boundary drifts unless something reads it back. - Nothing else.
LauncherPart.Findmatches every registered part Id and the weapon system selects whichever profile it finds.ArsenalTestschecks the registry hangs together, andvalidate-parts.pyalso checks that every registeredPartIdis declared in the XML.
A launcher that does not train is the same profile with TurretMarker and PodsMarker left
null. The drives are then skipped and IsLaid stays true, so fire control cannot deadlock waiting
for something that will never move.
The step that no longer needs a compiler¶
LauncherProfile and friends are pure data with no logic in them — C# object initialisers,
with nothing about them that requires code — so they are also expressible as a file.
Sim/PackReader.cs reads them out of XML and Ksa/InstalledPacks.cs finds that XML in a
KSArmory/ folder inside every installed mod, this mod included. A whole weapon system is then art
plus a file, with nothing to compile and no fork of this repository, which is the workflow you are
used to. docs/WEAPON-PACKS.md is the author's reference; docs/EXTENSIBILITY.md is why it looks
the way it does.
The constraint that shaped it is the one under What you do not need: Sim/ must stay free of KSA
types, so the reader takes a string and the file is found by Ksa/.
Where the rules are written down¶
| Read this | Before |
|---|---|
docs/FRAMES-AND-EPOCHS.md |
touching rounds, drawing or timing |
docs/KSA-MODDING-NOTES.md |
anything that calls into KSA |
docs/BLOCKED-ON-KSA.md |
proposing a feature that needs an engine hook |
CLAUDE.md |
committing — the message format is enforced and decides releases |
CONTRIBUTING.md |
setting up: ./tools/doctor.sh tells you what is missing |
Two rules that are not negotiable:
- A behaviour fix is unverified until it has been flown. Compiling, passing the suite and having a plausible mechanism are not evidence. The hardest bugs here live in the gap between the maths and what KSA actually does, and that gap is only visible in flight.
- A regression test only counts if it fails against the old code. Check that it does, every
time. A test that advances the platform by exactly the
v*dtit passes in cancels its own error and passes against the broken implementation too, which looks like proof and is worth nothing.
What you do not need¶
You do not need the game running, Blender, or a Windows box. Everything under
src/KSArmory/Sim/ is free of KSA types by construction: the test project links it wholesale and
references no KSA assembly, so a using KSA; there fails the test build. Guidance, fuses, threat
modelling, lead solutions, IFF and the drives all live there and fly whole engagements headlessly.
What you do still need is KSA's assemblies, even for that half: double3 comes from
Brutal.Numerics.dll, so the test project references it and tools/test.sh will not run
without it. ./tools/doctor.sh says what is missing and how to get it.
That is the easiest place to start, and the tests will tell you the truth without the game installed.