Treasure chest of Unity developer tools. Professional inspector tooling, high-performance utilities, spatial queries, and 20+ editor tools.
Protect your data with declarative validation and read-only presentation.
Unity Helpers provides validation attributes that help maintain data integrity and prevent accidental modifications. These attributes work seamlessly with the Unity inspector and can validate fields at runtime.
Displays a field in the inspector as read-only, preventing accidental modifications while keeping the value visible.
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class GameManagerReadOnly : MonoBehaviour
{
[WReadOnly]
public string sessionId = "abc-123-xyz";
[WReadOnly]
public float elapsedTime = 0f;
[WReadOnly]
[SerializeField]
private int internalScore = 100;
}
Behavior:
Visual Reference
Fields marked with [WReadOnly] appear grayed out and cannot be edited
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class EntityReadOnly : MonoBehaviour
{
// Auto-generated unique identifier
[WReadOnly]
public string entityId = System.Guid.NewGuid().ToString();
// Computed property exposed for debugging
[WReadOnly]
[SerializeField]
private float _currentHealth;
// Reference that should only be set via code
[WReadOnly]
public Transform cachedTarget;
// Frame counter for debugging
[WReadOnly]
public int framesSinceLastUpdate;
}
Why Use WReadOnly:
Visual Reference
Multiple field types (string, float, Transform, int) displayed as read-only
Validates that a field is not null, providing both visual inspector feedback and runtime validation. When a field marked with [WNotNull] is null, the inspector displays a warning or error HelpBox. Additionally, calling CheckForNulls() on an object will throw an ArgumentNullException for any null [WNotNull] fields.
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class PlayerControllerNotNull : MonoBehaviour
{
[WNotNull]
public Rigidbody2D rb;
[WNotNull]
public SpriteRenderer spriteRenderer;
[WNotNull]
[SerializeField]
private AudioSource audioSource;
private void Awake()
{
// Validates all [WNotNull] fields are assigned
// Throws ArgumentNullException if any are null in Editor ONLY
this.CheckForNulls();
}
}
Behavior:
this.CheckForNulls() to validate all [WNotNull] fieldsArgumentNullException with the field name if any marked field is nullObject types and plain C# objectsVisual Reference
Fields marked with [WNotNull] display a HelpBox in the inspector when null
The WNotNullMessageType enum controls how null fields are displayed in the inspector:
| Value | Description |
|---|---|
Warning |
Displays a yellow warning HelpBox (default) |
Error |
Displays a red error HelpBox |
The [WNotNull] attribute supports multiple constructor overloads for flexibility:
// Default: warning message type with auto-generated message
[WNotNull]
public GameObject target;
// Inspector shows: "target must be assigned"
// Error message type with auto-generated message
[WNotNull(WNotNullMessageType.Error)]
public AudioSource criticalAudioSource;
// Inspector shows red error: "criticalAudioSource must be assigned"
// Warning with custom message
[WNotNull("Player needs a target to attack")]
public Transform attackTarget;
// Inspector shows yellow warning: "Player needs a target to attack"
// Error with custom message
[WNotNull(WNotNullMessageType.Error, "Audio source is required for sound effects")]
public AudioSource audioSource;
// Inspector shows red error: "Audio source is required for sound effects"
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class EnemyAI : MonoBehaviour
{
// Yellow warning - nice to have
[WNotNull]
public ParticleSystem hitEffect;
// Red error - critical reference
[WNotNull(WNotNullMessageType.Error)]
public Transform patrolPath;
// Warning with helpful context
[WNotNull("Assign the player tag or the enemy won't detect the player")]
public string playerTag;
// Error with specific instructions
[WNotNull(WNotNullMessageType.Error, "Drag the NavMeshAgent component here - required for movement")]
public UnityEngine.AI.NavMeshAgent agent;
}
Visual Reference
Warning (yellow) and Error (red) HelpBoxes for null fields in the inspector
The CheckForNulls() extension method validates all [WNotNull] fields at runtime:
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class EnemySpawner : MonoBehaviour
{
[WNotNull]
public GameObject enemyPrefab;
[WNotNull]
public Transform spawnPoint;
[WNotNull(WNotNullMessageType.Error)]
public EnemyManager enemyManager;
private void Start()
{
// If any [WNotNull] field is null, this throws with the field name
// Example: ArgumentNullException("enemyPrefab")
this.CheckForNulls();
// Safe to use - we know these are assigned
SpawnEnemy();
}
private void SpawnEnemy()
{
GameObject enemy = Instantiate(enemyPrefab, spawnPoint.position, Quaternion.identity);
enemyManager.RegisterEnemy(enemy);
}
}
Both the inspector HelpBox display and the CheckForNulls() extension method are only active in the Unity Editor:
// The validation code only runs in UNITY_EDITOR
// In builds, CheckForNulls() does nothing (stripped for performance)
this.CheckForNulls();
This means:
public class UIManager : MonoBehaviour
{
// Required reference with error severity - validated at runtime
[WNotNull(WNotNullMessageType.Error)]
[SerializeField]
private Canvas mainCanvas;
// Optional reference - not validated
[SerializeField]
private AudioSource clickSound;
// Read-only and required
[WReadOnly]
[WNotNull]
public RectTransform cachedRect;
// Group with validation and custom message
[WGroup("UI Elements")]
[WNotNull("Start button required for main menu")]
public Button startButton; // In group
[WNotNull(WNotNullMessageType.Error, "Quit button required for main menu")]
[WGroupEnd("UI Elements")] // quitButton IS included, then closes
public Button quitButton; // In group (last field)
}
Why Use WNotNull:
CheckForNulls(), not when first usedValidates that a field is properly assigned, providing visual inspector feedback when validation fails. Unlike [WNotNull] which only checks for null references, [ValidateAssignment] validates that fields are “properly assigned” based on their type—including checking for empty strings, empty collections, and null references.
| Field Type | Validation Rule |
|---|---|
Unity Object references |
Not null |
| Strings | Not null or whitespace |
IList (arrays, List |
Has at least one element |
ICollection |
Has at least one element |
IEnumerable |
Has at least one element |
| Other types | Not null |
using System.Collections.Generic;
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class EnemySpawner : MonoBehaviour
{
[ValidateAssignment]
public GameObject enemyPrefab;
[ValidateAssignment]
public string enemyName;
[ValidateAssignment]
public List<Transform> spawnPoints;
private void Start()
{
// Logs warnings for any invalid [ValidateAssignment] fields
this.ValidateAssignments();
}
}
Behavior:
this.ValidateAssignments() to log warnings for invalid fieldsthis.AreAnyAssignmentsInvalid() to check if any fields are invalidObject types, strings, collections, and any reference typeVisual Reference
Fields marked with [ValidateAssignment] display a HelpBox in the inspector when invalid
The ValidateAssignmentMessageType enum controls how invalid fields are displayed in the inspector:
| Value | Description |
|---|---|
Warning |
Displays a yellow warning HelpBox (default) |
Error |
Displays a red error HelpBox |
The [ValidateAssignment] attribute supports multiple constructor overloads for flexibility:
// Default: warning message type with auto-generated message
[ValidateAssignment]
public GameObject target;
// Inspector shows: "target must be assigned"
// Error message type with auto-generated message
[ValidateAssignment(ValidateAssignmentMessageType.Error)]
public AudioSource criticalAudioSource;
// Inspector shows red error: "criticalAudioSource must be assigned"
// Warning with custom message
[ValidateAssignment("Enemy name is required for UI display")]
public string enemyName;
// Inspector shows yellow warning: "Enemy name is required for UI display"
// Error with custom message
[ValidateAssignment(ValidateAssignmentMessageType.Error, "Spawn points list cannot be empty")]
public List<Transform> spawnPoints;
// Inspector shows red error: "Spawn points list cannot be empty"
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
using System.Collections.Generic;
public class GameConfig : MonoBehaviour
{
// Yellow warning - validates not null
[ValidateAssignment]
public GameObject playerPrefab;
// Red error - validates string not empty/whitespace
[ValidateAssignment(ValidateAssignmentMessageType.Error)]
public string gameTitle;
// Warning with helpful context - validates list not empty
[ValidateAssignment("Add at least one difficulty level")]
public List<string> difficultyLevels;
// Error with specific instructions - validates array not empty
[ValidateAssignment(ValidateAssignmentMessageType.Error, "Spawn points are required - add Transform references")]
public Transform[] spawnPoints;
}
Visual Reference
Warning (yellow) and Error (red) HelpBoxes for various invalid field types
Two extension methods are available for runtime validation of [ValidateAssignment] fields:
Logs warnings to the console for all invalid fields:
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class LevelManager : MonoBehaviour
{
[ValidateAssignment]
public GameObject[] enemyPrefabs;
[ValidateAssignment]
public string levelName;
private void Start()
{
// Logs a warning for each invalid [ValidateAssignment] field
this.ValidateAssignments();
}
}
Returns true if any [ValidateAssignment] field is invalid:
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class SpawnManager : MonoBehaviour
{
[ValidateAssignment]
public GameObject spawnPrefab;
[ValidateAssignment]
public List<Transform> spawnLocations;
private void Start()
{
if (this.AreAnyAssignmentsInvalid())
{
Debug.LogError("SpawnManager has invalid assignments - spawning disabled");
enabled = false;
return;
}
// Safe to proceed - all assignments are valid
SpawnEnemies();
}
}
Both attributes validate fields and provide inspector feedback, but they serve different purposes:
| Feature | ValidateAssignment | WNotNull |
|---|---|---|
| Null object check | ✓ | ✓ |
| Empty string check | ✓ | ✗ |
| Empty collection check | ✓ | ✗ |
| Runtime behavior | Logs warnings | Throws ArgumentNullException |
| Best for | Comprehensive field validation | Strict null reference checking |
When to use which:
[ValidateAssignment] when you need to validate that strings are non-empty or collections have elements[WNotNull] when you want strict null checking with an exception thrown at runtime[ValidateAssignment] when you want softer runtime validation (warnings instead of exceptions)[WNotNull] for critical references where the game should fail fast if not assignedpublic class PlayerSetup : MonoBehaviour
{
// Use WNotNull for critical references - throws if null
[WNotNull(WNotNullMessageType.Error)]
public Rigidbody2D rb;
// Use ValidateAssignment for string validation
[ValidateAssignment]
public string playerName;
// Use ValidateAssignment for collection validation
[ValidateAssignment(ValidateAssignmentMessageType.Error, "Add at least one weapon")]
public List<GameObject> startingWeapons;
private void Awake()
{
// Throws ArgumentNullException if rb is null
this.CheckForNulls();
// Logs warnings if playerName is empty or startingWeapons is empty
this.ValidateAssignments();
}
}
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
using System.Collections.Generic;
public class UIManager : MonoBehaviour
{
// Group with validation
[WGroup("Required UI Elements")]
[ValidateAssignment(ValidateAssignmentMessageType.Error)]
public Canvas mainCanvas; // In group
[ValidateAssignment("Button text cannot be empty")]
public string startButtonText; // In group (auto-included)
[ValidateAssignment(ValidateAssignmentMessageType.Error, "Add menu items to display")]
[WGroupEnd("Required UI Elements")] // menuItems IS included, then closes
public List<GameObject> menuItems; // In group (last field)
// Conditional validation
[WShowIf(nameof(useCustomTheme))]
[ValidateAssignment("Custom theme name required when using custom theme")]
public string customThemeName;
public bool useCustomTheme;
}
Why Use ValidateAssignment:
ValidateAssignments() for warnings instead of exceptionsAreAnyAssignmentsInvalid() for conditional logicCall CheckForNulls() and ValidateAssignments() in Awake() or Start() to catch missing references immediately:
private void Awake()
{
// Throws for critical null references
this.CheckForNulls();
// Logs warnings for empty strings, collections, etc.
this.ValidateAssignments();
}
// Use WNotNull for critical object references (throws on null)
[WNotNull(WNotNullMessageType.Error)]
public Rigidbody2D rb;
// Use ValidateAssignment for strings (validates not empty/whitespace)
[ValidateAssignment]
public string playerName;
// Use ValidateAssignment for collections (validates not empty)
[ValidateAssignment(ValidateAssignmentMessageType.Error)]
public List<Transform> waypoints;
[WReadOnly]
public float Speed => rb.velocity.magnitude;
// Auto-wired but protected from manual changes
[WReadOnly]
[SiblingComponent]
public Collider2D col;
// Required: Must be assigned in inspector
[WNotNull]
public AudioClip attackSound;
// Required: Must not be empty
[ValidateAssignment]
public string characterName;
// Optional: May be null
public AudioClip hitSound;
[CreateAssetMenu]
public class GameConfig : ScriptableObject
{
[WNotNull]
public GameObject playerPrefab;
[WNotNull]
public Material defaultMaterial;
[ValidateAssignment("Game title cannot be empty")]
public string gameTitle;
[ValidateAssignment(ValidateAssignmentMessageType.Error)]
public List<string> supportedLanguages;
private void OnEnable()
{
this.CheckForNulls();
this.ValidateAssignments();
}
}