Interact system
Système d'interaction 3D + moteur de dialogues PNJ, sans aucune dépendance. Posez une interaction n'importe où sur la map : sur une entity, sur une coordonnée libre, ou sur un PNJ que vous faites apparaître depuis le même appel. Pas d'ox_lib, pas de framework, rien à configurer côté serveur.
Ce qu'il fait
Aucune dépendance
Depuis la 1.1.0, la ressource embarque sa propre gestion des DUI, ses points de proximité et ses helpers d'attente dans `bridges/compat.lua`, écrits en natifs purs. Rien à installer avant, aucun ordre de chargement à tenir. Si vous tournez déjà avec ox_lib et préférez lui laisser ce travail, passez `Config.UseOxLib = true` et décommentez une ligne du manifest.
Spécifications
techniques
Tout ce que vous
recevez
-
Quinze fichiers de langue, livrés remplis
Vos joueurs lisent le script dans leur langue dès le premier démarrage, et les fichiers sont hors escrow, donc vous pouvez corriger n'importe quelle ligne en production. Note honnête : ils sont traduits et relus par nos soins, pas par des natifs des quinze langues. Dites-nous ce qui sonne faux dans la vôtre, c'est corrigé.
-
Tout se règle dans config.lua
Label, touche, distances, icône et couleur par défaut d'un point, couleurs nommées, correspondance entre libellé de touche et control index, PNJ utilisé quand une entrée n'en précise pas, distance d'apparition, et `Config.Hud` pour choisir quel HUD est masqué pendant un dialogue. Tout ça est sorti de l'escrow en 1.1.0.
-
Trois exemples fonctionnels
Un watcher d'ATM enregistré par hash de modèle avec un menu à deux touches, un PNJ avec un dialogue à embranchements complet et un waypoint GPS, et un point de danse multi-touches. De vrais fichiers dans `config/`, à supprimer une fois les vôtres écrits.
-
Support Discord et mises à jour à vie
Accès au salon de support, et toutes les futures mises à jour sans surcoût. Pas de palier premium, pas d'extension payante.
Guide d'intégration
Installation
-
Déposez la ressource
Récupérez le script depuis votre compte Tebex, puis copiez le dossier
avenida_interact/dansresources/[avenida]/sur votre serveur. -
Activez dans server.cfg
Ajoutez
ensure avenida_interact. Rien n'a besoin de charger avant : depuis la 1.1.0 la ressource n'a aucune dépendance, l'ordre de chargement n'a donc pas d'importance. -
Réglez vos valeurs par défaut
Ouvrez
config/config.luaet ajustez ce qui s'applique à tous les points : label, touche, distancesshowIconetcanInteract, icône, couleur, couleurs nommées, distance d'apparition des PNJ, etConfig.Hudpour choisir quel HUD est masqué pendant un dialogue. -
Retirez les démos
Les exemples de
config/entities/,config/peds/etconfig/positions/sont actifs tant que leurs fichiers sont là. Supprimez ceux dont vous ne voulez pas, le manifest globe ces dossiers, il n'y a rien d'autre à modifier. -
Testez le rechargement à chaud
Démarrez le serveur, puis tapez
/restart avenida_interacten jeu. Les icônes disparaissent et reviennent proprement, et les points enregistrés par vos propres ressources survivent, sans relancer votre session.
Démarrage rapide
Votre premier point d'interaction en 30 secondes
Créez un `myscript/client.lua` dans votre propre ressource et collez ceci. Un marqueur cyan apparaît à 30m, le prompt "E - Hello" se déroule à 2m. La seule chose qui doit tourner, c'est avenida_interact lui-même.
-- myscript/client.lua
exports.avenida_interact:positionRegister({
coords = vec3(-265.0, -963.6, 31.2),
showIcon = 30.0, -- marker fades in at 30m
canInteract = 2.0, -- label unrolls at 2m
hintIcon = 'interact', -- see the icon list below
hintColor = '#22d3ee', -- hex, or an alias from Config.Colors
message = 'Hello',
bind = 'E',
onInteract = function()
TriggerEvent('chat:addMessage', { args = { 'Hello, world!' } })
end,
})Référence API
Exports publics groupés par domaine. Chaque ligne montre la signature d'appel
Interact Points
positionRegister
exports.avenida_interact:positionRegister(cfg) --> idEnregistre un point sur des coordonnées fixes. Accepte tous les champs visuels (
hintIcon,hintColor,showIcon,canInteract,offsetZ,blips) pluschoices[]pour plusieurs touches sur le même point.canInteractaccepte un nombre ou une fonction, vous pouvez donc conditionner le prompt à un job, un item ou un cooldown. Renvoie un id.pedRegister
exports.avenida_interact:pedRegister(cfg) --> idFait apparaître un PNJ configuré (modèle,
animDictetanimNameou un scenario, blip), lui attache un point et renvoie son index. Le ped est invincible, ne fuit pas et ne tombe pas en ragdoll. Il apparaît et disparaît autour deConfig.PedSpawnRange, 50m par défaut. MettezrandomComponents = falsesur un vendeur nommé, sinon chaque joueur voit une tenue différente.pedRemove
exports.avenida_interact:pedRemove(idx)Ajouté en 1.1.0. Fait disparaître un ped enregistré avec
pedRegisteret retire son enregistrement, pour qu'un donneur de quête temporaire puisse partir une fois la quête finie.entityRegister
exports.avenida_interact:entityRegister(cfg) --> idAttache un point sur une entity existante, passée dans
cfg.entity. Gèrecfg.bonepour accrocher le prompt sur un bone plutôt que sur le centre de l'entity. À utiliser pour ce qu'un autre script a fait apparaître : un véhicule, un prop posé, un objet lâché.entityRegisterByHash
exports.avenida_interact:entityRegisterByHash(hash, cfg)Watcher passif : la config s'applique à toutes les entities de ce modèle, celles déjà streamées et celles qui apparaîtront. Un seul thread couvre tous les hash enregistrés et balaye toutes les 5s. C'est ce qu'il vous faut pour les ATM, les distributeurs et les portes, plutôt qu'une liste de coordonnées à maintenir.
entityRemove
exports.avenida_interact:entityRemove(idx)Détache le point renvoyé par
entityRegister. L'entity elle-même n'est pas touchée.interactCreate
exports.avenida_interact:interactCreate(cfg) --> idPoint créé et retiré à la volée. À utiliser quand le point n'existe qu'un temps : un objectif de mission, un sac au sol, un corps à fouiller.
interactRemove
exports.avenida_interact:interactRemove(id)Retire un point créé par
interactCreate, et son blip s'il en déclarait un.unlockLastInteract
exports.avenida_interact:unlockLastInteract()Un point se verrouille une fois utilisé, pour qu'une touche maintenue ne le déclenche pas deux fois. Appelez ceci à la fin de votre action pour le réarmer. Si le joueur est encore à portée, le prompt revient directement, sinon il attend qu'il rentre à nouveau dans la zone.
Prompt API
HandleTextUI
exports.avenida_interact:HandleTextUI(id, data) --> duiHandlerCrée ou met à jour une bulle 3D autonome, sans point d'interaction derrière. Pour quand vous voulez piloter la visibilité depuis votre propre thread. Renvoie le handler à passer à
Draw3DSprite.Draw3DSprite
exports.avenida_interact:Draw3DSprite({ duiHandler, coords, maxDistance, hintOnly? })Dessine la bulle dans le monde depuis un thread de rendu, dé-étirée selon le ratio de l'écran. Avec
hintOnly = true, seul le marqueur est dessiné, c'est l'état longue distance d'un point normal.CloseTextUI
exports.avenida_interact:CloseTextUI(id)Masque une bulle mais garde son DUI en mémoire, la réouverture est donc instantanée.
RemoveTextUI
exports.avenida_interact:RemoveTextUI(id)Retire une bulle définitivement et libère son DUI. À utiliser quand vous savez qu'elle ne reviendra pas.
RemoveTextUIs
exports.avenida_interact:RemoveTextUIs()Retire toutes les bulles actives. Appelé pour vous quand la ressource s'arrête.
IsDuiVisible
exports.avenida_interact:IsDuiVisible() --> booleanVrai tant qu'un prompt est à l'écran. Lisez-le pour éviter que vos propres prompts s'empilent par-dessus une interaction.
Key handler
HandleHoldTextUI
exports.avenida_interact:HandleHoldTextUI(id, data) --> duiHandlerLa couche sur laquelle les points sont construits : elle dessine un prompt sur
Coordset surveille sa touche depuis un thread manager à 50ms.dataprendBindToHold(control index),DistanceHold,Coords,ChoicesUIetChoicesCtrlpour un prompt multi-touches,onCallback(id)etcanInteract(id, dist). Déclenche à la pression avec un debounce de 500ms, et votre callback tourne dans unpcall, donc une erreur de votre côté ne casse pas le prompt.CloseHoldTextUI
exports.avenida_interact:CloseHoldTextUI(id)Masque le prompt sans détruire l'instance, pour une sortie propre quand le joueur quitte la zone.
RemoveHoldTextUI
exports.avenida_interact:RemoveHoldTextUI(id)Détruit une instance et libère son DUI.
RemoveHoldTextUIs
exports.avenida_interact:RemoveHoldTextUIs()Détruit toutes les instances actives.
Recettes
Exemples copier-coller pour les cas courants. À déposer dans ta ressource, ajuster les valeurs, et c'est en prod.
Le cas le plus simple : un point sur des coordonnées, avec son blip déclaré dans la même table. Le marqueur s'affiche à 30m, le label à 2m. À déposer dans n'importe quel fichier client de votre ressource.
exports.avenida_interact:positionRegister({
coords = vec3(149.5, -1040.4, 29.4),
showIcon = 30.0,
canInteract = 2.0,
hintIcon = 'bank',
hintColor = 'blue',
message = 'Use the ATM',
bind = 'E',
onInteract = function()
TriggerEvent('myserver-banking:openATM')
end,
blips = {
sprite = 277,
color = 2,
scale = 0.8,
text = 'ATM',
display = 4,
},
})Le watcher enregistre votre config une fois par modèle et l'applique à chaque prop correspondant, déjà streamé ou non. Chaque choix porte son label, sa couleur et sa `condition`, le braquage n'apparaît donc que si votre script police l'autorise. Attention au nom du champ : un choix utilise `condition`, pas `canInteract`.
local ATM_PROPS = {
'prop_atm_01', 'prop_atm_02', 'prop_atm_03', 'prop_fleeca_atm',
}
for _, prop in ipairs(ATM_PROPS) do
exports.avenida_interact:entityRegisterByHash(prop, {
canInteract = 1.2,
offsetZ = 1.0,
hintIcon = 'bank',
hintColor = 'blue',
choices = {
{
bind = 'E',
message = 'Use the ATM',
onInteract = function()
TriggerEvent('myserver-banking:atmUse')
end,
},
{
bind = 'G',
message = 'Rob the ATM',
hintColor = 'red',
condition = function()
return exports['myserver-police']:hasEnoughCops(2)
end,
onInteract = function(entity)
TriggerServerEvent('myserver-robbery:startATM', NetworkGetNetworkIdFromEntity(entity))
end,
},
},
})
endUn donneur de quête complet : le ped apparaît avec son animation et son blip, et les réponses du dialogue exécutent ce que vous voulez, ici le natif `SetNewWaypoint`. `changeDialog` remplace le texte et les réponses, vous imbriquez donc aussi loin que la conversation le demande. `randomComponents = false` garde sa tenue identique pour tous les joueurs.
exports.avenida_interact:pedRegister({
coords = vec4(-1393.81, -1064.09, 3.17, 266.09),
model = 'a_f_y_vinewood_04',
animDict = 'anim@amb@waving@male',
animName = 'ground_wave',
randomComponents = false,
message = 'Talk with Maria',
showIcon = 10.0,
canInteract = 3.0,
hintIcon = 'talk',
hintColor = 'gold',
blips = { sprite = 119, color = 50, text = 'Lumberjack', scale = 0.8 },
dialogue = {
name = 'Maria',
startMsg = 'Hello, are you ready to start your shift?',
elements = {
{
label = 'Yes, where do I start?',
action = function(changeDialog, close)
SetNewWaypoint(-584.01, 5491.59)
changeDialog('The forest is on your GPS now.', {
{ label = 'Got it!', action = function(_, close) close() end },
})
end,
},
{
label = 'I\'ll come back later',
action = function(_, close) close() end,
},
},
},
})Questions fréquentes
- Non. Depuis la 1.1.0, `bridges/compat.lua` implémente la création des DUI, les points de proximité et les helpers d'attente en natifs purs, et la ligne `@ox_lib/init.lua` est commentée dans le manifest. Si vous préférez passer par ox_lib, mettez `Config.UseOxLib = true` et décommentez cette ligne. Les deux chemins sont maintenus, celui en natifs est le défaut.
- D'abord la portée : `showIcon` vaut 4m par défaut dans `Config.Defaults`, ce qui est court si vous attendiez un marqueur visible de loin, passez donc votre propre valeur. Ensuite, avec `entityRegister` l'entity doit exister au moment de l'appel, alors que `entityRegisterByHash` l'attend, ce qui est le bon choix pour les props du jeu. Enfin, mettez `Config.Debug = true` pour afficher les erreurs internes dans la console client.
- Un choix lit `condition`, pas `canInteract`. `canInteract` est le champ du point lui-même, où il accepte un nombre ou une fonction. Dans `choices[]`, la garde s'appelle `condition = function() ... end`, et un choix dont la condition renvoie faux n'est tout simplement pas dessiné.
- N'importe quel hex comme `#22d3ee`, ou un nom de `Config.Colors`, livré avec `red`, `blue`, `green`, `gold`, `purple` et `white`. Cette table est hors escrow, ajoutez-y la palette de votre serveur et utilisez vos propres noms partout. Un `hintIcon` inconnu est dessiné en texte, un emoji fait donc office d'icône ponctuelle.
- C'est corrigé en 1.1.0. La texture DUI est verrouillée en 1920x1080 et dé-étirée au rendu selon le vrai ratio de l'écran, et l'icône ne change plus de taille avec la distance. Les boîtes de réponse des dialogues ont aussi gagné en hauteur au-dessus de 2560x1440. Mettez à jour si vous êtes encore en 1.0.x.
- La propriété est suivie avec `GetInvokingResource()`, un point appartient donc à la ressource qui a appelé l'export. Si vous enregistrez depuis un handler partagé qui tourne dans le contexte d'une autre ressource, le nettoyage suit cette autre ressource. Encapsulez l'appel dans une fonction de la ressource propriétaire du point. Depuis la 1.1.0 les points sont aussi purgés au démarrage d'une ressource, un restart ne laisse donc plus de fantômes.
- Vous n'avez rien à brancher : la ressource ne connaît pas votre framework et ne parle jamais à votre serveur. Lisez le job ou le grade du joueur dans `canInteract` ou dans la `condition` d'un choix, et appelez vos propres events depuis `onInteract`. Tout ce qui tourne sur votre framework tourne derrière ces deux fonctions, sans modification.
- Mesuré à 0.00ms au repos avec 100 points. Le rendu ne se déclenche que dans la portée `showIcon`, et la surveillance des touches tourne à 50ms pour les instances à portée, donc des milliers de points répartis sur la map ne coûtent rien tant qu'ils ne sont pas tous empilés dans la même rue.
Ce qu'en disent les acheteurs
5.0 2 avis vérifiés
Revoria very good scriptwriters a reactive and competent listening team I recommend go there with your eyes closed!!
theara Best script, best support! Fast support and friendly!
EN AVANT Avenida TeamBarber shop
Un barbier mis en scène, avec une caméra que le joueur pilote vraiment. Le personnage entre, s'assoit, et le barbier travaille pendant qu'une caméra orbitale cadre la tête. Cheveux, barbe, overlays et tous les détails de peau, prévisualisés avant d'avoir dépensé un dollar.
EN AVANT Avenida TeamClothing store
Un magasin de vêtements avec tenues sauvegardées, garde-robes d'entreprise et un éditeur qui tarife le catalogue depuis le jeu. Tous les composants et tous les props, achetés pièce par pièce ou en tenue complète, avec un registre côté serveur qui empêche de porter ce qu'on n'a jamais payé.
EN AVANT Avenida TeamCore Skin (3 in 1)
Barbier, salon de tatouage et magasin de vêtements dans une seule ressource FiveM. 1615 tatouages, tous les composants et props de vêtements, tout le visage et la peau, répartis sur 36 boutiques. Une interface, une caméra, un flux d'achat, et une seule chose à installer sur ESX, QBCore, vRP ou en standalone.