# ESX Setup

### ✅ Requirements

* ESX Legacy (1.9.0+) or ESX Infinity
* ox\_lib
* oxmysql
* A compatible inventory
* A compatible clothing script (skinchanger or alternatives)

***

### 🚀 Quick Setup

#### Step 1: Enable Multicharacter in ESX

Edit `es_extended/config.lua`:

```lua
Config.Multichar = true  -- Enable multicharacter support
```

#### Step 2: Disable Default Multicharacter

```cfg
# server.cfg
# ensure esx_multicharacter  <-- Comment out or remove
ensure 0r-multicharacterv3
```

#### Step 3: Start Order

```cfg
ensure oxmysql
ensure ox_lib
ensure es_extended
ensure ox_inventory  # or qs-inventory
ensure skinchanger   # or bl_appearance
ensure 0r-multicharacterv3
```

***

### 🗄️ Database

ESX uses the `users` table for character storage:

| Column      | Usage                                               |
| ----------- | --------------------------------------------------- |
| identifier  | Character identifier (char1:license, char2:license) |
| firstname   | First name                                          |
| lastname    | Last name                                           |
| dateofbirth | Birth date                                          |
| sex         | Gender (m/f)                                        |
| job         | Job name                                            |
| job\_grade  | Job grade                                           |
| accounts    | Money accounts (JSON)                               |
| position    | Last position (JSON)                                |
| skin        | Appearance data (JSON)                              |

***

### 🔧 Character Identifier Format

ESX multicharacter uses a specific identifier format:

```
char{number}:{license}
```

Examples:

* `char1:abc123def456` - First character
* `char2:abc123def456` - Second character
* `char3:abc123def456` - Third character

Configure the prefix in `config/config.lua`:

```lua
Config.Prefix = 'char'  -- Creates char1:, char2:, etc.
```

***

### 📊 Data Conversion

The script converts ESX data to a standardized format:

```lua
-- ESX format
{
    identifier = 'char1:license123',
    firstname = 'John',
    lastname = 'Doe',
    dateofbirth = '1990-01-15',
    sex = 'm',
    job = 'unemployed',
    job_grade = 0,
    accounts = '{"money":500,"bank":5000}',
    position = '{"x":0,"y":0,"z":0}',
}

-- Converted format
{
    cid = 1,
    citizenid = 'char1:license123',
    charinfo = {
        firstname = 'John',
        lastname = 'Doe',
        birthdate = '1990-01-15',
        gender = 'm',
        nationality = 'N/A',
    },
    job = {
        name = 'Unemployed',
        label = 'Unemployed',
        grade = { name = 'Unemployed' }
    },
    money = {
        cash = 500,
        bank = 5000,
    },
    position = {
        x = 0.0,
        y = 0.0,
        z = 0.0,
        w = 0.0,
    }
}
```

***

### ⚡ Events

#### Server Events

```lua
-- When player loads character
RegisterNetEvent('esx:playerLoaded', function(player, xPlayer, isNew)
    -- Triggered after character selection
end)

-- When player disconnects
RegisterNetEvent('esx:playerDropped', function(playerId, reason)
    -- Cleanup
end)
```

#### Client Events

```lua
-- After spawning
TriggerServerEvent('esx:onPlayerSpawn')
TriggerEvent('esx:onPlayerSpawn')
TriggerEvent('playerSpawned')
TriggerEvent('esx:restoreLoadout')
```

***

### 🔄 Character Deletion & Reindexing

When a character is deleted, remaining characters are reindexed:

```lua
-- Before deletion: char1, char2, char3
-- Delete char2
-- After reindex: char1, char2 (was char3)
```

Configure tables in `config/database.lua`:

```lua
Database.List = {
    ['es_extended'] = {
        { table = 'users', column = 'identifier', type = 'citizenid' },
        { table = 'user_accounts', column = 'identifier', type = 'citizenid' },
        { table = 'user_inventory', column = 'identifier', type = 'citizenid' },
        { table = 'owned_vehicles', column = 'owner', type = 'citizenid' },
        { table = 'user_licenses', column = 'owner', type = 'citizenid' },
        -- Add more tables as needed
    }
}
```

***

### 📋 Complete Configuration

```lua
-- config/config.lua for ESX

Config.Debug = false
Config.DeveloperMode = false
Config.Locale = 'en'
Config.HideRadar = true
Config.Prefix = 'char'  -- ESX character prefix
Config.DefaultCharacterSlots = 2
Config.SkipWarning = false
Config.DisableDeleteCharacter = false

-- Spawn configuration
Config.SkipSpawnSelector = true
Config.SpawnSelector = '0r-spawn'
Config.ApartmentStart = false
Config.NewPlayerSpawnCoords = vec4(195.17, -933.77, 29.7, 144.5)
```

***

### 🆚 ESX vs QBCore Differences

| Feature       | ESX           | QBCore      |
| ------------- | ------------- | ----------- |
| Identifier    | char1:license | citizenid   |
| Gender        | m/f           | 0/1         |
| Money Storage | JSON accounts | JSON money  |
| Skin Storage  | users.skin    | playerskins |
| Player Object | xPlayer       | Player      |

***

### ❓ Troubleshooting

#### "Multichar not enabled" error

Ensure in `es_extended/config.lua`:

```lua
Config.Multichar = true
```

#### Skin not loading

1. Check `users.skin` column has data
2. Verify skinchanger is started
3. Ensure skin format is correct

#### Character reindex issues

If characters are out of order after deletion:

```sql
-- Manual reindex query
UPDATE users 
SET identifier = CONCAT('char', @row := @row + 1, ':', SUBSTRING_INDEX(identifier, ':', -1))
WHERE identifier LIKE 'char%:your-license-here'
ORDER BY identifier;
```

#### Job not showing correctly

The script reads job labels from ESX's job system. Ensure jobs are properly configured in your database.
