S&box Wiki

Hammer API

We advise against using this. It may be changed or removed in a future update. Hammer will be replaced with an in-scene mesh editor
This stuff isn't as mature as our games API, so this stuff will end up changing a fair amount as we figure out the best way to do things.

Hammer API

Tool addons can extend the capabilities of Hammer by using these APIs, you can interact with selected map nodes or procedurally create new map nodes. These nodes can be a MapMesh which can procedurally create a mesh, MapEntity for placing map entities and setting key values, or more.

Map Nodes

Map nodes can be created in the current map simply by calling their constructors.

// Create new map entity MapEntity entity = new(); entity.ClassName = "info_player_start"; entity.Position = Vector3.Up * 32.0f;

Selection

You can get all the selected map nodes, or set the selection with the Selection static class.

// Get the first selected map node MapNode node = Selection.All.FirstOrDefault(); // You can pattern match MapNodes if ( node is MapMesh mesh ) { // ... } // Create a new entity and add it to the selection Selection.Add( new MapEntity() );

Traces

The Trace API lets you ray cast within map worlds, there's options to only hit meshes or skip tools materials. This primarily has usage for pickers, but could be used to snap things down or some crazy procedural stuff.

view.BuildRay( out Vector3 rayStart, out Vector3 rayEnd ); var tr = Trace.Ray( rayStart, rayEnd ).Run( view.MapDoc.World ); var entity = new MapEntity(); entity.ClassName = classname; entity.Position = tr.HitPosition; Selection.Set( entity );

Map View Context Menu

You can extend the context menu in Hammer with the hammer.mapview.contextmenu event.

[Event( "hammer.mapview.contextmenu" )] static void OnMapViewContextMenu( Menu menu, MapView view ) { menu.AddSeparator(); var submenu = menu.AddMenu( "Create Point Entity" ); // ... }
image.png

Adding Menu Bar

Menus can be added to the menu bar in Hammer the same as other tools

[Menu( "Hammer", "My Cool Stuff/Log Selected", "info" )] public static void LogSelected() { Log.Info( Selection.All.First() ); }

Primitive Builders

You can add new primitives to the block tool.

[Title( "Rect" ), Icon( "rectangle" )] class RectPrimitive : PrimitiveBuilder { [Browsable( false )] public BBox BBox { get; set; } public override void SetFromBox( BBox box ) => BBox = box; public override void Build( PolygonMesh mesh ) { var mins = BBox.Mins; var maxs = BBox.Maxs; mesh.AddFace( new Vector3( mins.x, mins.y, maxs.z ), new Vector3( maxs.x, mins.y, maxs.z ), new Vector3( maxs.x, maxs.y, maxs.z ), new Vector3( mins.x, maxs.y, maxs.z ) ); } }

Map Drop Targets

Map drop targets enable you to create handlers for your own asset types.

Here's how we enable you to drop soundscapes into maps:

[CanDrop( "sndscape" )] class SoundscapeDropTarget : IMapViewDropTarget { MapEntity SoundEntity { get; set; } public void DragEnter( Asset asset, MapView view ) { SoundEntity = new MapEntity(); SoundEntity.ClassName = "snd_soundscape"; SoundEntity.SetKeyValue( "soundscape", asset.Path ); } public void DragMove( MapView view ) { view.BuildRay( out Vector3 rayStart, out Vector3 rayEnd ); var tr = Trace.Ray( rayStart, rayEnd ).Run( view.MapDoc.World ); SoundEntity.Position = tr.HitPosition; } }