Aller au contenu
Top-Metin2.org - Vous êtes à la recherche d'un serveur Metin 2 ? ×
×
×
  • Créer...

Création d'un nouveau module Python


Metin2 Dev

Messages recommandés

  • Robot

Bonsoir à tous.

 

Je ne participe quasiment jamais sur le forum, mais mieux vaut tard que jamais.

 

Aujourd'hui, je vais vous apprendre (ou pas) comment créer un module Python par le biais de vos sources client. Quel intérêt me direz-vous ? Et bien à vous de le décider. Je ne suis pas très active sur Metin2. Mais je me souviens il y a de ça 3 ans avoir fait un système et crée un nouveau module pour pouvoir mieux m'y retrouver, car mes fonctions ne rentraient vraiment dans aucun des nombreux modules disponibles. Et j'aime quand les choses sont bien rangées !

 

Vous vous doutez bien que pour suivre ce tutoriel, vous aurez besoin de votre tête, un cerveau si possible(/disponible après une bonne journée de travail) et de vos sources client.

 

Explications du code et préambule : 

Révélation

 

Avant de nous lancer tête baisser dans le code, ce qui serait efficace dans la pratique, mais pas dans l'apprentissage : je vous propose de comprendre d'abord le principe du code que nous allons écrire.

Il y a plusieurs méthodes de créer un module, vous n'êtes pas obligés de respecter la hiérarchie que je vais vous donner ci-après, cependant elle respecte la hiérarchie mit en plus par les sources originelles. Elle est rapide et efficace, sauf si vous avez une idée révolutionnaire, je vous conseille de la garder, si ce n'est que pour pouvoir vous inspirer sur les autres modules afin de compléter le votre.

 

Pour ce tutoriel, je vais utiliser le préprocesseur define afin que vous puissiez désactiver les modifications à tout moment juste en commentant une ligne.

 

Le préambule étant annoncé, nous pouvons commencer la théorie.

 

Tout d'abord, il faut comprendre ce qui se passe quand vous appelez une fonction d'un module crée par C++. Pour ça, un exemple va très bien illustrer mes propos.

Prenons comme exemple la fonction


SetShadowLevel()

Qu'est ce qui se passe quand nous appelons cette fonction ?

Déjà, il faut savoir que cette fonction prend pour paramètre un int, c'est un dire un nombre entier. Quand vous allez dire à votre code  d'éxecuter la fonction SetShadowLevel du module Background :


background.SetShadowLevel(5)

En réalité, Python va dire au C++ :  "Dans ton module Background, tu exécute la fonction SetShadowLevel avec comme paramètre l'entier 5".

Le C++ va donc se dire : "Hum... Ok, attends je vais voir à quelle fonction ça correspond de mon côté, et je te fais ça ! "

 

C'est très simpliste, je l'avoue, mais vous venez avec ça de comprendre quelque chose de fondamentale :

Une fonction python de votre module = une fonction écrite en C++ qui reçoit les données envoyées par Python.

Pour les faire correspondre, nous utiliserons une liste contenant le nom de la fonction python, et à quoi elle correspond en C++.

 

Et si nous codions ?!  

Ça vient ça vient ! 

 

je vous invite premièrement à créer un nouveau fichier dans vos sources client. Il va stocker notre nouveau module. Pour cela, vous allez vous rendre tout seul dans votre fichier où se trouvent tous les autres fichiers sources tels que PythonApplicationModule.cpp. Inspirez vous de ce nom, et créez par exemple PythonRoryModule (Rory étant le nom de votre module). Essayez de ne pas faire de fautes de frappes ! Quoi que vous seriez aux normes d'ymir... ;) 

291856Screenshot-1.png

Nous allons ensuite l'ajouter à nos sources pour cela, si vous utilisez visual studio

292105Screenshot-1.png

Allez ensuite chercher votre fichier.

Ouvrez le dans votre éditeur, et nous allons pouvoir commencer !

 

Pour commencer, nous allons inclure deux fichiers :

#include "Locale_inc.h"
#include "StdAfx.h"

Pourquoi le Locale_inc.h ? Car nous allons utiliser le préprocesseur define, et nous allons le définir dans ce fichier. Je vous invite d'ailleurs à le faire :

#define ENABLE_FIRST_MODULE

Ceci étant fait, je vous propre de directement ajouter le ifdef et coder de dans :

#include "Locale_inc.h"
#include "StdAfx.h"

#ifdef ENABLE_FIRST_MODULE

  
#endif

Pour commencer "vrai" code, nous allons créer la variable d'initialisation. On peut dire que c'est elle qui va poser la base de notre module. C'est la racine de l'arbre !

 

Elle sera du type void car nous n'attendrons pas de retour de la fonction :

void initrory()
{

}

(J'aurai ajouté une majuscule pour séparer les deux mots, mais ymir ne l'a pas fait avant, je respecte leur façon d'écrire et je ne change pas).

 

Dans cette fonction, nous allons faire trois choses différentes :

  • Enregistrer toutes nos fonctions
  • Enregistrer le module
  • Enregistrer différentes constantes.

 

Nous allons commencer par enregistrer nos méthodes, pour cela, nous allons créer une liste :

void initrory()
{
	static PyMethodDef s_methods[] =
	{

		{ NULL, NULL },
	};
}

Notez que j'ai déjà ajouter quelque chose dans s_methods: Il se finira toujours par cette ligne. Ça permet de créer une case vide si vous voulez, cela évite qu'elle soit vide dans tous les cas.

Avant cette ligne, vous allez pouvoir enregistrer autant de méthodes que vous le voudrez comme ceci :

{ "pyMethod", cppMethod, METH_VARARGS },

Comprenez bien que :

  • pyMethod : Nom de la fonction Python. 
  • cppMethod : Lien direct avec la fonction c++ que nous allons créer après.
  • METH_VARARGS : Par convention Cython. Ne vous souciez pas de ça, c'est rare d'avoir à le modifier sur Metin, je ne pense pas avoir vu autre chose comme METH_KEYWORDS par exemple.

 

Pour enregistrer notre module, nous allons ajouter l'instruction

PyObject * poModule = Py_InitModule("rory", s_methods);

"rory" étant le nom de votre module.

 

Ce qui donne

#include "Locale_inc.h"
#include "StdAfx.h"

#ifdef ENABLE_FIRST_MODULE
void initrory()
{
	static PyMethodDef s_methods[] =
	{

		{ NULL, NULL },
	};

	PyObject * poModule = Py_InitModule("rory", s_methods);
}
#endif

 

Voici ! Maintenant, il ne nous reste plus que quelques méthodes à voir.

 

je vais vous donner un exemple de fonction pour achever ce tutoriel :

Ajouter dans s_methods une fonction... Qui va récupérer un nombre entier et le renvoyer dans la console par exemple.

Par défaut, notre fonction va ressembler à ça :

PyObject * roryFirstMethod(PyObject * poSelf, PyObject * poArgs)
{

	return Py_BuildNone();
}

 

Maintenant, pour vous montrer de manière complète la chose, je vais imaginer que ma fonction requiert un argument comme un string par exemple.

 

Pour stocker cette argument, nous allons créer un pointeur. Cela évitera d'allouer de la mémoire pour rien. Créons donc un pointeur nommé text par exemple :

char* text = NULL;

Bien, maintenant nous allons récupérer l'argument 0 (le premier). Voici là méthode pour le faire et l'attribuer au pointeur text, :

PyTuple_GetString(poArgs, 0, &text)

Notez que nous avons pour habitude de le mettre dans une condition pour gérer dans la foulé le manque d'argument :

	if (!PyTuple_GetString(poArgs, 0, &text))
		return Py_BuildException();

Bien. Maintenant nous allons ajouter ça dans la console. Ce qui donne

Tracenf("%s", text);

 

Voilà ! Notre fonction est donc :

PyObject * roryFirstMethod(PyObject * poSelf, PyObject * poArgs)
{
	char* text = NULL;

	if (!PyTuple_GetString(poArgs, 0, &text))
		return Py_BuildException();

	Tracenf("%s", text);
	return Py_BuildNone();
}

Nous n'avons plus qu'à ajouter dans notre s_methods :

{ "Log",		roryFirstMethod,	METH_VARARGS },

 

 

Bien, maintenant nous allons nous rendre à deux endroits afin d'y ajouter un appel à notre fonction d'initialisation, et sa déclaration et nous aurons fini :

  • Dans RunMainScript se trouvant dans UserInterface.cpp 
#ifdef ENABLE_FIRST_MODULE
initrory();
#endif
  • Avec les autres dans le StAfx.h de l'UserInterface toujours pour la déclarer.
#ifdef ENABLE_FIRST_MODULE
void initrory();
#endif

 

Et voici, votre module est désormais disponible une fois vos sources compiler :

import rory

et :

rory.Log(arg)

 

Merci d'avoir lu jusqu'au bout, j'espère avoir été assez claire... Bonne chance de votre côté !

 

Amicalement.

Modifié par FBot
  • Love 2

french_banner.gif

Lien vers le commentaire
Partager sur d’autres sites

  • Robot

Ce n'est pas réellement une erreur dans le sens où je voulais donner une écriture générale à la fin. method devait prendre la forme du nom de la fonction Python comme indiqué plus haut. J'ajoute la précision, merci de ta contribution.

Désolée de m'être mal exprimée.

Modifié par FBot

french_banner.gif

Lien vers le commentaire
Partager sur d’autres sites

  • Développeur
il y a 42 minutes, Rory a dit :

Ce n'est pas réellement une erreur dans le sens où je voulais donner une écriture générale à la fin. method devait prendre la forme du nom de la fonction Python comme indiqué plus haut. J'ajoute la précision, merci de ta contribution.

Désolée de m'être mal exprimée.

 

Ouais mais du coup la personne qui va suivre le tutoriel ne comprendra pas pourquoi tu as mis method et pas Log, et inversement ^^.

Dans l'idée il aurait fallu éviter le générique pour que les personnes qui ne sont pas forcément à l'aise avec le code puissent trouver leurs marques.

 

Sinon à part ça, le tutoriel est plutôt correct dans l'ensemble, ça aidera peut-être certains développeurs débutants à s'habituer aux sources Metin2.

Lien vers le commentaire
Partager sur d’autres sites



  • brilliantdiscord_widget
  • Flux d'Activité

    1. 21

      Metin2 en 2020 peut-on en parler?

    2. 0

      METIN2Project

    3. 3

      Ressources - UnPack - Metin2 Client - Officiel

    4. 0

      Barre des tâches d'argent étendue

    5. 16

      Redémarrage automatique des channels

    6. 16

      Multi Logo GM / SGM / GA

    7. 0

      comment extraire les fichiers locale.epk locale.eix sur le serveur officiel ?

    8. 2

      Funky-emu.net -> fr.metin2.dev

  • En ligne récemment

    • Aucun utilisateur enregistré regarde cette page.

Information importante

Conditions d’utilisation / Politique de confidentialité / Règles / Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer.