# Usage / Integration

## Usage / Integration

This page covers how to integrate **force-characters** with your resources using events, exports, and the instance system.

### Table of Contents

* Client Events
* Server Events
* Client Exports
* Instance System
* Integration Examples

***

### Client Events

#### force-characters:client:openSpawnSelector

Opens the spawn selector UI for the player.

**Parameters:**

* `job` (string, optional): Job name to filter spawn locations. Defaults to `"unemployed"`.

**Usage:**

```lua
-- Open spawn selector with default job
TriggerEvent('force-characters:client:openSpawnSelector')

-- Open spawn selector filtered for police job
TriggerEvent('force-characters:client:openSpawnSelector', 'police')
```

**Example Use Cases:**

* Respawn system after player death
* Job-specific respawn locations
* Custom teleport systems
* Hospital release systems

***

#### force-characters:client:forceReset

Forces the character selection screen to reset, returning the player to character selection.

**Parameters:** None

**Usage:**

```lua
TriggerEvent('force-characters:client:forceReset')
```

**Example Use Cases:**

* Admin commands to force character reselection
* Logout systems
* Character switching functionality
* Server-side character kicks

***

#### instance:EventHandler

Handles instance-related events on the client side.

**Parameters:**

* `Event` (string): The event type to handle
* `Data` (table): Event-specific data

**Event Types:**

* `LoadInstances`: Loads all instances
* `AddPlayerToInstance`: Adds a player to an instance
* `RemovePlayerFromInstance`: Removes a player from an instance
* `AddEntityToInstance`: Adds an entity to an instance
* `RemoveEntityFromInstance`: Removes an entity from an instance

**Usage:**

```lua
-- This is typically handled internally, but can be triggered manually
TriggerEvent('instance:EventHandler', 'AddPlayerToInstance', {
  InstanceId = "myInstance",
  Player = GetPlayerServerId(PlayerId())
})
```

***

### Server Events

#### force-characters:server:logoutPlayer

Logs out a specific player, returning them to character selection.

**Parameters:**

* `target` (number): The server ID of the player to logout

**Usage:**

```lua
-- From client
TriggerServerEvent('force-characters:server:logoutPlayer', targetServerId)

-- From server
TriggerEvent('force-characters:server:logoutPlayer', targetServerId)
```

**Example Use Cases:**

```lua
-- Admin command to force player logout
RegisterCommand('logout', function(source, args)
  local targetId = tonumber(args[1])
  if targetId then
    TriggerEvent('force-characters:server:logoutPlayer', targetId)
  end
end, true)

-- Kick player to character select
local function KickToCharacterSelect(playerId)
  TriggerEvent('force-characters:server:logoutPlayer', playerId)
end
```

***

#### force-characters:server:setRoutingBucket

Sets the routing bucket for a player.

**Parameters:**

* `bucket` (number): The routing bucket ID

**Usage:**

```lua
-- From client
TriggerServerEvent('force-characters:server:setRoutingBucket', 5)
```

**Example Use Cases:**

```lua
-- Isolate player in separate dimension
TriggerServerEvent('force-characters:server:setRoutingBucket', 100)

-- Return player to main dimension
TriggerServerEvent('force-characters:server:setRoutingBucket', 0)
```

***

#### instance:EventHandler (Server)

Handles instance-related events on the server side.

**Parameters:**

* `Event` (string): The event type
* `Data` (table): Event-specific data

**Usage:**

```lua
-- Add player to instance
TriggerServerEvent('instance:EventHandler', 'AddPlayerToInstance', {
  InstanceId = "apartment_1",
  Player = playerId
})

-- Remove player from instance
TriggerServerEvent('instance:EventHandler', 'RemovePlayerFromInstance', {
  InstanceId = "apartment_1",
  Player = playerId
})
```

***

### Client Exports

#### OpenSpawnSelector

Opens the spawn selector UI for the current player.

**Parameters:**

* `job` (string, optional): Job filter for spawn locations

**Usage:**

```lua
-- Basic usage
exports['force-characters']:OpenSpawnSelector()

-- With job filter
exports['force-characters']:OpenSpawnSelector('police')
```

**Example:**

```lua
-- Custom respawn after death
AddEventHandler('playerDied', function()
  Citizen.Wait(5000)
  exports['force-characters']:OpenSpawnSelector()
end)
```

***

#### isCharacterLoaded

Checks if a character is currently loaded for the player.

**Returns:**

* `boolean`: `true` if character is loaded, `false` otherwise

**Usage:**

```lua
local hasCharacter = exports['force-characters']:isCharacterLoaded()

if hasCharacter then
  print("Character is loaded")
else
  print("No character loaded")
end
```

**Example:**

```lua
-- Wait for character to load before executing code
Citizen.CreateThread(function()
  while not exports['force-characters']:isCharacterLoaded() do
    Citizen.Wait(1000)
  end

  -- Character is now loaded, continue with initialization
  print("Character loaded, initializing systems...")
end)
```

***

#### EnterInstance

Enters a player into a specific instance.

**Parameters:**

* `InstanceId` (string): The unique instance identifier

**Usage:**

```lua
exports['force-characters']:EnterInstance('apartment_101')
```

**Example:**

```lua
-- Enter apartment instance
RegisterCommand('enterapt', function()
  exports['force-characters']:EnterInstance('apartment_' .. myApartmentId)
end)
```

***

#### LeaveInstance

Removes the player from their current instance.

**Parameters:** None

**Usage:**

```lua
exports['force-characters']:LeaveInstance()
```

**Example:**

```lua
-- Leave apartment
RegisterCommand('exitapt', function()
  exports['force-characters']:LeaveInstance()
  SetEntityCoords(PlayerPedId(), exitCoords)
end)
```

***

#### EnterEntityInstance

Adds an entity to a specific instance.

**Parameters:**

* `entity` (number): The entity handle
* `InstanceId` (string): The instance identifier

**Usage:**

```lua
local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)
exports['force-characters']:EnterEntityInstance(vehicle, 'apartment_101')
```

**Example:**

```lua
-- Bring vehicle into instance
local function BringVehicleToInstance(vehicle, instanceId)
  exports['force-characters']:EnterEntityInstance(vehicle, instanceId)
end
```

***

#### LeaveEntityInstance

Removes an entity from its current instance.

**Parameters:**

* `entity` (number): The entity handle

**Usage:**

```lua
local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)
exports['force-characters']:LeaveEntityInstance(vehicle)
```

***

#### GetInstance

Gets the current instance ID the player is in.

**Returns:**

* `string|boolean`: Instance ID if in an instance, `false` otherwise

**Usage:**

```lua
local currentInstance = exports['force-characters']:GetInstance()

if currentInstance then
  print("Currently in instance: " .. currentInstance)
else
  print("Not in any instance")
end
```

**Example:**

```lua
-- Check if player is in an instance before performing action
local function CanInteract()
  local instance = exports['force-characters']:GetInstance()
  return instance == false -- Can only interact when not in instance
end
```

***

### Instance System

The instance system allows you to create isolated spaces where players and entities can interact separately from the main world.

#### How Instances Work

* Each instance has a unique identifier (string)
* Players in different instances cannot see each other
* Entities can be added to instances
* Instances are automatically synced between clients and server
* Routing buckets are used for player isolation

#### Creating a Private Instance

```lua
-- Enter a unique instance
local instanceId = "apartment_" .. myApartmentId
exports['force-characters']:EnterInstance(instanceId)

-- Bring vehicle with you
local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)
if vehicle ~= 0 then
  exports['force-characters']:EnterEntityInstance(vehicle, instanceId)
end
```

#### Leaving an Instance

```lua
-- Leave current instance
exports['force-characters']:LeaveInstance()

-- Remove entities before leaving
local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)
if vehicle ~= 0 then
  exports['force-characters']:LeaveEntityInstance(vehicle)
end
```

#### Multi-Player Instances

```lua
-- Server-side: Create shared instance
local sharedInstance = "robbery_bank_1"

-- Add multiple players to same instance
for _, playerId in ipairs(players) do
  TriggerClientEvent('instance:EventHandler', playerId, 'AddPlayerToInstance', {
    InstanceId = sharedInstance,
    Player = playerId
  })
end
```

***

### Integration Examples

#### Hospital Respawn System

```lua
-- client.lua
RegisterNetEvent('hospital:respawn')
AddEventHandler('hospital:respawn', function()
  -- Show spawn selector with hospital as an option
  exports['force-characters']:OpenSpawnSelector()
end)
```

#### Admin Logout Command

```lua
-- server.lua
RegisterCommand('forcelogout', function(source, args)
  local targetId = tonumber(args[1])

  if not targetId then
    print("Usage: /forcelogout [player_id]")
    return
  end

  TriggerEvent('force-characters:server:logoutPlayer', targetId)
  print("Player " .. targetId .. " logged out to character select")
end, true) -- Restricted to admins
```

#### Apartment Instance System

```lua
-- client.lua
local myApartment = nil

function EnterApartment(apartmentId)
  myApartment = "apartment_" .. apartmentId

  -- Enter instance
  exports['force-characters']:EnterInstance(myApartment)

  -- Teleport to apartment interior
  SetEntityCoords(PlayerPedId(), apartmentInteriorCoords)

  print("Entered apartment " .. apartmentId)
end

function ExitApartment()
  if not myApartment then return end

  -- Leave instance
  exports['force-characters']:LeaveInstance()

  -- Teleport to exit
  SetEntityCoords(PlayerPedId(), apartmentExitCoords)

  myApartment = nil
  print("Exited apartment")
end
```

#### Wait for Character Load

```lua
-- client.lua
Citizen.CreateThread(function()
  -- Wait for character to be loaded
  while not exports['force-characters']:isCharacterLoaded() do
    Citizen.Wait(500)
  end

  -- Character is loaded, initialize your resource
  print("Character loaded - initializing resource")
  InitializeMyResource()
end)
```

#### Job-Based Spawn Selector

```lua
-- client.lua
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
  -- Store job for later use
  currentJob = job.name
end)

RegisterCommand('respawn', function()
  -- Open spawn selector with current job
  exports['force-characters']:OpenSpawnSelector(currentJob or 'unemployed')
end)
```

#### Heist Instance System

```lua
-- server.lua
local activeHeists = {}

function StartHeist(heistId, players)
  local instanceId = "heist_" .. heistId .. "_" .. os.time()
  activeHeists[heistId] = instanceId

  -- Add all players to the instance
  for _, playerId in ipairs(players) do
    TriggerClientEvent('instance:EventHandler', playerId, 'AddPlayerToInstance', {
      InstanceId = instanceId,
      Player = playerId
    })
  end

  return instanceId
end

function EndHeist(heistId)
  local instanceId = activeHeists[heistId]
  if not instanceId then return end

  -- Remove all players from instance (they'll auto-leave)
  activeHeists[heistId] = nil
end
```

#### Custom Character Switching

```lua
-- client.lua
RegisterCommand('switchchar', function()
  -- Check if not in combat or restricted situation
  if not IsPedInAnyVehicle(PlayerPedId(), false) then
    TriggerEvent('force-characters:client:forceReset')
  else
    print("Cannot switch characters while in a vehicle")
  end
end)
```

#### Instance-Based PvP Zones

```lua
-- client.lua
local pvpZones = {
  arena = {
    coords = vector3(0, 0, 0),
    radius = 50.0,
    instance = "pvp_arena"
  }
}

Citizen.CreateThread(function()
  while true do
    local playerCoords = GetEntityCoords(PlayerPedId())
    local currentInstance = exports['force-characters']:GetInstance()

    for zoneName, zone in pairs(pvpZones) do
      local distance = #(playerCoords - zone.coords)

      -- Entering zone
      if distance < zone.radius and not currentInstance then
        exports['force-characters']:EnterInstance(zone.instance)
        print("Entered PvP zone: " .. zoneName)

      -- Leaving zone
      elseif distance > zone.radius and currentInstance == zone.instance then
        exports['force-characters']:LeaveInstance()
        print("Left PvP zone: " .. zoneName)
      end
    end

    Citizen.Wait(1000)
  end
end)
```

***

### Best Practices

#### 1. Always Check Character Load State

```lua
-- Good
if exports['force-characters']:isCharacterLoaded() then
  -- Safe to execute character-specific code
end

-- Better
local function WaitForCharacterLoad(callback)
  Citizen.CreateThread(function()
    while not exports['force-characters']:isCharacterLoaded() do
      Citizen.Wait(500)
    end
    callback()
  end)
end
```

#### 2. Clean Up Instances

Always ensure players leave instances when they should:

```lua
-- Clean up on resource stop
AddEventHandler('onResourceStop', function(resource)
  if resource == GetCurrentResourceName() then
    exports['force-characters']:LeaveInstance()
  end
end)
```

#### 3. Handle Instance Transitions

```lua
-- Good practice: Clean transition
local function TransitionToInstance(newInstance)
  -- Leave current instance
  exports['force-characters']:LeaveInstance()

  -- Wait a tick
  Citizen.Wait(100)

  -- Enter new instance
  exports['force-characters']:EnterInstance(newInstance)
end
```

#### 4. Use Job Filters Appropriately

```lua
-- Filter spawns by job for better UX
local function OpenJobBasedSpawn(playerJob)
  exports['force-characters']:OpenSpawnSelector(playerJob)
end
```

#### 5. Synchronize Server and Client

```lua
-- Server should control instance logic
-- Client should handle visualization and UX

-- Server
RegisterNetEvent('myresource:enterInstance')
AddEventHandler('myresource:enterInstance', function(instanceId)
  local src = source
  -- Validate and create instance server-side
  TriggerClientEvent('myresource:client:enterInstance', src, instanceId)
end)

-- Client
RegisterNetEvent('myresource:client:enterInstance')
AddEventHandler('myresource:client:enterInstance', function(instanceId)
  exports['force-characters']:EnterInstance(instanceId)
end)
```

***

### Troubleshooting

#### Player Not Seeing Instance

* Ensure both players are added to the same instance ID
* Check routing bucket synchronization
* Verify instance event handlers are triggering

#### Instance Not Cleaning Up

* Always call `LeaveInstance()` when done
* Handle resource stops properly
* Check for instance ID conflicts

#### Character Load Detection Failing

* Use a while loop with waits instead of callbacks
* Check that the resource has fully started
* Verify `ox_lib` is loaded before checking

***

### Additional Resources

* Configuration Guide - Set up spawn points and options
* Introduction - Overview of force-characters
* Check the `config.lua` for all available settings
* Review the source code for advanced integration patterns

***

### Need Help?

If you encounter issues or need assistance with integration:

1. Enable `Config.Debug = true` for detailed logging
2. Check the F8 console for errors
3. Review the server console for server-side issues
4. Ensure all dependencies (`ox_lib`, `oxmysql`) are up to date
5. Contact Force Developments on Discord: @force3883


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forcedevelopments.com/resources/force-characters/usage-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
