FR/Introduction Programmation
Les ressources sont les parties clées de MTA. Une ressource est un dossier ou un .zip qui contient plusieurs fichiers, ainsi qu'une meta qui dit au serveur comment la resource doit-elle être chargée. Une ressource peut être comparée comme un programme qu'on peut lancer ou arrêter, il est possible de lancer plusieurs ressources en même temps.
Tout ce qui a un rapport avec la programmation se passe dans les ressources, se que fait la ressource, définie si c'est un gamemode, une map or quelque chose d'autre. MTA s'installe avec des ressources que vous pouvez facultativement utiliser dans vos gamemodes, comme la ressource "maplimits" pour garder les joueurs dans une certaine zone ou encore "deathpickups" pour créer des pickups pour ramasser une arme.
La première chose à faire avant de pouvoir programmer en Lua, c'est de se procurer un éditeur de texte qui supporte le Lua. Il vous sera beaucoup plus facile que de le faire avec le bloc-note de Windows. Nous vous recommandons donc Visual Studio Code ou Notepad++. Il y a aussi un logiciel non officiel MTA Script Editor (malheureusement l'auteur ne travail plus dessus) que vous pouvez tester.
Pour Visual Studio Code, il est également recommandé d'installer ce plugin qui permettra à l'éditeur de reconnaître les fonctions MTA, proposer de l'auto-complétion ainsi que la documentation associée.
Créer un script qui fonctionne
Nous allons voir tout d'abord voir comment créer un simple script étapes par étapes qui permettra aux joueurs de se déplacer dans la ville. Dans ce tutoriel, on utilisera Notepad++.
Où sont tous les scripts ?
Laissez moi d'abord vous présenter comment s’organise une ressource. Allez dans votre dossier MTA San Andreas et suivez le chemin suivant:
/server/mods/deathmatch/resources/
Vous y verrez de nombreux fichier avec l'extension .zip, ce sont des ressources avec à l'intérieur des exemples de scripts. Toutes les ressources chargées sont dézippées par le serveur afin de pouvoir les exécuter (les .zip ne sont pas obligatoires, vous pouvez aussi laissez votre ressource en tant que dossier). Pour créer votre propre ressource, créez simplement un nouveau dossier et nommez le comme vous voulez (évitez à tout prix les espaces, utilisez plutôt un underscore _ ou un tiret -) . Nommez le "myserveur" pour ce tutoriel.
Maintenant entrez dans votre dossier. Le chemin devrait donc être
/server/mods/deathmatch/resources/myserveur/
Identifier votre ressource
Pour que le serveur puisse savoir ce que contient votre ressource, un fichier meta.xml doit être créé afin d'établir une liste du contenu du dossier. Ce 'meta.xml' doit être à la racine de votre ressource (et non pas dans un autre sous-dossier), donc dans le dossier "myserveur" dans notre cas. Donc ouvrez Notepad++, créez un nouveau fichier (Ctrl + N), puis faite "Enregistrez sous ..." (Ctrl + Alt + S), dans "Nom:" écrivez "meta" et dans "Type:", sélectionnez "*.xml" ( avant-dernier de la liste ), sauvegardez le dans votre dossier "myserveur".
Maintenant, écrivez le code suivant dans votre meta.xml:
<meta> <info author="Votre Nom" type="gamemode" name="Mon serveur" description="Mon premier serveur MTA" /> <script src="script.lua" /> </meta>
Dans la balise <info />, il y a le champ "type" qui indique si la ressource est un gamemode ou une map, on y reviendra plus tard. Un gamemode est ce dont vous avez besoin pour que votre serveur ait une base.
La balise <script /> indique les scripts qui sont dans la ressource, que l'on va maintenant créer.
Créer un script simple
Notez que dans la balise <script />, le fichier .lua n'est pas dans un autre sous-dossier. Donc on va créer notre script.lua au même endroit que notre meta.xml (reproduisez la même opération mais "Nom:" écrivez 'script' et pour "Type:" choisissez 'Lua(*.lua)') puis copiez-collez le code suivant:
function joinHandler() local x = 1959.55 local y = -1714.46 local z = 10 spawnPlayer(source, x, y, z) fadeCamera(source, true) setCameraTarget(source, source) outputChatBox("Bienvenue sur mon serveur", source) end addEventHandler("onPlayerJoin", getRootElement(), joinHandler)
Ce script va vous faire apparaître aux coordonnées (x, y, z) spécifiés dans le code, lorsque vous vous connecterez au serveur. La fonction fadeCamera sinon l'écran restera noir. Vous devez aussi dire à la camera de suivre le joueur grâce à la fonction 'setCameraTarget' (sinon il verra une mer bleu).
La variable source indique qui 'déclenche' la fonction. Le fonction se 'déclenche' lorsqu'un joueur rejoint le serveur, vous utiliserez cette variable pour voir qui à rejoint le serveur. Donc lorsqu'un joueur ("la source") rejoindra notre serveur, on le fera apparaître aux coordonnées indiquées.
Focalisons-nous sur addEventHandler, vous pouvez voir 3 choses: 'onPlayerJoin', qui indique quand exécuter la fonction X. getRootElement(), qui indique sur qui/quoi peut être déclencher la fonction (getRootElement() veut dire toutes les choses et tous les joueurs). Et enfin la fonction X à exécuter (ici joinHandler). Pour les autres détails, nous verrons plus tard dans d'autres exemples mais tout d'abord testons notre premier gamemode !
Lancer le gamemode
Pour lancer le serveur, lancez simplement le 'MTA Server.exe' qui se trouve dans votre dossier 'MTA San Andreas/server'. Une liste d'info concernant le serveur apparaîtra en premier; notez le port du serveur (22003 par défaut), vous en aurez besoin pour rejoindre le serveur. Après, le serveur charge toutes les ressources du dossier 'resource', et enfin "ready to accept connections!"
Avant de pouvoir vous connecter, vous devez lancer votre gamemode. Tapez "start myserveur" dans la console et appuyez sur Entrer. Le serveur va alors lancer le gamemode que nous avons créé, et nous affichera aussi les erreurs s'il y en a (faites debugscript 3 dans la console). Maintenant, vous pouvez lancer MTA, cliquez sur "Quick Connect" et écrivez ceci: Dans Host: le 1er champ: 127.0.0.1 ou localhost (cela signifie que vous vous connectez au serveur du PC actuel) et le 2ème champ: le port (ici 22003) et cliquez sur 'Connect'. Si tout se passe bien, après quelques secondes, vous devriez apparaître et pouvoir aller où vous voulez.
Ensuite nous allons créer une commande que les joueurs pourront utiliser pour faire apparaître une voiture à coté d'eux.
Créer une commande
Revenons à l'intérieur de notre script.lua. Tout d'abord, nous devons créer une fonction qu'on pourra appeler/exécuter grâce à notre commande et la fonction 'addCommandHandler' afin de créer la commande que les joueurs pourront taper dans le chat( T ) ou la console( F8 ).
-- On crée la fonction qui sera appelée par notre commande avec les arguments: thePlayer, command, vehicleModel function createVehicleForPlayer(thePlayer, commandName, vehicleModel) -- Ici on crée le véhicule end -- on crée la commande et on l'attache à notre fonction addCommandHandler("createVehicle", createVehicleForPlayer)
Note: Grâce au wiki, vous pouvez cliquer sur le nom des fonctions et cela vous redirigera sur la documentation de cette fonction.
A propos du addCommandHandler
Le premier argument du addCommandHandler est le nom de la commande the player will be able to enter, le second le nom de la fonction à appeler, dans notre cas, createVehicleForPlayer.
Si vous avez déjà de l'expérience dans le codage, vous savez qu'un fonction s'appelle comme ceci:
nomDeLaFonction(argument1, argument2, argument3, ..)
Si l'on regarde bien l'exemple ci-dessus, nous pouvons voir que l'argument1 est thePlayer and argument2 le commandName. thePlayer est celui qui à tapé la commande et commandName contient le nom de la commande qu'il à tapé. Donc si un joueur tape "/greet", cet argument va contenir "greet". argument3 c'est ce que le joueur à tapé en plus de la commande, vous allez apprendre ceci dans le tutoriel. N'oubliez jamais que les deux premiers arguments sont les arguments standards, mais vous pouvez les renommé si vous voulez, seul l'ordre est important.
Par exemple: Un joueur tape "createVehicle 468" pour faire apparaître une Sanchez, la fonction addCommandHandler va appeler notre fonction createVehicleForPlayer, comme ceci:
createVehicleForPlayer(thePlayer,"createVehicle","468") -- thePlayer est l’élément joueur qui a tapé la commande
Comme nous pouvons le voir, il fournit plusieurs paramètres: le joueur qui a tapé la commande, la commande qu'il a tapé, et n'importe quelle texte qu'il a mis après, dans notre cas, "468" comme id de la Sanchez. Les deux premiers paramètres sont les même pour tous les addCommandHandler qu'on peut retrouver sur la page du addEventHandler. Vous devez toujours définir au moins ces deux paramètres pour utiliser les arguments après eux (par exemple pour traiter le texte qui a été entré après la commande, comme dans notre exemple le modèle du véhicule).
Note: Vous devez créer la commande APRÈS la fonction que vous allez utiliser pour cette commande, sinon il ne trouvera pas la fonction.
Ecrire la fonction
Pour remplir notre fonction d'instructions, nous devons d'abord pensez à ce que nous devons faire:
- Récupérer la position du joueur, donc on connaîtra la position où faire apparaître le véhicule (on veut le faire apparaître à droite du joueur)
- Calculer la position où faire apparaître le véhicule (nous ne voulons pas que le véhicule apparaisse dans le joueur)
- Faire apparaître les véhicule
- Vérifier si le véhicule a bien apparus, ou afficher un message d'erreur.
Pour ça, nous devons utiliser plusieurs fonctions. Pour trouver la fonction que nous devons utiliser, il faut aller faire un tour dans la La liste des fonctions serveur. D'abord nous avons besoin d'une fonction pour obtenir la position du joueur. Puisque les joueurs sont des éléments, nous devons allez dans la rubrique Element functions où l'on pourra trouver la fonction getElementPosition. En cliquant sur le nom de la fonction, le wiki va vous afficher sa description. On peut y voir la syntaxe, qu'est-ce que la fonction retourne. La syntaxe nous montre les argument qu'on peut ou qu'on doit envoyer.
Pour getElementPosition, la syntaxe est:
float, float, float getElementPosition ( element theElement )
Les trois float devant le nom de la fonction est le type de variable que la fonction nous retourne. Dans notre cas, la fonction retourne trois nombres à virgule(x, y et z). Dans les parenthèses, on peut voir les arguments que l'on doit envoyer, dans notre cas, l’élément dont on veut récupérer la position, le joueur dans notre exemple.
function createVehicleForPlayer(thePlayer, command, vehicleModel) -- on récupère la position x,y,z dans des variables locales -- une variable locale n'existe que dans le "périmètre" actuel. Ici, les variable x, y et z sont des variables locales qui se détruiront à la fin de la fonction. local x,y,z = getElementPosition(thePlayer) end
Ensuite, il faut s'assurer que le véhicule n'apparaît pas directement dans le joueur, donc on ajoute quelques unités à la variable x, qui le fera apparaître plus à l'est par rapport au joueur.
function createVehicleForPlayer(thePlayer, command, vehicleModel) local x,y,z = getElementPosition(thePlayer) -- On prent la position du joueur qui a tapé la commande x = x + 5 -- on ajoute 5 unité sur l'axes des x end
Maintenant nous avons besoin d'une autre fonction, celle qui va faire apparaître le véhicule. Nous allons la cherché encore une fois dans la liste des fonctions serveur, mais cette fois, comme nous parlons d'un véhicule, nous devons donc aller dans la catégorieVehicle functions, où l'on va trouver la fonction createVehicle. Dans la syntaxe, nous pouvons voir que cette fonction ne retourne qu'une seule variable, le véhicule ( de type élément ) que nous venons de créer. Nous pouvons aussi voir qu'il y a des arguments entre crochets [], cela veut dire que ce sont des arguments optionnels.
Nous avons déjà tous les arguments pour la fonction createVehicle dans notre fonction: La position que nous avons juste calculée dans les variables "x, y, z" et l'id du véhicule que nous avons fourni par la commande ("/createVehicle 468") et qui est stocké dans la variable vehicleModel.
function createVehicleForPlayer(thePlayer, command, vehicleModel) local x,y,z = getElementPosition(thePlayer) -- récupere la position du joueur dans les variables x, y et z x = x + 5 -- rajoute 5 unités sur x -- on crée le véhicule et on enregistre l'élément de type "vehicle" dans la variable ''createdVehicle'' local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z) end
Avec cette variable, on pourrait faire pas mal de choses sympa, mais ici nous allons juste vérifier si le véhicule à bien été créé ou non. Sur le wiki de la fonction createVehicle, il y a la partie nommée Returns, la fonction va retourner false si la voiture n'a pas été créé. Du coups, on va regarder la valeur de la variable createdVehicle.
Voilà notre code complet:
function createVehicleForPlayer(thePlayer, command, vehicleModel) local x,y,z = getElementPosition(thePlayer) -- On prent la position du joueur qui a tapé la commande x = x + 5 -- on ajoute 5 unités à x local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z) -- on crée le véhicule demandé par le joueur et on récupère ce que nous retourne la fonction dans la variable createdVehicle -- On vérifie si la valeur retournée est égal à ''false'' ( ce qui signifie que ça n'a pas marché ) if (createdVehicle == false) then -- si c'est le cas, on affiche un message d'erreur dans la chatbox mais seulement pour le joueur. outputChatBox("Erreur lors de la création du véhicule.",thePlayer) end end addCommandHandler("createVehicle", createVehicleForPlayer)
Comme vous pouvez le voir, nous avons utilisé une nouvelle fonction: outputChatBox. Vous devriez maintenant pouvoir regarder la description de cette fonction par vous même.
Ce que vous devez savoir
Vous avez déjà lu quelques informations sur les ressources, les commandes et trouvez des fonctions dans le wiki, mais il y a encore beaucoup à apprendre. Cette section vous donnera une vue d'ensemble plutôt courte sur certaines de ces choses, tout en regardant les pages du wiki si possible.
Les scripts client et serveur
Vous pouvez avoir déjà remarqué ces termes (serveur/client) quelque part sur ce wiki, le plus souvent pour les fonctions. MTA ne supporte pas seulement les scripts exécuté par le serveur et des commandes (comme celle que l'on vient de faire) ou d'autres fonctions, mais aussi les scripts exécute par le client MTA, ceux des joueurs qui se connecte au serveur. La raison est que certaines fonctions de MTA doit être du coté client comme par exemple le GUI - Graphical User Interface - ( Pour tout ce qui est fenêtres, boutons, etc ), d'autres devraient être du côté client parce qu'ils fonctionnent mieux mais d'autres sont mieux pensées pour être du côté serveur ou ne fonctionne tout simplement pas du côté client.
La plupart de vos scripts (gamemodes, maps) seront surement du côté serveur, comme celui que nous avons fait tout à l'heure. Si vous vous heurtez à quelque chose qui ne peut pas être résolu du côté serveur, vous devrez probablement le faire côté client. Pour un script client, vous devriez créer un script ordinaire (par exemple appelé client.lua) et spécifié dans la meta.xml, comme ceci:
<script src="client.lua" type="client" />
L'attribut type est par defaut 'server', donc nous avons juste besoin de spécifier que c'est un script client. Lorsque vous faites ceci, le fichier va être télécharger par le joueur sur son ordinateur lorsqu'il se connecte au serveur. Plus d'infos: Client side scripts.
Ressources plus complexes
La section précédente nous a montré brièvement comment ajouter des scripts clients à la ressource. Penchons nous maintenant sur la meta.xml et ce qu'elle fait.
Premier exemple - Un script utile
/admin_commands /meta.xml /commands.lua /client.lua
<meta> <info author="Someguy" description="admin commands" /> <script src="commands.lua" /> <script src="client.lua" type="client" /> </meta>
- Le "commands.lua" fournit quelques commandes d'admin, comme le fait d'interdire un joueur, en bannissant ou quelque chose d'autre ce qui peut être utilisé par l'admin du serveur
- Le "client.lua" fournit un GUI pour être capable d'exécuter les actions mentionnées facilement
Cet exemple de script doit tourner tout le temps (peut être même démarré en même temps que le serveur) car ces commandes d'admin peuvent être appelé à n'importe quelle moment.
Second exemple - Un gamemode
/counterstrike /meta.xml /counterstrike.lua /buymenu.lua
<meta> <info author="Quelqu'un" description="Counterstrike remake" type="gamemode" /> <script src="counterstrike.lua" /> <script src="buymenu.lua" type="client" /> </meta>
- Le "counterstrike.lua" contient des caractéristiques semblables aux dispositifs suivants :
- Laisser les joueurs choisirent leur équipe et les faire apparaître
- Leur fournir des armes, des cibles et des instructions (peut-être lues d'une carte, voir ci-dessous)
- Définir les règles du jeu, par exemple. La partie se finie, ce qui se produit quand un joueur meurt
- .. et peut-être encore plus
- Le "buymenu.lua" est un script du côté client et crée un menu pour acheter des armes
Cet exemple peut s'appeler un gamemode, il modifie le gameplay, mais définit réellement les règles de celui-ci. Le "type" attribut indique que cet exemple fonctionne avec Map Manager, encore une autre ressource qui a été écrite par l'équipe de MTA pour contrôler des gamemodes et le chargement de cartes. On recommande fortement que vous basiez vos gamemodes sur les techniques qu'il fournit.
Ceci signifie également que ce gamemode ne fonctionnera probablement pas sans carte. Les gamemodes devront toujours être aussi génériques que possible. Un exemple de gamemode utilisant une carte est énoncé dans le prochain exemple.
Troisième exemple - Une carte
/cs-airport /meta.xml /airport.map /airport.lua
<meta> <info author="Quelqu'un" description="Counterstrike airport map" type="map" gamemodes="counterstrike" /> <map src="airport.map" /> <script src="airport.lua" /> </meta>
- Le "airport.map" dans le fichier XML fournit des informations au sujet de la carte au gamemode, celui-ci peut inclure :
- Là où les joueurs devraient apparaître, avec quelles armes, avec quelle équipe
- Ce qui sont les cibles
- Temps, heure du monde, Limite de temps
- Fournir les véhicules
- Le airport.lua peut contenir des actions relatifs a la map comme:
- Ouvrir une certaine porte ou faire exploser quelque chose quand une autre chose de spécifique se produit
- Créer ou déplacer quelques objets faits sur commande, ou manœuvrez les objets qui sont créés dans le fichier .map
- .. toutes autre choses relatifs aux objets du .map
Comme vous pouvez le voir, l'attribut "type" a été changé en 'map', pour dire au Map Manager que cette ressource est une carte, tandis que l'attribut "gamemodes" indique pour quels gamemodes cette carte est valide, dans ce cas-ci le gamemode de l'exemple de tout à l'heure. Ce qui peut venir comme une surprise est qu'il y a aussi un script dans la ressource de carte. Évidemment ce n'est pas nécessaire dans une carte, mais ouvre une large gamme de possibilités pour les créateurs de cartes.
Le "airport.map" pourrait être semblable à ceci :
<map mode="deathmatch" version="1.0"> <terrorists> <spawnpoint posX="2332.23" posY="-12232.33" posZ="4.42223" skins="23-40" /> </terrorists> <counterterrorists> <spawnpoint posX="2334.23443" posY="-12300.233" posZ="10.2344" skins="40-50" /> </counterterrorists> <bomb posX="23342.23" posY="" posZ="" /> <vehicle posX="" posY="" posZ="" model="602" /> <vehicle posX="" posY="" posZ="" model="603" /> </map>
Quand un gamemode est commencé avec une carte, les ressources de carte est automatiquement démarrée par le mapmanager et les renseignements qu'il contient peut être lu par le gamemode. Quand la carte change, la ressource de carte actuelle est arrêtée et la ressource de carte suivante est commencée. Pour une explication plus détaillée et des exemples pour savoir comment les ressources de cartes sont utilisées dans le script principal, visitez s'il vous plaît la page Writing Gamemodes.
Événements
MTA utilise les événements pour signaler aux scripts que des choses s'est passé dans le jeu. Par exemple quand un joueur meurt, l’événement onPlayerWasted est déclenché. Pour exécuter n'importe quelle action quand un joueur meurt, votre script doit donner le nom de sa fonction à exécuter lorsque cet événement est déclenché par MTA grâce à la fonction addEventHandler. C'est très similaire à la fonction qui permet de déclencher une fonction via une commande.
Cet exemple produira un message avec le nom du joueur qui est mort :
function playerDied(totalAmmo, killer, killerWeapon, bodypart) outputChatBox(getPlayerName(source).." died!") end addEventHandler("onPlayerWasted", getRootElement(), playerDied)
Au lieu de lister les arguments qui sont nécessaires, la page de documentation pour un événement indique quels paramètres sont passés à la fonction que vous attachez à cet événement. Un autre point important est la variable "source", qui existe dans les fonction d’événement. Il ne doit pas être ajoutés à la liste des paramètres de la fonction, mais elle existe quand même à l'intérieur de votre fonction. Cette variable a une valeur différente d'un événement à l'autre, pour les événements de joueurs (comme dans l'exemple au-dessus) c'est le joueur responsable de son déclenchement. Comme autre exemple, vous pouvez jeter un coup d'œil au script qui permet de faire apparaître le joueur dans la première section pour avoir une idée de comment utiliser cette variable "source".
Où aller d'ici
Vous devriez maintenant être familier avec les aspects les plus fondamentaux du scripting sur MTA et aussi un peu avec la documentation. Le Main_Page vous fournit des liens vers plus de renseignements, tutoriels et Références qui permettent de se plonger plus profondément dans les thèmes que vous désirez apprendre.
D'ici nous recommandons de lire les tutos sur le debugging. Les bonnes pratiques pour débuguer vos scripts sont une nécessité absolue quand vous faites des scripts.