Compare commits
6 Commits
c2bedb0601
...
c490eaa301
Author | SHA1 | Date | |
---|---|---|---|
c490eaa301 | |||
0e7ebb4d78 | |||
c94138ad8b | |||
cfbc726dca | |||
ec2f3320e3 | |||
43ba4aba0c |
@@ -8,9 +8,10 @@
|
||||
#include "includes/raygui/raygui.h"
|
||||
#include "includes/exception_consts.hpp"
|
||||
#include "includes/raygui_helpers.hpp"
|
||||
#include "includes/display_text.hpp"
|
||||
#include "includes/timer.h"
|
||||
|
||||
GameType check_server(char* ip_text, char* port_text) {
|
||||
GameType check_server(char* ip_text, char* port_text, const int if_mode) {
|
||||
GameType type;
|
||||
std::string addr;
|
||||
uint16_t port;
|
||||
@@ -33,7 +34,7 @@ GameType check_server(char* ip_text, char* port_text) {
|
||||
/* Create server socket and wait for client to connect */
|
||||
Server* server = new Server(ES_UDP, addr.data(), port);
|
||||
server->create_socket();
|
||||
display_text_centered("Your code is " + code + "\nWaiting for connection...");
|
||||
display_text("Your code is " + code + "\nWaiting for connection...", if_mode);
|
||||
std::string response = "";
|
||||
char* temp_response = NULL;
|
||||
/* Wait for the client to connect. Since recvAll returns a char*, we need to create a temporary variable to check for NULL.
|
||||
@@ -44,30 +45,29 @@ GameType check_server(char* ip_text, char* port_text) {
|
||||
response = std::string(temp_response);
|
||||
|
||||
server->sendAll("U2");
|
||||
display_text_centered("Connection received from " + server->get_peer_addr());
|
||||
Timer timer = timer_init(3);
|
||||
while (!timer_done(timer)); // Wait for five seconds
|
||||
display_text("Connection received from " + server->get_peer_addr(), if_mode);
|
||||
|
||||
type.mode = M_SERVER;
|
||||
type.netsock = server;
|
||||
return type;
|
||||
}
|
||||
|
||||
GameType check_client(char* code_text) {
|
||||
GameType check_client(char* code_text, const int if_mode) {
|
||||
GameType type;
|
||||
std::vector<std::string> addr_port;
|
||||
std::string connect_code = std::string(code_text); /* The connect code is a special string, that contains the server address and port. It is given by the server. */
|
||||
try {
|
||||
addr_port = connect_code::decode(connect_code);
|
||||
if (check_ip_ver(addr_port[0].data()) < 0) {
|
||||
throw std::invalid_argument("Invalid code entered.");
|
||||
}
|
||||
Client* client = new Client(ES_UDP, addr_port[0].data(), std::stoi(addr_port[1]));
|
||||
client->create_socket();
|
||||
/* Send a specific message to the server, and wait for the appropriate response, to know that the server is ready */
|
||||
client->sendAll("GG");
|
||||
std::string msg_from_server = client->recvAllNB();
|
||||
std::string msg_from_server = client->recvAll();
|
||||
if (msg_from_server == "U2") {
|
||||
display_text_centered("Connection made");
|
||||
Timer timer = timer_init(3);
|
||||
while (!timer_done(timer));
|
||||
display_text("Connection made", if_mode);
|
||||
} else {
|
||||
throw std::invalid_argument("Server didn't respond with correct message.");
|
||||
}
|
||||
|
13
display_text.cpp
Normal file
13
display_text.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "includes/display_text.hpp"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
void display_text(std::string to_disp, const int if_mode) {
|
||||
if (if_mode == IF_CLI) {
|
||||
std::cout << to_disp << std::endl;
|
||||
}
|
||||
if (if_mode == IF_GUI) {
|
||||
display_text_raygui(to_disp);
|
||||
}
|
||||
return;
|
||||
}
|
@@ -17,12 +17,14 @@ typedef struct {
|
||||
|
||||
/* This function checks the IP address and port passed to it, and returns a struct,
|
||||
that contains information about the game mode, and contains the server socket.
|
||||
It assumes that both ip_text and port_text are non-null
|
||||
It assumes that both ip_text and port_text are non-null.
|
||||
Any errors are printed using the display_text function, with the given if_type.
|
||||
TODO - Add better error checking. */
|
||||
GameType check_server(char* ip_text, char* port_text);
|
||||
GameType check_server(char* ip_text, char* port_text, const int if_type);
|
||||
|
||||
/* NOT IMPLEMENTED YET - This function checks the code given to it, and returns a struct
|
||||
that contains information about the game mode, and contains the client socket. */
|
||||
GameType check_client(char* code);
|
||||
that contains information about the game mode, and contains the client socket.
|
||||
Any errors are printed using the display_text function, with the given if_type. */
|
||||
GameType check_client(char* code, const int if_type);
|
||||
|
||||
#endif
|
||||
|
10
includes/display_text.hpp
Normal file
10
includes/display_text.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "includes/raygui_helpers.hpp"
|
||||
|
||||
/* Constants that can be used by caller function. */
|
||||
const int IF_CLI = 1;
|
||||
const int IF_GUI = 2;
|
||||
|
||||
/* This function is used to display text. It is used to abstract the differences
|
||||
between GUI invocation and CLI invocation. The if_mode parameter is used to
|
||||
determine whether the game was launched from GUI or CLI. */
|
||||
void display_text(std::string to_disp, const int if_mode);
|
@@ -4,8 +4,8 @@
|
||||
|
||||
/* Display the given text, centered on the screen, as a label.
|
||||
NEEDS RAYGUI LIBRARY. */
|
||||
void display_text_centered(std::string to_disp);
|
||||
void display_text_raygui(std::string to_disp);
|
||||
|
||||
/* Display the given string, and exit the game after 'time' seconds. */
|
||||
void display_and_exit(std::string to_disp, int time);
|
||||
void display_and_exit_raygui(std::string to_disp, int time);
|
||||
#endif
|
||||
|
103
main.cpp
103
main.cpp
@@ -32,7 +32,7 @@
|
||||
#include "includes/server.hpp"
|
||||
#include "includes/exception_consts.hpp"
|
||||
#include "includes/check_input.hpp"
|
||||
#include "includes/raygui_helpers.hpp"
|
||||
#include "includes/display_text.hpp"
|
||||
#include "includes/easysock.h"
|
||||
#include "includes/serialization.h"
|
||||
#include "includes/timer.h"
|
||||
@@ -52,11 +52,11 @@ const float BASE_SPEED = sqrt(powf(BASE_SPEED_COMPONENTS, 2) * 2);
|
||||
std::string HELP_TEXT = "\nnetpong - A networked pong game for the internet era.\n"
|
||||
"\n"
|
||||
"Usage: \n"
|
||||
"netpong [MODE] [ADDRESS|CODE]\n"
|
||||
"netpong [MODE] [ADDRESS PORT]|[CODE]\n"
|
||||
"\n"
|
||||
"MODE: \n"
|
||||
"-S : Server mode. Starts a server to allow the other player to connect.\n"
|
||||
"IP address must be specified. Port is optional, 6500 is used as default.\n"
|
||||
"IP address and port must be specified.\n"
|
||||
"\n"
|
||||
"-C: Client mode. Connects to a server, using the provided connection code.\n"
|
||||
"\n"
|
||||
@@ -97,18 +97,24 @@ raylib::Vector2 changeVelocityAfterCollision(Paddle paddle, Ball ball) {
|
||||
/* Checks the number and type of the command-line arguments. Throws an exception
|
||||
if the args are invalid. DOES NOT PROCESS VALID ARGUMENTS. */
|
||||
void check_num_args(int argc, char** argv) {
|
||||
if (argc > 3) {
|
||||
if (argc > 4) {
|
||||
throw std::invalid_argument("ARGUMENT ERROR: Too many arguments. To view syntax, use -h or --help.");
|
||||
}
|
||||
if (argc > 1) { // Either server or client mode
|
||||
if (std::string(argv[1]) == "-S" && argc < 3) { // Server mode but no address
|
||||
throw std::invalid_argument("ARGUMENT ERROR: Server mode specified without any address.");
|
||||
if (std::string(argv[1]) == "-S") {
|
||||
if (argc < 4) { // Server mode but no address and/or port
|
||||
throw std::invalid_argument("ARGUMENT ERROR: Server mode specified without any address or port.");
|
||||
}
|
||||
}
|
||||
if (std::string(argv[1]) == "-C" && argc < 3) { // Client mode but no code
|
||||
throw std::invalid_argument("ARGUMENT ERRROR: Client mode specified without any code.");
|
||||
else if (std::string(argv[1]) == "-C") {
|
||||
if (argc < 3) { // Client mode but no code
|
||||
throw std::invalid_argument("ARGUMENT ERRROR: Client mode specified without any code.");
|
||||
}
|
||||
}
|
||||
if (std::string(argv[1]) == "-h" || std::string(argv[1]) == "--help") {
|
||||
throw new std::invalid_argument(HELP_TEXT); // I am abusing the exception mechanism here, so that I can ensure that the caller quits the program.
|
||||
else if (std::string(argv[1]) == "-h" || std::string(argv[1]) == "--help") {
|
||||
throw std::invalid_argument(HELP_TEXT); // I am abusing the exception mechanism here, so that I can ensure that the caller quits the program after printing the help message.
|
||||
} else {
|
||||
throw std::invalid_argument("Unrecognized argument.");
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -218,7 +224,8 @@ GameType check_server_client(int argc, char** argv) {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
/* Check the number of command-line arguments */
|
||||
/* Check the number and validity of command-line arguments. Invalid arguments
|
||||
will throw an exception. */
|
||||
try {
|
||||
check_num_args(argc, argv);
|
||||
} catch (std::invalid_argument& inv) {
|
||||
@@ -227,43 +234,43 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
/* From here on, we assume that:
|
||||
a. The program was started in single player mode, OR
|
||||
b. The program was started in server mode, and an address was given, OR
|
||||
c. The program was started in client mode, and a code was given. */
|
||||
a. The program was started with no arguments (User is prompted in GUI), OR
|
||||
b. The program was started in server mode, and an additional was given, OR
|
||||
c. The program was started in client mode, and an additional argument was given. */
|
||||
|
||||
/* Check if game was started in server or client mode, and set appropriate variables */
|
||||
|
||||
/* GameType struct, to define whether the game is in single or multi-player mode, and
|
||||
to hold the appropriate socket */
|
||||
GameType type;
|
||||
|
||||
try {
|
||||
type = check_server_client(argc, argv);
|
||||
} catch(int e) {
|
||||
if (e == EXCEPT_TOOFEWARGS) {
|
||||
std::cout << "Started in client mode, but no address was specified." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if (e == EXCEPT_INVALIDARGS) {
|
||||
std::cout << "Invalid argument." << std::endl;
|
||||
return -2;
|
||||
}
|
||||
if (e == EXCEPT_INVALIDIP) {
|
||||
std::cout << "Invalid IP address provided." << std::endl;
|
||||
return -5;
|
||||
}
|
||||
if (e == EXCEPT_WRONGRESPONSE) {
|
||||
std::cout << "The server didn't respond with the correct message. Are you sure you have used the right server?" << std::endl;
|
||||
return -6;
|
||||
}
|
||||
else {
|
||||
std::cout << strerror(e) << std::endl;
|
||||
return -7;
|
||||
}
|
||||
} catch(std::invalid_argument& inv) {
|
||||
/* Check if game was started in server or client mode, and call the appropriate function to process the arguments.
|
||||
If game was started in single-player mode (i.e. with no arguments), then the user is prompted in the GUI. */
|
||||
try { // I put this try-catch block outside the if-statement because the exception handling is the same for both client and server.
|
||||
if (argc > 1) { // Server or client mode
|
||||
if (std::string(argv[1]) == "-S") { // Server mode
|
||||
type = check_server(argv[2], argv[3], IF_CLI);
|
||||
}
|
||||
if (std::string(argv[1]) == "-C") { // Client mode
|
||||
type = check_client(argv[2], IF_CLI);
|
||||
}
|
||||
}
|
||||
} catch (std::invalid_argument& inv) {
|
||||
std::cout << inv.what() << std::endl;
|
||||
return -8;
|
||||
}
|
||||
} catch (int err) {
|
||||
std::cout << strerror(err) << std::endl;
|
||||
}
|
||||
|
||||
//try {
|
||||
//type = check_server_client(argc, argv);
|
||||
//} catch(int e) {
|
||||
|
||||
//else {
|
||||
//std::cout << strerror(e) << std::endl;
|
||||
//return -7;
|
||||
//}
|
||||
//} catch(std::invalid_argument& inv) {
|
||||
//std::cout << inv.what() << std::endl;
|
||||
//return -8;
|
||||
//}
|
||||
|
||||
/* Initialize window and other variables */
|
||||
SetTraceLogLevel(LOG_NONE);
|
||||
@@ -371,14 +378,14 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
try {
|
||||
type = check_server(ip_text, port_text);
|
||||
type = check_server(ip_text, port_text, IF_GUI);
|
||||
} catch (int e) {
|
||||
display_and_exit(std::string(std::strerror(e)) + "\nClosing game...", 2); // The server constructor throws the errno if it cannot create a socket
|
||||
display_and_exit_raygui(std::string(std::strerror(e)) + "\nClosing game...", 2); // The server constructor throws the errno if it cannot create a socket
|
||||
free(ip_text);
|
||||
free(port_text);
|
||||
return -1;
|
||||
} catch (std::invalid_argument& inv) {
|
||||
display_and_exit(std::string(inv.what()) + "\nClosing game...", 2);
|
||||
display_and_exit_raygui(std::string(inv.what()) + "\nClosing game...", 2);
|
||||
free(ip_text);
|
||||
free(port_text);
|
||||
return -1;
|
||||
@@ -411,12 +418,12 @@ int main(int argc, char** argv) {
|
||||
EndDrawing();
|
||||
}
|
||||
try {
|
||||
type = check_client(code_text);
|
||||
type = check_client(code_text, IF_GUI);
|
||||
} catch (int e) {
|
||||
display_and_exit(std::string(std::strerror(e)) + "\nClosing game...", 2); // The client constructor throws the errno if it cannot create a socket
|
||||
display_and_exit_raygui(std::string(std::strerror(e)) + "\nClosing game...", 2); // The client constructor throws the errno if it cannot create a socket
|
||||
return -1;
|
||||
} catch (std::invalid_argument& inv) {
|
||||
display_and_exit(std::string(inv.what()) + "\nClosing game...", 2);
|
||||
display_and_exit_raygui(std::string(inv.what()) + "\nClosing game...", 2);
|
||||
return -1;
|
||||
}
|
||||
free(code_text);
|
||||
|
@@ -34,7 +34,7 @@ if build_machine.system() == 'windows'
|
||||
endif
|
||||
|
||||
executable('pong',
|
||||
'main.cpp', 'sock.cpp','paddle.cpp', 'ball.cpp', 'numeric_base.cpp', 'connect_code.cpp', 'server.cpp', 'client.cpp', 'check_input.cpp', 'raygui_helpers.cpp',
|
||||
'main.cpp', 'sock.cpp','paddle.cpp', 'ball.cpp', 'numeric_base.cpp', 'connect_code.cpp', 'server.cpp', 'client.cpp', 'check_input.cpp', 'raygui_helpers.cpp', 'display_text.cpp',
|
||||
'serialization.c', 'timer.c', 'easysock.c',
|
||||
dependencies: [raylib, ws2_dep, winmm]
|
||||
)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#include "includes/raygui_helpers.hpp"
|
||||
#include "includes/raygui/raygui.h"
|
||||
#include "includes/timer.h"
|
||||
void display_text_centered(std::string to_disp) {
|
||||
void display_text_raygui(std::string to_disp) {
|
||||
const char* to_disp_cstr = to_disp.c_str();
|
||||
Vector2 label_size = MeasureTextEx(GetFontDefault(), to_disp_cstr, GuiGetStyle(DEFAULT, TEXT_SIZE)+1, GuiGetStyle(DEFAULT, TEXT_SPACING)+1); // The '+1' is there to account for any rounding errors
|
||||
|
||||
@@ -12,8 +12,8 @@ void display_text_centered(std::string to_disp) {
|
||||
return;
|
||||
}
|
||||
|
||||
void display_and_exit(std::string to_disp, int time) {
|
||||
display_text_centered(to_disp);
|
||||
void display_and_exit_raygui(std::string to_disp, int time) {
|
||||
display_text_raygui(to_disp);
|
||||
Timer timer = timer_init(time);
|
||||
while (!timer_done(timer));
|
||||
return;
|
||||
|
2
todo.txt
2
todo.txt
@@ -10,3 +10,5 @@
|
||||
10. Try to make the ball go between screens.
|
||||
11. Change the networking code, so that a single server can connect two clients with each other. The server should provide player 1 with a code, and player 2 can connect with player 1 using that code (essentially like a room).
|
||||
12. Add a --help option, that displays information about the game and how to run it.
|
||||
13. Add better error-checking to check_server() and check_client() (Use check_server_client() as inspiration).
|
||||
14. Ensure that check_server() and check_client() work properly for command-line invocation, then remove check_server_client().
|
||||
|
Reference in New Issue
Block a user