Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions skills/tilemap-palette-gridpaintingstate/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
name: tilemap-palette-gridpaintingstate
description: Manages Tile Palette painting states. Use when working with Tile Palette painting targets, brushes, palettes, or responding to painting state changes (active Grid Brush, active Target, etc.).
required_packages:
com.unity.2d.tilemap: ">=1.0.0"
modes: [agent]
---

# Tile Palette Grid Painting State

## Step 0: Confirm you can run C# in the Editor

`GridPaintingState` and `GridPaintPaletteWindow` are Editor-only types that describe the
*live* state of the Tile Palette window. Nothing on disk holds that state, so this skill
needs an Editor it can execute C# in.

**The `unity-cli` skill owns getting you there** — installing the CLI, confirming a connected
Editor, adding the project's `com.unity.pipeline` package, telling a genuinely absent Editor
apart from one stuck in Safe Mode, and discovering the Editor's command catalog. Follow it
first; don't re-derive any of it here.

Two things it can't know for you:

- **You need `eval` in particular**, not just a reachable Editor. Confirm it appears in the
catalog. Its presence depends on the Pipeline package version, not on the CLI — if it's
missing, say so and stop.
- **These types live in `UnityEditor.Tilemaps` and some are internal.** `eval` does reach
them (measured), so use them directly — only fall back to reflection if a compile error
actually reports a visibility problem.

Run C# through the connected Editor with the `eval` command. Discover its parameter shape
from `unity command --format json` rather than assuming one — the inline form is
`unity command eval --code '<snippet>'`, and some Pipeline versions also register
`eval_file` for running a snippet from a file. **Check the catalog before reaching for
`eval_file`; it is frequently absent.** `unity command` defaults to a 30 second timeout.

### Passing C# to `eval`

`eval` compiles a **statement block, not a file**. Two consequences, both of which cause a
compile error rather than a warning:

- **No `using` directives.** The compiler reads `using UnityEngine;` as a resource-disposal
statement and rejects it (`CS0210`).
- **Types must be fully qualified.** A bare `AssetDatabase` or `Volume` does not resolve
(`CS0246` / `CS0103`), and a bare `Object` is ambiguous with `object` (`CS0104`).

Where a snippet below is written as a file — with usings, for readability, or because it is
meant to be saved into the project — qualify the types before passing it to `eval`.

## Workflow

### Step 1: Pre-Flight Check
Ensure that the Tile Palette Window is open using:
```csharp
UnityEditor.EditorWindow.GetWindow<UnityEditor.Tilemaps.GridPaintPaletteWindow>();
```

Do not use `MenuItem` patterns to open the Tile Palette Window.

### Step 2: Generate and Execute Script
Create a script using the core pattern, run it through the Editor as described in Step 0,
and report the results.

### Step 3: Validate Results
Check the Unity console for errors and verify changes in the Project window.

### Step 4: Iterate (Max 3 Times)
If errors occur, fix and re-execute. After 3 attempts, **WAIT** for user guidance.

## Reference

**API Reference**: [references/references.md](references/references.md)

## Important Notes

- Always include a pre-flight check in generated scripts.
- Do NOT use `AssetDatabase` patterns for retrieving available assets such as palettes and brushes. Use the existing methods in GridPaintingState to retrieve them.
- Generate standalone snippets only — no `MenuItem`, no `AssetPostprocessor`. Return the
values you need to read; logs land in the Editor console.
- **Enum assignments:** Always use enum values and cast to numeric types. Never use raw numbers.
- ✅ Correct: `(int)SpriteAlignment.Center`
- ❌ Wrong: `1` (magic number)
189 changes: 189 additions & 0 deletions skills/tilemap-palette-gridpaintingstate/references/references.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# GridPaintingState Public API

`GridPaintingState` is a `ScriptableSingleton<GridPaintingState>` in `UnityEditor.Tilemaps` that controls the state of objects for painting with a Tile Palette.

**Source:** `Packages/com.unity.2d.tilemap/Editor/GridPaintingState.cs`

## Events

All events are static and can be subscribed to for monitoring painting state changes.

| Event | Type | Description |
|-------|------|-------------|
| `scenePaintTargetChanged` | `Action<GameObject>` | Fired when the active paint target changes |
| `scenePaintTargetEdited` | `Action<GameObject>` | Fired when the active paint target is edited |
| `brushChanged` | `Action<GridBrushBase>` | Fired when the active brush changes |
| `brushPickChanged` | `Action` | Fired when the brush's selection changes |
| `brushPickStoreChanged` | `Action` | Fired when the brush pick store changes |
| `brushToolsChanged` | `Action` | Fired when brush tools change |
| `beforePaletteChanged` | `Action` | Fired before the active palette changes |
| `paletteChanged` | `Action<GameObject>` | Fired when the active palette changes |
| `palettesChanged` | `Action` | Fired when the list of palettes changes |
| `validTargetsChanged` | `Action` | Fired when valid paint targets change |
| `editModeChanged` | `Action` | Fired when edit mode state changes |

**Example - Subscribing to events:**
```csharp
void OnEnable()
{
GridPaintingState.scenePaintTargetChanged += OnTargetChanged;
GridPaintingState.brushChanged += OnBrushChanged;
}

void OnDisable()
{
GridPaintingState.scenePaintTargetChanged -= OnTargetChanged;
GridPaintingState.brushChanged -= OnBrushChanged;
}

void OnTargetChanged(GameObject newTarget)
{
Debug.Log($"Paint target changed to: {newTarget?.name}");
}

void OnBrushChanged(GridBrushBase newBrush)
{
Debug.Log($"Brush changed to: {newBrush?.name}");
}
```

## Properties

### Paint Target

| Property | Type | Access | Description |
|----------|------|--------|-------------|
| `scenePaintTarget` | `GameObject` | get/set | The currently active painting target in the scene |
| `validTargets` | `GameObject[]` | get | All valid GameObjects that can be set as paint targets |

### Brush

| Property | Type | Access | Description |
|----------|------|--------|-------------|
| `gridBrush` | `GridBrushBase` | get/set | The currently active brush for painting |
| `brushes` | `IList<GridBrushBase>` | get | All available brushes |
| `brushPickStore` | `GridBrushPickStore` | get | Store of brush selection data for the current brush |
| `activeBrushEditor` | `GridBrushEditorBase` | get | The editor for the active brush |

### Palette

| Property | Type | Access | Description |
|----------|------|--------|-------------|
| `palette` | `GameObject` | get/set | The currently active palette GameObject |
| `palettes` | `IList<GameObject>` | get | All available palette GameObjects |
| `isPaletteEditable` | `bool` | get | Whether the active palette can be edited (false for model prefabs) |

### State

| Property | Type | Access | Description |
|----------|------|--------|-------------|
| `isEditing` | `bool` | get | Whether GridPaintingState is active for editing |
| `lastSceneViewMousePosition` | `Vector2` | get | Last mouse position on SceneView when painting is active |
| `lastSceneViewGridPosition` | `Vector3Int` | get | Last grid position on SceneView when painting is active |

## Methods

### IsPartOfActivePalette

```csharp
public static bool IsPartOfActivePalette(GameObject target)
```

Checks if a GameObject is part of the active palette.

**Parameters:**
- `target`: The GameObject to check

**Returns:** `true` if the target is part of the active palette, `false` otherwise

**Example:**
```csharp
if (UnityEditor.Tilemaps.GridPaintingState.IsPartOfActivePalette(selectedObject))
{
Debug.Log("Selected object is part of the active palette");
}
```

### SetPickOnActiveGridBrush

```csharp
public static void SetPickOnActiveGridBrush(bool user, int index)
```

Retrieves a stored selection from the current `GridBrushPickStore` and copies it into the active `GridBrush`.

**Parameters:**
- `user`: If `true`, uses user-saved selections; if `false`, uses last-saved selections
- `index`: Index of the selection in the store to apply

**Example:**
```csharp
// Apply the first user-saved brush selection
UnityEditor.Tilemaps.GridPaintingState.SetPickOnActiveGridBrush(user: true, index: 0);

// Apply the second automatically-saved brush selection
UnityEditor.Tilemaps.GridPaintingState.SetPickOnActiveGridBrush(user: false, index: 1);
```

## Common Usage Patterns

### Setting up a custom paint target

```csharp
// Get available targets
var targets = UnityEditor.Tilemaps.GridPaintingState.validTargets;
if (targets != null && targets.Length > 0)
{
// Set the first valid target
UnityEditor.Tilemaps.GridPaintingState.scenePaintTarget = targets[0];
}
```

### Changing the active brush

```csharp
// Get available brushes
var availableBrushes = UnityEditor.Tilemaps.GridPaintingState.brushes;
foreach (var brush in availableBrushes)
{
if (brush is MyCustomBrush)
{
UnityEditor.Tilemaps.GridPaintingState.gridBrush = brush;
break;
}
}
```

### Changing the active palette

```csharp
// Get available palettes. Fully qualified: this runs through `eval`, which takes no usings.
var availablePalettes = UnityEditor.Tilemaps.GridPaintingState.palettes;
if (availablePalettes.Count > 0)
{
// Setting an invalid palette throws ArgumentException
UnityEditor.Tilemaps.GridPaintingState.palette = availablePalettes[0];
}
```

### Monitoring edit state

```csharp
void Update()
{
if (GridPaintingState.isEditing)
{
Vector3Int gridPos = GridPaintingState.lastSceneViewGridPosition;
// Use grid position for custom visualization or logic
}
}
```

## Related Types

- `GridBrushBase` - Base class for all tile brushes
- `GridBrush` - Default tile brush implementation
- `GridBrushEditorBase` - Base class for brush editors
- `GridBrushPickStore` - Stores brush selection history
- `GridPalettes` - Manages available palettes (`GridPalettes.palettes`)
- `GridPaletteBrushes` - Manages available brushes (`GridPaletteBrushes.brushes`)