# Get Nodes (Query APIs)

These are **query-only APIs** matching the seven standard right-click Select menu items (excluding `[Debug]`). The verb is `get`; the primary goal is handle/name lookup. Scene selection happens only when you pass `select=1` (`select=0` default = query only, scene selection unchanged).

---

## Method List

| Method | Right-click Menu | Data Source |
| --- | --- | --- |
| `get_all_objects(slot, select=0)` | All Objects | All reference node handles |
| `get_skin_meshes(slot, select=0)` | Skin Meshes | Skin mesh handles |
| `get_skin_bones(slot, select=0)` | Skin Bones | Skin bone handles |
| `get_all_skin_objects(slot, select=0)` | All Skin Objects | Meshes + bones (deduped, meshes first) |
| `get_duplicate_nodes(slot, select=0)` | Duplicate Nodes | Nodes with duplicate names only |
| `get_biped_com(slot, select=0)` | Biped COM | Biped COM node handles |
| `get_biped_nodes(slot, select=0)` | Biped Nodes | All Biped node handles |

---

## Common Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `slot` | `int` | Yes | Slot number (0–9). **bool/str/float immediately raise `TypeError`** |
| `select` | `int` (0/1) or `bool` | No (default `0`) | `0`=query only, `1`=query then select in scene. `False`→`0`, `True`→`1`. Any other value immediately raises `ValueError` |

```text
select=0 (default) → Query only. Scene selection unchanged.
select=1           → Query, then select returned handles in the Max scene.
```

---

## Common Return Contract

```python
{
    "success": True,
    "slot": 0,
    "category": "skin_meshes",
    "count": 12,
    "handles": [101, 102, ...],
    "names": ["Mesh_A", ...],
    "selected": 0,
    "selected_count": 0,
    "message": "skin_meshes: 12개",
}
```

| Method | `category` | Extra fields |
| --- | --- | --- |
| `get_all_objects` | `"all_objects"` | `reference_name` |
| `get_skin_meshes` | `"skin_meshes"` | — |
| `get_skin_bones` | `"skin_bones"` | — |
| `get_all_skin_objects` | `"all_skin_objects"` | — |
| `get_duplicate_nodes` | `"duplicate_nodes"` | `duplicate_names` (`list[str]`) |
| `get_biped_com` | `"biped_com"` | — |
| `get_biped_nodes` | `"biped_nodes"` | — |

---

## Empty Results and Valid-Handle Recollection

- No stored handles, or all invalid (deleted) → `success=True`, `count=0`, `handles=[]`, `names=[]` (**not an error**).
- With no duplicates, `get_duplicate_nodes` returns `duplicate_names=[]`, `count=0`.
- Even with `select=1`, if nothing to select → `selected_count=0` (not an error).
- Returned `handles`/`names`/`count` are **recollected from currently valid scene nodes only**.

---

## Exceptions (FAIL FAST)

| Situation | Exception |
| --- | --- |
| `slot` is not `int` (including bool) | `TypeError` |
| `slot` out of range / empty slot (reference not loaded) | `ValueError` |
| `select` is not 0/1/bool | `ValueError` |

Invalid `slot`/`select` surfaces immediately as an **exception**, not `{"success": False}`.

---

## Removed select_* → get_* Replacement

The old `select_*` APIs were **fully removed** (no shim). If you hit `AttributeError`, replace as follows.

| Removed | Replacement |
| --- | --- |
| `select_reference_nodes` | `get_all_objects(select=1)` |
| `select_duplicate_nodes` | `get_duplicate_nodes(select=1)` |
| `select_skin_mesh` | `get_skin_meshes(select=1)` |
| `select_skin_bones` | `get_skin_bones(select=1)` |

---

## Example

```python
from os_fast_ref.api import FastRefAPI

api = FastRefAPI()

# Query only (no scene selection)
r = api.get_all_objects(slot=0)
print(r["reference_name"], r["names"])

# Query + scene selection (same as right-click menu)
api.get_skin_meshes(slot=0, select=1)

# Duplicate-name check for pipelines — prefer select=0
dup = api.get_duplicate_nodes(slot=0)
if dup["duplicate_names"]:
    print("duplicates:", dup["duplicate_names"])
```

Always use `FastRefAPI` for external automation. Only `FastRefAPI` is covered by the semver guarantee.