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

C++ - Support / Ticket in Game


Messages recommandés

  • Robot

Centre de Téléchargement

Hidden Content

    Give reaction to this post to see the hidden content.
( Interne )

Bonjour !

092058imageproxy.php.jpg

Je vous propose un tutoriel pour installer le système de ticket partagé par Shang, que j'ai corrigé car il contenait d'assez gros problèmes côté python, permettant des injections SQL.

 

 

I - Source client :

 

Dans le fichier Packet.h :

 

Chercher :

QUEST_INPUT_STRING_MAX_NUM = 64,

Ajouter juste après :

#ifdef ENABLE_TICKET_SYSTEM
	QUEST_INPUT_STRING_LONG_MAX_NUM = 512,
#endif

 

Chercher ensuite :

typedef struct command_quest_input_string
{
    BYTE        bHeader;
    char		szString[QUEST_INPUT_STRING_MAX_NUM+1];
} TPacketCGQuestInputString;

Ajouter :

#ifdef ENABLE_TICKET_SYSTEM
	typedef struct command_quest_input_long_string
	{
		BYTE		bHeader;
		char		szString[QUEST_INPUT_STRING_LONG_MAX_NUM];
	} TPacketCGQuestInputLongString;
#endif

 

Pour en finir avec ce fichier, chercher :

#ifdef __AUCTION__
	HEADER_CG_AUCTION_CMD							= 205,
#endif

Puis ajouter :

#ifdef ENABLE_TICKET_SYSTEM
	HEADER_CG_QUEST_INPUT_LONG_STRING				= 214,
#endif

Vérifiez qu'aucun de vos packets n'utilise le 214, sinon changez en conséquence, et vous ferez de même dans les sources serveur.

 

 

Dans le fichier PythonNetworkStream.h :

 

Chercher :

bool SendQuestInputStringPacket(const char * c_szString);

Ajouter :

#ifdef ENABLE_TICKET_SYSTEM
	bool SendQuestInputStringLongPacket(const char * c_pszString);
#endif

 

 

Dans le fichier PythonNetworkStreamModule.cpp :

 

Chercher :

PyObject* netSendQuestInputStringPacket(PyObject* poSelf, PyObject* poArgs)
{
	char * szString;
	if (!PyTuple_GetString(poArgs, 0, &szString))
		return Py_BuildException();

	CPythonNetworkStream& rns=CPythonNetworkStream::Instance();
	rns.SendQuestInputStringPacket(szString);

	return Py_BuildNone();
}

Ajouter :

#ifdef ENABLE_TICKET_SYSTEM
	PyObject * netSendQuestInputLongStringPacket(PyObject * poSelf, PyObject * poArgs)
	{
		char * szString;
		if (!PyTuple_GetString(poArgs, 0, &szString))
			return Py_BuildException();

		CPythonNetworkStream & rns = CPythonNetworkStream::Instance();
		rns.SendQuestInputStringLongPacket(szString);
		return Py_BuildNone();
	}
#endif

 

Chercher ensuite :

{ "SendQuestInputStringPacket",				netSendQuestInputStringPacket,				METH_VARARGS },

Ajouter :

#ifdef ENABLE_TICKET_SYSTEM
	{ "SendQuestInputLongStringPacket",			netSendQuestInputLongStringPacket,			METH_VARARGS },
#endif

 

 

Dans le fichier PythonNetworkSteamPhaseGame.cpp :

 

Chercher :

bool CPythonNetworkStream::SendQuestInputStringPacket(const char * c_szString)
{
	TPacketCGQuestInputString Packet;
	Packet.bHeader = HEADER_CG_QUEST_INPUT_STRING;
	strncpy(Packet.szString, c_szString, QUEST_INPUT_STRING_MAX_NUM);

	if (!Send(sizeof(Packet), &Packet))
	{
		Tracen("SendQuestInputStringPacket Error");
		return false;
	}

	return SendSequence();
}

Ajouter :

#ifdef ENABLE_TICKET_SYSTEM
	bool CPythonNetworkStream::SendQuestInputStringLongPacket(const char * c_pszString)
	{
		TPacketCGQuestInputLongString Packet;
		Packet.bHeader = HEADER_CG_QUEST_INPUT_LONG_STRING;
		strncpy(Packet.szString, c_pszString, QUEST_INPUT_STRING_LONG_MAX_NUM);

		if (!Send(sizeof(Packet), &Packet))
		{
			Tracen("SendQuestInputStringLongPacket Error");
			return false;
		}

		return SendSequence();
	}
#endif

 

 

Dans le fichier PythonApplicationModule.cpp :

 

Chercher :

#ifdef ENABLE_COSTUME_SYSTEM
	PyModule_AddIntConstant(poModule, "ENABLE_COSTUME_SYSTEM",	1);
#else
	PyModule_AddIntConstant(poModule, "ENABLE_COSTUME_SYSTEM",	0);
#endif

Ajouter :

#ifdef ENABLE_TICKET_SYSTEM
	PyModule_AddIntConstant(poModule, "ENABLE_TICKET_SYSTEM", 	1);
#else
	PyModule_AddIntConstant(poModule, "ENABLE_TICKET_SYSTEM",	0);
#endif

 

 

Dans le fichier Locale_inc.h :

 

Ajouter :

#define ENABLE_TICKET_SYSTEM

 

Vous pouvez maintenant lancer la compilation de vos sources client le temps qu'on s'occupe des sources serveur ! 

 

II - Source serveur :

 

Dans le fichier service.h :

 

Ajouter :

#define ENABLE_TICKET_SYSTEM

 

 

Dans le fichier input.h :

 

Chercher :

void		QuestInputString(LPCHARACTER ch, const void * pvData);

Ajouter :

#ifdef ENABLE_TICKET_SYSTEM
	void		QuestInputLongString(LPCHARACTER ch, const void * c_pvData);
#endif

 

 

Dans le fichier input_main.cpp :

 

Chercher :

void CInputMain::QuestInputString(LPCHARACTER ch, const void* c_pData)
{
	TPacketCGQuestInputString * p = (TPacketCGQuestInputString*) c_pData;

	char msg[65];
	strlcpy(msg, p->msg, sizeof(msg));
	sys_log(0, "QUEST InputString pid %u msg %s", ch->GetPlayerID(), msg);

	quest::CQuestManager::Instance().Input(ch->GetPlayerID(), msg);
}

Ajouter :

#ifdef ENABLE_TICKET_SYSTEM
	void CInputMain::QuestInputLongString(LPCHARACTER ch, const void * c_pvData)
	{
		const TPacketCGQuestInputLongString * p = reinterpret_cast<const TPacketCGQuestInputLongString*>(c_pvData);
		sys_log(0, "QUEST InputLongString pid %u msg %s", ch->GetPlayerID(), p->szMsg);
		quest::CQuestManager::Instance().Input(ch->GetPlayerID(), p->szMsg);
	}
#endif

 

Chercher :

		case HEADER_CG_QUEST_INPUT_STRING:
			QuestInputString(ch, c_pData);
			break;

Ajouter :

#ifdef ENABLE_TICKET_SYSTEM
		case HEADER_CG_QUEST_INPUT_LONG_STRING:
			QuestInputLongString(ch, c_pData);
			break;
#endif

 

 

Dans le fichier packet.h :

 

Chercher :

typedef struct command_quest_input_string
{
	BYTE header;
	char msg[64+1];
} TPacketCGQuestInputString;

Ajouter :

#ifdef ENABLE_TICKET_SYSTEM
	typedef struct command_quest_input_long_string
	{
		BYTE header;
		char szMsg[512];
	} TPacketCGQuestInputLongString;
#endif

 

Chercher :

HEADER_CG_XTRAP_ACK				= 204,

Ajouter :

#ifdef ENABLE_TICKET_SYSTEM
	HEADER_CG_QUEST_INPUT_LONG_STRING		= 214,
#endif

-->Penser à modifier le packet si vous l'avez fait dans les sources client.

 

 

Dans le fichier packet_info.cpp :

 

Chercher :

Set(HEADER_CG_STATE_CHECKER, sizeof(BYTE), "ServerStateCheck", false);

 

Ajouter :

#ifdef ENABLE_TICKET_SYSTEM
	Set(HEADER_CG_QUEST_INPUT_LONG_STRING, sizeof(TPacketCGQuestInputLongString), "QuestInputLongString", true);
#endif

 

 

Dans le fichier questlua_global.cpp :

 

Si, et seulement si vous n'avez pas mysql_direct_query, vous suivez cette étape, sinon, vous pouvez dores et déjà compiler vos sources.

 

Chercher :

void RegisterGlobalFunctionTable(lua_State* L)

Ajouter au dessus :

#ifdef _MSC_VER
#define INFINITY (DBL_MAX+DBL_MAX)
#define NAN (INFINITY-INFINITY)
#endif

	int _mysql_direct_query(lua_State* L)
	{
		// char szQuery[1024];

		if (!lua_isstring(L, 1))
			return 0;
		// strncpy(szQuery, lua_tostring(L, 1), sizeof(szQuery));

		int i=0, m=1;
		MYSQL_ROW row;
		MYSQL_FIELD * field;
		MYSQL_RES * result;
		// SQLMsg * pMsg = DBManager::instance().DirectQuery(szQuery);
		std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery(lua_tostring(L, 1)));
		if (pMsg.get())
		{
			// ret1 (number of affected rows)
			lua_pushnumber(L, pMsg->Get()->uiAffectedRows);
			//-1 if error such as duplicate occurs (-2147483648 via lua)
			//   if wrong syntax error occurs (4294967295 via lua)
			// ret2 (table of affected rows)
			lua_newtable(L);
			if ((result = pMsg->Get()->pSQLResult) &&
					!(pMsg->Get()->uiAffectedRows == 0 || pMsg->Get()->uiAffectedRows == (uint32_t)-1))
			{
				// LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
				// ch->ChatPacket(CHAT_TYPE_INFO, "<%s> Retrieved %u fields\n", __FUNCTION__, mysql_num_fields(result));
				// ch->ChatPacket(CHAT_TYPE_INFO, "<%s> Retrieved %u rows\n", __FUNCTION__, mysql_num_rows(result));
				// ch->ChatPacket(CHAT_TYPE_INFO, "<%s> Affected %u rows\n", __FUNCTION__, pMsg->Get()->uiAffectedRows);
				// ch->ChatPacket(CHAT_TYPE_INFO, "<%s> Num %u rows\n", __FUNCTION__, pMsg->Get()->uiNumRows);

				while((row = mysql_fetch_row(result)))
				{
					lua_pushnumber(L, m);
					lua_newtable(L);
					while((field = mysql_fetch_field(result)))
					{
						lua_pushstring(L, field->name);
						if (!(field->flags & NOT_NULL_FLAG) && (row[i]==NULL))
						{
							// lua_pushstring(L, "NULL");
							lua_pushnil(L);
						}
						else if (IS_NUM(field->type))
						{
							double val = NAN;
							lua_pushnumber(L, (sscanf(row[i],"%lf",&val)==1)?val:NAN);
						}
						else if (field->type == MYSQL_TYPE_BLOB)
						{
							lua_newtable(L);
							for (DWORD iBlob=0; iBlob < field->max_length; iBlob++)
							{
								lua_pushnumber(L, row[i][iBlob]);
								lua_rawseti(L, -2, iBlob+1);
							}
						}
						else
							lua_pushstring(L, row[i]);
						// LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
						// ch->ChatPacket(CHAT_TYPE_INFO, "<%s> Retrieved %d flag %s for %s\n", __FUNCTION__, field->type, field->name, row[i]?row[i]:"NULL");
						lua_rawset(L, -3);
						i++;
					}
					mysql_field_seek(result, 0);
					i=0;

					lua_rawset(L, -3);
					m++;
				}
			}
		}
		else {lua_pushnumber(L, 0); lua_newtable(L);}

		// delete pMsg;
		return 2;
	}

 

Chercher ensuite :

{	NULL,	NULL	}

 

Ajouter au dessus :

{	"mysql_direct_query",			_mysql_direct_query				},

 

Vous pouvez maintenant lancer la compilation de vos sources serveur, le temps qu'on s'occupe des fichiers serveur ! 

 

III - Serveur :

 

Vous allez dans cette partie, ajouter ceci dans votre quest_functions :

ticket.answer_ticket
ticket.create_ticket
ticket.load_answers
ticket.load_permisions
ticket.load_tickets
ticket.add_member
ticket.update_permisions
ticket.delete_member
ticket.has_permision
ticket.add_viewer
ticket.delete_viewer

 

Ajouter dans questlib :

dofile(get_locale_base_path().."/quest/ticket_lib.so")

 

Ajouter ensuite la lib disponible en pièce jointe, la quête et le dossiers "tickets" (Pièce jointe : QUEST.rar).

 

 

IV - MySQL :

 

je vous invite pour cette partie à lancer ces queries :

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for tickets
-- ----------------------------
DROP TABLE IF EXISTS `tickets`;
CREATE TABLE `tickets` (
  `order_id` int(11) NOT NULL AUTO_INCREMENT,
  `id` varchar(8) NOT NULL,
  `title` varchar(60) NOT NULL,
  `priority` varchar(150) NOT NULL,
  `date` datetime NOT NULL,
  `status` tinyint(1) NOT NULL,
  `creator` varchar(16) NOT NULL,
  `msg` varchar(500) NOT NULL,
  `category` int(2) NOT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for tickets_answers
-- ----------------------------
DROP TABLE IF EXISTS `tickets_answers`;
CREATE TABLE `tickets_answers` (
  `order_id` int(11) NOT NULL AUTO_INCREMENT,
  `id` varchar(8) NOT NULL,
  `creator` varchar(16) NOT NULL,
  `date` datetime NOT NULL,
  `msg` varchar(500) NOT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=MyISAM AUTO_INCREMENT=14 DEFAULT CHARSET=latin1;
SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for tickets_permisions
-- ----------------------------
DROP TABLE IF EXISTS `tickets_permisions`;
CREATE TABLE `tickets_permisions` (
  `pid` int(50) NOT NULL,
  `answer_permision` tinyint(1) NOT NULL,
  `delete_permision` tinyint(1) NOT NULL,
  `add_permision` tinyint(1) NOT NULL,
  PRIMARY KEY (`pid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

 

V - Client :

 

Dans votre locale_game.txt, ajouter :

TICKET_PRIORITY_HIGH	Élevée
TICKET_PRIORITY_MEDIUM	Normale
TICKET_PRIORITY_LOW	Faible
TICKET_STATE_ON_HOLD	En cours
TICKET_STATE_CLOSED	Fermé
TICKET_STATE_SOLVED	Résolu
TICKET_ADD_NAME	Nom:
TICKET_ADD_TITLE	Ajouter un membre
TICKET_ADD_ACCEPT	Accepter
TICKET_SEND	Envoyer
TICKET_TITLE	Asylum : Tickets
TICKET_MY_TICKETS	Mes Tickets
TICKET_ADMINISTRATION	Administration
TICKET_SORT_BY	Ordre :
TICKET_ID	ID
TICKET_TITLE_T	Titre
TICKET_PRIORITY	Priorité
TICKET_DATE	Date
TICKET_STATE	Etat
TICKET_CREATE_NEW	Créer un nouveau ticket
TICKET_SEARCH	Rechercher par ID:
TICKET_SEARCH_BUTTON	Rechercher
TICKET_NAME	Nom
TICKET_ANSWER	Répondre
TICKET_DELETE	Supprimer
TICKET_CHANGE_PERMISIONS	Modifier les permissions
TICKET_ADD_MEMBER	Ajouter un membre
TICKET_REFRESH	Actualiser
TICKET_CATEGORY	Categorie
TICKET_CATEGORY_0	Tous

 

 

Dans votre uiquest.py :

 

Chercher :

	def Destroy(self):
		self.ClearDictionary()
		if self.OnCloseEvent:
			self.OnCloseEvent()
			self.OnCloseEvent = None

			# QUEST_INPUT
			if self.needInputString:
				if self.editLine:
					text = self.editLine.GetText()
					net.SendQuestInputStringPacket(text)
			# END_OF_QUEST_INPUT

		self.imgTitle = None
		self.images = None
		self.eventCurtain = None
		self.board = None

 

Remplacer par :

	def Destroy(self):
		self.ClearDictionary()
		if self.OnCloseEvent:
			self.OnCloseEvent()
			self.OnCloseEvent = None

			# QUEST_INPUT
			if self.needInputString:
				if self.editLine:
					text = self.editLine.GetText()
					if app.ENABLE_TICKET_SYSTEM:
						if (len(text) > 64):
							net.SendQuestInputLongStringPacket(text)
						else:
							net.SendQuestInputStringPacket(text)
					else:
						net.SendQuestInputStringPacket(text)
			# END_OF_QUEST_INPUT

		self.imgTitle = None
		self.images = None
		self.eventCurtain = None
		self.board = None

 

 

Dans le fichier interfaceModule.py :

 

Ajouter :

if app.ENABLE_TICKET_SYSTEM:
	import uiTicket

 

Chercher :

		self.dlgShop = uiShop.ShopDialog()
		self.dlgShop.LoadDialog()
		self.dlgShop.Hide()

Ajouter :

		if app.ENABLE_TICKET_SYSTEM:
			self.wndTicket = uiTicket.TicketWindow()
			self.wndTicket.Hide()

 

Chercher :

		if self.dlgShop:
			self.dlgShop.Destroy()

 

Ajouter :

		if app.ENABLE_TICKET_SYSTEM:
			if self.wndTicket:
				self.wndTicket.Destroy()

 

Chercher :

del self.wndItemSelect

Ajouter :

		if app.ENABLE_TICKET_SYSTEM:
			del self.wndTicket

 

 

Dans le fichier costinfo.py :

 

Ajouter :

if app.ENABLE_TICKET_SYSTEM:
	Tickets = {
		'QID' : 0,
		'QCMD' : '',
		'MY_TICKETS' : [],
		'GLOBAL_TICKETS' : [],
		'ANSWERS' : {},
		'PERMISIONS' : []
	}
	CApiSetHide = 0

 

 

Dans le fichier game.py :

 

Chercher :

			"mall"					: self.__InGameShop_Show,

Ajouter :

			if app.ENABLE_TICKET_SYSTEM:
				"TICKETS"				: self.ManagerTickets,

 

Chercher :

def OpenQuestWindow(self, skin, idx):

Ajouter :

		if app.ENABLE_TICKET_SYSTEM:
			if constInfo.CApiSetHide == 1: 		
				net.SendQuestInputStringPacket(str(constInfo.SendString)) 		
				constInfo.CApiSetHide = 0 		
				return

 

Chercher :

	def __InGameShop_Show(self, url):
		if constInfo.IN_GAME_SHOP_ENABLE:
			self.interface.OpenWebWindow(url)

Ajouter :

	if app.ENABLE_TICKET_SYSTEM:
		def ManagerTickets(self, cmd):
			cmd = cmd.split('#')
			if cmd[0] == 'QID':
				constInfo.Tickets['QID'] = int(cmd[1])
			elif cmd[0] == 'INPUT':
				constInfo.INPUT_IGNORE = int(cmd[1])
			elif cmd[0] == 'SEND':
				net.SendQuestInputLongStringPacket(str(constInfo.Tickets['QCMD']))
				constInfo.Tickets['QCMD'] = ''
			elif cmd[0] == 'CLEAR_CONTENT':
				constInfo.Tickets['MY_TICKETS'] = []
				constInfo.Tickets['GLOBAL_TICKETS'] = []
			elif cmd[0] == 'CLEAR_PERMISIONS':
				constInfo.Tickets['PERMISIONS'] = []
			elif cmd[0] == 'SET_TICKET':
				date = cmd[4].split('[_]')
				constInfo.Tickets['GLOBAL_TICKETS'].append([cmd[1], cmd[2].replace('[_]', ' '), int(cmd[3]), date[0], date[1], int(cmd[5]), cmd[6], cmd[7].replace('[_]', ' '), int(cmd[8])])
				if cmd[6] == player.GetName():
					constInfo.Tickets['MY_TICKETS'].append([cmd[1], cmd[2].replace('[_]', ' '), int(cmd[3]), date[0], date[1], int(cmd[5]), cmd[6], cmd[7].replace('[_]', ' '), int(cmd[8])])
			elif cmd[0] == 'CREATE_ANSWER':
				constInfo.Tickets['ANSWERS'][cmd[1]] = []
			elif cmd[0] == 'SET_ANSWER':
				date = cmd[3].split('[_]')
				constInfo.Tickets['ANSWERS'][cmd[1]].append([cmd[2], date[0], date[1], cmd[4].replace('[_]', ' ')])
			elif cmd[0] == 'SET_PERMISION':
				constInfo.Tickets['PERMISIONS'].append([cmd[1], int(cmd[2]), int(cmd[3]), int(cmd[4])])
			elif cmd[0] == 'OPEN':
				self.interface.wndTicket.Open(int(cmd[1]))
			elif cmd[0] == 'REFRESH_CONTENT':
				self.interface.wndTicket.RefreshPage()

 

 

Dans le fichier ui.py :

 

Ajouter la class :

if app.ENABLE_TICKET_SYSTEM:
	class CoolButton(Window):
		
		BACKGROUND_COLOR = grp.GenerateColor(0.0, 0.0, 0.0, 1.0)
		DARK_COLOR = grp.GenerateColor(0.4, 0.4, 0.4, 1.0)
		
		WHITE_COLOR = grp.GenerateColor(1.0, 1.0, 1.0, 0.3)
		HALF_WHITE_COLOR = grp.GenerateColor(1.0, 1.0, 1.0, 0.2)
		
		def __init__(self, layer = "UI"):
			Window.__init__(self, layer)

			self.eventFunc = None
			self.eventArgs = None

			self.ButtonText = None
			self.ToolTipText = None
			
			self.EdgeColor = None
			self.isOver = FALSE
			self.isSelected = FALSE
			
			self.width = 0
			self.height = 0		

		def __del__(self):
			Window.__del__(self)

			self.eventFunc = None
			self.eventArgs = None

		def SetSize(self, width, height):
			Window.SetSize(self, width, height)
			self.width = width
			self.height = height
			
		def SetEvent(self, func, *args):
			self.eventFunc = func
			self.eventArgs = args

		def SetTextColor(self, color):
			if not self.ButtonText:
				return
			self.ButtonText.SetPackedFontColor(color)
			
		def SetEdgeColor(self, color):
			self.EdgeColor = color

		def SetText(self, text):
			if not self.ButtonText:
				textLine = TextLine()
				textLine.SetParent(self)
				textLine.SetPosition(self.GetWidth()/2, self.GetHeight()/2)
				textLine.SetVerticalAlignCenter()
				textLine.SetHorizontalAlignCenter()
				textLine.SetOutline()
				textLine.Show()
				self.ButtonText = textLine

			self.ButtonText.SetText(text)

		def SetToolTipText(self, text, x=0, y = -19):
			if not self.ToolTipText:		
				toolTip=createToolTipWindowDict["TEXT"]()
				toolTip.SetParent(self)
				toolTip.SetSize(0, 0)
				toolTip.SetHorizontalAlignCenter()
				toolTip.SetOutline()
				toolTip.Hide()
				toolTip.SetPosition(x + self.GetWidth()/2, y)
				self.ToolTipText=toolTip

			self.ToolTipText.SetText(text)

		def ShowToolTip(self):
			if self.ToolTipText:
				self.ToolTipText.Show()

		def HideToolTip(self):
			if self.ToolTipText:
				self.ToolTipText.Hide()
				
		def SetTextPosition(self, width):
			self.ButtonText.SetPosition(width, self.GetHeight()/2)
			self.ButtonText.SetHorizontalAlignLeft()
			
		def Enable(self):
			wndMgr.Enable(self.hWnd)

		def Disable(self):
			wndMgr.Disable(self.hWnd)
			
		def OnMouseLeftButtonDown(self):
			self.isSelected = TRUE
			
		def OnMouseLeftButtonUp(self):
			self.isSelected = FALSE
			if self.eventFunc:
				apply(self.eventFunc, self.eventArgs)

		def OnUpdate(self):
			if self.IsIn():
				self.isOver = TRUE
				self.ShowToolTip()
			else:
				self.isOver = FALSE
				self.HideToolTip()

		def OnRender(self):
			xRender, yRender = self.GetGlobalPosition()
			
			widthRender = self.width
			heightRender = self.height
			grp.SetColor(self.BACKGROUND_COLOR)
			grp.RenderBar(xRender, yRender, widthRender, heightRender)
			if self.EdgeColor:
				grp.SetColor(self.EdgeColor)
			else:
				grp.SetColor(self.DARK_COLOR)
			grp.RenderLine(xRender, yRender, widthRender, 0)
			grp.RenderLine(xRender, yRender, 0, heightRender)
			grp.RenderLine(xRender, yRender+heightRender, widthRender, 0)
			grp.RenderLine(xRender+widthRender, yRender, 0, heightRender)

			if self.isOver:
				grp.SetColor(self.HALF_WHITE_COLOR)
				grp.RenderBar(xRender + 2, yRender + 2, self.width - 3, heightRender - 3)

				if self.isSelected:
					grp.SetColor(self.WHITE_COLOR)
					grp.RenderBar(xRender + 2, yRender + 2, self.width - 3, heightRender - 3)

 

Chercher (EditLine):

self.eventKillFocus = None

Ajouter :

if app.ENABLE_TICKET_SYSTEM:
			self.CanClick = None

 

Chercher :

def SetTabEvent(self, event):
		self.eventTab = event

Ajouter :

	if app.ENABLE_TICKET_SYSTEM:
		def CanEdit(self, flag):
			self.CanClick = flag

 

Chercher :

def OnMouseLeftButtonDown(self):

En dessous de :

if FALSE == self.IsIn():
			return FALSE

Ajouter :

if app.ENABLE_TICKET_SYSTEM:
			if FALSE == self.CanClick:
				return

 

Déplacer ensuite les fichiers fournis dans l'archive PACK.rar où il faut, et voilà https://fr.metin2.dev/uploads/emoticons/biggrin.png !

 

C'est terminé. Vous pouvez maintenant ouvrir la fenêtre en utilisant la fonction :

if app.ENABLE_TICKET_SYSTEM:
	def OpenTicketWindow(self):
		import event
		constInfo.Tickets['QCMD'] = 'OPEN#'
		event.QuestButtonClick(constInfo.Tickets['QID'])
		return

 

Rendu (je vous renvoie sur la chaine de l'auteur) :

 

A ploush 

  • Metin2 Dev 3
  • Love 19

french_banner.gif

Lien vers le commentaire
Partager sur d’autres sites

  • 8 mois après...

Merci mais du coup, tu dis avoir corriger la partie python, qui pouvait causer des injections sql, je me demande, si on remodifie, et que l'on retrouve le script python original, les fail sql sont toujours presente non?

Lien vers le commentaire
Partager sur d’autres sites

  • 1 mois après...

Plop ! Je repasse seulement pas ici... Désolé du retard

 

Oui effectivement, vous pouvez virer la fonction côté Python et remplacer l'entrée dans vos sources grâce à la fonction :

http://www.digitalcoding.com/Code-Snippets/CPP-CLI/C-CLI-Code-Snippet-AddSlashes-StripSlashes-Escape-String.html

ou une équivalente... je ne sais pas s'il existe une fonction prédéfinie pour ça en cpp (je ne crois pas).

  • Love 1
Lien vers le commentaire
Partager sur d’autres sites



  • brilliantdiscord_widget
  • Flux d'Activité

    1. 37
    2. 21

      Metin2 en 2020 peut-on en parler?

    3. 0

      METIN2Project

    4. 3

      Ressources - UnPack - Metin2 Client - Officiel

    5. 0

      Barre des tâches d'argent étendue

    6. 16

      Redémarrage automatique des channels

    7. 16

      Multi Logo GM / SGM / GA

  • 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.