I'm back, again!
I have retaken my project after the MySql + OpenGL experiments
My first step after deciding to improve the graphics of my game was to update my horrible tileset, so I searched for GPL'ed tilesets,... I was about to surrender but finally I found a very nice place: RL Tiles , a nice collection of GPL tilesets that gave me basically all what I needed:
Monsters / characters (From Dungeon Crawl):
Items (From Dungeon Crawl):
But at this point I needed some aid with the terrains + some magic effects, so I remembered a very fun, addictive rogue like made in Java: Tyrant - The Java Roguelike I asked the creator, Mike Anderson if I could include the game images and he accepted if I redistribute it under GPL license, Thanks Mike!!
Mixed terrain from Dungeon crawl / Tyrant:
Magic Effects (Courtesy from Tyrant - the Java Roguelike):
All tilesets are 1024*1024 size, with the transparency set to Red:255/Green:0/Blue:255 (Pink), each one is divided into 32* 32 tiles with a size of 32*32 pixels (1024 tiles / tileset, space to grow!), finally all them are free to redistribute / use under GPL license.
In the next post I will speak about map storage with MySql and loading to ram..
Bye
Thursday, November 15, 2012
Monday, November 12, 2012
Banned from 4Shared
<Today I got a crazy e-mail from 4shared:>
Dear Sir/Madam,
We have received a notification that certain materials you posted on the 4Shared website as described below infringe upon someone else’s copyright:
http://www.4shared.com/zip/ HeeXFWb7/rpg.htm
<I got really shocked... me infringing copyrights? what??? Then I went to my blog and I got into my download section : >
<So a tutorial I have made coding with Open Source tools is infringing copyrights? libSDL? maybe Code::Blocks?>
<The e-mail continues:>
<So I have been accused by someone I don't know from something I have not done, and unless I demonstrate It's not right I may get permanently banned... strike one!!>
Counter Notification Requirements
If you do not believe that such materials are infringing and wish to have access restored, please provide a counter notification containing the following information to 4Shared Designated Agent for Notice of Claims of Copyright Infringement (“Designated Agent”) as set forth below:
1) Identify the material that was removed or disabled, and the location where it appeared before it was removed or disabled;
2) Declare under penalty of perjury that you have a good faith belief that the material at issue was removed or disabled as a result of either mistake or misidentification of the material to be removed or disabled;
3) Provide your name, address, and telephone number;
4) Provide a statement that you consent to the jurisdiction of the federal district court for the judicial district in which your address is located, or if your address is outside of the United States, for any judicial district in which 4Shared may be found, and that you will accept service of process from the person who provided the notification or an agent of such person.
5) Provide your physical or electronic signature.
Such counter notification must be sent via e-mail to our Designated Agent at dmca_agent@4Shared.com.
<So if I want to avoid being banned I have to send my PERSONAL ADDRESS, PHONE and I HAVE TO SIGN??? is that a judgement? should I pay a lawyer???, the email continues...>
Alternatively, you may send the counter notification to our Designated Agent using the contact information below:
Name of Designated Agent: Ganka Hadjipetrova
Address of Designated Agent: 745 Distel Dr., Ste. 110, Los Altos, CA 94022
Facsimile Number of Designated Agent: (650) 433-5471
If we receive a proper counter notice, then we may replace or cease disabling access to the allegedly infringing materials in ten business days in accordance with the provisions of the DMCA, unless our Designated Agent first receives notice that an action has been filed by the complainant seeking a court order to restrain the account holder from engaging in infringing activity relating to the material on our system or network.
You should also note that if you make any material misrepresentation in your counter notification that the material or activity was removed or disabled by mistake or misidentification, you will be liable for all damages, including costs and attorneys’ fees, incurred by 4Shared or any copyright owner or copyright owner’s authorized licensee as the result of our relying upon such misrepresentation in replacing the removed material or ceasing to disable access to it.
In the event you provide us with counter notification compliant with all requirements described above and the rights owner does not pursue the infringement claim further, 4shared will remove this instance of copyright infringement from your record and will not consider the take-down notice for purposes of the three-strike repeat infringer termination policy. If we receive a compliant counter notification, we will also re-activate your account’s sharing capability. Note that regardless of whether or not you challenge the infringement claim via a counter notification, 4shared will keep the take-down notification for its records.
<So resuming FIRST: Take down my content with no real facts that it's something illegal , THEN if you dare give all your personal data to someone you don't know you may get your content restored... It stinks!! >
Re-Activation of the Sharing Function of Your Account
Note that if you send us a counter notification fulfilling all requirements described above, your account’s sharing functionality will be re-activated.
In case you do not challenge the take-down notification, you may still be able to re-activate the sharing function of your account. To do that, you must remove all copyrighted content for which you do not hold author’s rights and do not otherwise have authorization to use. Once you have removed all unauthorized materials from your account, you must declare under penalty of perjury that your account does not contain infringing files here. Take note that you will still have access to your files if you do not verify your account is infringement free, but you will not be able to share them publicly.
Thank you.
Sincerely,
4shared Support Team
support@4shared.com
<At this moment I was thinking.... OK I'm pretty sure that is just an scammer, but when I got into my 4shared account and found my file has been removed I got really angry!!!!>
< Guess what? I wont reply, I wont stay in a place I can get blamed for anybody with no , I will let the account die and will never return here>
< +1 to Digital Millennium Copyright Act, they have stopped an indie developer from sharing his Open Source - projects at 4shared!! Must feel real pride..>
<Sweet Internet Freedom>
Dear Sir/Madam,
We have received a notification that certain materials you posted on the 4Shared website as described below infringe upon someone else’s copyright:
http://www.4shared.com/zip/
<I got really shocked... me infringing copyrights? what??? Then I went to my blog and I got into my download section : >
<So a tutorial I have made coding with Open Source tools is infringing copyrights? libSDL? maybe Code::Blocks?>
<The e-mail continues:>
Access to the material complained of has been temporarily disabled or such material has been removed. In addition, the public sharing function for your account has been disabled. For instructions on how to dispute the copyright infringement claim, please read the section titled Counter Notification Requirements below. For instructions on how to re-activate your sharing function, read the section titled Re-activation of the sharing function of your account at the end of this letter.
In accordance with 4shared’s Copyright Policy, to which you are bound by virtue of agreeing to our Terms of Use, your account will be terminated and your access to 4shared services permanently banned following three instances of copyright infringement. Unless you respond by counter notification and successfully dispute the copyright owner’s claim, this will be considered your FIRST instance of infringement under the three-strike policy.
In accordance with 4shared’s Copyright Policy, to which you are bound by virtue of agreeing to our Terms of Use, your account will be terminated and your access to 4shared services permanently banned following three instances of copyright infringement. Unless you respond by counter notification and successfully dispute the copyright owner’s claim, this will be considered your FIRST instance of infringement under the three-strike policy.
<So I have been accused by someone I don't know from something I have not done, and unless I demonstrate It's not right I may get permanently banned... strike one!!>
Counter Notification Requirements
If you do not believe that such materials are infringing and wish to have access restored, please provide a counter notification containing the following information to 4Shared Designated Agent for Notice of Claims of Copyright Infringement (“Designated Agent”) as set forth below:
1) Identify the material that was removed or disabled, and the location where it appeared before it was removed or disabled;
2) Declare under penalty of perjury that you have a good faith belief that the material at issue was removed or disabled as a result of either mistake or misidentification of the material to be removed or disabled;
3) Provide your name, address, and telephone number;
4) Provide a statement that you consent to the jurisdiction of the federal district court for the judicial district in which your address is located, or if your address is outside of the United States, for any judicial district in which 4Shared may be found, and that you will accept service of process from the person who provided the notification or an agent of such person.
5) Provide your physical or electronic signature.
Such counter notification must be sent via e-mail to our Designated Agent at dmca_agent@4Shared.com.
<So if I want to avoid being banned I have to send my PERSONAL ADDRESS, PHONE and I HAVE TO SIGN??? is that a judgement? should I pay a lawyer???, the email continues...>
Alternatively, you may send the counter notification to our Designated Agent using the contact information below:
Name of Designated Agent: Ganka Hadjipetrova
Address of Designated Agent: 745 Distel Dr., Ste. 110, Los Altos, CA 94022
Facsimile Number of Designated Agent: (650) 433-5471
If we receive a proper counter notice, then we may replace or cease disabling access to the allegedly infringing materials in ten business days in accordance with the provisions of the DMCA, unless our Designated Agent first receives notice that an action has been filed by the complainant seeking a court order to restrain the account holder from engaging in infringing activity relating to the material on our system or network.
You should also note that if you make any material misrepresentation in your counter notification that the material or activity was removed or disabled by mistake or misidentification, you will be liable for all damages, including costs and attorneys’ fees, incurred by 4Shared or any copyright owner or copyright owner’s authorized licensee as the result of our relying upon such misrepresentation in replacing the removed material or ceasing to disable access to it.
In the event you provide us with counter notification compliant with all requirements described above and the rights owner does not pursue the infringement claim further, 4shared will remove this instance of copyright infringement from your record and will not consider the take-down notice for purposes of the three-strike repeat infringer termination policy. If we receive a compliant counter notification, we will also re-activate your account’s sharing capability. Note that regardless of whether or not you challenge the infringement claim via a counter notification, 4shared will keep the take-down notification for its records.
<So resuming FIRST: Take down my content with no real facts that it's something illegal , THEN if you dare give all your personal data to someone you don't know you may get your content restored... It stinks!! >
Re-Activation of the Sharing Function of Your Account
Note that if you send us a counter notification fulfilling all requirements described above, your account’s sharing functionality will be re-activated.
In case you do not challenge the take-down notification, you may still be able to re-activate the sharing function of your account. To do that, you must remove all copyrighted content for which you do not hold author’s rights and do not otherwise have authorization to use. Once you have removed all unauthorized materials from your account, you must declare under penalty of perjury that your account does not contain infringing files here. Take note that you will still have access to your files if you do not verify your account is infringement free, but you will not be able to share them publicly.
Thank you.
Sincerely,
4shared Support Team
support@4shared.com
<At this moment I was thinking.... OK I'm pretty sure that is just an scammer, but when I got into my 4shared account and found my file has been removed I got really angry!!!!>
< Guess what? I wont reply, I wont stay in a place I can get blamed for anybody with no , I will let the account die and will never return here>
< +1 to Digital Millennium Copyright Act, they have stopped an indie developer from sharing his Open Source - projects at 4shared!! Must feel real pride..>
<Sweet Internet Freedom>
Thursday, October 4, 2012
libNoise, OpenGL and George R.R. Martin
Hello
I've been quite busy in the last weeks, but still had time to investigate a pair of libs:
When I was thinking in how to make a procedural generated map I saw simple-map-generation from Amit Pattel, so I knew I had to use a noise function generator, that lead me to discovered libnoise: it is a simple library that allows to generate noise maps, apply colors , generate height maps, and many other things!!:
After playing a while with it I knew my maps would be generated by 2D noise functions , first I loaded the map with standard SDL, and made a map explorer, with the zoomed map..
Then I tought.. what if those colored quads were drawn by OpenGL???
I was kinda afraid and excited about the idea at the same time...
Excited about all the things I could do with OpenGL...
Afraid because OpenGL meant start from 0 again .... So I got all the courage I had and told me myself... "If you are into computers you will be learning all your life"
So I started to read the "OpenGL RedBook" and after like 250 pages and failing a few times I finally got my color-map to load on screen with Opengl!
Well, it was just a bunch of quads, but you could just Imagine it is a map...
After that I loaded the height map too and made the "z" from the map depend in the height, so I got the first improvements:
But I didn't wanted to make a minecraft-clone... so I decided to make the quads based in the corners, not just floating quads...
I failed in my first attempt, but had a very fun land strips...
But finally made it! I was starting to get very satisfied with the results, but I wanted to make it smooth so I divided the quads into triangles:
It looked much better, but after I applied normals to all vertexes I got the look I was looking for:
Got it, finally!! , so resuming:
A final Note: had a few hard weeks at work so many days I just didn't had energy to code, I have been reading instead George R.R.Martin book "A song of Ice and fire", and got pretty hooked to it, in fact I read the 3rd book (+-900 pages) in a week...
I'm still were do I continue now, any suggestions?
See you
I've been quite busy in the last weeks, but still had time to investigate a pair of libs:
When I was thinking in how to make a procedural generated map I saw simple-map-generation from Amit Pattel, so I knew I had to use a noise function generator, that lead me to discovered libnoise: it is a simple library that allows to generate noise maps, apply colors , generate height maps, and many other things!!:
<2d noise map loaded (left), and a zoomed window (right) >
After playing a while with it I knew my maps would be generated by 2D noise functions , first I loaded the map with standard SDL, and made a map explorer, with the zoomed map..
Then I tought.. what if those colored quads were drawn by OpenGL???
I was kinda afraid and excited about the idea at the same time...
Excited about all the things I could do with OpenGL...
Afraid because OpenGL meant start from 0 again .... So I got all the courage I had and told me myself... "If you are into computers you will be learning all your life"
So I started to read the "OpenGL RedBook" and after like 250 pages and failing a few times I finally got my color-map to load on screen with Opengl!
Well, it was just a bunch of quads, but you could just Imagine it is a map...
After that I loaded the height map too and made the "z" from the map depend in the height, so I got the first improvements:
But I didn't wanted to make a minecraft-clone... so I decided to make the quads based in the corners, not just floating quads...
I failed in my first attempt, but had a very fun land strips...
But finally made it! I was starting to get very satisfied with the results, but I wanted to make it smooth so I divided the quads into triangles:
It looked much better, but after I applied normals to all vertexes I got the look I was looking for:
Got it, finally!! , so resuming:
<A Map>
+
<An height map>
=
<A 3D map!>
A final Note: had a few hard weeks at work so many days I just didn't had energy to code, I have been reading instead George R.R.Martin book "A song of Ice and fire", and got pretty hooked to it, in fact I read the 3rd book (+-900 pages) in a week...
I'm still were do I continue now, any suggestions?
See you
Monday, August 20, 2012
Handle user accounts with MySql
Hello
Now we have a solid way to store and request data the next step is going to be the creation of user accounts.
First we are going to prepare the database, to do so we will connect to the mysql server:
Create a database
Use the newly created database
Then create a table, that will store the user accounts
We want to login into the game with an existent account or to create a new one, after that step we will get into game character creation (the next step), to simplify things I'm gonna make a text-only client , and a simplified server too.
The logic will be:
After filling all the data, it will pack it and sent it to the server
After we receive the message in the server we are going to unpack the data and get the email.
We will make a query to the MySql server with that email account
If there is already an account with the same email we will reject the data and send a "duplicate account" message to the client, if we don't find it, then we save a new account to the server and send a "account created properly" message to the client
After we create a new user, it will return to the main menu.
After filling the data, it will pack and sent it to the server
After we receive the message in the server we are going to unpack the data and get the email.
With the email we are going to make a query to the server asking for accounts with that email.
If we receive no accounts, obviously, there is no such account.
If we have found that account we check the password match the one the user has typed.
If the password is right, it will send an ACCOUNT_ACCEPTED message.
In the client side, after sending data to creating a new account or login with an existing account we will wait to the server to send us a reply
And basically that's all, We have now authenticated users, ready for the next step: Player creation process!
Notes:
See you!
Now we have a solid way to store and request data the next step is going to be the creation of user accounts.
First we are going to prepare the database, to do so we will connect to the mysql server:
mysql -h localhost -u root -p
Create a database
crete database rpgdata;
Use the newly created database
use rpgdata;
Then create a table, that will store the user accounts
CREATE TABLE accounts ( id INT AUTO_INCREMENT, fullname VARCHAR(60), email VARCHAR(120), password VARCHAR(30),
lastlogin TIMESTAMP,
PRIMARY KEY (id));
We want to login into the game with an existent account or to create a new one, after that step we will get into game character creation (the next step), to simplify things I'm gonna make a text-only client , and a simplified server too.
The logic will be:
- Client connect to the server socket
- Client displays two options:2a-create a new character, 2b-login with an existing character
- If we choose to create a new character the client will show list of text fields we need to fill to create the account
- If we choose to login with an existing account we will fill our username (email) and password.
- Full user name
- email(we will use it like our user account)
- password
- password (another time), to prevent mistakes when typing
cout << "NEW ACCOUNT CREATION" << endl; cout << "Full name?: "; cin >> fullname; cout << "e-mail?: "; cin >> username; cout << "Password?: "; cin >> password; cout << "Repeat Password?: "; cin >> password2; if(password.compare(password2)==0) { done=true; }else{ cout << "Passwords don't match" << endl; }
After filling all the data, it will pack it and sent it to the server
std::stringstream Msg;
Msg << fullname << "#"<< username << "#" << password << "#";
NET.SockSend(CREATE_NEW_ACCOUNT,Msg.str().c_str());
After we receive the message in the server we are going to unpack the data and get the email.
switch (command){ case CREATE_NEW_ACCOUNT: cout << "New account request" << endl; data2.clear(); split(data[3],'#',data2);//I split it into strings fullname = data2[0]; username = data2[1]; password = data2[2]; cout << "Fullname " << fullname << endl; cout << "Username " << username << endl; cout << "Password " << password << endl;
We will make a query to the MySql server with that email account
aquery.clear(); aquery = "select * from accounts where email = '"; aquery+= username; aquery += "'"; cout << aquery << endl; aSQL.executequery(aquery.c_str());//executing select query
If there is already an account with the same email we will reject the data and send a "duplicate account" message to the client, if we don't find it, then we save a new account to the server and send a "account created properly" message to the client
if (aSQL.getrow()) { //Username duplicate.. cout << "Duplicate username.." << endl; aNET.Clients[atoi(data[0].c_str())]->SockSend(DUPLICATE_ACCOUNT,""); }else{ //We have not found username, ok to insert.. cout << "We have not found username, ok to insert.." << endl; aquery.clear(); aquery = "insert into accounts values (NULL,'"; aquery+= fullname; aquery+="' , '"; aquery+= username; aquery+="' , '"; aquery+= password; aquery+="', NULL)"; cout << aquery << endl; aSQL.executequery(aquery.c_str());//executing select query cout << "New user inserted" << endl; aNET.Clients[atoi(data[0].c_str())]->SockSend(NEW_ACCOUNT_ACCEPTED,""); } break;
After we create a new user, it will return to the main menu.
In the second case, it asks for:
- password
After filling the data, it will pack and sent it to the server
cout << "ACCOUNT LOGIN" << endl; cout << "e-mail?: "; cin >> username; cout << "Password?: "; cin >> password; std::stringstream Msg; Msg << username << "#" << password << "#"; NET.SockSend(LOGIN_WITH_ACCOUNT,Msg.str().c_str());
After we receive the message in the server we are going to unpack the data and get the email.
case LOGIN_WITH_ACCOUNT: cout << "Login request" << endl; data2.clear(); split(data[3],'#',data2);//I split it into strings username = data2[0]; password = data2[1]; cout << "Username " << username << endl; cout << "Password " << password << endl;
With the email we are going to make a query to the server asking for accounts with that email.
aquery.clear(); aquery = "select * from accounts where email = '"; aquery+= username; aquery += "'"; cout << aquery << endl; aSQL.executequery(aquery.c_str());//executing select query
If we receive no accounts, obviously, there is no such account.
if (aSQL.getrow()) {
/...
}else{ //We have not found username.. cout << "Username not found.." << endl; aNET.Clients[atoi(data[0].c_str())]->SockSend(UNKNOW_USERNAME,""); }
If we have found that account we check the password match the one the user has typed.
//Username found cout << aSQL.row[0] << " " << aSQL.row[1] << " " << aSQL.row[2] << " " << aSQL.row[3] << " " << aSQL.row[4] << endl; std::string pass; pass = aSQL.row[3]; if (pass.compare(password)==0) { cout << "Username/password match, login ok" << endl; aNET.Clients[atoi(data[0].c_str())]->SockSend(ACCOUNT_ACCEPTED,""); aNET.Clients[atoi(data[0].c_str())]->Login = true; }else{ //wrong password cout << "Password mismatch.. " << endl; aNET.Clients[atoi(data[0].c_str())]->SockSend(BAD_PASSWORD,""); }
If the password is right, it will send an ACCOUNT_ACCEPTED message.
In the client side, after sending data to creating a new account or login with an existing account we will wait to the server to send us a reply
switch(command) { case ACCOUNT_ACCEPTED: cout << "ACCOUNT_ACCEPTED" << endl; reply = true; logedin = true; break; case NEW_ACCOUNT_ACCEPTED: cout << "NEW_ACCOUNT_ACCEPTED" << endl; reply = true; break; case DUPLICATE_ACCOUNT : cout << "DUPLICATE_ACCOUNT " << endl; reply = true; break; case UNKNOW_USERNAME: cout << "UNKNOW_USERNAME" << endl; reply=true; break; case BAD_PASSWORD: cout << "BAD_PASSWORD" << endl; reply=true; break; }//switch
And basically that's all, We have now authenticated users, ready for the next step: Player creation process!
Notes:
- Don't look for encryption: it is not yet implemented so the server / client are not secure, the reason for that is 1-Simplicity 2-Easier to understand incoming / outgoing packets and 3-It is very easy to add encryption later.
- Messages are not encoded: no binary numbers, just plain text, the reason the same in point 1.1 and 1.2 : making things simpler to understand.
See you!
Tuesday, August 7, 2012
A server socket class
Hello
I'm going to describe a new class, (last one before I start with the server)
We already have a class to store persistent data, now we need a way to communicate with the world.
I need a class to start a TCP socket server then accept incoming TCP connections , I need to be able to send data to any of the clients too, and finally enqueue the incoming data so I can process it when I need to do.
What the class is going to do is:
<network.h>
Then I have the client implementation:
<client.cpp>
Notice the client stores the data in two different queues depending if the client has loged in or not, finally we have the main socket server class:
<network.cpp>
There are many things here, but I will resume it to the maximum, to do that, below there is a simple example to use the class:
That's all for now, in the next post I will mix everything to make the client login a reality, I will make a text based client too and hope everything is clear that way.
I'm going to describe a new class, (last one before I start with the server)
We already have a class to store persistent data, now we need a way to communicate with the world.
I need a class to start a TCP socket server then accept incoming TCP connections , I need to be able to send data to any of the clients too, and finally enqueue the incoming data so I can process it when I need to do.
What the class is going to do is:
- Open a server socket in a port X
- Start a thread that will be listening in port X
- When we receive connections it will save the client info (ip/port) to a vector so we can communicate with the client, every client starts a new thread to get the incoming data from each client (it is a blocking-socket server)
- The data is stored into two different queues depending if the client has logged in or not, I made that because I will apply different priority for the queues , the main (client updates) must be processed with maximum priority other way clients will be lagging.. in the other hand client login request can wait a pair of seconds without big problems.
<network.h>
#ifndef NETWORK_H #define NETWORK_H #define MAXLEN 1024 #include "SDL/SDL.h" #include "SDL/SDL_net.h" #include "SDL/SDL_thread.h" #include <vector> #include <queue> #include <iostream> #include <sstream> using namespace std; class cNetwork; class cClient //the connected clients
{ public: //functions cClient();//creator virtual ~cClient();//destructor void StartThreads();//Start listener thread static int listener( void *data );//Listener Thread void Send(const char* Msg);//Send data to client //variables cNetwork *_server;//To comunicate with main server instance TCPsocket socket;//client socket SDL_Thread *ListenerThread;//The network client thread int threadReturnValueclient; Uint16 UID;//Unique identifier bool Connected;//socket connected? bool Login; //loged in? }; class cNetwork//main network server class { friend class cClient; public: //functions cNetwork(); virtual ~cNetwork(); void Start(Uint16 MAXUsers, Uint16 Port); void CleanClient(unsigned int Client);//clean a client so we can use it static int Master( void *data );//Master listener function/thread void ClearClients();//Clear disconnected clients void Finish();//close all client connections and finish server //variables queue<std::string> InputQueue;//Here we store received data queue<std::string> LoginQueue;//Here we store login requests SDL_sem *ClientsLock; //Semaphore to prevent server from accesing a variable from different threads cNetwork *myserver;//server pointer vector<cClient*> Clients;//Here I store clients SDL_Thread *MasterThread;//The Master thread >> accepts new clients int threadReturnMaster;//return value for master thread bool ShutDown;//closing the server? private: //private variables IPaddress ip;//Server ip address TCPsocket ServerSock; //Server socket }; #endif // NETWORK_H
Then I have the client implementation:
<client.cpp>
#include "network.h" cClient::cClient() { //ctor ListenerThread = NULL; Connected = false; } cClient::~cClient() { //dtor //Stop the thread SDL_KillThread( ListenerThread ); //close the socket SDLNet_TCP_Close(socket); } void cClient::StartThreads() { //Create and run the thread + ListenerThread = SDL_CreateThread( &listener, this ); } int cClient::listener( void *data ) { //While the program is not over cout << "Starting client listener Thread..." << endl; int result; char in_msg[MAXLEN]; bool quit=false; while( quit == false ) { memset(in_msg, 0, MAXLEN); // Clear in buffer if ( ((cClient*)data)->Connected)//If I'm connected... { result=SDLNet_TCP_Recv(((cClient*)data)->socket,in_msg,MAXLEN);//Check for incoming data if(result<=0) { //NO DATA // TCP Connection is broken. (because of error or closure) SDLNet_TCP_Close(((cClient*)data)->socket); cout << "Socket closed..." << endl; ((cClient*)data)->Connected = false; quit=true; } stringstream idmsg; idmsg << ((cClient*)data)->UID << "#" << in_msg;// I will add the UID from the client to the incoming message try{ SDL_SemWait(((cClient*)data)->_server->ClientsLock);//lock smaphore to prevent client to freeze cout << idmsg.str();//only for debuging if (((cClient*)data)-> Login==true)//Am I loged in? { ((cClient*)data)->_server->InputQueue.push(idmsg.str()); //I'm logged in }else{ ((cClient*)data)->_server->LoginQueue.push(idmsg.str()); //New player requests } SDL_SemPost(((cClient*)data)->_server->ClientsLock);//unlock smaphore } catch(exception& e) { cout << "QUEUE IN ERROR: " << e.what() << endl; } }//if connected }//while cout << "Closing client listener thread..." <<endl; return 0; } void cClient::Send(const char* Msg) { if (Connected==true) { int len; int result; len=strlen(Msg+1); // add one for the terminating NULL result=SDLNet_TCP_Send(socket,Msg,len); if(result<len) //If I can't send data probably I've been disconnected so.... { cout << "SDLNet_TCP_Send: " << endl << SDLNet_GetError(); Connected = false; } }else{ cout << "Not connected!!" << endl; } }
Notice the client stores the data in two different queues depending if the client has loged in or not, finally we have the main socket server class:
<network.cpp>
#include "network.h" cNetwork::cNetwork() { //ctor if(SDLNet_Init()==-1) {//Start SDL_NET cout << "SDLNet_TCP_INIT: \n " << SDLNet_GetError(); exit(2); } //Clean thread variables MasterThread = NULL; ClientsLock = NULL; ClientsLock = SDL_CreateSemaphore( 1 );//semafor protector, previene que mas de un thread vuelque informaciĆ³n a la vez a la cola } cNetwork::~cNetwork() { //dtor SDLNet_TCP_Close(ServerSock);//Close socket SDLNet_Quit();//Close SDL_NET } void cNetwork::CleanClient(unsigned int Client)//clean a client so we can use it { //cout << "cleaning client: " << Client << endl; Clients[Client]->UID =Client; Clients[Client]->socket = NULL; Clients[Client]->_server = myserver; Clients[Client]->Connected = false; Clients[Client]->Login = false; } void cNetwork::Start(Uint16 MAXUsers, Uint16 Port) { //1-initialize MAXUsers clients //2-Start sock server unsigned int x; for (x=1;x<=MAXUsers;x++) { Clients.push_back(new cClient());//insert a new client into the clients vector CleanClient(Clients.size() -1); } cout << "OPENING SERVER SOCKET... " << endl; if(SDLNet_ResolveHost(&ip,NULL,Port)==-1) { cout << "SDLNet_TCP_ResolveHost:" << endl << SDLNet_GetError(); exit(1); } ServerSock=SDLNet_TCP_Open(&ip); if(!ServerSock) { cout << "SDLNet_TCP_open: " << endl << SDLNet_GetError(); exit(2); } ShutDown = false; //Create and run the threads MasterThread = SDL_CreateThread( &Master, this ); } int cNetwork::Master( void *data )//Master listener function/thread { TCPsocket new_tcpsock; //Temporary socket to store incoming connections new_tcpsock=NULL; cout << "Waiting for incoming connections... " << endl; bool doneMain=false; while(!doneMain)//MAIN LOOP { if(!new_tcpsock)//We have a new client incoming { new_tcpsock=SDLNet_TCP_Accept(((cNetwork*)data)->ServerSock); // accept a connection coming in on server_tcpsock SDL_Delay(5);//No new clients, wait a little }else{ cout << "New client incoming..." << endl; unsigned int x; for(x=0;x<((cNetwork*)data)->Clients.size();x++) { if (((cNetwork*)data)->Clients[x]->Connected==false) { ((cNetwork*)data)->CleanClient(x); ((cNetwork*)data)->Clients[x]->socket=new_tcpsock;//asign the socket ((cNetwork*)data)->Clients[x]->Connected = true; ((cNetwork*)data)->Clients[x]->Login = false; ((cNetwork*)data)->Clients[x]->StartThreads();//start client listener thread break; } }//for new_tcpsock=NULL;//release temporary socket var }//if new data if (((cNetwork*)data)->ShutDown==true)doneMain =true; }//while cout << "Exiting Main thread..." << endl; return 0; } void cNetwork::ClearClients()//Clear disconnected clients { unsigned int x; bool done = false; //SDL_SemWait(ClientsLock); if (Clients.size()>0) { x=0; while (!done) { if (!Clients[x]->Connected) { Clients.erase(Clients.begin()+x); // cout << "Number of clients:" << Clients.size() << endl; if (x>0)x--; }//if !connected x++; if(x>=Clients.size())done=true; } }//clients size } void cNetwork::Finish() { ShutDown =true; SDL_WaitThread(MasterThread,&threadReturnMaster); unsigned int x; for(x=0;x<Clients.size();x++) { Clients[x]->Connected=false;//force disconnection }//for while (Clients.size()>0) { ClearClients(); } }
There are many things here, but I will resume it to the maximum, to do that, below there is a simple example to use the class:
#include "network.h"//socket server class
cNetwork NET; NET.myserver = &NET; NET.Start(100,55555); //start networking, up to 100 clients on port 55555
std::sting text;
SDL_SemWait( NET.ClientsLock ); text = NET.InputQueue.front();//take a message out from the queue NET.InputQueue.pop(); SDL_SemPost( NET.ClientsLock );
NET.Clients[X]->Send("data");//will send "data" to client X
NET.Finish();//finish socket server
- We include the class
- Then instantiate it
- Start the listener thread (at this moment it is fully functional)
- Then I extract a message from the input queue (let's suppose we have a connected client that send it..)
- I send a message to the server ("data")
- Finally, I close the server
That's all for now, in the next post I will mix everything to make the client login a reality, I will make a text based client too and hope everything is clear that way.
Friday, August 3, 2012
SVN UP! New code repository
Hello again
Before going any further (and after all the things that happened with Megaupload), I knew I wont be able to continue uploading my project / tools / whatever to 4shared, and yes I was right, in a few days 4shared started to ask for "user accounts" to be able to download things...
I had to start using another away to store my project.. and I needed a way to control the versions from my project.
The solution was quite simple (basically because a good friend showed me from the advantages of using subversion aka "svn")
So I went back to Google.. again.. went to http://code.google.com and signed for a new account, created a new project (http://code.google.com/p/jbfprj/) and voila! I got my own svn server :)
So now anybody can checkout in my software repository and get the source for my projects, at the moment I just uploaded SimpleSQL:
<copied from code.google.com>
Use this command to anonymously check out the latest project source code:
Anyway, that's all you will need to get the source, and of course, type "svn up" whenever you want to check if there are updates...>
In the next post I'll be back to the server program, but now I'm going to reduce the posts to a size that anybody can handle, starting for login to the server..
Before going any further (and after all the things that happened with Megaupload), I knew I wont be able to continue uploading my project / tools / whatever to 4shared, and yes I was right, in a few days 4shared started to ask for "user accounts" to be able to download things...
I had to start using another away to store my project.. and I needed a way to control the versions from my project.
The solution was quite simple (basically because a good friend showed me from the advantages of using subversion aka "svn")
So I went back to Google.. again.. went to http://code.google.com and signed for a new account, created a new project (http://code.google.com/p/jbfprj/) and voila! I got my own svn server :)
So now anybody can checkout in my software repository and get the source for my projects, at the moment I just uploaded SimpleSQL:
<copied from code.google.com>
Use this command to anonymously check out the latest project source code:
# Non-members may check out a read-only working copy anonymously over HTTP.
svn checkout http://jbfprj.googlecode.com/svn/trunk/ jbfprj-read-only
svn checkout http://jbfprj.googlecode.com/svn/trunk/ jbfprj-read-only
Notice you will need to install subversion:
sudo apt-get install subversion
under linux or you can use another client for windows like tortoise-svn...
In the next post I'll be back to the server program, but now I'm going to reduce the posts to a size that anybody can handle, starting for login to the server..
Thursday, August 2, 2012
A class to use MYSQL
<After installing and setting up the MySql server ,we need to access the MySql database from code::blocks>
To achieve the objective I'm going to make a class to connect and launch SQL queries to the MySql server , and of course a test project to use the class.
So the steps to get started are:
Basically there are 5 functions: the creator and destructor, a function to connect to the mysql server, a function to execute queries and finally a function to get the result from SELECT queries.
Now the implementation (csql.cpp):
It is quite simple to follow the code:
I make an instance from the mysql class, then I connect to the server, clean the table "accounts", and then I insert a pair of data rows, I display the results from select queries too, there are other SQL commands like UPDATE which I have not used, but I think that it is quite enough to show the use from the class.
<Notice that I am using the password "rpgdata", the database "rpgdata", the table "accounts".. if you don't use the same database or table names, the example wont work(I explained how to set it up in the previous two posts)>
Finally there is one final thing you need to set up to make the project compile:
Other way the compiler wont find mysql and it will refuse to work...
<So basically we have a simple class to use the freshly new installed MySql server, now we can use it in any project, but obviously I'm going to add it to the socket server, in the next post I will show another new I'm going to use to host the project development...>
See you!
To achieve the objective I'm going to make a class to connect and launch SQL queries to the MySql server , and of course a test project to use the class.
So the steps to get started are:
- Open code::blocks
- Create an empty project
- Add a file and save it "main.cpp"
- Add a new class with the wizard and name it "csql"
#ifndef CSQL_H #define CSQL_H #include <mysql.h>//Needed to use MySql #include <string.h> #include <sstream> using namespace std; class csql { public: MYSQL_ROW row; //Here we store query results in rows csql(); //constructor virtual ~csql();//destructor bool connect(const char * serverip, const char * username, const char * password, const char * database);//connecto to a server , with username and password and select database void executequery(const char *query);//execute SQL query bool getrow();//we get a row from the results from a query private: MYSQL mysql;//mysql class MYSQL_RES *res ;//mysql results for queries }; #endif // CSQL_H
Basically there are 5 functions: the creator and destructor, a function to connect to the mysql server, a function to execute queries and finally a function to get the result from SELECT queries.
Now the implementation (csql.cpp):
#include "csql.h" using namespace std; csql::csql() { //ctor mysql_init(&mysql);//start mysql } csql::~csql() { //dtor mysql_close(&mysql);//close mysql } //We use connect() to connect to the database needed bool csql::connect( const char * serverip, const char * username, const char * password, const char * database) { if (mysql_real_connect(&mysql ,serverip ,username ,password ,database,0,NULL,0)) { return true;//everything ok }else{ return false;//connection failed } } void csql::executequery(const char *query)//Execute SQL query { mysql_real_query(&mysql,query,strlen(query)); res = mysql_store_result(&mysql); } bool csql::getrow()//We extract a row from the result from an SQL query (or get false if empty) { if ((row = mysql_fetch_row(res))) { return true;//we have extracted a row }else{ return false; // no rows to extract } }
It is quite simple to follow the code:
- csql() (constructor) just initializes the mysql class used to work with the DB
- ~csql() (destructor) frees the class, closing any active connection
- connect() connect to the server, using 4 parameters: the server IP, the username, the password and the database to connect (it returns true if the it connects ok, false when there is a failure)
- executequery() used to launch SQL queries, just plain SQL commands like "select * from table"
- getrow() get a data row from the results of a select query, if there are rows it will return true and we can access the data columns with csql_instance.row[index], other way it returns false
#include <iostream> #include "csql.h" using namespace std; int main(int argc, char *argv[]) { csql sql;//we use the sql class cout << "Connecting to database.." << endl; if (!sql.connect("localhost","root","rpgdata","rpgdata"))//we connect using the serverip, username, password and database { cout << "Error connecting to database" << endl; return -1; } cout << "DELETING.." << endl; sql.executequery("delete from accounts");//executing delete query sql.executequery("select * from accounts");//executing select query while (sql.getrow()) { cout << sql.row[0] << " " << sql.row[1] << " " << sql.row[2] << " " << sql.row[3] << " " << sql.row[4] << endl; } cout << "INSERTING Jorge.." << endl; sql.executequery("insert into accounts values (NULL, 'Jorge','jorge@hotmail.com','pass',NULL)");//executing insert query sql.executequery("select * from accounts");//executing select query while (sql.getrow()) { cout << sql.row[0] << " " << sql.row[1] << " " << sql.row[2] << " " << sql.row[3] << " " << sql.row[4] << endl; } cout << "INSERTING Paul.." << endl; sql.executequery("insert into accounts values (NULL, 'Paul','paul@gmail.com','pass',NULL)");//executing insert query sql.executequery("select * from accounts");//executing select query while (sql.getrow()) { cout << sql.row[0] << " " << sql.row[1] << " " << sql.row[2] << " " << sql.row[3] << " " << sql.row[4] << endl; } return 0; }
I make an instance from the mysql class, then I connect to the server, clean the table "accounts", and then I insert a pair of data rows, I display the results from select queries too, there are other SQL commands like UPDATE which I have not used, but I think that it is quite enough to show the use from the class.
<Notice that I am using the password "rpgdata", the database "rpgdata", the table "accounts".. if you don't use the same database or table names, the example wont work(I explained how to set it up in the previous two posts)>
Finally there is one final thing you need to set up to make the project compile:
- Go to "project" > "build options"
- Then in "compiler" > "other options"
`mysql_config --cflags`
- And in "linker" > "other linker options"
`mysql_config --libs`
Other way the compiler wont find mysql and it will refuse to work...
<So basically we have a simple class to use the freshly new installed MySql server, now we can use it in any project, but obviously I'm going to add it to the socket server, in the next post I will show another new I'm going to use to host the project development...>
See you!
MYSQL + Command Line
<In the last post I spoke about my decision to start using MySql , now I will speak about how to set up a simple test database using the command line prompt>
CONNECTING TO THE SERVER
MySql has a basic tool to set up (almost) everything you need from your SQL server.
After installing MySql you just need to use the command:
That will connect to the mysql server with ServerIp, and try to validate, if you don't write the IP it will default to localhost, the username is the username used to login into the server, and finally -p makes mysql to ask for the password of the username:
Here we are, logged in..
CREATING DATABASES AND TABLES
Next step would be very simple, create our database:
Notice the semicolon ";", every instruction in the mysql command prompt must finish with ";", it's the end of sentence command
It will create a new database "rpgdata" , then we can check the databases in our server:
We can delete the databases with the command:
After creating a database and before we can actually work with it we need to "use" it with the command:
Next step would be creating the tables to store the data:
Example:
Now we can check the tables we have in our database:
And another interesting thing: we can check the database structure with the command:
DATA HANDLING
At this point, we can start using standard SQL sentences to handle the data:
A pair of examples:
SQL Language is almost a programming language itself so it's way beyond my hand to teach the language, anyway I will explain the sentences when I use them so you don't have to worry about it.
BACKUPS AND RESTORES
Finally, to make a backup from a database to a plain text file and restore it later we have two commands:
To make a backup from a database to a file...
To restore a database from a backup file
<Notice that in both commands you have to execute the commands from the terminal window, not from the mysql prompt>
And that's all for now, that's all we are going to need to start using the mysql server, creating our database and the tables inside, we can now design our game database, and we could even insert the desired data inside (I Wont recommend that!), but instead we are going to use c++ to connect to the mysql server and launch SQL sentences...
In the next post: Using mysql from c++ + code::blocks.
CONNECTING TO THE SERVER
MySql has a basic tool to set up (almost) everything you need from your SQL server.
After installing MySql you just need to use the command:
mysql -h ServerIp -u username -p
That will connect to the mysql server with ServerIp, and try to validate, if you don't write the IP it will default to localhost, the username is the username used to login into the server, and finally -p makes mysql to ask for the password of the username:
jbea@eeepc1005HA:~$ mysql -h localhost -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 39 Server version: 5.5.24-0ubuntu0.12.04.1 (Ubuntu) Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
CREATING DATABASES AND TABLES
Next step would be very simple, create our database:
mysql> CREATE DATABASE rpgdata; Query OK, 1 row affected (0.00 sec)
Notice the semicolon ";", every instruction in the mysql command prompt must finish with ";", it's the end of sentence command
It will create a new database "rpgdata" , then we can check the databases in our server:
mysql> SHOW DATABASES; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | rpgdata | +--------------------+ 3 rows in set (0.00 sec)
We can delete the databases with the command:
mysql>DROP DATABASE rpgdata;
After creating a database and before we can actually work with it we need to "use" it with the command:
mysql>USE rpgdata;
Next step would be creating the tables to store the data:
mysql>CREATE TABLE table (datafield1, datafield2..);
mysql> CREATE TABLE accounts ( -> id INT AUTO_INCREMENT, -> fullname VARCHAR(60), -> email VARCHAR(120), -> password VARCHAR(30), -> PRIMARY KEY (id)); Query OK, 0 rows affected (0.06 sec)
Now we can check the tables we have in our database:
mysql> SHOW TABLES; +-------------------+ | Tables_in_rpgdata | +-------------------+ | accounts | +-------------------+ 1 row in set (0.00 sec)
And another interesting thing: we can check the database structure with the command:
mysql> DESCRIBE accounts; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | fullname | varchar(60) | YES | | NULL | | | email | varchar(120) | YES | | NULL | | | password | varchar(30) | YES | | NULL | | +----------+--------------+------+-----+---------+----------------+ 4 rows in set (0.00 sec)
DATA HANDLING
At this point, we can start using standard SQL sentences to handle the data:
>INSERT INTO > Insert data
>UPDATE > update data
>DELETE FROM > delete data
>SELECT FROM > Get data
A pair of examples:
mysql> INSERT INTO accounts VALUES -> (NULL, 'Jorge Bea Frau','jbeafrau@gmail.com','password'); Query OK, 1 row affected (0.00 sec) mysql> mysql> SELECT * FROM accounts; +----+----------------+--------------------+----------+ | id | fullname | email | password | +----+----------------+--------------------+----------+ | 1 | Jorge Bea Frau | jbeafrau@gmail.com | password | +----+----------------+--------------------+----------+ 1 row in set (0.00 sec) mysql>
SQL Language is almost a programming language itself so it's way beyond my hand to teach the language, anyway I will explain the sentences when I use them so you don't have to worry about it.
BACKUPS AND RESTORES
Finally, to make a backup from a database to a plain text file and restore it later we have two commands:
mysqldump -h localhost -u root -p DATABASE > backupfile.sql
mysql -h localhost -u root -p DATABASE < backupfile.sql
<Notice that in both commands you have to execute the commands from the terminal window, not from the mysql prompt>
And that's all for now, that's all we are going to need to start using the mysql server, creating our database and the tables inside, we can now design our game database, and we could even insert the desired data inside (I Wont recommend that!), but instead we are going to use c++ to connect to the mysql server and launch SQL sentences...
In the next post: Using mysql from c++ + code::blocks.
Monday, July 30, 2012
Finally, MYSQL + code::blocks!
Hello everybody, today I'll make a "postmortem analysis" and will install and set up MySql server
<Been out for a long time <again>, had many things to do and my project got stucked again, but it didn't get forgotten! I have been reading all the code again and had time to think about it, the things I have done right and which things should I change / improve, and made an small list:>
GOOD THINGS
So I took a hard decision, dropped the code and to make a second server with all the good things the first server had + all the things it SHOULD HAVE like persistent data, and a true server-client model.
Having persistent data meant to use some kind of static storage, so I thought in using just plain files plus standard c++ io functions to write data, but I dropped the idea fast because there are already libraries to solve the "writing another text parser" like TinyXml , but after playing with that again I found that if I used that library I will be making two times the work because:
<NOTE: I have completely dropped support for windows in the server part, that means I wont be posting how to install and make it run under Windows OS family, basically I made that because that's the OS I will be using to make and run the server and I cant loose more time in something I wont be using, although anybody could check how to download and install the required libraries for the OS you choose..>
So I installed the mysql server:
It just asked me for the "root" database password, it is very important because it will be used to connect to MySql and use the database, NOTE: it is not the linux root account so you can / should have different passwords .
I installed too MySql tuner:
Used to get advice to tune the databases
And the client libraries:
Used to connect from the client app
To check that the MySql server is running:
You can restart the service with:
<You can see installing MySql server is quite simple, in the next post I will write about comand-line database management, and finally start using it with code::blocks>
<Been out for a long time <again>, had many things to do and my project got stucked again, but it didn't get forgotten! I have been reading all the code again and had time to think about it, the things I have done right and which things should I change / improve, and made an small list:>
GOOD THINGS
- The server actually works!
- Client program able to create players, connect, and "move around"
- Worked quite fast in a desktop computer using small amounts of RAM
- Ugly code, I feel really ashamed about that, but it is the result of writing code in a "fast 15 min way"
- Server is unstable, yeah, after fixing many, many bugs it did worked, but still had things to fix.
- I was not using a real scenario , data was not being loaded from server, so player creation, maps, etc was everything client-side, obviously that is not good, for many reasons (security, for example)
- World didn't had persistent data, players, objects, etc were not stored after closing client program
So I took a hard decision, dropped the code and to make a second server with all the good things the first server had + all the things it SHOULD HAVE like persistent data, and a true server-client model.
Having persistent data meant to use some kind of static storage, so I thought in using just plain files plus standard c++ io functions to write data, but I dropped the idea fast because there are already libraries to solve the "writing another text parser" like TinyXml , but after playing with that again I found that if I used that library I will be making two times the work because:
- First I will have to write all the data in .xml files
- To later rewrite the code again to switch to a real database..
<NOTE: I have completely dropped support for windows in the server part, that means I wont be posting how to install and make it run under Windows OS family, basically I made that because that's the OS I will be using to make and run the server and I cant loose more time in something I wont be using, although anybody could check how to download and install the required libraries for the OS you choose..>
So I installed the mysql server:
sudo apt-get install mysql-server
I installed too MySql tuner:
sudo apt-get install mysqltuner
And the client libraries:
sudo apt-get install libmysqlclient-dev
To check that the MySql server is running:
sudo netstat -tap | grep mysql
You can restart the service with:
sudo service mysql restart
<You can see installing MySql server is quite simple, in the next post I will write about comand-line database management, and finally start using it with code::blocks>
Tuesday, April 3, 2012
Rpg Client update: Rotate players
Welcome back!
Player's point of view is quite clear now...
Since I decided to continue the project I started to think again in all the things I could make to improve it, and the first thing was to make it clear where players / foes were looking at, it's basic to make you know:
SPRIG: The SDL Primitive Generator
A great job from Jhonny D
To use the library you will need the subversion client, (in linux "sudo apt-get install subversion", in Windows you can use Tortoise SVN client, for example)
To download / install it under linux:
svn checkout http://sprig.googlecode.com/svn/trunk/ sprig
cd sprig
make
sudo make install
(Haven't tested it under windows yet)
I created a new function: RotateBlitTileset( x,y,image,angle), that functions draws the rotated tile (image) at x,y.
Notice I can't just call Sprig rotate function because I would get a rotated tile with pink background, so I have to use the tmp surface to set the color-key, that way is not optimized at all so I will think in a way to make it faster later, but at the moment is ok.
In the next post: Let's chat!
Player's point of view is quite clear now...
Since I decided to continue the project I started to think again in all the things I could make to improve it, and the first thing was to make it clear where players / foes were looking at, it's basic to make you know:
- Where are you going (the red dot did not helped a lot)
- Where are going all the other players / enemies
- Can I ambush somebody?, am I being ambushed?
SPRIG: The SDL Primitive Generator
A great job from Jhonny D
To use the library you will need the subversion client, (in linux "sudo apt-get install subversion", in Windows you can use Tortoise SVN client, for example)
To download / install it under linux:
svn checkout http://sprig.googlecode.com/svn/trunk/ sprig
cd sprig
make
sudo make install
(Haven't tested it under windows yet)
I created a new function: RotateBlitTileset( x,y,image,angle), that functions draws the rotated tile (image) at x,y.
void Engine::RotateBlitTileset(int x, int y, int tile, float Angle) //Rotate and Blits a tile from our tileset to the screen { SDL_Surface * tmpBlit = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCCOLORKEY |SDL_RLEACCEL,TileSize,TileSize,32,0,0,0,0); SDL_Surface * tmpBlit2 = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCCOLORKEY |SDL_RLEACCEL,TileSize,TileSize,32,0,0,0,0); //1-fill temporary surface with pink SDL_FillRect(tmpBlit, 0, SDL_MapRGB(tmpBlit->format, 255, 0, 255)); start.x= (tile%10)*TileSize; //Column = tile % 8 (0-7) start.y= (tile/10)*TileSize; //Row = tile / 8 (0-7) start.w=TileSize; start.h=TileSize; end.x =0; // X end.y =0; // Y end.w = TileSize; end.h = TileSize;
//2-Blit the desired tile to the temporary surface SDL_BlitSurface(tileset, &start, tmpBlit, &end); //3-I call sprig function SPG_Rotate() to rotate the temporary surface and get the resulting surface into a 2nd temporary surface tmpBlit2 = SPG_Rotate(tmpBlit, Angle -90, SDL_MapRGB(tmpBlit-> format, 255, 0, 255)); SDL_SetColorKey(tmpBlit2,SDL_SRCCOLORKEY |SDL_RLEACCEL,SDL_MapRGB(tmpBlit2-> format, 255, 0, 255));//set the color key start.x=0; start.y=0; start.w=TileSize; start.h=TileSize; //set the cliping for the destination surface (the screen) end.x =x; // X end.y =y; // Y end.w = TileSize; end.h = TileSize; SDL_BlitSurface(tmpBlit2, NULL, screen, &end); //Blits the rotated tile to the screen SDL_FreeSurface( tmpBlit); SDL_FreeSurface( tmpBlit2); }
Notice I can't just call Sprig rotate function because I would get a rotated tile with pink background, so I have to use the tmp surface to set the color-key, that way is not optimized at all so I will think in a way to make it faster later, but at the moment is ok.
In the next post: Let's chat!
Tuesday, March 27, 2012
I'm alive!!
I could tell you I had a very bad car accident, maybe that I got into the drugs , got kidnapped or abducted but I really can't say other thing than the truth:
I have not made anything in the project for about two months :(
Got quite frustrated trying to make the project to work the non-blocking way, and in fact I made it to "work" quite easy, I was very happy because I thought I could make the server work faster and use less resources than I was using...
WRONG!, server worked fine with a low load (say less than 50 users), but when I started to add more users it just collapsed with nasty segmentation fault errors, sometimes when a client disconnected it just blocked the server, I didn't had all those problems with the "old" server and I although I tried to debug the code, errors never went away..
But that's not the worst thing, worst think is performance was poor.. I never felt the non-blocking approach was faster, basically because my blocking approach used many, many threads, a good approach if you use a multi-core processor, but the non blocking used only 3-4 threads for everything, with separate functions like accepting new clients, updating player states or sending data, so some threads have little load while other threads couldn't handle the load at all.
What happens when you have problems? usually it starts to appear more like mushrooms (Damn Murphy's law ), and I was just trying to solve other problems that were not related to the blog...
And then I let the blog die slowly, but even without posting more blogs many people entered and read it, and today I arrived to 3k visits and I knew I had to do something, like trying to reanimate the zombie-blog.
Then I remembered a comment I got from wise Amit Patel : How many users do I plan to have? maybe the problem is not being able to handle 10k users·
Now I can say I was distracting myself from my biggest objective, actually making the game!!! so I put my hands on the blocking sockets code again and re-started again, it has been hard, but in this week I expect to launch two updates for the game that will make it a little more user friendly and usable..
Thanks for reading and see you soon (promise)
I have not made anything in the project for about two months :(
Got quite frustrated trying to make the project to work the non-blocking way, and in fact I made it to "work" quite easy, I was very happy because I thought I could make the server work faster and use less resources than I was using...
WRONG!, server worked fine with a low load (say less than 50 users), but when I started to add more users it just collapsed with nasty segmentation fault errors, sometimes when a client disconnected it just blocked the server, I didn't had all those problems with the "old" server and I although I tried to debug the code, errors never went away..
But that's not the worst thing, worst think is performance was poor.. I never felt the non-blocking approach was faster, basically because my blocking approach used many, many threads, a good approach if you use a multi-core processor, but the non blocking used only 3-4 threads for everything, with separate functions like accepting new clients, updating player states or sending data, so some threads have little load while other threads couldn't handle the load at all.
What happens when you have problems? usually it starts to appear more like mushrooms (Damn Murphy's law ), and I was just trying to solve other problems that were not related to the blog...
And then I let the blog die slowly, but even without posting more blogs many people entered and read it, and today I arrived to 3k visits and I knew I had to do something, like trying to reanimate the zombie-blog.
Then I remembered a comment I got from wise Amit Patel : How many users do I plan to have? maybe the problem is not being able to handle 10k users·
Now I can say I was distracting myself from my biggest objective, actually making the game!!! so I put my hands on the blocking sockets code again and re-started again, it has been hard, but in this week I expect to launch two updates for the game that will make it a little more user friendly and usable..
Thanks for reading and see you soon (promise)
Friday, January 27, 2012
Blocking-sockets Windows binaries released!
I have compiled the projects under MS Windows, surprisingly almost everything worked as expected and the binaries are available in Downloads(-RPGServer / Client / Bot Tutorial ->Windows Binaries), feel free to download and test it.
There were only two problems:
The server has certain limits like not being able to accept more than 1018 clients and to use too much resources, but if you plan to work with a limited amount of users (200-300) it will make the job.
I would be glad to hear (constructive) comments about the code, the bugs you may found and well, basically your opinion.
Thanks to everybody!
There were only two problems:
- Server include paths were wrong, I had <SDL/SDL.h> so I replaced them with <SDL.h> and compiled fine
- The bot was giving me errors in the line srand(time(NULL)), solved with a #include <time.h>, curious it worked fine under linux.
The server has certain limits like not being able to accept more than 1018 clients and to use too much resources, but if you plan to work with a limited amount of users (200-300) it will make the job.
I would be glad to hear (constructive) comments about the code, the bugs you may found and well, basically your opinion.
Thanks to everybody!
Blocking-Sockets server code released
Hello again!
After I decided to stop the development for a while I tought it would be nice to share the code with everybody interested, so after a huge cleanup (probably not enought) I have uploaded the code for the server, the client and a silly bot I did to test multiple client connections, they are now in Downloads (-RPGServer / Client / Bot Tutorial -> Source code), feel free to download and test it.
The server has certain limits like not being able to accept more than 1018 clients and to use too much resources, but if you plan to work with a limited amount of users (200-300) it will make the job.
Server isuntested under windows (it works!), client and bot wont care too much for the OS (will work in linux / windows), I don't have a machine with Mac OS X to test so I couldn't test it (any volunteer to try with an apple computer?)
I would be glad to hear (constructive) comments about the code, the bugs you may found and well, basically your opinion.
Thanks to everybody!
After I decided to stop the development for a while I tought it would be nice to share the code with everybody interested, so after a huge cleanup (probably not enought) I have uploaded the code for the server, the client and a silly bot I did to test multiple client connections, they are now in Downloads (-RPGServer / Client / Bot Tutorial -> Source code), feel free to download and test it.
The server has certain limits like not being able to accept more than 1018 clients and to use too much resources, but if you plan to work with a limited amount of users (200-300) it will make the job.
Server is
I would be glad to hear (constructive) comments about the code, the bugs you may found and well, basically your opinion.
Thanks to everybody!
Tuesday, January 3, 2012
STOP & GO
Blocking socket limits
After a long time trying to fix errors / improve performance I have arrived to a sad point: My server with blocking sockets wont support more than 1.018 users, I arrived that limit making an stress test trying to arrive to the 2.000 users barrier, no more clients were accepted after client 1.018.
The problem comes from the design I choose to make the server, I was using blocking sockets, that means for every client we need a thread to wait for data, 1.018 users = 1.018 threads + threads used by the server reached the default limit in Linux (1.024), I have been reading about that , and I know that limit can be modified but it's not a real solution for the problem because my test computer used 90% processor time to handle "only" 1.000 users, so I have to switch to another technology..
That technology is non-blocking sockets, because basically with a single thread you could theoretically handle 1.000 maybe 2.000 connected users, I have been speaking with people that has worked in the game industry and for linux servers the best / fastest way is to use epoll , epoll is basically used to handle I/O from many file descriptors (connections) in real time, but using epoll to me would have meant throwing away all what I have been working on in the last 3 months.... (Thanks Neils for showing me the right way!)
Finally I decided to use socket sets , that is the SDL_net non-blocking approach for that problem , so basically I have to re-write all the networking code for my server...
I have decided to take a rest in the development and I have started a collaboration with a friend to make a multiplayer platformer, it is very good because I have time to think in other things and learn, I'm just finding that I was making many errors and many things could be improved.
See you soon
After a long time trying to fix errors / improve performance I have arrived to a sad point: My server with blocking sockets wont support more than 1.018 users, I arrived that limit making an stress test trying to arrive to the 2.000 users barrier, no more clients were accepted after client 1.018.
The problem comes from the design I choose to make the server, I was using blocking sockets, that means for every client we need a thread to wait for data, 1.018 users = 1.018 threads + threads used by the server reached the default limit in Linux (1.024), I have been reading about that , and I know that limit can be modified but it's not a real solution for the problem because my test computer used 90% processor time to handle "only" 1.000 users, so I have to switch to another technology..
That technology is non-blocking sockets, because basically with a single thread you could theoretically handle 1.000 maybe 2.000 connected users, I have been speaking with people that has worked in the game industry and for linux servers the best / fastest way is to use epoll , epoll is basically used to handle I/O from many file descriptors (connections) in real time, but using epoll to me would have meant throwing away all what I have been working on in the last 3 months.... (Thanks Neils for showing me the right way!)
Finally I decided to use socket sets , that is the SDL_net non-blocking approach for that problem , so basically I have to re-write all the networking code for my server...
I have decided to take a rest in the development and I have started a collaboration with a friend to make a multiplayer platformer, it is very good because I have time to think in other things and learn, I'm just finding that I was making many errors and many things could be improved.
See you soon
Subscribe to:
Posts (Atom)