Lua scripting SDK for HammerTime (a Sledge-based GoldSrc map editor).
Snippets instead of buttons. Batch entity/KV operations, map linting, texture work and geometry helpers in 5–60 lines of Lua — without writing, deploying and maintaining a native C# plugin for every idea.
Editor.Transaction("Rename sky", function()
Map.World.skyname = "desert"
end)dev — the core is functional and covered by a smoke test: transactions with
atomic commit/rollback, hybrid KV dot-notation, staging, stale-object protection,
texture-locked transforms, entity origin editing. Vertex-level operations work
but are considered experimental — see Editor limitations.
- Build the project against a HammerTime source tree (the
.csprojreferences..\Sledge.*projects; the editor's DLLs are expected next toHammerTime.exe). - Copy
HammerTime.Lua.dllandMoonSharp.Interpreter.dllnext toHammerTime.exe(required by MEF plugin discovery). - Copy the
scripts/folder toplugins/HammerTime.Lua/scripts/:
<HammerTime root>
├── HammerTime.exe
├── HammerTime.Lua.dll
├── MoonSharp.Interpreter.dll
└── plugins/
└── HammerTime.Lua/
└── scripts/
├── libs/include/core.lua SDK stdlib (safe, each, dump) — auto-injected
├── autoload/ resident scripts, run at editor startup
├── examples/ shipped examples (see below)
├── tests/ SmokeTest.lua — run it after building
└── user/ your snippets
A flat scripts/ folder next to the DLL also works as a fallback.
Tools → Lua → Run Script... opens a picker listing every script under
scripts/ (except libs/), with a filter box; double-click to run. Scripts in
autoload/ run automatically at startup and stay resident (kill switch in
Settings → Tools/Plugins → Lua SDK).
Every map modification must happen inside a transaction — atomic, one Undo entry:
Editor.Transaction("My change", function()
-- writes go here
end)| Global | Purpose |
|---|---|
Editor |
Transactions, logging, event subscription (On/Subscribe) |
Map |
Object lookup: Find(fn), FindByClass, FindByTargetName, World |
Selection |
GetObjects(), GetEntities(), GetSolids() |
Grid |
Spacing, Snap(v), Translate(v, dir, steps) |
Providers |
Brush creation via the editor's brush generators |
Plugin |
Script metadata (Name, Version) |
Core / HT |
Stdlib: safe(fn), each(list, fn), dump(obj) |
Entity keyvalues read and write through dot-notation: ent.targetname,
ent.skyname = "desert". Reserved fields (ID, ClassName, Origin, KV,
BoundingBox, IsStale) are accessed as properties; use ent.KV:Set(...) for
a KV that collides with a reserved name.
| Script | What it shows |
|---|---|
MapLint.lua |
Read-only linter: broken target/killtarget/master links, duplicate targetnames |
RenameChain.lua |
Rename a targetname and every reference to it in one atomic transaction |
ReplaceTexture.lua |
Mass texture replace on the selection (or the whole map) |
SnapToGrid.lua |
Snap all vertices of selected solids to the current grid |
WeldVertices.lua |
Cluster and weld nearby vertices across selected solids |
Warning
Reopening any format in Sledge/HammerTime triggers destructive solid
reconstruction: saved vertices are recalculated from face planes (which are
themselves derived from the first three vertices of each face). Off-grid
vertex edits may not survive a save/reload cycle. On-grid (integer) geometry
survives losslessly — prefer grid-aligned operations (SnapToGrid.lua
exists for exactly this), and use .rmf to transfer geometry between editors.
Also note: the editor rounds entity angles to whole degrees on any
transform, including pure translation — moving an entity with fractional angles
loses that precision. This is engine behaviour, not specific to Lua.
MIT