> For the complete documentation index, see [llms.txt](https://corex-zombies.gitbook.io/corex-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://corex-zombies.gitbook.io/corex-docs/resources/player/corex-spawn.md).

# corex-spawn

> Spawn flow + character creator. Remembers last position. Falls back to a default spawn for new characters.

{% hint style="info" %}
**Required:** Yes for any server with players · **Depends on:** `corex-core`, `corex-inventory` · **Version:** `1.0.0`
{% endhint %}

## Quick Facts

| Dependencies                    | Server Exports | Client Exports | Events |
| ------------------------------- | -------------- | -------------- | ------ |
| `corex-core`, `corex-inventory` | 3              | —              | 4      |

## Overview

Handles the end-to-end spawn flow. On reconnect: load last position from metadata. On new character: run the creator, apply skin, drop at first-spawn. Persists the chosen skin to metadata so it survives re-logins.

## Quick Start

```cfg
ensure corex-core
ensure corex-inventory
ensure corex-spawn
```

Spawn runs automatically after `corex:server:playerReady`. Configure spawn points in `config.lua`.

## Configuration

### Spawn points

| Key                           | Type              | Description                                           |
| ----------------------------- | ----------------- | ----------------------------------------------------- |
| `Config.FirstSpawnLocation`   | `{x,y,z,heading}` | Where brand-new characters land                       |
| `Config.DefaultSpawnLocation` | `{x,y,z,heading}` | Fallback when `lastPosition` is invalid               |
| `Config.SaveLastLocation`     | `boolean`         | Persist `lastPosition` on disconnect (default `true`) |

### Models

| Key                         | Default              | Description         |
| --------------------------- | -------------------- | ------------------- |
| `Config.DefaultMaleModel`   | `'mp_m_freemode_01'` | Baseline male ped   |
| `Config.DefaultFemaleModel` | `'mp_f_freemode_01'` | Baseline female ped |

### Clothing catalog

`Config.ClothingCategories` defines the category names shown in the creator (shirt, pants, hair, etc.). Each entry has `id`, `label`, and `icon`. Default categories: `face`, `masks`, `torso`, `legs`, `shoes`, `accessories`.

### Clothing components (GTA V component IDs)

`Config.ClothingComponents` maps readable names to GTA's numeric component slots:

| Name    | ID | Name         | ID |
| ------- | -- | ------------ | -- |
| `face`  | 0  | `shoes`      | 6  |
| `mask`  | 1  | `accessory`  | 7  |
| `hair`  | 2  | `undershirt` | 8  |
| `torso` | 3  | `kevlar`     | 9  |
| `legs`  | 4  | `badge`      | 10 |
| `bags`  | 5  | `overlay`    | 11 |

### Prop components

`Config.PropComponents` — the five prop slots GTA exposes:

| Name        | ID |
| ----------- | -- |
| `hats`      | 0  |
| `glasses`   | 1  |
| `ears`      | 2  |
| `watches`   | 6  |
| `bracelets` | 7  |

### Debug

`Config.Debug = false` — enables verbose spawn-flow logging.

## Server Exports

### `GetPlayerSkin(source)`

Returns the full skin table from metadata.

```lua
local skin = exports['corex-spawn']:GetPlayerSkin(source)
```

### `GetPlayerPosition(source)`

Returns `{x, y, z, heading}` — current position snapshot (server-side view, may lag client by up to one tick).

### `SetPlayerSkin(source, skinData)`

Writes a new skin to metadata and sync to the client. Triggers the apply on the client.

```lua
exports['corex-spawn']:SetPlayerSkin(source, {
    model = 'mp_m_freemode_01',
    face = 4,
    components = { [3] = {drawable=15, texture=0}, … },
})
```

## Events

### Emitted / handled

Server-side:

* `corex-spawn:server:markSpawnReady` — client reports spawn complete
* `corex-spawn:server:savePosition` — client reports last position for persistence
* `corex-spawn:server:saveSkin` — client saves character skin
* `corex-spawn:server:respawnPlayer` — internal, part of death flow
* `corex-spawn:server:checkPlayer` — validation
* `corex-spawn:server:playerDied` — fired from `corex-death` to gate spawn logic

Client-side:

* `corex-spawn:client:spawnPlayer` — server triggers the actual spawn
* `corex-spawn:client:requestPosition` — server asks client for its current position
* `corex-spawn:client:skinSaved` — confirmation
* `corex-spawn:client:clearSpawnFlags` — reset flags after respawn

### Listens to

* `corex:server:playerReady` — kicks off the spawn flow
* `corex-death:server:playerDied` — handshakes the death→respawn flow

{% hint style="info" %}
Third-party resources typically react to `corex:server:playerReady` (from corex-core) to run post-spawn logic. The `corex-spawn:*` events are mostly server-internal handshakes.
{% endhint %}

## StateBag Keys

None directly. Skin persists via metadata (`metadata.skin`). Last position persists via metadata (`metadata.lastPosition`).

## Troubleshooting

**Player spawns in an unexpected location.** → `lastPosition` is being restored with a stale/invalid value. Validate against map bounds before saving. See bug [P0-2](https://github.com/ABUGIZA/corex-docs) in Task Blueprint.

**Character creator doesn't show for a new player.** → Metadata already has `skin` set. Check: `SELECT JSON_EXTRACT(metadata,'$.skin') FROM players WHERE identifier = ?`. Clear it to re-trigger.

**Skin doesn't apply on reconnect.** → `SetPlayerSkin` on the client races the StateBag sync. Wait for `corex:client:coreReady` on the client before reading `GetMetaData('skin')`.

**Black screen on spawn.** → `Config.DefaultSpawnLocation` points to an unloaded collision area. Pick a coord with `GetGroundZFor_3dCoord` returning a valid Z before using it.
