// SDL_net Client | r3dux.org | 14/01/2011
#include <stdlib.h>
#include <stdio.h>
#include <fstream>
#include <iostream>
#include <sstream>
//Allegro include files
#include <allegro5/allegro.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
//SDL include files
#include "SDL.h"
#include "SDL_net.h"
const unsigned short PORT = 1337; // The port we are connecting to
const unsigned short BUFFER_SIZE = 512; // Size of our message buffer (i.e. maximum length of characters in a message)
ALLEGRO_DISPLAY *display;
ALLEGRO_EVENT_QUEUE *event_queue;
ALLEGRO_TIMER *timer;
ALLEGRO_FONT *font;
IPaddress serverIP;
Uint8 * dotQuad;
int lastFromServer = 0;//message duplicate containter/flag
int FPS = 60;//display frames per second
std::string text = "";
bool redraw = false;
int main(int argc, char **argv)
{
const char *host; // Where we store the host name
int status = 0; int status_before = 0;
std::ofstream file("log.txt");
file << "Program initialized" << std::endl;
TCPsocket clientSocket; // The socket to use
std::string serverName; serverName = "localhost"; // The server name
std::string cpp_cl_0 = "";//line of chat we can show other clients
std::string userInput = ""; // A string to hold our user input
int inputLength = 0; // The length of our string in characters
char buffer[BUFFER_SIZE]; // Array of character's we'll use to transmit our message. We get input into the userInput string for ease of use, then just copy it to this character array and send it.
std::string FPScount_string = "none";
std::stringstream myString;
if (!al_init()) {
file << "Allegro could not be initialized" << std::endl;
return -1;
}
al_set_window_title(display, "Client");
// create ourself a display
display = al_create_display(640, 480);
if (!display)
{
al_destroy_display(display);
file << "Display could not be created" << std::endl;
return -1;
}
event_queue = al_create_event_queue();
if (!event_queue) {
al_destroy_event_queue(event_queue);
file << "Event queue could not be created!" << std::endl;
return -1;
}
timer = al_create_timer(1.0 / FPS);
if (!timer) {
al_destroy_timer(timer);
file << "Timer could not be created!" << std::endl;
return -1;
}
// Initialise SDL_net
if (SDLNet_Init() < 0)
{
file << "Failed to intialise SDN_net " << std::endl;
return -1;
}
al_install_keyboard();
al_init_font_addon();
al_init_ttf_addon();
font = al_load_font("data/fonts/bookosb.ttf", 0, 24);
al_register_event_source(event_queue, al_get_display_event_source(display));
al_register_event_source(event_queue, al_get_timer_event_source(timer));
al_register_event_source(event_queue, al_get_keyboard_event_source());
al_start_timer(timer);
// Create the socket set with enough space to store our desired number of connections (i.e. sockets)
SDLNet_SocketSet socketSet = SDLNet_AllocSocketSet(1);
if (socketSet == NULL)
{
file << "Failed to allocate the socket set." << std::endl;
exit(-1); // Quit!
}
else
{
file << "Successfully allocated socket set." << std::endl;
}
// Try to resolve the host. If successful, this places the connection details in the serverIP object
int hostResolved = SDLNet_ResolveHost(&serverIP, serverName.c_str(), PORT);
if (hostResolved == -1)
{
file << "Failed to resolve the server hostname: " << "\nContinuing..." << std::endl;
}
else // If we successfully resolved the host then output the details
{
// Get our IP address in proper dot-quad format by breaking up the 32-bit unsigned host address and splitting it into an array of four 8-bit unsigned numbers...
dotQuad = (Uint8*)&serverIP.host;
//... and then outputting them cast to integers. Then read the last 16 bits of the serverIP object to get the port number
file << "Successfully resolved host to IP: " << (unsigned short)dotQuad[0] << "." << (unsigned short)dotQuad[1] << "." << (unsigned short)dotQuad[2] << "." << (unsigned short)dotQuad[3] << ":" << PORT << std::endl;
}
// Try to resolve the IP of the server, just for kicks
if ((host = SDLNet_ResolveIP(&serverIP)) == NULL)
{
file << "Failed to resolve the server IP address." << std::endl;
}
else
{
file << "Successfully resolved IP to host: " << host << std::endl;
}
// Flag to keep track of when to disconnect and when to shutdown.
bool shutdownClient = false;//bool shutdownClient = true;
bool clientConnected = false;
clientSocket = SDLNet_TCP_Open(&serverIP);
if (!clientSocket)
{
file << "Failed to open socket to server: " << SDLNet_GetError() << std::endl;
text = "Server seems to be down";
}
else // If we successfully opened a connection then check for the server response to our connection
{
file << "Connection okay, about to read connection status from the server..." << std::endl;
// Add our socket to the socket set for polling
SDLNet_TCP_AddSocket(socketSet, clientSocket);
// Wait for up to five seconds for a response from the server
// Note: If we don't check the socket set and WAIT for the response, we'll be checking before the server can respond, and it'll look as if the server sent us nothing back
int activeSockets = SDLNet_CheckSockets(socketSet, 5000);
file << "There are " << activeSockets << " socket(s) with data on them at the moment." << std::endl;
// Check if we got a response from the server
int gotServerResponse = SDLNet_SocketReady(clientSocket);
if (gotServerResponse != 0)
{
file << "Got a response from the server... " << std::endl;
int serverResponseByteCount = SDLNet_TCP_Recv(clientSocket, buffer, BUFFER_SIZE);
file << "Got the following from server: " << buffer << "(" << serverResponseByteCount << " bytes)" << std::endl;
// We got an okay from the server, so we can join!
if (strcmp(buffer, "OK") == 0)
{
// So set the flag to say we're not quitting out just yet
clientConnected = true; shutdownClient = false;
file << "Joining server now..." << std::endl << std::endl;
text = "Now connected";
}
else
{
file << "Server is full... Terminating connection." << std::endl;
text = "Server reports FULL";
}
}
else
{
file << "No response from server..." << std::endl;
text = "Server failed to respond";
}
} // End of if we managed to open a connection to the server condition
bool wrotePrompt = false; // Whether or not we've already written the prompt
bool sendMessage = false; // Whether or not it's time to send the message (flips to true when the user presses return)
// While it's not time to shutdown the client...
do
{
//SDL_Delay(500);
if (sendMessage == true)
{
file << "the message to be sent is>" << userInput << std::endl;
if (clientConnected == true)
{
// Copy our user's string into our char array called "buffer"
strcpy_s(buffer, userInput.c_str());
// Calculate the length of our input and then add 1 (for the terminating character) to get the total number of characters we need to send
inputLength = strlen(buffer) + 1;
// Send the message to the server
if (SDLNet_TCP_Send(clientSocket, (void *)buffer, inputLength) < inputLength)
{
file << "Failed to send message: " << std::endl;
// exit(-1);
}
else
{
file << "Message sent successfully." << std::endl;
//quit=tell server to disconnect me
if (sendMessage == true && (userInput == "quit"))
{
text = "Server disconnecting";
}
//exit=tell server I'm shutting down
if (sendMessage == true && (userInput == "exit"))
{
text = "Shutting down";
shutdownClient = true;
}
//shutdown=tell server to shut it's self down
if (sendMessage == true && (userInput == "shutdown"))
{
text = "Server shut down sent";
}
}//end of failed to send message
}//end of clientConnected == true
//reset for the next message
sendMessage = false;
userInput = "";
} // End of if message needs sent
// Check our socket set for activity. Don't wait if there's nothing on the socket just continue
int socketActive = SDLNet_CheckSockets(socketSet, 0);
//cout << "Sockets with data on them at the moment: " << activeSockets << endl;
if (socketActive != 0)
{
// Check if we got a response from the server
int messageFromServer = SDLNet_SocketReady(clientSocket);
if (messageFromServer != 0)//removed lastfromserver
{
file << "Got a response from the server... " << std::endl;
int serverResponseByteCount = SDLNet_TCP_Recv(clientSocket, buffer, BUFFER_SIZE);
file << "Received: " << buffer << std::endl;// "(" << serverResponseByteCount << " bytes)" << endl;
if (strcmp(buffer, "shutdown") == 0)
{
std::cout << "Server is going down. Disconnecting..." << std::endl;
text = "Server has gone down";
shutdownClient = true;
}
}
else
{
file << "No response from server..." << std::endl;
text = "Server reports it is down";
}
lastFromServer = messageFromServer;//message duplicate checking
} // End of if socket has activity check
myString.str("");//most awesome way to clear a stringstream
myString << FPS;//int to stringstream
FPScount_string = myString.str();//stringstream to string
//check for events (currently keyboard events handled)
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue, &ev);
if (ev.type == ALLEGRO_EVENT_TIMER) {
redraw = true;
}
else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
shutdownClient = true; // If we must quit, then do so
}
// Has a key been pressed down?
else if (ev.type == ALLEGRO_EVENT_KEY_DOWN)
{
if (ev.keyboard.keycode == ALLEGRO_KEY_ENTER)
{
if (userInput.length() > 0) { sendMessage = true; }
}//send the message
}
if (ev.type == ALLEGRO_EVENT_KEY_CHAR) { //Add to the message
status = ev.keyboard.unichar; // Get the keypress
file << "the key pressed was " << status << " " << (char)status << std::endl;
if (status == 8) {
if (userInput.length() > 0) {
userInput.erase(userInput.length() - 1);
}
}
else if (status >= 65 && status <= 122) {
userInput += (char)status;
}
}
else {
status = -1;
}
if (redraw && al_is_event_queue_empty(event_queue)) {
al_clear_to_color(al_map_rgb(0, 0, 0));
al_draw_text(font, al_map_rgb(255, 255, 255), 20, 20, 0, "Hello");
//al_draw_text(font, al_map_rgb(255, 255, 255), 20, 20, 0, userInput.c_str());
//al_draw_text(font, al_map_rgb(255, 255, 255), 20, 20, 0, text.c_str());
al_flip_display();
}
}while (shutdownClient == false); // End of main while loop
file << "Client shutting down" << std::endl;
// Close our socket, cleanup SDL_net, reset the terminal mode and finish!
SDLNet_TCP_Close(clientSocket);
SDLNet_Quit();
al_destroy_font(font);
al_destroy_display(display);
al_destroy_event_queue(event_queue);
al_destroy_timer(timer);
return 0;
}