Register for your free account! | Forgot your password?

Go Back   elitepvpers > Popular Games > Silkroad Online > SRO Guides & Templates
You last visited: Today at 22:02

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



[Guide] Creating your own ingame Silkroad GUI

Discussion on [Guide] Creating your own ingame Silkroad GUI within the SRO Guides & Templates forum part of the Silkroad Online category.

Reply
 
Old   #1
 
elite*gold: 0
Join Date: Jun 2008
Posts: 188
Received Thanks: 106
[Guide] Creating your own ingame Silkroad GUI

As I already said , in the last few weeks (actually months, haven't been working actively on it), I've been creating a generic ingame GUI, which is fully movable/draggable around, features control support and with which you can make your own modifications to the game user interface easily. I changed my mind about releasing the full open-source application which features a totally Silkroad-like interface - because the code is too much complicated and it definetly requires a rewrite (I didn't know much stuff back then). After the rewrite, I might release it.

Seeing the tutorials, I will be writing this tutorial in his style (breaking it into a few parts).

Creating your own ingame Silkroad GUI

I. Purpose

Why would you actually want to make a built-in GUI ? Well, did you ever think of a bot with a GUI inside the actual game ? Like, you press one key and all options appear there, without even alt-tabbing ! Have you ever thought of building some utilities, like an ingame IRC or Winamp / WMP control in game ? Well, if you did, this guide should help you.

II. Requirements

I assume that you have some basic knowledge of C++ and D3D (you'll actually need to know the screen coordinate system). The tools you are going to need are as following :
  • Microsoft Visual Studio 2008, or any other IDE you use that properly works with the following :
  • DirectX SDK (I use the one from February 2008, so even older should do)
  • A DirectX 9.0 game to test the application on (Silkroad)
  • A DirectX 9.0 hook, I made my own, but for this guide's sake, we are going to use Direct3D StarterKit v3.0b by Azorbix, which you can - the hook is great and should work properly with our GUI
  • A LOT of patience, the guide is huge

Obviously, the following application created in this guide is generic, which means it will work on almost every DX9.0 game, as long as you hooked the DirectX interface properly. Incase you want to do this only for Silkroad, you can use and , which will help you in hooking the Silkroad DX interface.

III. Theory

Well, in theory, what we are trying to do should not be very hard, and it truly isn't hard at all once we see some code. We are going to make a DLL which will hook the DirectX interface, which will also make a global hook for mouse so we can enable dragging the windows around. Also we will need a DLL injector (you can use any around, there's also an other great guide from pushedx which will help you in that), so we can inject our DLL into our game. Our GUI will be consisting of windows and controls, to whom which we will, from now on, refer as to widgets. We will have two kinds of widgets; parent and child widgets. Child widgets are controls (altho you can make them parent also). Since we don't need anything complicated (like moving a window in a window), child widgets are those widgets whose coordinates are relative to the parent widgets. For example, if parent's coordinates would be X: 10, Y:20, and child's widgets would be X: 5 and Y: 7, then, when drawing on screen, we would have to draw the child widget at coordinate X: 15, Y: 27. Yeah, it's a bit complicated now, but as I said in Requirements, I assume you have some idea about these coordinates. There will be a lot of code, so prepare to read ! I will be commenting the code as much as I can, so you could understand everything.

IV. Implementation

First of all, we need to open up our project. Open the folder where you have extracted Direct3D Starterkit v3.0b, then go to folder D3D9 and open TatniumD3D solution (incase you are using VS6, you'd have to go to D3D9/old_workspace). Create 3 new files:
  • cUI.cpp
  • cUI.h
  • Common.h

And include them to your project. Now, let's get down to the real deal !

As I already mentioned before, I assume you have some basic knowledge of D3D. I'm going to post up the DrawRectangle function right here, because we will use it for creating our widgets :

Code:
// Can't remember who wrote it :'(
// Draws a simple rectangle
// x, y are the coordinates
// w, h are width and height
// col is the color of the box (you can use alpha transparency - ARGB),
// eg. D3DCOLOR_ARGB(255, 255, 255, 255) is white color with zero transparency
void cUI::DrawRectangle(IDirect3DDevice9 *pD3Ddev, int x, int y, int w, int h, D3DCOLOR col)
{
	sQuadVertex qV[4];

	qV[0].dwColor = qV[1].dwColor = qV[2].dwColor = qV[3].dwColor = col;
	qV[0].z   = qV[1].z   = qV[2].z   = qV[3].z   = 0.0f;
	qV[0].rhw = qV[1].rhw = qV[2].rhw = qV[3].rhw = 0.0f;

	qV[0].x = (float)x;
	qV[0].y = (float)(y + h);
	qV[1].x = (float)x;
	qV[1].y = (float)y;
	qV[2].x = (float)(x + w);
	qV[2].y = (float)(y + h);
	qV[3].x = (float)(x + w);
	qV[3].y = (float)y;

	pD3Ddev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, qV, sizeof(sQuadVertex));
}
Now, open d3d9dev.cpp. You will see a lot of code here (Direct3D Starterkit by Azorbix) - don't let that to confuse you, we won't be doing much stuff here. First, delete all includes and put the code below (we will going to include headers elsewhere). The start of d3d9dev.cpp should look something like this :

Code:
// d3d9dev.cpp
/*	Direct3D9 Device */

#include "cUI.h"
#define D3DHOOK_TEXTURES //comment this to disable texture hooking
Now, open up cUI.h and add the following :

Code:
// cUI.h
#include "Common.h"
Pfeeh. Now (again lol) open up Common.h and add the following to the start :

Code:
// Common.h
#include <iostream>
#include <vector>
#include <io.h>
#include <fcntl.h>
#include <windows.h>
#include <basetsd.h>
#include <string>
#include "main.h"
#include "d3d9.h"
A lot of includes there is so we can use the console output. However, we won't need it in this article, so you can delete the unneccessary includes.

Let's see what data will our widget have. We will need the following :
  • X Coordinate
  • Y Coordinate
  • Width of the widget
  • Height of the widget
  • Type of the widget (window, control ...)
  • Unique ID of the widget for handling events (on click etc.)
  • Unique ID of the widget's parent (-1 if none)
  • Color of the widget (this should support alpha channels)
  • Text (if any - we could use this for more stuff, like if the widget is a picture - path to the picture)
  • Color of the text
  • Default font size (default will be 16)
  • bool - Is the mouse over widget?
  • bool - Is the widget being pressed ?
  • Look of the button (3D look, just-border etc.)
  • Value of the widget, for controls like progressbar or checkbox (0 for widgets who won't support value)

After a little brainstorming, we decide that our widget struct should be as following (used PHP tags so it keeps the format atleast a little) :

PHP Code:
struct sWidget 
{
    
int         x;            // X coordinate
    
int         y;            // Y coordinate
    
int         w;            // Width of the widget
    
int         h;            // Height of the widget
    
int         type;        // Type of the widget (control, static graphic object etc.)
    
int         id;        // Unique ID of the widget for handling events
    
int         parent;    // Unique ID of widget's parent
    
D3DCOLOR color;        // Color of the widget
    
char     *text;        // Text (if any)
    
D3DCOLOR txtColor;  // Color of the text
    
int         fontSize;  // Default font size
    
bool     over;        // Is the mouse over this widget
    
bool     pressed;    // Is the button pressed
    
int         look;        // The look of the widget
    
int         value;        // Value of the widget
}; 
We will immediately add this struct to our Common.h file, so we can use it in our other files (cUI.h and cUI.cpp). After we have added this struct to our Common.h file, you have (if not, you have should) certainly seen the sQuadVertex struct in our DrawRectangle() function. I won't bother much explaining this struct, if you're interested go read some D3D tutorials (:

Code:
struct sQuadVertex 
{
	float x, y, z, rhw;
	DWORD dwColor;
};
Add this struct to Common.h too. After we've done that, we should start thinking about how are we going to handle all these widgets. Well, it's simple, we're going to put ALL widgets in one vector (since all widgets are going to use sWidget struct) and later, in our main drawing function, check the types (don't forget we have type in our sWidget struct) and draw the widgets according to their type. Let's start creating our main class, cUI :

Quote:
//cUI.h
#include "Common.h"

class cUI
{
};
We should think about what should be private and what not. I will not explain this either, if you're interested go read some C++ tutorials concerning classes. After some more brainstorming, we decided which members should be private, so our cUI class looks like this now :

Code:
class cUI
{
private:
	// Vector of all widgets
	vector<sWidget> widgets;	

	// Default font drawing class
	ID3DXFont *defFont;

        // The coordinates of the mouse; to be explained later
	int	lastX;
	int	lastY;
	int	lastClick;

	// Is the UI visible or not
	bool visible;
}
Everything is commented, if something is not clear, don't worry ... Read on.

Now, how we should create our windows ? Again, after some thinking, we quickly thought up of an idea :

Code:
// Adds a new window to UI
void AddWindow(int x, int y, int w, int h, char *title, int fontSize, D3DCOLOR col, int id, int look);
Everything there is pretty clear, we are just going to create a new widget and push it to our vector. We are going to create other widgets on the same way, so our cUI class looks like this now :

Code:
class cUI
{
private:
	// Vector of all widgets
	vector<sWidget> widgets;	

	// Default font drawing class
	ID3DXFont *defFont;

	int	lastX;
	int	lastY;
	int	lastClick;

	// Is the UI visible or not
	bool visible;
public:
	//  Default constructor
	cUI();

	// Adds a new window to UI
	void AddWindow(int x, int y, int w, int h, char *title, int fontSize, D3DCOLOR col, int id, int look);

	// Adds a button to some window
	void AddButton(int parentWnd, int x, int y, int w, int h, char *text, int fontSize, D3DCOLOR col, int id, int look);

	// Sets the font color of a widget
	void SetWidgetFontColor(int id, D3DCOLOR col);

	// Draw UI - this MUST be called every EndScene, it's the main drawing function
	void DrawUI(IDirect3DDevice9 *pD3Ddev);	

	// Main event handler
	void HandleCtrlEvents(int id);

	// This takes care of mouse drag events
	bool HandleMouseEvents(WPARAM wParam, LPARAM lParam);

	// Returns the position of a widget in the vector by passing only ID
	int GetWidget(int id);

	// Makes the UI visible
	void MakeVisible();

	// Draws a simple rectangle
	void DrawRectangle(IDirect3DDevice9 *pD3Ddev, int x, int y, int w, int h, D3DCOLOR col);

	// Initialize all stuff we have
	void Initialize(IDirect3DDevice9 *pD3Ddev);

	// Deinitialize all stuff we have
	void Deinitialize(IDirect3DDevice9 *pD3Ddev);
};
Ok, ok, I know that you don't understand a lot of stuff there. Because our class will be called from d3d9dev.cpp, we will initialize / deinitialize our stuff from d3d9dev.cpp, because there we have access to our Direct3D device. I'm pretty sure there is even more stuff that isn't clear, but as you read on, you'll understand.

Since we now have 50% of the class work done, we can now begin actually writing our functions. We are going to start with the simplest ones, so let's start (the code below is meant to be added in cUI.cpp) :

Code:
// Default constructor
// Use this to create some default widgets
cUI::cUI()
{
        // We won't show the UI by default
	visible = false;

	defFont = NULL;
}
Code:
// Adds a window to the UI
// Coordinates are relative to the client's screen
// Everything else is probably self-explanatory
// Incase the width and/or height of the button is not enough for the
// title to be printed, the window WON'T automatically resize
void cUI::AddWindow(int x, int y, int w, int h, char *title, int fontSize, D3DCOLOR col, int id, int look)
{
	sWidget wnd;
	wnd.x = x; wnd.y = y;
	wnd.w = w; wnd.h = h;
	wnd.id = id;
	wnd.parent   = -1;	
	wnd.color    = col;
	wnd.text     = title;
	wnd.txtColor = D3DCOLOR_ARGB(255, 255, 255, 255);
	wnd.fontSize = fontSize;
	wnd.type     = W_WINDOW;
	wnd.look	 = look;
	wnd.over     = false;
	wnd.pressed  = false;

	widgets.push_back(wnd);
}

// Adds a button to an existing window
// Coordinates are relative to the parent window
// The first parameter is the ID of the parent window
// Everything else is probably self-explanatory
void cUI::AddButton(int parentWnd, int x, int y, int w, int h, char *text, int fontSize, D3DCOLOR col, int id, int look)
{
	sWidget button;
	button.x = x; button.y = y;
	button.w = w; button.h = h;
	button.id       = id;
	button.parent   = parentWnd;	
	button.color    = col;
	button.text     = text;
	button.txtColor = D3DCOLOR_ARGB(255, 255, 255, 255);
	button.fontSize = fontSize;
	button.type     = W_CTRL_BUTTON;
	button.look     = look;
	button.over     = false;
	button.pressed  = false;

	widgets.push_back(button);
}
OK, now you are wondering what is W_WINDOW, W_CTRL_BUTTON and W_CTRL_EDITBOX ? Well, it's just another "name" for the following integers, so we actually know what are we dealing with (this will make stuff easier in our main drawing function) :

Code:
// Add this to Common.h
#define W_WINDOW			1
#define W_STATIC_GRAPHIC	        2
#define W_STATIC_TEXT		3
#define W_CTRL_BUTTON		4
#define W_CTRL_EDITBOX		5
Let's explain a little these AddWindow and AddButton functions. It declares a struct variable, fills it in and then pushes it to our widgets vector. We could have made this on a better (but much more complicated) way, which you will hopefully see one day in the open-source release of my "NitroUI".

Next, we will need our font drawing class. So, we are going to make the Initialize() function :

Code:
// Initialize all stuff we have
void cUI::Initialize(IDirect3DDevice9 *pD3Ddev)
{
	D3DXCreateFont(pD3Ddev,						//D3D Device
                     16,						//Font height
                     0,							//Font width
                     FW_NORMAL,					//Font Weight
                     1,							//MipLevels
                     false,						//Italic
                     DEFAULT_CHARSET,			//CharSet
                     OUT_DEFAULT_PRECIS,		//OutputPrecision
                     ANTIALIASED_QUALITY,		//Quality
                     DEFAULT_PITCH|FF_DONTCARE,	//Pitch and family
                     "Arial",					//pFacename,
                     &defFont);					//ppFont

}

// Deinitialize all stuff we have
void cUI::Deinitialize(IDirect3DDevice9 *pD3Ddev)
{
	// DEINITIALIZE ALL STUF HERE !
	// Otherwise, you would crash the application
	// on exit !
}
Google up D3DXCreateFont in order to learn more. I'm also going to create another simpler functions :

Code:
// Returns the position of a widget in the vector by passing the ID
// Everything is self-explanatory
int cUI::GetWidget(int id)
{
	for(int i = 0; i < widgets.size(); i++)
		if(widgets[i].id == id) return i;

	return -1;
}

// Makes the UI visible
// Just so I don't need to make the visible variable public lol
// Oh and, this switched between visible / invisible
void cUI::MakeVisible()
{
	visible =! visible;
}

// Changes the font color of a widget
// Nothing complicated
void cUI::SetWidgetFontColor(int id, D3DCOLOR col)
{
	for(int i = 0; i < widgets.size(); i++)
		if(widgets[i].id == id) widgets[i].txtColor = col;
}
At this moment, we're missing a few functions of our class: HandleCtrlEvents(), HandleMouseEvents(), DrawUI(). The last two are the ones that will take most time to develop, and the second one took a lot of thinking of how it would be done. From my point of view, the following code is highly inefficent (does more operations than it should), but the point of this article is to learn you the basics of creating a GUI. As I already said before, this is *not* the best way to do it - but should be OK for the beginning.

The function HandleMouseEvents() will require us to build a global (system-wide) mouse hook, so let's get right to the point. In d3d9dev.cpp, put the following code (either on top, or on bottom, then later declare the functions):

Code:
HHOOK mouseHook;

// Mouse hook
// We need it to track down the mouse and DOWN and UP events
// For some weird reason I couldn't implement it into UI class
// I always get a weird error with something about typecast & __stdcall
// Incase you fix it, submit it
LRESULT WINAPI CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) 
{	
	if(code > 0)
	{
		bool ret = cUI.HandleMouseEvents(wParam, lParam);
		if(ret == false) return 1;
	}

	return CallNextHookEx(mouseHook,code,wParam,lParam); 
}

// As the function name says,hooks the mouse
void HookMouse() 
{ 
	HWND hWnd = FindWindow(NULL, "SRO_Client"); // Obviously, change SRO_Client to the title of the game you're testing this on
	mouseHook = SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseProc, GetModuleHandle(NULL), GetWindowThreadProcessId(hWnd,NULL)); 
} 

// Self-explanatory
void UnhookMouse() 
{ 
	UnhookWindowsHookEx(mouseHook); 
}
I will later explain how to use all this code, once we finish our class. Let's create HandleCtrlEvents():

Code:
// This takes care of control events
// You HAVE to add your code here in order to
// register the mouse clicks for your controls.
// In the ID switch, you have to add your own
// case for your own control ID
// For example, if you created a button with ID
// 2, then you would have to deal with that button
// under case 2. It's easy :)
void cUI::HandleCtrlEvents(int id)
{
	switch(id)
	{
		case 1:
		{
			// If a control with ID 1 has been pressed
		} break;
		case 2:
		{
			// If a control with ID 2 has been pressed
		} break;
	}
}
We will call this function from HandleMouseEvents(), where we will check if some control is pressed, than call HandleCtrlEvents() with the specific ID of the control that has been pressed. HandleMouseEvents:

Code:
// This takes care of all mouse events
// Call the function in your mouse callback
bool cUI::HandleMouseEvents(WPARAM wParam, LPARAM lParam)
{
	// Now calculate 
	// May seem complicated, it's easy actually
	if(visible)
	{
		// X and Y coordinates of the mouse
		int x, y;

		// Let's get the current position of the mouse
		POINT cPos; 
		GetCursorPos(&cPos); 

		x = cPos.x; y = cPos.y;

		// Now let's handle the messages
		switch(wParam)
		{
			// Mouse pressed down
			case WM_LBUTTONDOWN:
			{
				if(lastClick == 0)
				{
					lastClick++;
					lastX = x;
					lastY = y;

					// We're going to apply the mouse pressed effect
					// for the child widgets
					for(int i = 0; i <= widgets.size(); i++)
					{	
						if(widgets[i].parent != -1)
						{
							// Parent widget
							int p = GetWidget(widgets[i].parent);

							// Child widget coordinates
							int cX, cY;

							cX = widgets[p].x + widgets[i].x;
							cY = widgets[p].y + widgets[i].y;

							// If we pressed some child widget
							if((x >= cX) && (x <= cX + widgets[i].w) &&
							   (y >= cY) && (y <= cY + widgets[i].h))
							{
								widgets[i].pressed = true;
							}
							else
							{
								widgets[i].pressed = false;
							}
						}
					}
				}
			} break;

			// Mouse is being moved
			case WM_MOUSEMOVE:
			{
				// Mouse is actually being dragged
				// We could have done this on easier way (GetAsyncKeyState), but meh
				if(lastClick == 1)
				{
					// First we have to deal with the parent widgets
					// We'll only make window widgets draggable
					for(int i = 0; i <= widgets.size(); i++)
					{	
						if(widgets[i].parent == -1)
						{						
							if((x >= widgets[i].x) && (x <= widgets[i].x + widgets[i].w)  && 
							   (y >= widgets[i].y) && (y <= widgets[i].y + W_WINDOW_TITLEBAR) && 
							    widgets[i].type == W_WINDOW)
							{
								// Widget is being moved to the right
								if(x > lastX)
								{
									widgets[i].x += x - lastX;

									// You can do more stuff here, like add some effects
									// eg. trail or something. Try some stuff :)
								}

								// Widget is being moved left
								if(x < lastX)
								{
									widgets[i].x -= lastX - x;
								}

								// Widget is being moved down
								if(y > lastY)
								{
									widgets[i].y += y - lastY;
								}

								// Widget is being moved up
								if(y < lastY)
								{
									widgets[i].y -= lastY - y;
								}								
							}
						}
						else
						{
							// Do the child widgets dragging logic here	
							// We won't make child widgets draggable,
							// so we are only going to add the pressed effect
							// while you are dragging
							if(widgets[i].parent != -1)
							{
								// Parent window
								int p = GetWidget(widgets[i].parent);

								// Child widget coordinates
								int cX, cY;
								cX = widgets[p].x + widgets[i].x;
								cY = widgets[p].y + widgets[i].y;

								// If we're hovering over some child widget
								if((x >= cX) && (x <= cX + widgets[i].w) &&
								   (y >= cY) && (y <= cY + widgets[i].h))
								{
									// Just an empty space for an else, cbf to do it on the normal way
								}
								else
								{
									widgets[i].pressed = false;
								}
							}
						}
					}

					lastX = x;
					lastY = y;
				}
				else
				{
					// You can apply some effects here
					// eg. mouse over effect and other stuff

					// We're going to apply the mouse over effect
					// for the child widgets
					for(int i = 0; i <= widgets.size(); i++)
					{	
						if(widgets[i].parent != -1)
						{
							// Parent window
							int p = GetWidget(widgets[i].parent);

							// Child widget coordinates
							int cX, cY;
							cX = widgets[p].x + widgets[i].x;
							cY = widgets[p].y + widgets[i].y;

							// If we're hovering over some child widget
							if((x >= cX) && (x <= cX + widgets[i].w) &&
							   (y >= cY) && (y <= cY + widgets[i].h))
							{
								widgets[i].over = true;
							}
							else
							{
								widgets[i].over = false;
							}
						}
					}
				}
			} break;

			// Left mouse button isn't pressed anymore 
			case WM_LBUTTONUP:
			{
				if(lastClick == 1)
					lastClick--;

				// Now, we're going to handle events
				for(int i = 0; i <= widgets.size(); i++)
				{	
					if(widgets[i].parent != -1)
					{
						// Parent window
						int p = GetWidget(widgets[i].parent);

						// Child widget coordinates
						int cX, cY;
						cX = widgets[p].x + widgets[i].x;
						cY = widgets[p].y + widgets[i].y;

						// If we pressed some child widget
						if((x >= cX) && (x <= cX + widgets[i].w) &&
						   (y >= cY) && (y <= cY + widgets[i].h))
						{
							widgets[i].pressed = false;

							// Call the event handler
							HandleCtrlEvents(widgets[i].id);							
						}
					}
				}
			} break;
		}
	}
	return true;
}
I think this function is commented a lot, so read it whole in order to get what is it about. In a sentence, it loops through the widgets vector to check is the mouse over/pressing/dragging them - if so, it will do what should be done (call the proper function and/or modify the widget's over/pressed properties).

By now, we have done most of the work concerning the dragging / moving of the widgets, firing up proper events on clicking controls and other stuff I may have forgot.

Also, you may have seen another stuff we're not familiar with. Add the following to the Common.h file :

Code:
#define W_WINDOW_TITLEBAR   30	// Height of the widget window title bar

#define W_LOOK_3D	100
Let's get onto the main drawing function. Read the comments !

Code:
// Draws everything, incase you want to 
// modify the look of the controls -
// this is where you should do it
// This is the main drawing functions, so a lot
// of stuff is done here. I recommend that you
// read this function line-by-line to understand
// what it does. It's not hard actually, even though
// it looks complicated
void cUI::DrawUI(IDirect3DDevice9 *pD3Ddev)
{
	if(visible)
	{
		for(int i = 0; i < widgets.size(); i++)
		{
			switch(widgets[i].type)
			{				
				case W_WINDOW:
				{
					// Draw the window
					DrawRectangle(pD3Ddev, widgets[i].x, widgets[i].y, widgets[i].w, widgets[i].h, widgets[i].color);

					D3DCOLOR bColor;

					// The 3D look
					if(widgets[i].look == W_LOOK_3D)
					{
						// We need to make the border to give the control the 3Dish look
						// Incase you want to make the borders thicker, you'll
						// have to change some stuff: you'll notice the +-2,
						// just change the 2 and you should be good.
						// Oh and, 4 is the 2x of the thickness
						// Oh and #2, is drawing 8 lines faster than drawing 4
						// rectangles ? Decide by yourself.
						bColor = D3DCOLOR_ARGB(100, 255, 255, 255);

						// The top line
						DrawRectangle(pD3Ddev, widgets[i].x, widgets[i].y, widgets[i].w, 2, bColor);

						// The left line
						DrawRectangle(pD3Ddev, widgets[i].x, widgets[i].y + 2, 2, widgets[i].h - 2, bColor);

						// Now the darker color
						bColor = D3DCOLOR_ARGB(100, 0, 0, 0);

						// The bottom line
						DrawRectangle(pD3Ddev, widgets[i].x + 2, widgets[i].y + widgets[i].h - 2, widgets[i].w - 2, 2, bColor);

						// The right line
						DrawRectangle(pD3Ddev, widgets[i].x + widgets[i].w - 2, widgets[i].y + 2, 2, widgets[i].h - 4, bColor);

					}

					// The title bar should be darker
					D3DCOLOR titleCol = D3DCOLOR_ARGB(50, 0, 0, 0);

					DrawRectangle(pD3Ddev, widgets[i].x, widgets[i].y, widgets[i].w, W_WINDOW_TITLEBAR, titleCol);

					// Now let's draw the title
					RECT r;
					
					// widgets[i].x + 5 adds a little padding to the left
					SetRect(&r, widgets[i].x + 5, widgets[i].y, widgets[i].x + widgets[i].w, widgets[i].y + W_WINDOW_TITLEBAR);

					defFont->DrawText(NULL, widgets[i].text, -1, &r, DT_VCENTER | DT_NOCLIP | DT_WORDBREAK, widgets[i].txtColor);

				} break;

				case W_CTRL_BUTTON:
				{
					// Draw the button
					// Incase the button is a child
					if(widgets[i].parent != -1)
					{
						// The parent widget
						int p = GetWidget(widgets[i].parent);

						// Child widget coordinates
						int cX, cY;
						cX = widgets[p].x + widgets[i].x;
						cY = widgets[p].y + widgets[i].y;

						// Now we have to draw the widget inside the parent
						// We already made the coordinates relative, so it will be easy
						DrawRectangle(pD3Ddev, cX, cY, widgets[i].w, widgets[i].h, widgets[i].color);

						// Now let's draw the button text
						RECT rR;		

						SetRect(&rR, cX, cY, cX + widgets[i].w, cY + widgets[i].h);

						defFont->DrawText(NULL, widgets[i].text, -1, &rR, DT_CENTER | DT_VCENTER | DT_NOCLIP | DT_WORDBREAK, widgets[i].txtColor);

						D3DCOLOR bColor;
						
						if(widgets[i].look == W_LOOK_3D)
						{
							// We need to make the border,
							// to give the control the 3Dish look
							// Incase you want to make the borders thicker, you'll
							// have to change some stuff: you'll notice the +-2,
							// just change the 2 and you should be good.
							// Oh and, 4 is the 2x of the thickness
						    bColor = D3DCOLOR_ARGB(100, 255, 255, 255);

							// The top line
							DrawRectangle(pD3Ddev, cX, cY, widgets[i].w, 2, bColor);

							// The left line
							DrawRectangle(pD3Ddev, cX, cY + 2, 2, widgets[i].h - 2, bColor);

							// Now the darker color
							bColor = D3DCOLOR_ARGB(100, 0, 0, 0);

							// The bottom line
							DrawRectangle(pD3Ddev, cX + 2, cY + widgets[i].h - 2, widgets[i].w - 2, 2, bColor);

							// The right line
							DrawRectangle(pD3Ddev, cX + widgets[i].w - 2, cY + 2, 2, widgets[i].h - 4, bColor);

						}

						// If the mouse is over the widget
						// We're going to apply the mouseover effect
						if(widgets[i].over)
						{
							D3DCOLOR oColor = D3DCOLOR_ARGB(50, 255, 255, 255);

							DrawRectangle(pD3Ddev, cX, cY, widgets[i].w, widgets[i].h, oColor);
						}

						// If the mouse is pressed and over the widget
						// We're going to apply the pressed effect
						if(widgets[i].pressed)
						{
							if(widgets[i].look = W_LOOK_3D)
							{
								// The top line
								DrawRectangle(pD3Ddev, cX, cY, widgets[i].w, 2, bColor);

								// The left line
								DrawRectangle(pD3Ddev, cX, cY + 2, 2, widgets[i].h - 2, bColor);
								
							    bColor = D3DCOLOR_ARGB(100, 255, 255, 255);

								// The bottom line
								DrawRectangle(pD3Ddev, cX + 2, cY + widgets[i].h - 2, widgets[i].w - 2, 2, bColor);

								// The right line
								DrawRectangle(pD3Ddev, cX + widgets[i].w - 2, cY + 2, 2, widgets[i].h - 4, bColor);
							}

							bColor = D3DCOLOR_ARGB(50, 0, 0, 0);

							DrawRectangle(pD3Ddev, cX, cY, widgets[i].w, widgets[i].h, bColor);
						}
					
					}
					// Incase it's not a child widget
					else
					{
						// You'll have to add your own drawing for non-child buttons :)
						// DrawRectangle(pD3Ddev, widgets[i].x, widgets[i].y, widgets[i].w, widgets[i].h, widgets[i].color);
					}
				} break;

				case W_STATIC_GRAPHIC:
				{
					// Handle graphics with the image class here
					// The "text" attribute should be the filename
					// Can be either relative or absolute path
				} break;

				case W_STATIC_TEXT:
				{
					// Draw the text here
				} break;			
			}
		}
	}
}
All that is left to us now is the actual implementation, which is easy. Open up d3d9dev.cpp and add the following to the top of the file :

Code:
cUI cUI;
The CD3DManager::Initialize() function should look like the following :

Code:
HRESULT CD3DManager::Initialize()
{
	/*
	initialize Resources such as textures 
	(managed and unmanaged [D3DPOOL]), 
	vertex buffers, and other D3D rendering resources
	...
	m_pD3Ddev->CreateTexture(..., ..., &m_pD3Dtexture);
	*/

	cUI.Initialize(m_pD3Ddev);
	HookMouse();

	return S_OK;
}
And finally, hkIDirect3DDevice9::EndScene() should look like this :

Code:
HRESULT APIENTRY hkIDirect3DDevice9::EndScene()
{
	if(GetAsyncKeyState(VK_NUMPAD0)&1)
		cUI.MakeVisible();

	cUI.DrawUI(m_pD3Ddev);
	return m_pD3Ddev->EndScene();
}
Now you can be proud of yourself if you have read the whole article thoroughly (:

Last thing, if you want to make an example widget, your ctor should look something like :

Code:
// Default constructor
// Use this to create some default windows
cUI::cUI()
{
	visible = false;

	AddWindow(200,	200, 400, 400, "A Widget Window", 16, D3DCOLOR_ARGB(100, 0, 0, 200),  1, W_LOOK_3D);
	AddButton(1, 50, 50, 100, 100, "Cool btn", 16, D3DCOLOR_ARGB(255, 0, 0, 255), 2, W_LOOK_3D);

	defFont = NULL;
}
You should have a basic understanding of creating ingame GUIs and you should be able to make your own controls now. Please note that some controls are more complicated and will require pretty much knowledge, time and will to successfully implement them. All what is left for you is to inject the DLL into Silkroad, and once you're in login screen / or ingame, press numpad 0 !


V. Conclusion

Let me congratulate you, since you have read the whole guide !

If you just take a look at how this article is long, then I believe that you will understand how much time the actual coding, not to mention writing this guide took. You can show your gratitude by pressing the Thanks button below and posting screenshots of your GUI

Enjoy!
maxbot is offline  
Thanks
50 Users
Old 06/27/2009, 18:38   #2
 
strukel's Avatar
 
elite*gold: 20
Join Date: Jul 2007
Posts: 2,215
Received Thanks: 1,360
Its good to see pushedx is not the only one posting great guides
strukel is offline  
Old 06/27/2009, 19:00   #3
 
elite*gold: 20
Join Date: Jul 2007
Posts: 1,617
Received Thanks: 574
Quote:
Originally Posted by strukel View Post
Its good to see pushedx is not the only one posting great guides
dude, my first thought = nice again pushedx did a great job

thx for this great guide, maxbot!
recking is offline  
Old 06/27/2009, 19:45   #4
 
elite*gold: 0
Join Date: Jun 2008
Posts: 188
Received Thanks: 106
I'll be fixing stuff I didn't notice. Like "create two 3 files". I was tired :/
maxbot is offline  
Old 06/28/2009, 03:52   #5
 
elite*gold: 0
Join Date: Oct 2007
Posts: 7
Received Thanks: 1
Nice post, looks like it took alot of work. Im sure this will be on the forum for a while to help a lot of skiddes including myself. Thanks for the guide, it helps! Try posting it on a few forums so you can be further rewarded for your hardwork.
mitchell0715 is offline  
Old 07/26/2009, 21:38   #6
 
Shadowz75's Avatar
 
elite*gold: 0
Join Date: Mar 2009
Posts: 443
Received Thanks: 597
Im getting an error:
Quote:
Error 4 error C2065: 'widgets' : undeclared identifier
//cUI.h
Quote:
#include "Common.h"

class cUI
{
private:
// Vector of all widgets
vector<sWidget> widgets;

// Default font drawing class
ID3DXFont *defFont;

int lastX;
int lastY;
int lastClick;

// Is the UI visible or not
bool visible;
public:
// Default constructor
cUI();

// Adds a new window to UI
void AddWindow(int x, int y, int w, int h, char *title, int fontSize, D3DCOLOR col, int id, int look);

// Adds a button to some window
void AddButton(int parentWnd, int x, int y, int w, int h, char *text, int fontSize, D3DCOLOR col, int id, int look);

// Sets the font color of a widget
void SetWidgetFontColor(int id, D3DCOLOR col);

// Draw UI - this MUST be called every EndScene, it's the main drawing function
void DrawUI(IDirect3DDevice9 *pD3Ddev);

// Main event handler
void HandleCtrlEvents(int id);

// This takes care of mouse drag events
bool HandleMouseEvents(WPARAM wParam, LPARAM lParam);

// Returns the position of a widget in the vector by passing only ID
int GetWidget(int id);

// Makes the UI visible
void MakeVisible();

// Draws a simple rectangle
void DrawRectangle(IDirect3DDevice9 *pD3Ddev, int x, int y, int w, int h, D3DCOLOR col);

// Initialize all stuff we have
void Initialize(IDirect3DDevice9 *pD3Ddev);

// Deinitialize all stuff we have
void Deinitialize(IDirect3DDevice9 *pD3Ddev);
};
// Common.h
Quote:
#include <iostream>
#include <vector>
#include <io.h>
#include <fcntl.h>
#include <windows.h>
#include <basetsd.h>
#include <string>
#include "main.h"
#include "d3d9.h"

struct sWidget
{
int x; // X coordinate
int y; // Y coordinate
int w; // Width of the widget
int h; // Height of the widget
int type; // Type of the widget (control, static graphic object etc.)
int id; // Unique ID of the widget for handling events
int parent; // Unique ID of widget's parent
D3DCOLOR color; // Color of the widget
char *text; // Text (if any)
D3DCOLOR txtColor; // Color of the text
int fontSize; // Default font size
bool over; // Is the mouse over this widget
bool pressed; // Is the button pressed
int look; // The look of the widget
int value; // Value of the widget
};

struct sQuadVertex
{
float x, y, z, rhw;
DWORD dwColor;
};

#define W_WINDOW 1
#define W_STATIC_GRAPHIC 2
#define W_STATIC_TEXT 3
#define W_CTRL_BUTTON 4
#define W_CTRL_EDITBOX 5

#define W_WINDOW_TITLEBAR 30 // Height of the widget window title bar

#define W_LOOK_3D 100
Shadowz75 is offline  
Old 07/26/2009, 21:39   #7
 
Shadowz75's Avatar
 
elite*gold: 0
Join Date: Mar 2009
Posts: 443
Received Thanks: 597
edit://****** forum laggs
Shadowz75 is offline  
Old 07/27/2009, 16:07   #8
 
elite*gold: 0
Join Date: Jun 2008
Posts: 188
Received Thanks: 106
Uhm, I need to know in which file did you get that error. Have you forgotten to put cUI:: in front of the function name (if the error is in function) ?
maxbot is offline  
Old 07/29/2009, 09:46   #9
 
elite*gold: 0
Join Date: Nov 2008
Posts: 61
Received Thanks: 8
im getting an error, can anyone confirm that it works?
amzar89 is offline  
Thanks
2 Users
Old 07/29/2009, 10:45   #10
 
elite*gold: 0
Join Date: Jun 2008
Posts: 188
Received Thanks: 106
What error ? Post the compiler log here and we may solve it together
maxbot is offline  
Thanks
2 Users
Old 07/31/2009, 23:42   #11
 
purex123456's Avatar
 
elite*gold: 0
Join Date: Jul 2008
Posts: 338
Received Thanks: 11
wat does gui stand for?
purex123456 is offline  
Old 08/01/2009, 00:16   #12
 
Kazuyaš's Avatar
 
elite*gold: 0
Join Date: Apr 2007
Posts: 449
Received Thanks: 236
Quote:
Originally Posted by purex123456 View Post
wat does gui stand for?
Graphical user interface

ever heard of google? nub
Kazuyaš is offline  
Old 12/02/2009, 22:09   #13
 
TeRawLyY's Avatar
 
elite*gold: 0
Join Date: Jul 2009
Posts: 339
Received Thanks: 74
Great Jop
TeRawLyY is offline  
Old 01/20/2010, 18:42   #14
 
elite*gold: 0
Join Date: Aug 2008
Posts: 6
Received Thanks: 0
I'm sorry if I'm bringing a old topic to life. It didn't seem to be to old tho.

First I would like to thank you for this tutorial. I've been doing something similare, but ofcourse I think to strange. This was a more simple way then I was trying to XD

However, I'm working on this for a GG protected game. I've managed to get my way around GG, but for some reason, the UI turns grayscale after the intro-videon. It startsup blue, as on your picture, but then turns gray.

I've been googling about this without any luck. Is there anything simple you can think of, or am I just missing anything? D:

Any help is appriciated. Again, thanks for a nice tutorial.

Edit:

Here's a screenshot of how it looks after intro-video:


Note, I've translated your code into Delphi code. But it should not differ alot, since it's still the same with directx. If you have any ideas on what or how to fix this, I'll be gladly to try to convert back those peices of my code needed to C++ for easier reading.
p0ke is offline  
Old 01/21/2010, 12:18   #15
 
elite*gold: 0
Join Date: Jun 2008
Posts: 188
Received Thanks: 106
Hmm it's weird. I've tested the UI on two games, and it worked nicely. Try your UI on some other game and tell me the results The results vary from game to game, and the most usual problem is related to the hook, not the UI code.
maxbot is offline  
Reply


Similar Threads Similar Threads
[Guide] Creating a Simple Loader with Injected DLL for Silkroad
02/02/2016 - SRO Coding Corner - 37 Replies
This next article in my series is a very important one for anyone wanting to get started with client modifications or understanding the client itself. This is the base article that will be used for all my future articles that explain various Silkroad development concepts. Like my previous article, there is nothing terribly exciting with this one as we have to get through the necessary boring stuff first before we can have any real fun. Unfortunately, this article is very heavy text wise and...
[GUIDE].c3 files creating
07/10/2011 - CO2 Weapon, Armor, Effects & Interface edits - 85 Replies
As I've promised, I'm releasing .c3 files CREATING guide. Even thought nearly whole guide on creating them was around E*PvPers for years most of it's members never got to find it out... Tbh, I wouldn't get to find it out without other people's support but... Credits below. I'll eventually add "How to properly texture new weapons" guide somewhat in future either here on different thread, anywho... NOTE: This is not modelling tutorial.. My modelling ability is rather... none, so if you want...
[GUIDE] Zygor's Ingame Level Guide [2.0.1196 (29.06.10)]
08/10/2010 - WoW Guides & Templates - 20 Replies
Zygor's Ingame Level Guide 2.0.1196 (June 29th, 2010) (aktuellste Version) (Beinhaltet/Includes: Guide, Dailies, Events, Bonus PDF Guides) RapidShare.com uploaded.to PW: 4ePvPers ------------------------------------------------- -------------------------------------------------- ------------------
How creating items in Silkroad Online.
03/07/2007 - Silkroad Online - 1 Replies
Hello folks ! I heard from several people that it's possible to create object in silkroad with a hack. And I saw several low levels with alot of SOS in their stall in the new server Alexander. Do you know something about that ? Thanks !



All times are GMT +1. The time now is 22:04.


Powered by vBulletin®
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2025 elitepvpers All Rights Reserved.