codeAPI Reference
ToolMode Base Class for Toolgun Modes
ToolMode Base Class
Abstract base class for creating toolgun modes in s&box. Handles input registration, action dispatch, and HUD rendering.
Class Overview
CSHARP
public abstract partial class ToolMode : Component, IToolInfo
{
public Toolgun Toolgun => GetComponent<Toolgun>();
public Player Player => GetComponentInParent<Player>();
/// <summary>
/// The mode should set this true or false in OnControl to indicate if the current state is valid.
/// </summary>
public bool IsValidState { get; protected set; } = true;
/// <summary>
/// When true, the toolgun absorbs mouse input so the camera doesn't move.
/// </summary>
public virtual bool AbsorbMouseInput => false;
/// <summary>
/// Display name for the tool, defaults to TypeDescription title.
/// </summary>
public virtual string Name => Game.Language.GetPhrase((TypeDescription?.Title ?? GetType().Name).TrimStart('#'));
/// <summary>
/// Tags that TraceSelect will ignore. Defaults to "player".
/// </summary>
public virtual IEnumerable<string> TraceIgnoreTags => ["player"];
/// <summary>
/// When true, TraceSelect will also hit hitboxes.
/// </summary>
public virtual bool TraceHitboxes => false;
}Action Registration
CSHARP
protected void RegisterAction(ToolInput input, Func<string> name, Action callback, InputMode mode = InputMode.Pressed)
{
if (IsProxy) return;
_actions.Add(new ToolActionEntry(input, name, callback, mode));
}
// Example usage in a derived class:
protected override void OnStart()
{
base.OnStart();
RegisterAction(ToolInput.Primary, () => "Create", OnCreatePressed);
RegisterAction(ToolInput.Secondary, () => "Remove", OnRemovePressed, InputMode.Down);
}Object Tracking
CSHARP
/// <summary>
/// Track a GameObject created by this tool action for post-action events.
/// </summary>
protected void Track(params GameObject[] objects)
{
foreach (var go in objects)
{
if (go.IsValid())
_createdObjects.Add(go);
}
}
// Usage:
void OnCreatePressed()
{
var prop = Prefab.Clone(WorldTransform);
Track(prop); // Tracked for IToolActionEvents
}Screen Display (Toolgun Screen)
CSHARP
public virtual void DrawScreen(Rect rect, HudPainter paint)
{
var title = Game.Language.GetPhrase(TypeDescription.Title.TrimStart('#'));
var t = $"{TypeDescription.Icon} {title}";
var text = new TextRendering.Scope(t, Color.White, 64);
text.LineHeight = 0.75f;
text.FontName = "Poppins";
text.TextColor = Color.Orange;
text.FontWeight = 700;
// Auto-scroll (marquee) if text is too wide
var measured = text.Measure();
if (measured.x <= rect.Width)
{
paint.DrawText(text, rect, TextFlag.Center);
}
else
{
const float scrollSpeed = 80f;
const float gap = 60f;
float cycle = measured.x + gap;
float offset = (Time.Now * scrollSpeed) % cycle;
// Draw scrolling text...
}
}Cookie Persistence
ToolModes automatically save/load settings via cookies:
CSHARP
protected override void OnEnabled()
{
if (Network.IsOwner)
this.LoadCookies(); // Loads saved settings
}
protected override void OnDisabled()
{
if (Network.IsOwner)
this.SaveCookies(); // Saves current settings
}Stats Integration
CSHARP
[Rpc.Owner]
protected void CheckContraptionStats(GameObject anchor)
{
var builder = new LinkedGameObjectBuilder();
builder.AddConnected(anchor);
var wheels = builder.Objects.Sum(o => o.GetComponentsInChildren<WheelEntity>().Count());
var thrusters = builder.Objects.Sum(o => o.GetComponentsInChildren<ThrusterEntity>().Count());
Sandbox.Services.Stats.SetValue("tool.contraption.wheel", wheels);
Sandbox.Services.Stats.SetValue("tool.contraption.thruster", thrusters);
}
Was this helpful?