mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-09-04 17:23:25 +00:00
feat: add LB migration and reorganize configuration
This commit is contained in:
@@ -1,261 +1,189 @@
|
||||
# sky_phone
|
||||
# Sky Phone
|
||||
|
||||
## Payphones
|
||||
Sky Phone is a complete, standalone FiveM smartphone resource with a modern iPhone-inspired interface, persistent device data, physical or virtual SIM support, social apps, media, services, games, and framework integrations.
|
||||
|
||||
Payphone dialing is validated against server-owned booth positions. Vanilla GTA V positions live
|
||||
in `sky_phone/config/payphones.lua`; the server compares its own player coordinates with this list
|
||||
and does not trust coordinates or models sent by the NUI or client.
|
||||
The production frontend is included. Customers do not need Node.js or pnpm for a normal server installation.
|
||||
|
||||
For a custom map or MLO, add each booth to `Config.Payphones.Locations` in that server-only file:
|
||||
## Highlights
|
||||
|
||||
```lua
|
||||
{ model = "prop_phonebox_01a", coords = { x = 123.45, y = 678.90, z = 21.0 } },
|
||||
```
|
||||
|
||||
The model must also be present in `Config.Payphones.Props`. Coordinates must be finite Lua numbers
|
||||
inside the supported world bounds. Restart `sky_phone` after changing the list. If payphones are
|
||||
enabled but the list is empty or contains invalid entries, the server logs a visible warning and
|
||||
rejects calls that cannot be matched to a valid configured location.
|
||||
|
||||
## Custom Apps
|
||||
|
||||
`sky_phone` erkennt Registrierungen gestarteter Fremd-App-Ressourcen über integrierte
|
||||
Hersteller-Aliase und übernimmt unterstützte Apps automatisch in Springboard und App Store. In
|
||||
App-Ressourcen müssen dafür keine Sky-Vorlagen abgelegt werden. Unterstützt werden die
|
||||
dokumentierten Basisverträge von LB Phone, 17Movement, High Phone, Quasar Smartphone V3 und
|
||||
YSeries; die Resource- und Cfx-Export-Aliase `lb-phone`, `17mov_Phone`, `high-phone`,
|
||||
`qs-smartphone` und `yseries` werden direkt von `sky_phone` bereitgestellt. Einrichtung und
|
||||
ehrliche Kompatibilitätsgrenzen stehen in der
|
||||
[deutschen Custom-App-Anleitung](docs/custom-apps.md).
|
||||
|
||||
## FlipTok verification
|
||||
|
||||
FlipTok verification is server-authoritative and limited to the framework groups configured in
|
||||
`Config.FlipTok.AdminGroups`; no command ACE is required. Use
|
||||
`/fliptokverify <@handle> [on|off]`. Without `on` or `off`, the current blue-check state is toggled.
|
||||
The command name is configurable through `Config.FlipTok.VerifyCommand`.
|
||||
Verification command access uses `Config.FlipTok.AdminGroups`. The report moderation overview is
|
||||
server-authoritative and independently restricted through `Config.FlipTok.ReportAdminGroups`.
|
||||
|
||||
## FlipTok music
|
||||
|
||||
Licensed music can be exposed in the composer through `Config.FlipTok.MusicTracks`. Keep the IDs
|
||||
stable because published videos store the selected ID; URLs must be directly playable by the NUI.
|
||||
|
||||
```lua
|
||||
MusicTracks = {
|
||||
{ Id = "night-drive", Title = "Night Drive", Artist = "Sky Radio", Url = "https://cdn.example.com/night-drive.ogg" },
|
||||
}
|
||||
```
|
||||
|
||||
## Music app
|
||||
|
||||
The standalone `Music` app plays audio only inside the current player's NUI. It never creates a
|
||||
world sound, voice channel, positional event, or 3D-audio state that another player can hear.
|
||||
|
||||
Server-owned MP3/OGG tracks and their optional artwork live directly in
|
||||
`sky_phone/config/music`. Define only their stable ID, title, and artist in
|
||||
`sky_phone/config/music.lua`:
|
||||
|
||||
```lua
|
||||
Tracks = {
|
||||
{
|
||||
Id = "night-drive",
|
||||
Title = "Night Drive",
|
||||
Artist = "Sky Records",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The resource searches `config/music` and all of its subdirectories for files whose name matches
|
||||
the ID. For the example above, place `night-drive.ogg` or `night-drive.mp3` anywhere below that
|
||||
directory. Optional artwork uses the same name with `.webp`, `.png`, `.jpg`, or `.jpeg`. If both
|
||||
audio formats exist, OGG wins; artwork priority is WEBP, PNG, JPG, then JPEG. More than one file
|
||||
with the selected extension and ID is ambiguous and the server reports it in the console. Folder
|
||||
names may contain spaces, but must not contain path separators or control characters. Do not name
|
||||
a folder itself with a supported audio or artwork extension.
|
||||
|
||||
No frontend build is needed when tracks change. Restart the resource so FiveM republishes the
|
||||
files and reloads the track configuration. Keep existing track IDs stable because playlists store
|
||||
those IDs. Moving matching files between subdirectories does not affect playlists.
|
||||
|
||||
When upgrading from the previous path-based configuration, rename each audio and artwork file to
|
||||
its existing ID and remove the `File` and `Artwork` fields. Do not change the ID itself, otherwise
|
||||
existing playlist entries can no longer resolve the track.
|
||||
|
||||
Players can add public YouTube video links to their own library. Metadata is requested through
|
||||
YouTube's oEmbed endpoint on the server, while playback uses the embedded YouTube player only on
|
||||
that player's NUI. Personal songs and playlists are stored per linked Sky Cloud account, or per phone
|
||||
IMEI while signed out, in the `sky_phone_music_*` tables. Limits and rate controls are configured in
|
||||
`config/music.lua`.
|
||||
|
||||
## FlipTok accounts
|
||||
|
||||
FlipTok profiles use their own username and password login. Registration requires a linked Sky Cloud
|
||||
account once so an existing creator profile, videos, followers, and verification can be claimed
|
||||
without data loss. Login sessions are stored per phone IMEI and survive resource or server restarts;
|
||||
signing out removes only that device session.
|
||||
|
||||
Set a private, stable password pepper in `server.cfg` before players register. Changing it later
|
||||
invalidates every existing FlipTok password:
|
||||
|
||||
```cfg
|
||||
set sky_phone_fliptok_password_pepper "replace-with-a-long-random-secret"
|
||||
```
|
||||
|
||||
Passwords are stored as salted hashes. The pepper is read server-side from the convar and is never
|
||||
included in the NUI bundle.
|
||||
|
||||
Standalone FiveM phone built with Vue 3, TypeScript, Pinia, Vue Router, the Sky-owned FiveM UI system, and Tailwind CSS 4. Konsta UI remains only for screens that have not yet completed their migration. The phone opens through the usable item; `/phone` is disabled unless `Config.Phone.DevelopmentCommand` is enabled explicitly. `Config.Phone.AllowMovement` controls whether game input remains active while the mobile phone is open. Phone identity and SIM-card behavior are selected independently through `Config.Phone.Unique` and `Config.Sim.Enabled`.
|
||||
|
||||
### Ingame test data
|
||||
|
||||
On development servers, enable `Config.TestData.Enabled` and run `/phonetestdata` as the player who
|
||||
owns the phone. The command creates or refreshes idempotent, player-scoped fixtures for contacts,
|
||||
calls, messages, mail, notes, gallery, banking history, billing, calendar, map markers, music, radio,
|
||||
EasyShare, CityMarkt, Local Pages, Picstagram, FlipTok, Feather, Flare, DarkChat, CrewLink, SkyRide,
|
||||
and company requests. It also creates a linked Sky Cloud account and a registered SIM when the selected
|
||||
phone does not have them yet. Reopen the phone after the command completes.
|
||||
|
||||
Garage and Housing intentionally continue to use the real configured provider data. Apps without
|
||||
persistent content, such as Calculator, Camera, Clock, Weather, Settings, and Payphone, do not need
|
||||
database fixtures. Set `Config.TestData.AdminOnly = true` to restrict the command to the configured
|
||||
framework admin groups, and disable the feature outside development environments.
|
||||
|
||||
A Sky Cloud account is optional. Unlinked devices retain local settings, alarms, media, apps, notes, contacts, and recent calls. Linking from Mail or Settings moves local data into an empty Sky Cloud account; an existing Sky Cloud dataset wins over local contacts and recents. Signing out keeps an editable local snapshot without deleting Sky Cloud data.
|
||||
|
||||
## Phone identity and SIM modes
|
||||
|
||||
Both compatibility switches default to the physical, unique-item behavior:
|
||||
|
||||
```lua
|
||||
Config.Phone.Unique = true
|
||||
Config.Sim.Enabled = true
|
||||
```
|
||||
|
||||
For backwards compatibility, an omitted switch is also treated as `true`.
|
||||
|
||||
With `Config.Phone.Unique = true`, every phone item is one transferable physical Device. Its unique
|
||||
15-digit IMEI is stored in item metadata, so its settings, PIN, local app data, linked Sky Cloud
|
||||
account, and installed SIM travel with that item. The item must be non-stackable.
|
||||
|
||||
With `Config.Phone.Unique = false`, the server assigns each framework character one persistent
|
||||
virtual Device. Possessing any configured phone item grants access to that Device, but the item does
|
||||
not own its IMEI or data. Losing a handset therefore removes access only until the character obtains
|
||||
another one; the replacement opens the same data, PIN, account session, and number. Phone items may
|
||||
be stackable in this mode, although at least one phone item is still required to use or receive the
|
||||
phone. The character mapping is server-authoritative and uses the framework character identifier,
|
||||
never a client-supplied owner value.
|
||||
|
||||
With `Config.Sim.Enabled = true`, a physical registered or anonymous SIM item must be inserted before
|
||||
the Device has cellular service. SIM items remain unique and non-stackable. With
|
||||
`Config.Sim.Enabled = false`, SIM inventory items are not required. The first time a Device without
|
||||
an attached SIM is resolved, the server creates an anonymous virtual SIM with a random unique phone
|
||||
number using `Config.Sim.NumberPrefix` and `NumberLength`; `NumberGroups` controls its display
|
||||
format. Physical SIM insertion and ejection are disabled in this mode. An already attached physical
|
||||
SIM and its number are preserved when SIM requirements are disabled.
|
||||
|
||||
The switches are independent. An automatic number follows a physical handset when unique phones are
|
||||
enabled and follows the character's persistent virtual Device when unique phones are disabled.
|
||||
Likewise, a physical SIM inserted while unique phones are disabled belongs to the character's
|
||||
virtual Device and remains available after replacing the handset.
|
||||
|
||||
### Existing installations and first use
|
||||
|
||||
After changing an existing installation to `Config.Phone.Unique = false`, the first phone item a
|
||||
character uses establishes the persistent mapping. If that item has a valid legacy IMEI which is not
|
||||
already mapped to another character, the complete existing Device is adopted. This preserves its
|
||||
local content, PIN, linked account, and attached SIM. If the legacy IMEI cannot be adopted, the
|
||||
server creates a fresh virtual Device instead. Historic unique Devices did not record an owner, so
|
||||
the character carrying a handset on its first use after the change is the character that claims it.
|
||||
|
||||
When `Config.Sim.Enabled = false`, an existing attached physical SIM is kept; only Devices without a
|
||||
SIM receive a random virtual one. If SIM cards are enabled again, automatically created virtual SIMs
|
||||
are detached during resource startup so those Devices once again require a physical SIM. Stored
|
||||
character-to-Device mappings remain available, but changing back to unique phones does not copy a
|
||||
virtual Device's data onto an arbitrary inventory item. Treat production mode changes as migrations
|
||||
and restart the resource after updating the configuration.
|
||||
- Modern Sky UI with light and dark mode support
|
||||
- Unique physical phones or one persistent virtual phone per character
|
||||
- Registered, anonymous, physical, and automatic virtual SIM cards
|
||||
- Calls, Messages, Mail, DarkChat, Radio, EasyShare, and payphones
|
||||
- Picstagram, FlipTok, Feather, Flare, and CrewLink
|
||||
- Banking, Billing, Garage, Housing, Companies, CityMarkt, Local Pages, Maps, SkyRide, and Weazel News
|
||||
- Camera, Photos, Music, Calendar, Clock, Notes, Voice Memos, Weather, and Calculator
|
||||
- Built-in games and an App Store
|
||||
- English and German language support
|
||||
- Automatic database installation and upgrades
|
||||
- Command-only LB Phone database migration with preview and rollback
|
||||
- Compatibility adapters for popular frameworks, inventories, voice systems, housing resources, and external phone apps
|
||||
|
||||
## Requirements
|
||||
|
||||
- ESX Legacy (`es_extended`), Qbox (`qbx_core`), or QBCore (`qb-core`). The bridge selects a running supported framework when `Config.Bridge.Framework` is set to `"auto"`.
|
||||
- A supported inventory: `ox_inventory`, `qb-inventory`, `lj-inventory`, `qs-inventory`, `codem-inventory`, `core_inventory`, `mf-inventory`, or `smx-inventory`. The bridge auto-detects a running provider and normalizes metadata, slots, counts, item mutations, and usable-item callbacks. `mf-inventory` and `smx-inventory` require ESX. Because SMX stores standard ESX items as stacks, its adapter persists one active Phone/SIM metadata record per player and item type in ESX player metadata.
|
||||
- An inventory item named `phone`. It must be non-stackable when `Config.Phone.Unique = true` and may be stackable when it is `false`.
|
||||
- When `Config.Sim.Enabled = true`, two unique, non-stackable inventory items named `sky_phone_sim_registered` and `sky_phone_sim_anonymous`. Their metadata is initialized automatically on first use, so shops and crafting recipes add plain items without supplying a number. These item definitions are not required when SIM cards are disabled.
|
||||
- `oxmysql` with MySQL/MariaDB.
|
||||
- `pma-voice` when `Config.Calls.VoiceProvider` is set to `"pma"` (the alias `"pma-voice"` selects the same adapter), or SaltyChat when it is set to `"saltychat"` (alias `"salty"`). SaltyChat additionally enables the in-call speaker control; PMA Voice keeps that control unavailable instead of simulating a local-only state. Set `Config.Speaker.Enabled = false` to disable the SaltyChat phone and radio speaker system globally; the controls then stay unavailable and server callbacks reject attempts to enable them.
|
||||
- A FiveManage V3 Media API token for Camera photo/video uploads, Voice Memo audio uploads, and Gallery deletion. Set it in the
|
||||
server-only `sky_phone/config/media.lua`; the token is never sent to NUI because clients receive
|
||||
temporary presigned upload URLs instead:
|
||||
### Required
|
||||
|
||||
```lua
|
||||
Config.Media.FiveManage.ApiKey = "replace-with-your-media-token"
|
||||
```
|
||||
- `yaca-voice`, `pma-voice`, or `saltychat` when the Radio app is enabled. `Config.Radio.VoiceProvider = "auto"` selects the first running provider in that order.
|
||||
- MySQL or MariaDB
|
||||
- `oxmysql`
|
||||
- One supported framework:
|
||||
- ESX Legacy (`es_extended`)
|
||||
- Qbox (`qbx_core`)
|
||||
- QBCore (`qb-core`)
|
||||
- One supported inventory:
|
||||
- `ox_inventory`
|
||||
- `qb-inventory`
|
||||
- `lj-inventory`
|
||||
- `qs-inventory`
|
||||
- `codem-inventory`
|
||||
- `core_inventory`
|
||||
- `mf-inventory`
|
||||
- `smx-inventory`
|
||||
|
||||
## Messages GIF provider
|
||||
`mf-inventory` and `smx-inventory` are supported with ESX.
|
||||
|
||||
Configure GIF search directly in the server-only `sky_phone/config/media.lua`:
|
||||
### Voice
|
||||
|
||||
```lua
|
||||
Config.Media.GiphyApiKey = "replace-with-your-giphy-api-key"
|
||||
Phone calls support:
|
||||
|
||||
- PMA Voice
|
||||
- SaltyChat
|
||||
|
||||
The Radio app supports:
|
||||
|
||||
- YACA
|
||||
- PMA Voice
|
||||
- SaltyChat
|
||||
|
||||
Start the selected voice resource before Sky Phone.
|
||||
|
||||
### Optional services
|
||||
|
||||
- FiveManage V3 Media API for Camera uploads, videos, Voice Memos, and remote Gallery deletion
|
||||
- GIPHY API for GIF search
|
||||
- Supported Garage and Housing resources when those apps should use external provider data
|
||||
|
||||
## Quick installation
|
||||
|
||||
1. Copy the resource into your FiveM resources directory.
|
||||
2. Keep the resource folder name `sky_phone`.
|
||||
3. Start `oxmysql`, your framework, inventory, and voice resource before Sky Phone.
|
||||
4. Open `sky_phone/config/config.lua` and review the configuration.
|
||||
5. Add the required inventory items.
|
||||
6. Add `ensure sky_phone` to `server.cfg`.
|
||||
7. Restart the server and watch the console for warnings.
|
||||
|
||||
Example start order:
|
||||
|
||||
```cfg
|
||||
ensure oxmysql
|
||||
ensure es_extended
|
||||
ensure ox_inventory
|
||||
ensure pma-voice
|
||||
ensure sky_phone
|
||||
```
|
||||
|
||||
GIPHY provides trending and searched GIFs through a paginated server-side proxy. Only the server
|
||||
reads the key. Never expose it to the client or NUI. Photo and video actions in Messages use media
|
||||
captured by the Camera app.
|
||||
Replace the example framework, inventory, and voice resources with the providers used by your server.
|
||||
|
||||
Database migrations run automatically. Existing `sky_phone_mail_accounts` installations are renamed to `sky_phone_accounts` while preserving account IDs and mail foreign keys. The migration also creates `sky_phone_character_devices` for persistent non-unique phone mappings and marks automatic SIMs through `sky_phone_sims.is_virtual`. Sky Cloud passwords are intentional in-character credentials and remain plaintext `VARCHAR(64)` values; registration screens warn players never to reuse a real password.
|
||||
Sky Phone creates and upgrades its database tables automatically. A manual SQL import is normally not required.
|
||||
|
||||
Camera and Gallery media is stored in `sky_phone_media`. Signed-out captures belong to the current
|
||||
IMEI; linking a Sky Cloud account moves those rows into the account gallery so every linked phone sees
|
||||
them. Signing out hides Sky Cloud media without deleting it. Factory reset removes device-local media
|
||||
and attempts to delete only remote FiveManage files created by `sky_phone`; account-owned media
|
||||
remains in Sky Cloud. Media imported from a website is removed locally but never deleted at its
|
||||
source. Register import websites under `Config.Media.Import.Websites` in
|
||||
`sky_phone/config/media.lua`; built-in adapters support FiveManage files and version-1 JSON
|
||||
manifests. The Gallery import form accepts direct HTTPS image/video links only when their hostname
|
||||
matches the selected website's `AllowedMediaHosts`.
|
||||
## Configuration
|
||||
|
||||
For a fresh manual database installation, import `sky_phone/sql/install.sql`. It contains the complete current table, key, index, collation, and foreign-key schema. Runtime migrations remain authoritative for upgrading an existing installation and must stay enabled.
|
||||
All customer settings are organized in:
|
||||
|
||||
Framework, inventory, callback, notification, and database integrations live under `sky_phone/source/bridge`. The resource has no dependency on any other Sky resource.
|
||||
```text
|
||||
sky_phone/config/config.lua
|
||||
```
|
||||
|
||||
## Weazel News app
|
||||
The file contains clearly separated sections for:
|
||||
|
||||
The built-in Weazel News app publishes articles for every phone user and exposes its editorial
|
||||
desk only to server-authorized jobs. Configure the job-to-minimum-grade map in
|
||||
`sky_phone/config/weazel_news.lua`; unlisted jobs remain read-only:
|
||||
| Section | Purpose |
|
||||
| --- | --- |
|
||||
| `Config.Bridge` | Framework, inventory, language, callback timeout, and debug mode |
|
||||
| `Config.Phone` | Phone item, movement, unique-device mode, and development command |
|
||||
| `Config.Sim` | Physical or virtual SIM behavior and number formatting |
|
||||
| `Config.Calls` / `Config.Radio` | Voice providers, call behavior, radio limits, and permissions |
|
||||
| `Config.Payphones` | Payphone pricing, props, validation, and server-owned locations |
|
||||
| `Config.Animations` | Phone prop, animations, and portrait/landscape transforms |
|
||||
| App sections | Limits and behavior for every built-in app |
|
||||
| `Config.Server` | Stable password and passcode peppers |
|
||||
| `Config.Companies` | Company directory, jobs, services, and permissions |
|
||||
| `Config.Media` | FiveManage, GIPHY, uploads, and Gallery imports |
|
||||
| `Config.Music` | Server music library and playlist limits |
|
||||
| `Config.Migrations` | Manual LB Phone migration domains |
|
||||
| `Config.WeazelNews` | Editorial jobs, categories, and article limits |
|
||||
|
||||
Restart `sky_phone` after changing Lua configuration.
|
||||
|
||||
### Language
|
||||
|
||||
Available locales:
|
||||
|
||||
- English: `en`
|
||||
- German: `de`
|
||||
|
||||
Select the language near the top of `config.lua`:
|
||||
|
||||
```lua
|
||||
AllowedJobs = {
|
||||
weazel = 0,
|
||||
reporter = 2,
|
||||
Config.Bridge.Locale = "en"
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```lua
|
||||
Config.Bridge.Locale = "de"
|
||||
```
|
||||
|
||||
Locale files are stored separately:
|
||||
|
||||
```text
|
||||
sky_phone/config/locales/en.lua
|
||||
sky_phone/config/locales/de.lua
|
||||
```
|
||||
|
||||
The German locale uses the complete English structure as a fallback, so newly introduced keys never leave the interface without text.
|
||||
|
||||
### Debug output
|
||||
|
||||
```lua
|
||||
Config.Bridge.Debug = false
|
||||
```
|
||||
|
||||
When enabled, Sky Phone prints debug and informational messages. Warnings and errors are always shown.
|
||||
|
||||
The short LB Phone detection notice also remains visible when debug mode is disabled.
|
||||
|
||||
## Security values
|
||||
|
||||
Sky Phone ships with stable generated defaults in `Config.Server`:
|
||||
|
||||
```lua
|
||||
Config.Server = {
|
||||
PasscodePepper = "...",
|
||||
FlipTokPasswordPepper = "...",
|
||||
PicstagramPasswordPepper = "...",
|
||||
}
|
||||
```
|
||||
|
||||
Every create, update, and delete request rechecks the player's current framework job and grade on
|
||||
the server. Authorized editorial jobs share the newsroom and can manage drafts and published
|
||||
articles. Cover images must come from the current phone's Gallery, changes use revision checks, and
|
||||
deletion is retained as an audit-safe soft delete. Runtime migration creates
|
||||
`sky_phone_weazel_articles` automatically; fresh installations receive the same schema through
|
||||
`sky_phone/sql/install.sql`.
|
||||
For a production server, replace them with your own long, random, different values before players create passcodes or social accounts.
|
||||
|
||||
## Radio app
|
||||
Important:
|
||||
|
||||
The built-in Radio app supports a primary frequency, volume, recent channels, participant lists, automatic rejoin, join/leave notifications, and an optional service number. YACA and SaltyChat support the configured secondary frequency; PMA Voice exposes one radio channel, so the secondary input is hidden automatically. SaltyChat also exposes the provider-backed radio speaker control when `Config.Speaker.Enabled` is enabled. The control is omitted when the global speaker system is disabled and for YACA or PMA Voice because those adapters do not provide an equivalent speaker API.
|
||||
- Keep the values private and stable.
|
||||
- Changing `PasscodePepper` invalidates existing device passcodes.
|
||||
- Changing a social-app pepper invalidates existing passwords for that app.
|
||||
- Do not replace these values during routine updates.
|
||||
|
||||
Configure frequency bounds and precision, restricted channel ranges and allowed jobs, history length, defaults, badge validation, radio display-name permissions, and the built-in speaker HUD under `Config.Radio`. `Config.Radio.DisplayName.AllowedJobs` maps authoritative framework job names to their minimum grade. Unlisted jobs cannot change the name; an empty name restores the normal player or character name. Channel and display-name access are always checked server-side. `Config.Radio.Hud` controls the phone-owned overlay, its screen edge, offsets, and recent-speaker duration without depending on another HUD resource. Active-speaker highlighting uses the YACA radio events; the Radio app itself continues to support every configured voice provider.
|
||||
Sky Cloud logins are in-character credentials for the roleplay phone. Players must never reuse a
|
||||
real-world password. FlipTok and Picstagram passwords are stored as salted hashes using their
|
||||
configured peppers.
|
||||
|
||||
Radio profiles are stored in `sky_phone_radio_profiles`. Runtime migration creates the table automatically; fresh installations receive it through `sky_phone/sql/install.sql`.
|
||||
The server-only block is evaluated only on the server. Because the project uses a customer-requested single configuration file that is also present in the client resource package, protect access to your distributed resource files if these values must remain strictly secret.
|
||||
|
||||
Inventory metadata has no framework-wide standard: providers differ in export names, callback payloads, slot handling, and whether metadata is called `metadata` or `info`. For that reason, `sky_phone` uses explicit provider adapters instead of guessing exports at runtime. Every supported adapter implements slot lookup, item lookup, metadata replacement, capacity handling, add/remove operations, and usable-item registration. Providers without a separate capacity export use their authoritative add operation as the final capacity gate. Phone item metadata is authoritative only when `Config.Phone.Unique = true`; in non-unique mode the persistent character mapping is authoritative instead.
|
||||
## Inventory items
|
||||
|
||||
When physical SIMs are enabled and a SIM is ejected or replaced, the returned inventory item is rebuilt from the authoritative `sky_phone_sims` row. Its metadata contains `sim_metadata_version`, `sim_id`, `phone_number`, `formatted_number`, and `sim_type`. Registered SIMs additionally contain `firstname`, `lastname`, `birthdate`, and `registered_at`. The internal framework owner identifier remains database-only. Inserting the item again resolves the SIM by `sim_id`; contacts and device/Sky Cloud data remain attached to their existing Device or Sky Cloud persistence instead of being copied into inventory metadata. Automatically created virtual SIMs remain database-only and never become inventory items.
|
||||
### ox_inventory
|
||||
|
||||
For `ox_inventory`, configure the phone with `stack = false` when `Config.Phone.Unique = true`; it may use `stack = true` in non-unique mode. Physical SIM items always use `stack = false` and are only needed when `Config.Sim.Enabled = true`. Every usable item should use `consume = 0`. Do not configure a client event or export. Ox then completes its normal server-authoritative use flow and emits `ox_inventory:usedItem`; the bridge resolves the authoritative slot again and only opens the matching Device or SIM. A client export would return before Ox calls `useItem` and therefore prevent `ox_inventory:usedItem` from being emitted.
|
||||
|
||||
Example `ox_inventory/data/items.lua` entries for the default unique-phone, physical-SIM modes:
|
||||
Default entries for unique phones with physical SIM cards:
|
||||
|
||||
```lua
|
||||
["phone"] = {
|
||||
@@ -265,6 +193,7 @@ Example `ox_inventory/data/items.lua` entries for the default unique-phone, phys
|
||||
close = true,
|
||||
consume = 0,
|
||||
},
|
||||
|
||||
["sky_phone_sim_registered"] = {
|
||||
label = "Registered SIM",
|
||||
weight = 5,
|
||||
@@ -272,6 +201,7 @@ Example `ox_inventory/data/items.lua` entries for the default unique-phone, phys
|
||||
close = true,
|
||||
consume = 0,
|
||||
},
|
||||
|
||||
["sky_phone_sim_anonymous"] = {
|
||||
label = "Anonymous SIM",
|
||||
weight = 5,
|
||||
@@ -281,54 +211,328 @@ Example `ox_inventory/data/items.lua` entries for the default unique-phone, phys
|
||||
},
|
||||
```
|
||||
|
||||
For QBCore-style item tables, set the phone's `unique` value to match `Config.Phone.Unique`, and use `useable = true` and `shouldClose = true`. When physical SIMs are enabled, define both SIM items with `unique = true`, `useable = true`, and `shouldClose = true`; omit them when SIMs are disabled. The provider adapter registers the server-side usable callbacks; no `lb-phone` event or export is used.
|
||||
Do not configure an LB Phone client event or client export. Sky Phone registers the usable items through its server-side inventory adapter.
|
||||
|
||||
The homescreen is an original implementation inspired by the interaction and layout concepts in [lukejacksonn/homescreen](https://github.com/lukejacksonn/homescreen), inspected at commit [`98a812f`](https://github.com/lukejacksonn/homescreen/tree/98a812f4f7c33594e791d65092f73b8f54b3c598). No source code or image assets from that project are included.
|
||||
### QBCore-style item tables
|
||||
|
||||
## Development
|
||||
- Set the phone's `unique` value to match `Config.Phone.Unique`.
|
||||
- Set `useable = true` and `shouldClose = true`.
|
||||
- Physical SIM items must always be unique.
|
||||
- SIM items are not required when `Config.Sim.Enabled = false`.
|
||||
|
||||
From `frontend/`, run `pnpm dev` for browser development. The phone opens automatically and NUI callbacks are mocked with stateful data. Every built-in app can be opened directly by appending its id to `http://localhost:5174/?apiPort=3002#/apps/`:
|
||||
## Phone and SIM modes
|
||||
|
||||
| Area | App ids |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------- |
|
||||
| Communication | `phone`, `messages`, `mail`, `darkchat`, `radio` |
|
||||
| Social | `feather`, `fliptok`, `picstagram`, `flare`, `crewlink` |
|
||||
| Services | `companies`, `citymarkt`, `local-pages`, `banking`, `billing`, `garage`, `house`, `map`, `skyride`, `weather` |
|
||||
| Media and utilities | `camera`, `photos`, `music`, `calendar`, `notes`, `calculator`, `clock`, `app-store`, `settings` |
|
||||
| Games | `snake`, `memory`, `number-merge`, `minesweeper`, `tower-stack`, `sky-flappy`, `neon-drop` |
|
||||
The two mode switches are independent:
|
||||
|
||||
The browser bootstrap includes contacts, calls, messages, mail, invoices, transactions, vehicles, properties, companies, marketplace profiles and listings, social feeds, media, calendar entries, notes, alarms, game high scores, app settings, and persisted notifications. Mutating callbacks update the in-memory mock state until the mock server restarts. Unknown callbacks fail with `mock_endpoint_missing` instead of silently succeeding.
|
||||
```lua
|
||||
Config.Phone.Unique = true
|
||||
Config.Sim.Enabled = true
|
||||
```
|
||||
|
||||
System overlays are available through dedicated preview parameters:
|
||||
| Phone mode | Behavior |
|
||||
| --- | --- |
|
||||
| `Unique = true` | Every phone item receives its own IMEI. Settings, apps, local data, linked account, and SIM move with the item. The item must not stack. |
|
||||
| `Unique = false` | Every framework character receives one persistent virtual device. Any configured phone item opens that device. The item may stack. |
|
||||
|
||||
- Lock screen: `http://localhost:5174/?apiPort=3002&lockScreenPreview=1`
|
||||
- SIM picker: `http://localhost:5174/?apiPort=3002&simPickerPreview=1`
|
||||
- Payphone: `http://localhost:5174/?apiPort=3002&payphonePreview=1` (dial `5551110001` for a connected call or `5550000000` for a busy line)
|
||||
| SIM mode | Behavior |
|
||||
| --- | --- |
|
||||
| `Enabled = true` | A registered or anonymous physical SIM item is required for cellular service. |
|
||||
| `Enabled = false` | Sky Phone creates a persistent automatic number for devices without a SIM. Physical SIM items are not required. |
|
||||
|
||||
Feather can be opened directly with the following browser scenarios:
|
||||
When changing these modes on an existing production server, restart the resource and test with a copy of the database first. The first phone used after switching to non-unique mode may adopt an existing valid IMEI so its local data is preserved.
|
||||
|
||||
- Full data: `http://localhost:5174/?apiPort=3002#/apps/feather`
|
||||
- Login and registration: `http://localhost:5174/?apiPort=3002&testScenario=feather-login#/apps/feather`
|
||||
- Profile onboarding: `http://localhost:5174/?apiPort=3002&testScenario=feather-onboarding#/apps/feather`
|
||||
- Empty states: `http://localhost:5174/?apiPort=3002&testScenario=feather-empty#/apps/feather`
|
||||
## Database
|
||||
|
||||
EasyShare browser data is available from every app that exposes a share action. Open the seeded
|
||||
Gallery directly, share an item, and then use the EasyShare and History actions in the sheet:
|
||||
Runtime migrations create and update the Sky Phone schema automatically.
|
||||
|
||||
- Full data, including incoming, transferring, accepted, completed, declined, cancelled, expired,
|
||||
and failed transfers: `http://localhost:5174/?apiPort=3002&testScenario=easyshare-full#/apps/photos`
|
||||
- Incoming request only: `http://localhost:5174/?apiPort=3002&testScenario=easyshare-incoming#/apps/photos`
|
||||
- Transfer history without active requests: `http://localhost:5174/?apiPort=3002&testScenario=easyshare-history#/apps/photos`
|
||||
- Complete content catalog with contact, document, link, location, note, photo, playlist, post,
|
||||
profile, text, track, and video: `http://localhost:5174/?apiPort=3002&testScenario=easyshare-catalog#/apps/photos`
|
||||
- Empty nearby and history states: `http://localhost:5174/?apiPort=3002&testScenario=easyshare-empty#/apps/photos`
|
||||
For hosts that require a manual fresh installation, import:
|
||||
|
||||
In the full scenario, sending to Mia or Jamie creates a pending transfer. Sending to Noah creates a
|
||||
transfer at 58 percent so the progress and cancel states can be tested. Visibility changes and
|
||||
accepting or declining the seeded incoming request are kept in memory until the mock server restarts.
|
||||
The catalog also contains source examples from Companies, Mail, Garage, and House; completed history
|
||||
rows and rich chat cards can be clicked to verify app/deep-link navigation.
|
||||
```text
|
||||
sky_phone/sql/install.sql
|
||||
```
|
||||
|
||||
The full-data scenario includes posts, replies, quotes, media grids, profiles, ranked hashtags, network search results, and every notification type. Run `pnpm test`, `pnpm typecheck`, `pnpm lint`, and `pnpm build` before packaging.
|
||||
Keep runtime migrations enabled after importing the SQL file because they remain responsible for future upgrades.
|
||||
|
||||
`pnpm build` uses `build.cjs` to replace `sky_phone/source/html` deterministically with the Vite output. Production assets use relative paths so they work through the FiveM NUI protocol.
|
||||
A Sky Cloud account is optional. Devices without an account retain local settings and supported local app data. Linking an account synchronizes supported data across linked devices.
|
||||
|
||||
## Media and uploads
|
||||
|
||||
Configure FiveManage in the server-only media section:
|
||||
|
||||
```lua
|
||||
Config.Media.FiveManage.ApiKey = "your-fivemanage-v3-media-token"
|
||||
```
|
||||
|
||||
Without a valid token:
|
||||
|
||||
- Camera uploads are disabled
|
||||
- Video uploads are disabled
|
||||
- Voice Memo uploads are disabled
|
||||
- FiveManage Gallery imports are unavailable
|
||||
|
||||
Configure GIF search with:
|
||||
|
||||
```lua
|
||||
Config.Media.GiphyApiKey = "your-giphy-api-key"
|
||||
```
|
||||
|
||||
Gallery import websites are configured under `Config.Media.Import.Websites`. Direct URLs are accepted only when their HTTPS hostname matches the configured allowed hosts.
|
||||
|
||||
## Music
|
||||
|
||||
Place server-owned audio files anywhere below:
|
||||
|
||||
```text
|
||||
sky_phone/config/music/
|
||||
```
|
||||
|
||||
Supported audio formats:
|
||||
|
||||
- OGG
|
||||
- MP3
|
||||
|
||||
Optional artwork may use:
|
||||
|
||||
- WEBP
|
||||
- PNG
|
||||
- JPG
|
||||
- JPEG
|
||||
|
||||
Configure each track in `Config.Music.Tracks`:
|
||||
|
||||
```lua
|
||||
Config.Music.Tracks = {
|
||||
{
|
||||
Id = "night-drive",
|
||||
Title = "Night Drive",
|
||||
Artist = "Sky Records",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Name the audio and artwork files after the stable track ID, for example:
|
||||
|
||||
```text
|
||||
night-drive.ogg
|
||||
night-drive.webp
|
||||
```
|
||||
|
||||
Restart Sky Phone after adding files. A frontend rebuild is not required.
|
||||
|
||||
Players may also add public YouTube video links to their personal music library.
|
||||
|
||||
## Voice and Radio
|
||||
|
||||
### Calls
|
||||
|
||||
```lua
|
||||
Config.Calls.VoiceProvider = "pma"
|
||||
```
|
||||
|
||||
Supported values:
|
||||
|
||||
- `pma` or `pma-voice`
|
||||
- `saltychat` or `salty`
|
||||
|
||||
SaltyChat supports the provider-backed call speaker feature. PMA Voice keeps the speaker option unavailable.
|
||||
|
||||
### Radio
|
||||
|
||||
```lua
|
||||
Config.Radio.VoiceProvider = "auto"
|
||||
```
|
||||
|
||||
Automatic selection checks YACA, PMA Voice, and SaltyChat. Restricted frequency ranges and job access are configured in `Config.Radio.LockedChannels`.
|
||||
|
||||
Radio display-name permissions are configured in `Config.Radio.DisplayName.AllowedJobs`.
|
||||
|
||||
## Payphones
|
||||
|
||||
Sky Phone includes server-authoritative GTA V payphone locations. Pricing, payment account, props, validation distances, and custom locations are configured under `Config.Payphones`.
|
||||
|
||||
Custom location example:
|
||||
|
||||
```lua
|
||||
Config.Payphones.Locations = {
|
||||
{ model = "prop_phonebox_01a", coords = { x = 123.45, y = 678.90, z = 21.0 } },
|
||||
}
|
||||
```
|
||||
|
||||
The model must also be listed in `Config.Payphones.Props`.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Where | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `/phone` | In game | Opens the development phone command when `Config.Phone.DevelopmentCommand` is enabled |
|
||||
| `/phonetestdata` | In game | Creates customer-scoped test data when `Config.TestData.Enabled` is enabled |
|
||||
| `/fliptokverify <@handle> [on\|off]` | In game | Toggles or sets FlipTok verification for configured admin groups |
|
||||
| `/picstagramverify <@handle> <on\|off>` | In game | Sets Picstagram verification for configured admin groups |
|
||||
| `skyphone:migrate lb-phone dry` | Server console | Previews the LB Phone migration |
|
||||
| `skyphone:migrate lb-phone` | Server console | Imports enabled LB Phone domains |
|
||||
| `skyphone:migrate lb-phone force` | Server console | Re-runs enabled domains idempotently |
|
||||
| `skyphone:migrate lb-phone remove` | Server console | Removes imported Sky Phone records and migration markers |
|
||||
|
||||
Command names and admin groups for the social apps are configurable.
|
||||
|
||||
Disable test data on production servers:
|
||||
|
||||
```lua
|
||||
Config.TestData.Enabled = false
|
||||
```
|
||||
|
||||
## LB Phone migration
|
||||
|
||||
Sky Phone detects supported LB Phone database tables during startup and prints a short notice. Detection never starts a migration automatically.
|
||||
|
||||
Recommended workflow:
|
||||
|
||||
1. Create a database backup.
|
||||
2. Run the preview:
|
||||
`skyphone:migrate lb-phone dry`
|
||||
3. Review the domain summaries.
|
||||
4. Run the import:
|
||||
`skyphone:migrate lb-phone`
|
||||
5. Restart and verify the migrated accounts and apps.
|
||||
|
||||
The importer:
|
||||
|
||||
- Reads LB Phone source tables without modifying them
|
||||
- Supports preserved `_lb` tables created by sd-phone migrations
|
||||
- Records per-domain completion markers
|
||||
- Can be retried safely with `force`
|
||||
- Can remove migration-created Sky Phone data with `remove`
|
||||
- Reports unsupported source records instead of forcing them into incompatible Sky Phone structures
|
||||
|
||||
Supported domains include devices, settings, alarms, contacts, blocked numbers, calls, messages, photos, notes, wallet, voice memos, Picstagram, Mail, map markers, compatible DarkChat data, FlipTok, and Feather.
|
||||
|
||||
The migration command is server-console only.
|
||||
|
||||
## Garage, Housing, and Companies
|
||||
|
||||
### Garage
|
||||
|
||||
Select the provider under `Config.Garage.System`. Vehicle images use the configured CDN template with an icon fallback when no image is available.
|
||||
|
||||
### Housing
|
||||
|
||||
Select the provider under `Config.Housing.System`. Automatic mode supports the configured provider priority.
|
||||
|
||||
### Companies
|
||||
|
||||
Company jobs, public profiles, service numbers, services, permissions, locations, and default availability are configured under `Config.Companies.Definitions`.
|
||||
|
||||
### Weazel News
|
||||
|
||||
Configure editorial jobs and minimum grades:
|
||||
|
||||
```lua
|
||||
Config.WeazelNews.AllowedJobs = {
|
||||
weazel = 0,
|
||||
reporter = 2,
|
||||
}
|
||||
```
|
||||
|
||||
Unlisted jobs can read news but cannot manage articles.
|
||||
|
||||
## External custom apps
|
||||
|
||||
Sky Phone includes compatibility adapters for supported custom-app contracts from:
|
||||
|
||||
- LB Phone
|
||||
- 17Movement
|
||||
- High Phone
|
||||
- Quasar Smartphone
|
||||
- YSeries
|
||||
|
||||
The resource provides the compatibility aliases `lb-phone`, `17mov_Phone`, `high-phone`, `qs-smartphone`, and `yseries`.
|
||||
|
||||
See [Custom App Integration](docs/custom-apps.md) for setup details and compatibility limits.
|
||||
|
||||
## Updating Sky Phone
|
||||
|
||||
Before updating:
|
||||
|
||||
1. Back up the database.
|
||||
2. Back up `config/config.lua` and any custom media.
|
||||
3. Keep the three pepper values unchanged.
|
||||
4. Replace the resource files.
|
||||
5. Reapply customer-specific configuration carefully.
|
||||
6. Restart Sky Phone and review warnings and errors.
|
||||
|
||||
Do not overwrite a production configuration without comparing it to the new version.
|
||||
|
||||
## Frontend development
|
||||
|
||||
Customers installing a release do not need to build the frontend.
|
||||
|
||||
For development:
|
||||
|
||||
```powershell
|
||||
cd frontend
|
||||
pnpm install
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
Create a production frontend build with:
|
||||
|
||||
```powershell
|
||||
pnpm build
|
||||
```
|
||||
|
||||
The production output is written to `sky_phone/source/html`.
|
||||
|
||||
Useful checks:
|
||||
|
||||
```powershell
|
||||
pnpm typecheck
|
||||
pnpm test
|
||||
pnpm lint
|
||||
pnpm build
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### The phone item does nothing
|
||||
|
||||
- Confirm the framework and inventory are supported and started first.
|
||||
- Confirm the item name matches `Config.Phone.Item`.
|
||||
- Confirm the item is usable.
|
||||
- In unique mode, confirm the phone is non-stackable.
|
||||
- Check the server console for inventory adapter warnings.
|
||||
|
||||
### Calls connect without audio
|
||||
|
||||
- Confirm the configured voice resource is running.
|
||||
- Confirm `Config.Calls.VoiceProvider` matches the installed provider.
|
||||
- Start the voice resource before Sky Phone.
|
||||
|
||||
### Camera or Voice Memos cannot upload
|
||||
|
||||
- Configure a valid FiveManage V3 Media API token.
|
||||
- Confirm the token has the required file permissions.
|
||||
- Restart Sky Phone after changing the token.
|
||||
|
||||
### Social app password or passcode warnings appear
|
||||
|
||||
- Check the values in `Config.Server`.
|
||||
- Use long, stable values.
|
||||
- Do not change them after accounts or passcodes have been created.
|
||||
|
||||
### The LB Phone notice appears
|
||||
|
||||
This is only a detection notice. No data is imported automatically. Run the `dry` command from the server console when you are ready.
|
||||
|
||||
### More diagnostic output is needed
|
||||
|
||||
Enable:
|
||||
|
||||
```lua
|
||||
Config.Bridge.Debug = true
|
||||
```
|
||||
|
||||
Reproduce the problem, collect the relevant server and client console lines, and disable debug mode again afterward.
|
||||
|
||||
## Credits and notices
|
||||
|
||||
Third-party acknowledgements and license information are available in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
|
||||
|
||||
Reference in New Issue
Block a user