Aller au contenu

Nouveau membre ?! Pense à te présenter pour accéder au contenu du forum !

New member ?! Introduce yourself to get access to the forum !

Messages recommandés

Posté(e) (modifié)

Bonjour !

 

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à :D !

 

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 !

Contenu Masqué !

    Donnez un like à l'auteur afin de pouvoir visualiser tout le contenu.

Contenu Masqué !

    Donnez un like à l'auteur afin de pouvoir visualiser tout le contenu.

Modifié par Kameyu
Correction orthographique.

Partager ce message


Lien à poster
Partager sur d’autres sites

×

Information importante

By using this site, you agree to our Conditions d’utilisation.