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

# Installation

Step by step installation of Complete Car Radio for ESX, QBCore, Qbox and standalone servers.

### **How to download the script**

To download the asset, you need to have completed the purchase using your own Cfx.re account.

Once your purchase is confirmed, the asset appears in the **Granted Assets** of your account on the [Cfx.re Portal](https://portal.cfx.re) (formerly Keymaster). From there you can download it and install it by following the steps below.

{% hint style="info" %} <mark style="color:blue;">**If the asset was bought through a different account, you can transfer it from the Cfx.re Portal (Keymaster) transfer system**</mark>
{% endhint %}

{% hint style="danger" %} <mark style="color:red;">**Do not rename the downloaded folders. They must stay exactly**</mark><mark style="color:red;">**&#x20;**</mark><mark style="color:red;">**`complete_carplay`**</mark><mark style="color:red;">**&#x20;**</mark><mark style="color:red;">**and**</mark><mark style="color:red;">**&#x20;**</mark><mark style="color:red;">**`complete_carplay_prop`**</mark><mark style="color:red;">**, otherwise the internal events and callbacks will not work.**</mark>
{% endhint %}

{% hint style="info" %} <mark style="color:blue;">**The product is called Complete Car Radio, but the resource, the item, the commands and the exports still use the technical name**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**`carplay`**</mark><mark style="color:blue;">**. This is intended: keep them as shipped.**</mark>
{% endhint %}

### **Dependencies**

{% hint style="warning" %} <mark style="color:orange;">**Run your server on one of the latest recommended server artifacts. Old artifacts can break ox\_lib, oxmysql and the in-car screen.**</mark>
{% endhint %}

{% hint style="danger" %} <mark style="color:red;">**This asset relies on certain essential dependencies to function correctly. If these dependencies are not installed, the asset may start, but you could encounter errors or warnings in the command console**</mark>
{% endhint %}

| Script                                                                               | Download                                                   |
| ------------------------------------------------------------------------------------ | ---------------------------------------------------------- |
| **ox\_lib**                                                                          | <https://github.com/overextended/ox_lib/releases>          |
| **oxmysql**                                                                          | <https://github.com/overextended/oxmysql/releases>         |
| **complete\_carplay\_prop**                                                          | *included in the package*                                  |
| <p><strong>ONE sound player:</strong><br><strong>xsound</strong> (free)</p>          | <https://github.com/Xogy/xsound>                           |
| <p><strong>OR mx-surround</strong><br><em>paid, third party</em></p>                 | <https://mxstore.tebex.io/package/5864855>                 |
| <p><strong>OR high\_3dsounds</strong><br><em>paid, third party</em></p>              | <https://docs.high-scripts.com/high-3dsounds/installation> |
| <p><strong>Phone script</strong><br><em>optional, for contacts and messages</em></p> | see [Phone configuration](#phone-configuration)            |
| <p><strong>ox\_inventory</strong><br><em>optional, detected automatically</em></p>   | <https://github.com/overextended/ox_inventory/releases>    |

Frameworks: **ESX**, **QBCore** and **Qbox** are detected automatically. If none of them is started, the script uses the **custom** (standalone) bridge.

### **Correct Asset Placement**

{% hint style="danger" %} <mark style="color:red;">**Properly placing the assets is crucial to avoid errors, FOLLOW THIS ORDER. Your framework, inventory, phone and sound player must start BEFORE Car Radio.**</mark>
{% endhint %}

To ensure the asset runs smoothly, configure your server.cfg with the sequence specified below:

```lua
# at the bottom of the file and after all the dependencies add

ensure oxmysql
ensure ox_lib

# your framework, inventory and phone start here (es_extended / qb-core / qbx_core, ox_inventory, your phone...)

# only ONE sound player, the same one you set in Config.SoundPlayer
ensure xsound
# ensure mx-surround
# ensure high_3dsounds

ensure complete_carplay_prop
ensure complete_carplay
```

### **Database Configuration**

You must update your database for the script to work. Open the **/database** folder of `complete_carplay`, pick the file for your framework (`esx.sql`, `qbcore.sql`, `qbox.sql` or `custom.sql`) and import it into your database (HeidiSQL, phpMyAdmin...). Make sure you select the database your server is actually using first.

{% hint style="warning" %} <mark style="color:orange;">**Updating from v2? Delete the old**</mark><mark style="color:orange;">**&#x20;**</mark><mark style="color:orange;">**`complete_carplay`**</mark><mark style="color:orange;">**&#x20;**</mark><mark style="color:orange;">**table and the old**</mark><mark style="color:orange;">**&#x20;**</mark><mark style="color:orange;">**`carplayid`**</mark><mark style="color:orange;">**&#x20;**</mark><mark style="color:orange;">**column of your vehicles table before importing, otherwise you will get "Table already exists" or "Duplicate column name 'carplayid'" errors. Updating from v3.0, 3.1 or 3.2 needs no database change.**</mark>
{% endhint %}

<details>

<summary>ESX (database/esx.sql)</summary>

```sql
CREATE TABLE `complete_carplay` (
  `carplayid` int NOT NULL AUTO_INCREMENT,
  `plate` varchar(255) NOT NULL,
  `license` varchar(255) NOT NULL,
  `controls` longtext,
  `playlists` longtext,
  PRIMARY KEY (`carplayid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ALTER TABLE `owned_vehicles`
ADD `carplayid` int;

INSERT INTO `items` (name, label, weight) VALUES
	('carplay', 'Carplay', 3)
;
```

</details>

<details>

<summary>QBCore (database/qbcore.sql)</summary>

```sql
CREATE TABLE `complete_carplay` (
  `carplayid` int NOT NULL AUTO_INCREMENT,
  `plate` varchar(255) NOT NULL,
  `license` varchar(255) NOT NULL,
  `controls` longtext,
  `playlists` longtext,
  PRIMARY KEY (`carplayid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ALTER TABLE `player_vehicles`
ADD `carplayid` int;

INSERT INTO `items` (name, label, weight) VALUES
	('carplay', 'Carplay', 3)
;
```

{% hint style="info" %} <mark style="color:blue;">**Standard QBCore keeps items in**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**`qb-core/shared/items.lua`**</mark><mark style="color:blue;">**, not in the database. If your database has no**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**`items`**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**table, the last**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**`INSERT`**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**fails: that is fine, the table and the column are already created. Add the item as shown in Item Configuration.**</mark>
{% endhint %}

</details>

<details>

<summary>Qbox (database/qbox.sql)</summary>

```sql
CREATE TABLE `complete_carplay` (
  `carplayid` int NOT NULL AUTO_INCREMENT,
  `plate` varchar(255) NOT NULL,
  `license` varchar(255) NOT NULL,
  `controls` longtext,
  `playlists` longtext,
  PRIMARY KEY (`carplayid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ALTER TABLE `player_vehicles`
ADD `carplayid` int;
```

</details>

<details>

<summary>Standalone / custom framework (database/custom.sql)</summary>

```sql
CREATE TABLE `complete_carplay` (
  `carplayid` int NOT NULL AUTO_INCREMENT,
  `plate` varchar(255) NOT NULL,
  `license` varchar(255) NOT NULL,
  `controls` longtext,
  `playlists` longtext,
  PRIMARY KEY (`carplayid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```

</details>

### **Item Configuration**

The Car Radio is installed in a vehicle with the `carplay` item. The item name must stay exactly `carplay`; you can change the label (for example to `Car Radio`) and the weight. The procedure depends on your framework and inventory:

<details>

<summary>ESX (default inventory)</summary>

The item is added by `database/esx.sql`. If you skipped it, run:

```sql
INSERT INTO `items` (name, label, weight) VALUES
	('carplay', 'Carplay', 3)
;
```

The item is registered as usable in `framework/esx/server.lua` (`ESX.RegisterUsableItem('carplay', ...)`).

</details>

<details>

<summary>QBCore (qb-inventory and inventories that read qb-core shared items)</summary>

Add this to `qb-core/shared/items.lua`:

```lua
carplay = {
    name = 'carplay',
    label = 'Car Radio',
    weight = 3000,
    type = 'item',
    image = 'carplay.png',
    unique = false,
    useable = true,
    shouldClose = true,
    description = 'Complete Car Radio'
},
```

If your inventory has its own item list (for example `qs-inventory/shared/items.lua`), add the same entry there. Put an image called `carplay.png` in your inventory images folder, or change `image` to one you already have.

The item is registered as usable in `framework/qbcore/server.lua` and is removed from the inventory when the installation starts.

</details>

<details>

<summary>ox_inventory (ESX, QBCore or Qbox)</summary>

Add this to `ox_inventory/data/items.lua`:

```lua
['carplay'] = {
    label = 'Car Radio',
    weight = 3000,
    stack = true,
    close = true,
    description = 'Complete Car Radio',
},
```

Car Radio detects `ox_inventory` automatically and uses it to check (and on QBCore / Qbox remove) the item. Using the item runs the usable-item handler of your framework bridge.

</details>

<details>

<summary>Standalone / custom framework</summary>

The custom bridge has no item system of its own. If `ox_inventory` is started, the `/carplay-install` command checks the `carplay` item with ox\_inventory; otherwise the check always passes.

To make an item from your own inventory start the installation, trigger this client event from your usable-item handler (server side):

```lua
TriggerClientEvent('complete_carplay:client:InstallCarplay', source)
```

You can edit the item check in `HasCarplayItem` inside `framework/custom/server.lua`.

</details>

{% hint style="info" %} <mark style="color:blue;">**With**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**`Config.RequireMechanic = true`**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**only the jobs in**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**`Config.MechanicJobName`**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**can install or uninstall the Car Radio, with the item or with**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**`/carplay-install`**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**and**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**`/carplay-uninstall`**</mark><mark style="color:blue;">**.**</mark>
{% endhint %}

### **Phone configuration**

The Messages app reads the contacts and sends messages through your phone script. Set `Config.PhoneType` in `config.lua` to the value of your phone. It is not detected automatically, so it must match the phone you really run.

| `Config.PhoneType` | Phone script               |
| ------------------ | -------------------------- |
| `gcphone`          | gcphone                    |
| `qbphone`          | qb-phone (QBCore / Qbox)   |
| `quasar-pro`       | qs-smartphone-pro          |
| `gksphone`         | GKS Phone v1               |
| `gksphone2`        | GKS Phone v2               |
| `dphone`           | D-Phone                    |
| `highphone`        | High Phone (`high_phone`)  |
| `chezza`           | Chezza Phone               |
| `npwd`             | npwd                       |
| `roadphone`        | RoadPhone                  |
| `lbphone`          | lb-phone                   |
| `custom`           | any other phone, see below |

* **No phone, or a phone that is not in the list:** set `Config.DisablePhone = true`. The rest of the Car Radio keeps working; the Messages app simply has no contacts.
* **Custom phone:** set `Config.PhoneType = 'custom'` and fill in `GetContactsCustomPhone` and `SendMessageCustomPhone` in `framework/<your framework>/server.lua` (and `SendMessageCustomPhone` in `client.lua` if your phone sends messages from the client). Your phone must expose exports to read contacts and send messages.
* Contacts are read from the database of the **vehicle owner**, so the Messages app shows contacts only on owned vehicles (not in restricted mode).

### **Audio**

Car Radio plays music through **one** sound player. Set it in `config.lua`; it must be the same resource you start in `server.cfg`:

{% code title="config.lua" %}

```lua
Config.SoundPlayer = 'xsound' -- xsound | high_3dsounds | mx-surround
```

{% endcode %}

* Start the sound player **before** `complete_carplay`.
* Keep the folder name of the sound player as its author ships it (for example `xsound`, not `xsound-main` or `xsound-1.5`) and make sure there is only one copy of it in your resources.
* The music app plays only the tracks you list in `Config.MusicLibrary`. Players cannot paste links. See [Music library](/complete-scripts/scripts/complete-carradio/music-library.md) to add your songs.

### Configure the script

As the last step, open the config files and edit them as you like. Make sure you have a minimum of coding knowledge before editing them: a single wrong character stops the code from starting.

* **Main config:** `complete_carplay/config.lua` (commands, keys, installation, phone, navigator, sound player, music library, texts). See [Config](/complete-scripts/scripts/complete-carradio/config.md).
* **UI config:** `complete_carplay/html/config.js` (enabled apps and commands, map waypoints, navigator position, playlists sharing, 3D model). See [Config](/complete-scripts/scripts/complete-carradio/config.md).
* **Framework functions:** `complete_carplay/framework/<esx | qbcore | custom>/client.lua` and `server.lua` (notifications, job, item check, vehicle owner lookup, custom phone). Qbox uses the `qbcore` folder. If you use another framework, edit the `custom` folder.

{% hint style="info" %} <mark style="color:blue;">**After an update, compare your old**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**`config.lua`**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**and**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**`html/config.js`**</mark><mark style="color:blue;">**&#x20;**</mark><mark style="color:blue;">**with the new ones instead of copying the old files over: new options are added and old ones are removed between versions.**</mark>
{% endhint %}
