Exports et state bags
Deux portes dâentrĂ©e, et la plus Ă©conomique dâabord.
phoneapi <id> affiche tout ce qui suit pour un joueur, dans la console du serveur. Si quelque chose ne renvoie pas le rĂ©sultat attendu, exĂ©cutez cette commande avant dâaller plus loin â câest bien plus rapide que de deviner de quel cĂŽtĂ© vient lâerreur.
State bags â les rĂ©ponses qui ne coĂ»tent rien
Section intitulĂ©e « State bags â les rĂ©ponses qui ne coĂ»tent rien »Un state bag ne nĂ©cessite aucun callback, aucun Ă©vĂ©nement et aucun accord avec cette ressource. Il sâagit dâune table lue localement sur la machine qui pose la question, elle survit au redĂ©marrage de cette ressource en arriĂšre-plan, et elle fonctionne de la mĂȘme maniĂšre cĂŽtĂ© client et cĂŽtĂ© serveur.
-- serverif Player(src).state.onCallWith then ... end
-- client, about somebody elseif Player(GetPlayerFromServerId(id)).state.phoneOpen then ... end| Bag | Type | |
|---|---|---|
phoneNumber | string | le numéro du téléphone transporté |
phoneName | string | le nom affichĂ© par ce tĂ©lĂ©phone lorsquâil appelle quelquâun |
phoneDevice | string | nil | identifiant de lâitem tĂ©lĂ©phone en mode item. nil quand le tĂ©lĂ©phone appartient au personnage |
phoneOpen | boolean | le tĂ©lĂ©phone est sorti et visible Ă lâĂ©cran |
onCallWith | number | nil | la source du correspondant Ă lâautre bout |
callAnswered | boolean | quelquâun a dĂ©crochĂ©. false tant que la sonnerie retentit |
speakerphone | boolean | haut-parleur activé |
mutedCall | boolean | le joueur sâest mis en sourdine |
otherMutedCall | boolean | le correspondant sâest mis en sourdine |
flashlight | boolean | la lampe torche est allumée. Chaque client affiche le faisceau sur ce ped |
phoneCamera | boolean | le viseur est ouvert : le joueur est sur le point de prendre une photo |
phoneSignal | number | nombre de barres, de 0 à Config.Signal.Bars. 0 signifie téléphone injoignable |
Trois points importants :
Ils sont renseignĂ©s par le serveur. Le client en a Ă©galement connaissance et pourrait les publier en moins de lignes, mais un client peut mentir sur chacune de ces valeurs, et un state bag lu par un anticheat doit ĂȘtre digne de confiance.
La sonnerie compte comme un appel en cours. onCallWith est dĂ©fini dĂšs quâun tĂ©lĂ©phone commence Ă sonner, car la ligne est occupĂ©e â ce qui nâest pas encore acquis est que quelquâun ait dĂ©crochĂ©, ce qui correspond Ă callAnswered.
onCallWith peut valoir nil au cours dâun appel rĂ©el. Lâautre correspondant peut utiliser son navigateur web plutĂŽt que dâĂȘtre un joueur prĂ©sent dans la ville. callAnswered reste true ; il nây a simplement aucun ID de source FiveM Ă dĂ©signer.
Le state bag flashlight nâa Ă©tĂ© implĂ©mentĂ© que lorsque la torche a rĂ©ellement Ă©clairĂ© la scĂšne, partant du principe quâun bag valant constamment false est pire quâun bag absent â lâun est une fonctionnalitĂ© manquante, lâautre est une fausse information. La torche Ă©claire dĂ©sormais, lâĂ©tat est donc publiĂ©.
Exports serveur
Section intitulĂ©e « Exports serveur »exports.mic_phone:GetNumber(src) --> '555-010-2048'exports.mic_phone:GetName(src) --> 'Jean Dupont'exports.mic_phone:GetIdentifier(src) --> 'char1:abcâŠ' or 'device:abcâŠ' in item modeexports.mic_phone:GetDevice(src) --> the phone item's id, or nilexports.mic_phone:HasPhone(src) --> are they carrying one at allexports.mic_phone:IsOpen(src)exports.mic_phone:IsInCall(src)exports.mic_phone:CallWith(src) --> the other source, or nil
exports.mic_phone:GetSource(number) --> src, for a numberexports.mic_phone:NumberOf(identifier) --> works for somebody who is not onlineexports.mic_phone:IdentifierOf(number)
exports.mic_phone:Call(src, number) --> rings it from their phone, exactly as dialling wouldexports.mic_phone:EndCall(src)exports.mic_phone:AddContact(src, name, number, { email =, notes =, favorite = })exports.mic_phone:RemoveContact(src, number)exports.mic_phone:SendNotification(src, { app =, title =, body = })exports.mic_phone:OpenApp(src, 'messages')exports.mic_phone:OpenPhone(src) / ClosePhone(src)
exports.mic_phone:SendMessage(number, text, from)exports.mic_phone:SendMail(identifierOrNumber, fromName, fromAddress, subject, body)exports.mic_phone:SendInvoice(senderSrc, targetNumber, label, amount, society)Call renvoie ce qui aurait Ă©tĂ© signifiĂ© au tĂ©lĂ©phone lui-mĂȘme â { ok = false, reason = 'busy' }, 'airplane', 'unknown', 'offline' â car il emprunte le mĂȘme gestionnaire que le composeur natif du tĂ©lĂ©phone. Il nâexiste quâune seule branche de code et un seul ensemble de rĂšgles susceptibles dâĂ©chouer.
Un export dont la rĂ©ponse est nil ne renvoie aucune valeur, et non une valeur nil. PlacĂ© directement dans une liste dâarguments, il ne devient pas "nil" â il raccourcit la liste. Stockez-le dâabord dans une variable locale :
local with = exports.mic_phone:CallWith(src) -- and not print(exports.mic_phone:CallWith(src), x)Le tĂ©lĂ©phone lui-mĂȘme
Section intitulĂ©e « Le tĂ©lĂ©phone lui-mĂȘme »Les questions quâune autre ressource devait sans cesse trancher par ses propres moyens. Chacune correspond Ă une vĂ©rification que le tĂ©lĂ©phone effectue dĂ©jĂ , garantissant un comportement strictement identique.
exports.mic_phone:GetBattery(src) --> 0-100, or nil when this city has no battery at allexports.mic_phone:SetBattery(src, 40) --> your own charger, or a story that drains oneexports.mic_phone:IsCharging(src)exports.mic_phone:HasAirplaneMode(src) --> the city cannot reach them; their own phone still works
exports.mic_phone:GetSignal(src) --> 0 to Config.Signal.Bars. Also the `phoneSignal` state bagexports.mic_phone:SetJammed(src, true) --> takes their bars away: a heist, a prison, a story
exports.mic_phone:GetGallery(src) --> every picture: { id, url, width, height, kind, created }exports.mic_phone:AddPhoto(src, url, w, h) --> puts one in it, and it appears without a rebootexports.mic_phone:GetContacts(src)
exports.mic_phone:GetInvoices(src) --> every invoice on that phone, paid and unpaidexports.mic_phone:UnpaidInvoices(src) --> count, total
exports.mic_phone:SendLocation(number, x, y, 'The docks', from) --> a map pin in a conversation
exports.mic_phone:GetSocialHandle(src, 'instapic') --> 'nightshift', or nil if they never signed upexports.mic_phone:SocialPost(src, 'twixel', { text = 'Anybody seen a blue Sultan?' })exports.mic_phone:SetVerified(src, 'twixel', true) --> the tick beside their name, per app
exports.mic_phone:GetRadioChannel(src) --> 12, or nilexports.mic_phone:SetRadioChannel(src, 12) --> 0 takes them off itLe fait que GetBattery rĂ©ponde nil nâest pas Ă©quivalent Ă rĂ©pondre 0 : nil indique que ce serveur nâa jamais activĂ© la gestion de la batterie. Un script traitant les deux cas de la mĂȘme maniĂšre empĂȘcherait dâappeler les secours dans une ville oĂč les tĂ©lĂ©phones ne se dĂ©chargent jamais.
AddPhoto valide lâURL par rapport aux hĂ©bergeurs autorisĂ©s par ce serveur, exactement comme le clichĂ© pris depuis lâappareil photo. Une galerie capable dâafficher nâimporte quelle adresse serait une faille permettant dâafficher nâimporte quoi.
SocialPost et SetRadioChannel appellent les gestionnaires internes du tĂ©lĂ©phone, et respectent donc les mĂȘmes rĂšgles que lâinterface : lâabsence de compte sur cette application empĂȘche la publication, et un canal interdit Ă ce mĂ©tier est Ă©galement refusĂ© ici.
Le marché crypto
Section intitulĂ©e « Le marchĂ© crypto »Six devises tarifĂ©es par le serveur via une minuterie inaccessible depuis un client. Tout ce qui suit est formulĂ© en devises entiĂšres et en argent â jamais dans les millioniĂšmes utilisĂ©s pour les calculs internes â, ainsi un script versant un quart dâunitĂ© transmettra 0.25.
exports.mic_phone:Coins() --> every coin: id, name, symbol, price, change, window, historyexports.mic_phone:CoinPrice('santo') --> 42137.55, in money. nil when there is no such coinexports.mic_phone:GetCrypto(src, 'santo') --> 0.4218exports.mic_phone:GetCryptoValue(src) --> what their whole portfolio is worth, in money
exports.mic_phone:AddCrypto(src, 'omen', 12.5) --> true when it landedexports.mic_phone:RemoveCrypto(src, 'omen', 12.5) --> false when they did not have it, and nothing movesexports.mic_phone:SetCoinPrice('omen', 0.4) --> move the market for a storyRemoveCrypto rejette la transaction plutĂŽt que de crĂ©er un solde nĂ©gatif, sa rĂ©ponse indique donc Ă©galement si le joueur Ă©tait en mesure de payer â ce qui est exactement la question quâune boutique acceptant la cryptomonnaie souhaite poser :
if exports.mic_phone:RemoveCrypto(src, 'omen', price) then giveThem(thing) endLe portefeuille est rattachĂ© soit au personnage soit au tĂ©lĂ©phone, selon la configuration de Config.Apps.Crypto.Wallet. En mode appareil, voler un tĂ©lĂ©phone subtilise le portefeuille dâactifs ; en mode personnage, un tĂ©lĂ©phone volĂ© prĂ©sente une application vide au voleur. Les exports acceptent un ID source dans les deux cas et nâont pas besoin de connaĂźtre ce mode.
phonecrypto dans la console affiche lâĂ©tat du marchĂ©, phonecrypto <id> dĂ©taille les avoirs dâun joueur, et phonecrypto price <coin> <money> ajuste le cours manuellement.
Batterie et lampe torche
Section intitulĂ©e « Batterie et lampe torche »Toutes deux sâactivent ou se dĂ©sactivent depuis la configuration â shared/config/battery.lua et Config.Flashlight â la batterie Ă©tant dĂ©sactivĂ©e par dĂ©faut et la torche activĂ©e.
exports.mic_phone:BatteryLevel(src) --> 0-100, or 100 when the battery is switched offexports.mic_phone:IsPhoneCharging(src)exports.mic_phone:ChargePhone(src, true) -- plug in; false unplugsUn chargeur nâa pas nĂ©cessairement besoin dâĂȘtre un item dans une poche. Config.Battery.Charger.Item en fournit un clĂ© en main, et ChargePhone couvre toutes les autres intĂ©grations : cĂąble allume-cigare en vĂ©hicule, prise murale, accessoire de bureau.
phonebattery [charge|unplug|full|empty] <id> force lâĂ©tat, idĂ©al pour tester la batterie sans mettre sa propre patience Ă lâĂ©preuve.
Commandes dâadministration
Section intitulĂ©e « Commandes dâadministration »Les administrateurs en jeu (ainsi que la console) disposent de quelques commandes pour diagnostiquer un comportement inattendu. Elles permettent dâinspecter ou de modifier dĂ©libĂ©rĂ©ment le tĂ©lĂ©phone dâun joueur ; aucune nâinvente de donnĂ©es.
phoneapi <id> | state bags, exports et batterie dâun joueur |
phoneapps | liste des applications telles que résolues par la config |
phonedevice [backup|restore] <id> | quel téléphone le joueur possÚde et sauvegardes associées |
phonebattery [charge|unplug|full|empty] <id> |
phoneapi affiche Ă©galement si ce tĂ©lĂ©phone capte du rĂ©seau et les donnĂ©es en attente dâacheminement, ce qui rĂ©sume la chaĂźne dâĂ©vĂ©nements entre âaucun signalâ et âla notification est arrivĂ©eâ en deux lignes. Ce flux traversant quatre Ă©tapes, il Ă©tait auparavant complexe dâidentifier laquelle bloquait.
Le niveau nâest pas un compte Ă rebours. Une ligne enregistre le niveau prĂ©cĂ©dent, lâhorodatage et lâĂ©tat du tĂ©lĂ©phone â ouvert, en poche ou en charge â et le niveau actuel est calculĂ© mathĂ©matiquement Ă lâinstant T. Cent joueurs mobilisent cent nombres au lieu de cent timers actifs, et un tĂ©lĂ©phone laissĂ© en charge pendant un redĂ©marrage du serveur revient rechargĂ© plutĂŽt que figĂ©.
EmpĂȘcher votre interface dâapparaĂźtre dans les photos des joueurs
Section intitulĂ©e « EmpĂȘcher votre interface dâapparaĂźtre dans les photos des joueurs »(Cette notion ainsi que les rĂšgles de cohabitation â le ped, le prop, le mode item â sont rassemblĂ©es dans votre ressource Ă ses cĂŽtĂ©s.)
Une photo capture lâĂ©cran entier. Tout ce que votre ressource affichait au moment du dĂ©clenchement â texte dâaide, marqueur 3D, barre de progression â figurera sur lâimage, et cette ressource ne peut pas vous empĂȘcher de lâafficher.
phoneCamera est mis Ă disposition pour vous permettre de suspendre ces affichages. Ce state bag est true dĂšs lâouverture du viseur jusquâĂ sa fermeture ; une seule condition dans votre boucle de rendu rĂ©sout le problĂšme :
if LocalPlayer.state.phoneCamera then goto skip endLâinterface propre au tĂ©lĂ©phone sâefface dâelle-mĂȘme : Config.Apps.Camera.HideHud masque la mini-carte et les jauges de vie du jeu tant que lâappareil photo est actif, assurant que le clichĂ© obtenu corresponde fidĂšlement au cadrage du joueur.
La torche sâappuie sur le state bag flashlight, de sorte que tous les autres clients projettent le faisceau lumineux depuis le ped de ce joueur. Elle ne reste allumĂ©e que lorsque le tĂ©lĂ©phone est sorti et sâĂ©teint dĂšs quâil est rangĂ©.
Exports client
Section intitulĂ©e « Exports client »exports.mic_phone:Open() / Close() / Toggle() / IsOpen()exports.mic_phone:CanOpen() --> ok, reasonexports.mic_phone:Restricted() --> 'Dead' | 'Cuffed' | 'Swimming' | ⊠| nilexports.mic_phone:OpenApp('bank') / CloseApp()exports.mic_phone:GetNumber() / GetDevice() / HasPhone() / IsBooted()exports.mic_phone:IsInCall() / IsTablet() / SetTablet(true)exports.mic_phone:Notify({ app =, title =, body = })Rien ici ne contourne les contrĂŽles que le tĂ©lĂ©phone sâapplique Ă lui-mĂȘme. Open et OpenApp rencontrent les mĂȘmes refus quâun joueur appuyant sur F1, pour les mĂȘmes raisons â un tĂ©lĂ©phone qui sâouvrirait alors que son propriĂ©taire est mort sous prĂ©texte quâune ressource le demande poliment nâest pas un systĂšme fiable. CanOpen et Restricted existent pour vous permettre de vĂ©rifier lâĂ©ligibilitĂ© en amont, afin de griser une option plutĂŽt que de proposer un bouton inopĂ©rant.
Noms de clés
Section intitulée « Noms de clés »Les noms de state bags correspondent à ceux de lb-phone lorsque la signification est identique, permettant à un script conçu pour ce dernier de fonctionner ici sans la moindre modification.