Modding

Trader Compass

Wandering traders near you show on the compass. Range on Settings ▸ Mods. Console: traders.

Updated 11 Oct 2026

Wandering traders near you show on the compass. Range on Settings ▸ Mods. Console: traders.

Mod id example.tradercompass, side client.

A code mod: build it with dotnet build (see Making mods) and put the output folder in the game's Mods folder.

mod.json

{
    "id": "example.tradercompass",
    "name": "Trader Compass",
    "version": "1.1",
    "author": "Seeds & Circuits",
    "side": "client",
    "description": "Wandering traders near you show on the compass. Range on Settings ▸ Mods. Console: traders."
}

TraderCompass.cs

using System.Collections.Generic;
using System.Linq;
using SeedsAndCircuits.DebugConsole;
using SeedsAndCircuits.Mods;
using SeedsAndCircuits.Player;
using SeedsAndCircuits.Player.UI;
using SeedsAndCircuits.Town;
using UnityEngine;
using Compass = SeedsAndCircuits.Player.UI.Compass;   // UnityEngine has a Compass too (the device sensor)

namespace TraderCompass
{
    /// <summary>
    /// Shows wandering traders near the player on the compass, as gold diamonds. Side "client": it only changes this
    /// player's screen, so it works on any host (and a host offers it to players who join).
    /// </summary>
    public sealed class TraderCompass : Mod
    {
        static readonly Color Gold = new Color(1f, 0.78f, 0.25f, 1f);

        static ModSlider s_Range;
        Sprite _icon;
        Texture2D _texture;

        public override void OnLoad()
        {
            _icon = MakeDiamond(out _texture);
            // Settings ▸ Mods: how far away traders show.
            s_Range = AddSlider("range", "Show traders within (m)", 50f, 1000f, 300f, 50f);
            Compass.CollectMarkers += AddTraders;
        }

        public override void OnUnload()
        {
            Compass.CollectMarkers -= AddTraders;
            if (_icon != null)
                Object.Destroy(_icon);
            if (_texture != null)
                Object.Destroy(_texture);
        }

        void AddTraders(List<Compass.ExtraMarker> markers)
        {
            PlayerSpawn local = PlayerSpawn.Local;
            if (local == null)
                return;
            Vector3 me = local.Feet;
            foreach (TownNpc npc in NearbyTraders(me))
                markers.Add(new Compass.ExtraMarker(npc.transform.position, Gold, _icon));
        }

        /// <summary>Wandering traders (traders without a home) within range, nearest first.</summary>
        static IEnumerable<TownNpc> NearbyTraders(Vector3 from) =>
            TownNpc.All.Where(npc => npc != null && npc.HomeId == 0 && npc.Character != null && npc.Character.IsTrader &&
                                     (npc.transform.position - from).sqrMagnitude <= Range * Range)
                       .OrderBy(npc => (npc.transform.position - from).sqrMagnitude);

        static float Range => s_Range != null ? s_Range.Value : 300f;

        /// <summary>A small gold diamond, drawn in code (no image files needed).</summary>
        static Sprite MakeDiamond(out Texture2D texture)
        {
            const int size = 32;
            texture = new Texture2D(size, size, TextureFormat.RGBA32, false) { name = "Trader Diamond", filterMode = FilterMode.Bilinear };
            var pixels = new Color32[size * size];
            float c = (size - 1) * 0.5f;
            for (int y = 0; y < size; y++)
            {
                for (int x = 0; x < size; x++)
                {
                    float d = Mathf.Abs(x - c) + Mathf.Abs(y - c);
                    float a = Mathf.Clamp01(c - d);   // soft edge
                    pixels[y * size + x] = new Color(1f, 1f, 1f, a);
                }
            }
            texture.SetPixels32(pixels);
            texture.Apply();
            return Sprite.Create(texture, new Rect(0, 0, size, size), new Vector2(0.5f, 0.5f), 100f);
        }

        [ConsoleCommandAttribute("traders", "Wandering traders near you, nearest first.", Local = true)]
        static string List()
        {
            PlayerSpawn local = PlayerSpawn.Local;
            if (local == null)
                return "Not in a world.";
            List<TownNpc> traders = NearbyTraders(local.Feet).ToList();
            if (traders.Count == 0)
                return $"No wandering traders within {Range:0} m.";
            return string.Join("\n", traders.Select(npc =>
                $"{npc.NpcName}: {Vector3.Distance(npc.transform.position, local.Feet):0} m"));
        }

        [ConsoleCommandAttribute("traders.range", "How far away (m) traders show on the compass (also on Settings ▸ Mods).", Usage = "[meters]", Local = true)]
        static string RangeCommand(ConsoleArgs args)
        {
            if (args.Count > 0 && s_Range != null)
                s_Range.Value = args.Float(0);
            return $"Traders show within {Range:0} m.";
        }
    }
}

TraderCompass.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <!-- Build settings and game references: ../Mod.props. Output: bin/Trader Compass/ -->
  <PropertyGroup>
    <AssemblyName>TraderCompass</AssemblyName>
    <ModFolder>Trader Compass</ModFolder>
  </PropertyGroup>
  <Import Project="../Mod.props" />
</Project>