Compare commits
14 Commits
418579a627
...
4001135451
| Author | SHA1 | Date | |
|---|---|---|---|
| 4001135451 | |||
| 66d7585297 | |||
| 727aeafdb9 | |||
| 3bdfdb114c | |||
| f840ff9c00 | |||
| 986e386098 | |||
| 53282727ec | |||
| d43dc41f25 | |||
| 0058e7e411 | |||
| 764f343f5d | |||
| cdd1db6808 | |||
| ae044c1905 | |||
| 8011c5e8b9 | |||
| 24eda2d16a |
@@ -30,7 +30,7 @@ GameType check_server(char* ip_text, char* port_text) {
|
||||
std::string code = connect_code::encode(addr, std::to_string(port));
|
||||
|
||||
/* Create server socket and wait for client to connect */
|
||||
Server* server = new Server(check_ip_ver(addr.data()), ES_UDP, addr.data(), port);
|
||||
Server* server = new Server(ES_UDP, addr.data(), port);
|
||||
server->create_socket();
|
||||
display_text_centered("Your code is " + code + "\nWaiting for connection...");
|
||||
std::string response = "";
|
||||
@@ -58,7 +58,7 @@ GameType check_client(char* code_text) {
|
||||
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);
|
||||
Client* client = new Client(4, ES_UDP, addr_port[0].data(), std::stoi(addr_port[1]));
|
||||
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");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
@@ -82,9 +83,12 @@ namespace connect_code {
|
||||
|
||||
|
||||
std::string encode(std::string address, std::string port) {
|
||||
std::string addr_coded;
|
||||
/* Convert the address to decimal, and convert that to hex */
|
||||
std::string addr_coded = "";
|
||||
if (check_ip_ver(address.data()) == 4) {
|
||||
/* First, convert the address into a decimal format. Then convert this decimal format
|
||||
into base-32, and also convert the port number into base-32. Join these together with
|
||||
a "_". */
|
||||
|
||||
/* I don't really have a reason to use my own function (dotted_dec_to_dec()
|
||||
and dec_to_dotted_dec()), to convert the IP address from text to binary.
|
||||
The inet_pton() and inet_ntop() functions can do this just fine, and also
|
||||
@@ -101,10 +105,9 @@ namespace connect_code {
|
||||
Then, tokenize the string, using colons as the delimiters.
|
||||
Finally, take each token in the string, and convert it from base-16 to base-32, appending a '-' as a delimiter. */
|
||||
std::string addr_expanded = expand_ip6_addr(address);
|
||||
std::string addr_coded = "";
|
||||
std::vector<std::string> addr_tokenized = tokenize_str(addr_expanded, ":");
|
||||
|
||||
for (int i = 0; i < addr_tokenized.size()-1; i++ ) {
|
||||
for (size_t i = 0; i < addr_tokenized.size()-1; i++ ) {
|
||||
addr_coded += base_convert(addr_tokenized[i], 16, 32);
|
||||
addr_coded += "-";
|
||||
}
|
||||
@@ -113,9 +116,6 @@ namespace connect_code {
|
||||
/* TODO - Check if the IP address is actually converted properly, and test if the server socket is created correctly.
|
||||
Also do the same for client side, and check client-server connection. */
|
||||
|
||||
std::cout << addr_coded << std::endl;
|
||||
abort();
|
||||
|
||||
}
|
||||
|
||||
/* Convert the port to hex */
|
||||
@@ -127,32 +127,59 @@ namespace connect_code {
|
||||
}
|
||||
|
||||
std::vector<std::string> decode(std::string connect_code) {
|
||||
//<AIRPLANE_CODE>
|
||||
if (connect_code.find("_") == std::string::npos) {
|
||||
throw std::invalid_argument("Invalid code entered."); // There must be an underscore, to separate the address part from the port part
|
||||
}
|
||||
|
||||
int ip_ver = 0;
|
||||
if (connect_code.find("-") == connect_code.npos) {
|
||||
if (connect_code.find("-") != std::string::npos) {
|
||||
ip_ver = 6; // If the string contains hyphens, it must be an IPv6 address encoding.
|
||||
} else {
|
||||
ip_ver = 4;
|
||||
}
|
||||
|
||||
//</AIRPLANE_CODE>
|
||||
if (connect_code.find("_") == std::string::npos) {
|
||||
throw std::invalid_argument("Invalid code entered.");
|
||||
}
|
||||
std::vector<std::string> result = tokenize_str(connect_code, "_"); /* Split the string into address and port */
|
||||
std::string address = result[0]; /* Address (in base 16) */
|
||||
std::string port = result[1]; /* Port (in base 16) */
|
||||
|
||||
/* Base 16 to base 10 - These lines convert the string to a base 10 number, and convert the result back into a string */
|
||||
address = std::to_string(std::stoul(address, 0, 32));
|
||||
port = std::to_string(std::stoul(port, 0, 32));
|
||||
|
||||
/* Convert decimal address to dotted decimal */
|
||||
address = dec_to_dotted_dec(address);
|
||||
|
||||
std::string address = result[0]; /* Address (in base 32) */
|
||||
std::string port = result[1]; /* Port (in base 32) */
|
||||
|
||||
std::vector<std::string> ret_val;
|
||||
ret_val.push_back(address);
|
||||
ret_val.push_back(port);
|
||||
|
||||
/* The IPv6 and IPv4 encodings are slightly different - I use a hyphen as a delimiter
|
||||
for IPv6, while there is no delimiter for IPv4. This is why I need to check if the address
|
||||
is IPv4 or IPv6. */
|
||||
if (ip_ver == 4) {
|
||||
/* Base 32 to base 10 - These lines convert the string to a base 10 number, and convert the result back into a string */
|
||||
address = std::to_string(std::stoul(address, 0, 32));
|
||||
port = std::to_string(std::stoul(port, 0, 32));
|
||||
|
||||
/* Convert decimal address to dotted decimal */
|
||||
address = dec_to_dotted_dec(address);
|
||||
|
||||
/* Create a vector containing the address and the port, which will be returned */
|
||||
ret_val.push_back(address);
|
||||
ret_val.push_back(port);
|
||||
} else {
|
||||
/* IPv6 */
|
||||
/* There are three main steps to decoding for IPv6:
|
||||
1. Tokenize the address using the delimiter set while encoding ('-', in my case).
|
||||
2. Convert each token from base-32 to base-16.
|
||||
3. Join the string vector back together into a string, this time using ':' as a delimiter. This will give us our IP address. */
|
||||
|
||||
std::string conv_addr = ""; // Stores the final address
|
||||
std::vector<std::string> address_tokenized = tokenize_str(address, "-"); // Step 1
|
||||
|
||||
for (size_t i = 0; i < address_tokenized.size()-1; i++) {
|
||||
address_tokenized[i] = base_convert(address_tokenized[i], 32, 16); // Step 2
|
||||
conv_addr += address_tokenized[i] + ":"; // Step 3
|
||||
}
|
||||
conv_addr += base_convert(address_tokenized[address_tokenized.size()-1], 32, 16); // Add the last token
|
||||
|
||||
port = std::to_string(std::stoul(port, 0, 32));
|
||||
|
||||
ret_val.push_back(conv_addr);
|
||||
ret_val.push_back(port);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@ meson compile -C "$BASE_DIR/build/"
|
||||
|
||||
# Package the application:
|
||||
# 1. Copy the executable to REL_DIR
|
||||
# 2. Create a tarball
|
||||
# 2. Create a tarball after cd'ing into the parent directory.
|
||||
|
||||
cp "$BASE_DIR/build/pong" "$REL_DIR"
|
||||
tar -czf "$BASE_DIR/release/pong.tar.gz" "$REL_DIR"
|
||||
tar -C "$BASE_DIR/release/static" -czf "$BASE_DIR/release/pong.tar.gz" "pong/"
|
||||
|
||||
# Reset default build target to shared
|
||||
meson configure -Ddefault_library=shared "$BASE_DIR/build/"
|
||||
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
~Client();
|
||||
|
||||
/* Normal constructor that calls the parent constructor to set the given values */
|
||||
Client(int ip_ver, char protocol, const char* address, int port) : Sock(ip_ver, protocol, address, port) {}
|
||||
Client(char protocol, const char* address, int port) : Sock(protocol, address, port) {}
|
||||
|
||||
void create_socket() override;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
/* Constructors */
|
||||
Server() {}
|
||||
|
||||
Server(int ip_ver, char protocol, const char* address, int port) : Sock(ip_ver, protocol, address, port) {}
|
||||
Server(char protocol, const char* address, int port) : Sock(protocol, address, port) {}
|
||||
|
||||
/* Destructor */
|
||||
~Server();
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
virtual ~Sock();
|
||||
|
||||
/* Regular constructor - defined in sock.cpp */
|
||||
Sock(int ip_ver, char protocol, const char* address, int port);
|
||||
Sock(char protocol, const char* address, int port);
|
||||
|
||||
/* Method to send data in 'to_send' through the 'other_socket' socket */
|
||||
void sendAll(std::string to_send);
|
||||
|
||||
19
main.cpp
19
main.cpp
@@ -99,7 +99,11 @@ GameType check_server_client(int argc, char** argv) {
|
||||
connect_code = std::string(argv[2]); /* 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);
|
||||
Client* client = new Client(4, ES_UDP, addr_port[0].data(), std::stoi(addr_port[1]));
|
||||
/* Check IP address version */
|
||||
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");
|
||||
@@ -148,7 +152,7 @@ GameType check_server_client(int argc, char** argv) {
|
||||
std::cout << "Your code is " << code << std::endl;
|
||||
|
||||
/* Create server socket and wait for client to connect */
|
||||
Server* server = new Server(4, ES_UDP, addr.data(), port);
|
||||
Server* server = new Server(ES_UDP, addr.data(), port);
|
||||
server->create_socket();
|
||||
std::cout << "Waiting for connection..." << std::endl;
|
||||
std::string response = "";
|
||||
@@ -376,11 +380,18 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
/* For client (wait for start message from server) */
|
||||
/* For client (wait for start or quit message from server): When the peer quits the
|
||||
game, it sends a serialized struct, containing all zeros, with the last bit turned
|
||||
on as a flag. We catch this zero bit, as it indicates that the peer quit the game. */
|
||||
if (type.mode == M_CLIENT) {
|
||||
do {
|
||||
response = type.netsock->recvAll();
|
||||
} while (response[0] != 'S');
|
||||
} while (response[0] != 'S' && response[0] != 0);
|
||||
if (response[0] == 0) {
|
||||
CloseWindow();
|
||||
std::cout << "Peer unexpectedly quit game." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
game_started = true;
|
||||
std::cout << "Game has been started by server." << std::endl;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "includes/numeric_base.hpp"
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
std::string possible_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
@@ -12,10 +13,10 @@ unsigned int to_decimal(std::string num, int from_base) {
|
||||
|
||||
/* Here, we convert 'num' to decimal (base 10) - Find the index of
|
||||
every character in the string, in 'possible_chars' and
|
||||
compute the value using */
|
||||
compute the value using the position of the character in the number. */
|
||||
for (int i=0; i < (int)num.length(); i++) {
|
||||
current_char = num.at(i);
|
||||
index = possible_chars.find(current_char);
|
||||
index = possible_chars.find(toupper(current_char)); // Convert the character to upper-case, so that the earliest match is detected
|
||||
value += pow(from_base, num.length() - i - 1) * index;
|
||||
}
|
||||
|
||||
|
||||
12
sock.cpp
12
sock.cpp
@@ -18,11 +18,12 @@ Sock::~Sock() {}
|
||||
|
||||
|
||||
/* Constructor - This function initializes the object attributes with the given
|
||||
parameters. It throws an exception if an IPv4 address was given, but the type
|
||||
given is IPv6 (or the other way around). */
|
||||
parameters. The address version (IPv4 or IPv6) is determined based on the given address. */
|
||||
|
||||
Sock::Sock(int ip_ver, char protocol, const char* address, int port) {
|
||||
Sock::Sock(char protocol, const char* address, int port) {
|
||||
/* Error checking */
|
||||
this->ip_ver = check_ip_ver(address);
|
||||
|
||||
if (ip_ver != 4 && ip_ver != 6) {
|
||||
throw std::invalid_argument("Invalid IP address type");
|
||||
}
|
||||
@@ -37,11 +38,6 @@ Sock::Sock(int ip_ver, char protocol, const char* address, int port) {
|
||||
this->protocol = protocol;
|
||||
this->port = port;
|
||||
this->address = std::string(address);
|
||||
|
||||
/* Check to see if the given IP address matches the given ip_ver */
|
||||
if ((check_ip_ver(address) != 6 && ip_ver == 6) || (check_ip_ver(address) != 4 && ip_ver == 4)) {
|
||||
throw std::invalid_argument("Invalid IP address for given type.");
|
||||
}
|
||||
}
|
||||
|
||||
/* This method sends the given data, through the 'other_sockt' variable.. Client
|
||||
|
||||
22
todo.txt
22
todo.txt
@@ -1,13 +1,13 @@
|
||||
1. Try to make the ball go between screens.
|
||||
2. ----SHOULD BE DONE---- Add code to zip the dist/ folder inside the release_build script.
|
||||
3. Sign Windows executable, to remove 'Unknown Publisher' warnings.
|
||||
4. Create and publish statically-linked Linux binary, and create a build script for packaging it.
|
||||
5. Figure out how to build statically-linked Mac binary, and create a build script for packaging it.
|
||||
6. ----IN PROGRESS---- Figure out how to input game mode and (if applicable) IP address and port through the GUI, instead of the command-line.
|
||||
7. Clean up / refactor the raygui code in main.cpp, that asks user for game mode. Instead of just having a giant blob of code in main.cpp, maybe split it into a function, or move it to another file. It should be easy to split it into a different function, since none of the functions take any specific parameters. The text box function, for example, only takes in the rectangle coordinates, and the text to display. I can move the code to a function, and then pass in any parameters that I need to pass in (I don't think I need to pass many parameters, though).
|
||||
8. Allow the user to quit before the game actually starts i.e. while they are inputting the game mode.
|
||||
9. Add better error checking in check_server and check_client functions in check_input.cpp.
|
||||
10. Add 'install' target to Meson, to allow the user to install the game. This should also copy the .so files to the right locations.
|
||||
11. Allow the user to specify which paddle they want to control, in multi-player mode.
|
||||
12. Add IPv6 support for the server and client sockets (and everything that goes along with it, such as error handling for IP addresses).
|
||||
13. Figure out how to make 'tar' not include the entire directory structure, when creating the archive in create_static_linux.sh.
|
||||
4. Figure out how to build statically-linked Mac binary, and create a build script for packaging it.
|
||||
5. ----IN PROGRESS---- Figure out how to input game mode and (if applicable) IP address and port through the GUI, instead of the command-line.
|
||||
6. Clean up / refactor the raygui code in main.cpp, that asks user for game mode. Instead of just having a giant blob of code in main.cpp, maybe split it into a function, or move it to another file. It should be easy to split it into a different function, since none of the functions take any specific parameters. The text box function, for example, only takes in the rectangle coordinates, and the text to display. I can move the code to a function, and then pass in any parameters that I need to pass in (I don't think I need to pass many parameters, though).
|
||||
7. Allow the user to quit before the game actually starts i.e. while they are inputting the game mode.
|
||||
8. Add better error checking in check_server and check_client functions in check_input.cpp. e.g. If client fails to connect, display a message in GUI.
|
||||
9. Add 'install' target to Meson, to allow the user to install the game. This should also copy the .so files to the right locations.
|
||||
10. Allow the user to specify which paddle they want to control, in multi-player mode.
|
||||
11. Add IPv6 support for the server and client sockets (and everything that goes along with it, such as error handling for IP addresses).
|
||||
12. Communicate the paddle reset position to the peer, after a round.
|
||||
13. Test with valgrind.
|
||||
14. Use the struct to establish a connection, and to start each round (instead of sending strings).
|
||||
|
||||
Reference in New Issue
Block a user