Compare commits
98 Commits
Author | SHA1 | Date | |
---|---|---|---|
f42ac94a45 | |||
4ff840e91e | |||
fd4ad04aeb | |||
d842485103 | |||
3bf65ab8f9 | |||
f3dcbc3b3e | |||
463dfbd3e5 | |||
d3716536f9 | |||
8805402241 | |||
3d0aeac943 | |||
c490eaa301 | |||
0e7ebb4d78 | |||
c94138ad8b | |||
cfbc726dca | |||
ec2f3320e3 | |||
43ba4aba0c | |||
c2bedb0601 | |||
77a147e08f | |||
26999a1145 | |||
f41c3d22e2 | |||
9f1f313091 | |||
8401f74922 | |||
d2dd95b7cc | |||
5cf11ac014 | |||
0dbf8936fd | |||
3ab97b3853 | |||
aea8f3dfd2 | |||
94e08f3863 | |||
a847da5339 | |||
550643281e | |||
ef869710e5 | |||
00d20ebc88 | |||
839efc3c44 | |||
0a1934fdf9 | |||
24b2a83044 | |||
7d4fd929c7 | |||
54f7dbe7ee | |||
06f44d385d | |||
6f292699f8 | |||
6a40a596c1 | |||
fc59a7221b | |||
7f0898c81e | |||
4001135451 | |||
66d7585297 | |||
727aeafdb9 | |||
3bdfdb114c | |||
f840ff9c00 | |||
986e386098 | |||
53282727ec | |||
d43dc41f25 | |||
0058e7e411 | |||
764f343f5d | |||
cdd1db6808 | |||
ae044c1905 | |||
8011c5e8b9 | |||
24eda2d16a | |||
418579a627 | |||
6acbf90d80 | |||
2c7d1d0b43 | |||
00b83e6de2 | |||
9881567009 | |||
f23f307e17 | |||
dd658c9c1d | |||
52f8034f4e | |||
8758060bfb | |||
10f91fafd4 | |||
e9405b69e7 | |||
9a12edcdb1 | |||
83a0d5beb4 | |||
eeae444b1d | |||
f9d5e8cdeb | |||
9972e146d5 | |||
8848f0ff8c | |||
07ac3f9166 | |||
9e0990156e | |||
1423cc19a0 | |||
352d3f26f1 | |||
788b334e7c | |||
9de9353936 | |||
a3392308c4 | |||
0e9088beb6 | |||
7812611fe6 | |||
bc0d644399 | |||
d05ba0daa1 | |||
c8f29d1336 | |||
0d1dc049b5 | |||
f4bbb6ef6a | |||
1f470e23ee | |||
97e6da3b2b | |||
0286878c70 | |||
e9da48d9a0 | |||
832dae977a | |||
613b81c542 | |||
28c4b421d2 | |||
13ce75067b | |||
635d71f1c5 | |||
8c4a515046 | |||
f25e7fae38 |
21
README.md
21
README.md
@@ -4,16 +4,21 @@ __Netpong__ is a network-enabled Pong game, written in C++. It enables two playe
|
||||
|
||||
## How it works
|
||||
|
||||
The game has only one runtime dependency: The [raylib](https://www.raylib.com/) graphics system. In order to write idiomatic C++, I chose to use the [raylib-cpp](https://robloach.github.io/raylib-cpp/) wrapper, which provides an object-oriented interface to the Raylib library. However, this wrapper is bundled with the project, and is thus not required to be installed.
|
||||
The game has only one runtime dependency: The [raylib](https://www.raylib.com/) graphics library. In order to write idiomatic C++, I chose to use the [raylib-cpp](https://robloach.github.io/raylib-cpp/) wrapper, which provides an object-oriented interface to the Raylib library.
|
||||
|
||||
## Building
|
||||
|
||||
This application uses [Meson](https://mesonbuild.com/) as a build system. To build the application:
|
||||
1. Install __meson__ from the link above.
|
||||
2. Install __raylib__ from the link above (THIS IS OPTIONAL, SEE STEP 5)
|
||||
3. Set up the build directory with the `meson setup build` command.
|
||||
4. Compile the application, with the existing raylib installation, using `meson compile -C build`.
|
||||
5. If you don't have raylib installed, you can create a statically linked version of the library on Linux by running the following commands:
|
||||
1. Install meson from the link above.
|
||||
2. Set up the build directory.
|
||||
```
|
||||
meson setup build
|
||||
```
|
||||
3. Compile the application. Meson should use a system installation of raylib, if it exists. If not, it falls back to a bundled version.
|
||||
```
|
||||
meson compile -C build
|
||||
```
|
||||
4. You can also create a statically-linked version of the game (with no runtime dependencies) on Linux by running the following commands:
|
||||
|
||||
```
|
||||
meson configure -Ddefault_library=static build/
|
||||
@@ -30,3 +35,7 @@ This application uses [Meson](https://mesonbuild.com/) as a build system. To bui
|
||||
- One player runs the application in Server mode, specifying their IP address and a port: `build/pong -S <ip_address> <port>`
|
||||
- The other player connects to the first player by running in Client mode, specifying the first player's IP address and port: `build/pong -C <ip_address> <port>`.
|
||||
- The server controls the left paddle by default (WIP to allow the user to modify this), and the client controls the right paddle.
|
||||
|
||||
## TODO
|
||||
|
||||
See todo.txt.
|
||||
|
83
check_input.cpp
Normal file
83
check_input.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include "includes/easysock.h"
|
||||
#include "includes/connect_code.hpp"
|
||||
#include "includes/server.hpp"
|
||||
#include "includes/client.hpp"
|
||||
#include "includes/check_input.hpp"
|
||||
#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, const int if_mode) {
|
||||
GameType type;
|
||||
std::string addr;
|
||||
uint16_t port;
|
||||
|
||||
/* Check if IP address and port are in valid forms */
|
||||
if (check_ip_ver(ip_text) < 0) {
|
||||
throw std::invalid_argument("Invalid IP address.");
|
||||
}
|
||||
if (port_to_num(port_text) < 0) {
|
||||
throw std::invalid_argument("Invalid port.");
|
||||
}
|
||||
|
||||
/* From here on, we assume that the IP and port are valid */
|
||||
|
||||
addr = std::string(ip_text);
|
||||
port = std::stoi(std::string(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(ES_UDP, addr.data(), port);
|
||||
server->create_socket();
|
||||
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.
|
||||
TODO - Check that the client actually sends 'GG'. */
|
||||
do {
|
||||
temp_response = server->recvAll();
|
||||
} while (temp_response == NULL);
|
||||
response = std::string(temp_response);
|
||||
|
||||
server->sendAll("U2");
|
||||
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, 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->recvAll();
|
||||
if (msg_from_server == "U2") {
|
||||
display_text("Connection made", if_mode);
|
||||
} else {
|
||||
throw std::invalid_argument("Server didn't respond with correct message.");
|
||||
}
|
||||
type.mode = M_CLIENT;
|
||||
type.netsock = client;
|
||||
return type;
|
||||
} catch (int e) {
|
||||
throw;
|
||||
} catch (std::exception& e) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,7 @@
|
||||
#include <fcntl.h>
|
||||
#include "includes/client.hpp"
|
||||
#include "includes/exception_consts.hpp"
|
||||
#include "includes/sock.hpp"
|
||||
#include "includes/easysock.hpp"
|
||||
#include "includes/easysock.h"
|
||||
|
||||
/* Destructor - closes any open sockets */
|
||||
Client::~Client() {
|
||||
|
137
connect_code.cpp
137
connect_code.cpp
@@ -1,10 +1,21 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include "includes/connect_code.hpp"
|
||||
#include "includes/numeric_base.hpp"
|
||||
#include "includes/easysock.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <In6addr.h>
|
||||
#include <Ws2tcpip.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
namespace connect_code {
|
||||
|
||||
@@ -44,13 +55,69 @@ namespace connect_code {
|
||||
uint32_t addr_val = (std::stoul(octets[0]) << 24) + (std::stoul(octets[1]) << 16) + (std::stoul(octets[2]) << 8) + (std::stoul(octets[3]));
|
||||
return std::to_string(addr_val);
|
||||
}
|
||||
|
||||
/* Expand an IPv6 address (expand '::' into ':0000:', for example).
|
||||
This is done by first converting the address into a binary representation,
|
||||
and then printing every character of the binary representation into a string. */
|
||||
std::string expand_ip6_addr(std::string addr) {
|
||||
char ip6_string[40]; // 32 characters + 7 colons
|
||||
struct in6_addr* ip6_s_ptr = (struct in6_addr *)malloc(sizeof(in6_addr)); // Struct pointer, to store the binary representation of the address
|
||||
inet_pton(AF_INET6, addr.data(), ip6_s_ptr); // Convert the string representation into a binary form
|
||||
|
||||
/* This abomination, converts the binary representation into a string.
|
||||
It uses sprintf to print every byte in the binary representation into a string.
|
||||
The bytes are formatted as 2-character hexadecimal values. */
|
||||
sprintf(ip6_string,
|
||||
"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
ip6_s_ptr->s6_addr[0], ip6_s_ptr->s6_addr[1],
|
||||
ip6_s_ptr->s6_addr[2], ip6_s_ptr->s6_addr[3],
|
||||
ip6_s_ptr->s6_addr[4], ip6_s_ptr->s6_addr[5],
|
||||
ip6_s_ptr->s6_addr[6], ip6_s_ptr->s6_addr[7],
|
||||
ip6_s_ptr->s6_addr[8], ip6_s_ptr->s6_addr[9],
|
||||
ip6_s_ptr->s6_addr[10], ip6_s_ptr->s6_addr[11],
|
||||
ip6_s_ptr->s6_addr[12], ip6_s_ptr->s6_addr[13],
|
||||
ip6_s_ptr->s6_addr[14], ip6_s_ptr->s6_addr[15]);
|
||||
|
||||
return std::string(ip6_string);
|
||||
}
|
||||
|
||||
|
||||
std::string encode(std::string address, std::string port) {
|
||||
/* Convert the address to decimal, and convert that to hex */
|
||||
std::string addr_coded = dotted_dec_to_dec(address);
|
||||
addr_coded = base_convert(addr_coded, 10, 32);
|
||||
|
||||
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
|
||||
take care of edge cases. Maybe someday, I might change this code. I could probably
|
||||
repurpose the functions for something else, though. */
|
||||
|
||||
/* First, convert the address into a 32-bit integer (the integer is stored as a string).
|
||||
Then, convert the address into base-32. */
|
||||
addr_coded = dotted_dec_to_dec(address);
|
||||
addr_coded = base_convert(addr_coded, 10, 32);
|
||||
}
|
||||
if (check_ip_ver(address.data()) == 6) {
|
||||
/* First, expand the address into the full 39-character format (32 hex values + 7 colons).
|
||||
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::vector<std::string> addr_tokenized = tokenize_str(addr_expanded, ":");
|
||||
|
||||
for (size_t i = 0; i < addr_tokenized.size()-1; i++ ) {
|
||||
addr_coded += base_convert(addr_tokenized[i], 16, 32);
|
||||
addr_coded += "-";
|
||||
}
|
||||
addr_coded += base_convert(addr_tokenized[addr_tokenized.size()-1], 16, 32); // I put this outside the loop, because I don't want a hyphen after it
|
||||
|
||||
/* 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. */
|
||||
|
||||
}
|
||||
|
||||
/* Convert the port to hex */
|
||||
std::string port_coded = base_convert(port, 10, 32);
|
||||
std::string ret_val = addr_coded + "_" + port_coded;
|
||||
@@ -61,22 +128,58 @@ namespace connect_code {
|
||||
|
||||
std::vector<std::string> decode(std::string connect_code) {
|
||||
if (connect_code.find("_") == std::string::npos) {
|
||||
throw std::invalid_argument("Invalid code entered.");
|
||||
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("-") != std::string::npos) {
|
||||
ip_ver = 6; // If the string contains hyphens, it must be an IPv6 address encoding.
|
||||
} else {
|
||||
ip_ver = 4;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script copies required DLLs, and the application itself into a folder called 'release'. It only runs on MinGW.
|
||||
|
||||
BASE_DIR=$(dirname $0)
|
||||
REL_DIR="$BASE_DIR/release/dist"
|
||||
|
||||
mkdir -p "$REL_DIR"
|
||||
|
||||
# Parse the output of the 'ldd' command, and create a file with the required DLL paths.
|
||||
ldd build/pong.exe | awk ' NF == 4 {print $3}' > "$BASE_DIR/tmp_file.txt"
|
||||
|
||||
# Copy the required DLLs.
|
||||
cp $(cat "$BASE_DIR/tmp_file.txt") "$REL_DIR"
|
||||
|
||||
# Copy the executable itself
|
||||
cp "$BASE_DIR/build/pong" "$REL_DIR"
|
||||
|
||||
# Remove the temporary file.
|
||||
rm "$BASE_DIR/tmp_file.txt"
|
||||
|
35
create_release_mingw.sh
Normal file
35
create_release_mingw.sh
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script copies required DLLs, and the application itself into a folder called 'release'. It only runs on MinGW.
|
||||
|
||||
set -o errexit # Stop executing when a command fails
|
||||
BASE_DIR=$(dirname $0)
|
||||
REL_DIR="$BASE_DIR/release/dist"
|
||||
RAYLIB_DLL="$BASE_DIR/build/subprojects/raylib/libraylib.dll"
|
||||
|
||||
mkdir -p "$REL_DIR"
|
||||
|
||||
# Set up the build directory
|
||||
meson setup build/
|
||||
|
||||
# Build the application
|
||||
meson compile -C build/
|
||||
|
||||
# Parse the output of the 'ldd' command (using only DLLs that are found) and create a file with the required DLL paths.
|
||||
ldd build/pong.exe | awk ' NF == 4 {print $3}' | grep -i "dll" > "$BASE_DIR/tmp_file.txt"
|
||||
|
||||
# Copy the required DLLs.
|
||||
cp $(cat "$BASE_DIR/tmp_file.txt") "$REL_DIR"
|
||||
|
||||
# Copy the raylib DLL, if it does not exist in the directory
|
||||
cp -n "$RAYLIB_DLL" "$REL_DIR"
|
||||
|
||||
# Copy the executable itself
|
||||
cp "$BASE_DIR/build/pong" "$REL_DIR"
|
||||
|
||||
# Remove the temporary file.
|
||||
rm "$BASE_DIR/tmp_file.txt"
|
||||
|
||||
#Zip the $REL_DIR folder
|
||||
zip -r "$BASE_DIR/release/netpong-win.zip" "$REL_DIR"
|
||||
|
26
create_static_linux.sh
Executable file
26
create_static_linux.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script creates and packages a statically-linked build of the game, for Linux.
|
||||
# It must be placed in the root of the source code.
|
||||
|
||||
set -o errexit # Stop executing when a command fails
|
||||
BASE_DIR=$(dirname 0)
|
||||
REL_DIR="$BASE_DIR/release/static/pong"
|
||||
|
||||
mkdir -p "$REL_DIR"
|
||||
|
||||
# Set the default build target to static
|
||||
meson configure -Ddefault_library=static "$BASE_DIR/build/"
|
||||
|
||||
# Build the application
|
||||
meson compile -C "$BASE_DIR/build/"
|
||||
|
||||
# Package the application:
|
||||
# 1. Copy the executable to REL_DIR
|
||||
# 2. Create a tarball after cd'ing into the parent directory.
|
||||
|
||||
cp "$BASE_DIR/build/pong" "$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/"
|
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;
|
||||
}
|
@@ -1,8 +1,9 @@
|
||||
#include "includes/easysock.hpp"
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#include "includes/easysock.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -51,22 +52,23 @@ SOCKET create_socket(int network, char transport) {
|
||||
|
||||
int newSock = socket(domain,type,0);
|
||||
|
||||
/* Set REUSEADDR flag, allowing program to be run twice */
|
||||
int set_opt = 1;
|
||||
setsockopt(newSock, SOL_SOCKET, SO_REUSEADDR, (char *)&set_opt, sizeof(set_opt));
|
||||
|
||||
/* Set REUSEADDR flag for TCP, allowing program to be run twice */
|
||||
if (transport == ES_TCP) {
|
||||
int set_opt = 1;
|
||||
setsockopt(newSock, SOL_SOCKET, SO_REUSEADDR, (char *)&set_opt, sizeof(set_opt));
|
||||
}
|
||||
return newSock;
|
||||
}
|
||||
|
||||
|
||||
int create_addr(int network, const char* address, int port,struct sockaddr* dest) {
|
||||
int create_addr(int network, const char* address, int port,struct sockaddr_storage* dest) {
|
||||
if (network == 4) {
|
||||
struct sockaddr_in listen_address;
|
||||
|
||||
listen_address.sin_family = AF_INET;
|
||||
listen_address.sin_port = htons(port);
|
||||
inet_pton(AF_INET,address,&listen_address.sin_addr);
|
||||
memcpy(dest,&listen_address,sizeof(listen_address));
|
||||
memcpy((struct sockaddr *)dest,&listen_address,sizeof(listen_address));
|
||||
return 0;
|
||||
|
||||
} else if (network == 6) {
|
||||
@@ -74,7 +76,7 @@ int create_addr(int network, const char* address, int port,struct sockaddr* dest
|
||||
listen_ipv6.sin6_family = AF_INET6;
|
||||
listen_ipv6.sin6_port = htons(port);
|
||||
inet_pton(AF_INET6,address,&listen_ipv6.sin6_addr);
|
||||
memcpy(dest,&listen_ipv6,sizeof(listen_ipv6));
|
||||
memcpy((struct sockaddr_in6 *)dest,&listen_ipv6,sizeof(listen_ipv6));
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
@@ -83,7 +85,7 @@ int create_addr(int network, const char* address, int port,struct sockaddr* dest
|
||||
|
||||
}
|
||||
|
||||
SOCKET create_local (int network, char transport, const char* address, int port,struct sockaddr* addr_struct) {
|
||||
SOCKET create_local (int network, char transport, const char* address, int port,struct sockaddr_storage* addr_struct) {
|
||||
int socket = create_socket(network,transport);
|
||||
if (socket < 0) {
|
||||
return (-1 * errno);
|
||||
@@ -102,14 +104,14 @@ SOCKET create_local (int network, char transport, const char* address, int port,
|
||||
This should be set to the size of 'sockaddr_in' for IPv4, and 'sockaddr_in6' for IPv6.
|
||||
See https://stackoverflow.com/questions/73707162/socket-bind-failed-with-invalid-argument-error-for-program-running-on-macos */
|
||||
|
||||
int i = bind (socket,addr_struct,(socklen_t)addrlen);
|
||||
int i = bind (socket,(struct sockaddr *)addr_struct,(socklen_t)addrlen);
|
||||
if (i < 0) {
|
||||
return (-1 * errno);
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
|
||||
SOCKET create_remote (int network,char transport, const char* address,int port,struct sockaddr* remote_addr_struct) {
|
||||
SOCKET create_remote (int network,char transport, const char* address,int port,struct sockaddr_storage* remote_addr_struct) {
|
||||
|
||||
struct addrinfo hints; /* Used to tell getaddrinfo what kind of address we want */
|
||||
struct addrinfo* results; /* Used by getaddrinfo to store the addresses */
|
||||
@@ -129,7 +131,7 @@ SOCKET create_remote (int network,char transport, const char* address,int port,s
|
||||
if (err_code != 0) {
|
||||
return (-1 * err_code);
|
||||
}
|
||||
remote_addr_struct = results->ai_addr;
|
||||
remote_addr_struct = (struct sockaddr_storage *)results->ai_addr;
|
||||
network = inet_to_int(results->ai_family);
|
||||
} else {
|
||||
create_addr(network,address,port,remote_addr_struct);
|
||||
@@ -187,6 +189,29 @@ int check_ip_ver(const char* address) {
|
||||
}
|
||||
}
|
||||
|
||||
int port_to_num(const char* port_str) {
|
||||
/* The largest possible port value is 65535: a 5 character string */
|
||||
if (strlen(port_str) > 5) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < strlen(port_str); i++) {
|
||||
if (isdigit(port_str[i]) == 0) { // Ensure that every character in port_str is a digit (isidigit() returns 0 if the parameter is not a digit)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Convert the string to a base-10 integer */
|
||||
int port_num = (int)strtol(port_str, NULL, 10);
|
||||
if (port_num > 65535) {
|
||||
return -1;
|
||||
}
|
||||
if (port_num < 1024) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
return port_num;
|
||||
}
|
||||
|
||||
int int_to_inet(int network) {
|
||||
if (network == 4) {
|
||||
return AF_INET;
|
30
includes/check_input.hpp
Normal file
30
includes/check_input.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef _CHECK_INPUT_H
|
||||
#define _CHECK_INPUT_H
|
||||
|
||||
#include "includes/sock.hpp"
|
||||
|
||||
typedef enum {M_SINGLE, M_CLIENT, M_SERVER} Mode;
|
||||
|
||||
/* This struct contains a Mode enum, which indicates the type of game we are
|
||||
playing (Single player, client mode or server mode). The netsock parameter is
|
||||
a 'Sock' object - Client and Server classes inherit from this object, so this
|
||||
parameter can be instantiated to either a client or server, depending on the
|
||||
game type. */
|
||||
typedef struct {
|
||||
Mode mode;
|
||||
Sock* netsock;
|
||||
} GameType;
|
||||
|
||||
/* 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.
|
||||
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, 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.
|
||||
Any errors are printed using the display_text function, with the given if_type. */
|
||||
GameType check_client(char* code, const int if_type);
|
||||
|
||||
#endif
|
@@ -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;
|
||||
|
||||
|
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);
|
@@ -1,12 +1,18 @@
|
||||
#ifndef EASYSOCK_HPP_
|
||||
#define EASYSOCK_HPP_
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifndef EASYSOCK_H_
|
||||
#define EASYSOCK_H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#define NOGDI // All GDI defines and routines
|
||||
#define NOUSER // All USER defines and routines
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <winsock.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
#ifdef __unix__
|
||||
#if defined(__unix) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
@@ -44,7 +50,7 @@ and dest is a pointer to the sockaddr struct that will be filled in.
|
||||
The function returns with -202 if the network parameter contained neither '4'
|
||||
nor '6'. */
|
||||
|
||||
int create_addr(int network, const char* address, int port,struct sockaddr* dest);
|
||||
int create_addr(int network, const char* address, int port,struct sockaddr_storage* dest);
|
||||
|
||||
|
||||
|
||||
@@ -54,7 +60,7 @@ same as above.
|
||||
|
||||
It prints the error returned by 'bind' if something went wrong, and returns ( -1 * errno ).*/
|
||||
|
||||
SOCKET create_local (int network, char transport, const char* address, int port,struct sockaddr* addr_struct);
|
||||
SOCKET create_local (int network, char transport, const char* address, int port,struct sockaddr_storage* addr_struct);
|
||||
|
||||
|
||||
/* This function utilizes the same functions as 'create_local' but _connects_ to the
|
||||
@@ -63,13 +69,19 @@ as above. This function needs an empty 'sockaddr *' structure passed to it, whic
|
||||
|
||||
If something goes wrong, this function returns with ( -1 * errno ). */
|
||||
|
||||
SOCKET create_remote (int network,char transport, const char* address,int port,struct sockaddr* remote_addr_struct);
|
||||
SOCKET create_remote (int network,char transport, const char* address,int port,struct sockaddr_storage* remote_addr_struct);
|
||||
|
||||
/* check_ip_ver - This function checks if the given string is an IPv4 address (returns 4),
|
||||
IPv6 address (returns 6) or neither (returns -1). */
|
||||
|
||||
int check_ip_ver(const char* address);
|
||||
|
||||
/* port_to_num - Converts a string representing a port, into a numeric value.
|
||||
Returns -1 if the string is not numeric, or exceeds the maximum port length.
|
||||
Returns -2 if the string is lower than 1024, This serves as a warning, as ports less
|
||||
than 1023 are reserved. */
|
||||
int port_to_num(const char* port_str);
|
||||
|
||||
/* int_to_inet - Takes an int value (4 for IPv4, 6 for IPv6) and returns AF_INET or
|
||||
AF_INET6 respectively. */
|
||||
|
||||
@@ -92,3 +104,6 @@ int sock_quit(void);
|
||||
int sock_close(SOCKET);
|
||||
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
5535
includes/raygui/raygui.h
Normal file
5535
includes/raygui/raygui.h
Normal file
File diff suppressed because it is too large
Load Diff
589
includes/raygui/style_dark.h
Normal file
589
includes/raygui/style_dark.h
Normal file
@@ -0,0 +1,589 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// StyleAsCode exporter v2.0 - Style data exported as a values array //
|
||||
// //
|
||||
// USAGE: On init call: GuiLoadStyleDark(); //
|
||||
// //
|
||||
// more info and bugs-report: github.com/raysan5/raygui //
|
||||
// feedback and support: ray[at]raylibtech.com //
|
||||
// //
|
||||
// Copyright (c) 2020-2024 raylib technologies (@raylibtech) //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define DARK_STYLE_PROPS_COUNT 23
|
||||
|
||||
// Custom style name: Dark
|
||||
static const GuiStyleProp darkStyleProps[DARK_STYLE_PROPS_COUNT] = {
|
||||
{ 0, 0, 0x878787ff }, // DEFAULT_BORDER_COLOR_NORMAL
|
||||
{ 0, 1, 0x2c2c2cff }, // DEFAULT_BASE_COLOR_NORMAL
|
||||
{ 0, 2, 0xc3c3c3ff }, // DEFAULT_TEXT_COLOR_NORMAL
|
||||
{ 0, 3, 0xe1e1e1ff }, // DEFAULT_BORDER_COLOR_FOCUSED
|
||||
{ 0, 4, 0x848484ff }, // DEFAULT_BASE_COLOR_FOCUSED
|
||||
{ 0, 5, 0x181818ff }, // DEFAULT_TEXT_COLOR_FOCUSED
|
||||
{ 0, 6, 0x000000ff }, // DEFAULT_BORDER_COLOR_PRESSED
|
||||
{ 0, 7, 0xefefefff }, // DEFAULT_BASE_COLOR_PRESSED
|
||||
{ 0, 8, 0x202020ff }, // DEFAULT_TEXT_COLOR_PRESSED
|
||||
{ 0, 9, 0x6a6a6aff }, // DEFAULT_BORDER_COLOR_DISABLED
|
||||
{ 0, 10, 0x818181ff }, // DEFAULT_BASE_COLOR_DISABLED
|
||||
{ 0, 11, 0x606060ff }, // DEFAULT_TEXT_COLOR_DISABLED
|
||||
{ 0, 16, 0x00000010 }, // DEFAULT_TEXT_SIZE
|
||||
{ 0, 17, 0x00000000 }, // DEFAULT_TEXT_SPACING
|
||||
{ 0, 18, 0x9d9d9dff }, // DEFAULT_LINE_COLOR
|
||||
{ 0, 19, 0x3c3c3cff }, // DEFAULT_BACKGROUND_COLOR
|
||||
{ 0, 20, 0x00000018 }, // DEFAULT_TEXT_LINE_SPACING
|
||||
{ 1, 5, 0xf7f7f7ff }, // LABEL_TEXT_COLOR_FOCUSED
|
||||
{ 1, 8, 0x898989ff }, // LABEL_TEXT_COLOR_PRESSED
|
||||
{ 4, 5, 0xb0b0b0ff }, // SLIDER_TEXT_COLOR_FOCUSED
|
||||
{ 5, 5, 0x848484ff }, // PROGRESSBAR_TEXT_COLOR_FOCUSED
|
||||
{ 9, 5, 0xf5f5f5ff }, // TEXTBOX_TEXT_COLOR_FOCUSED
|
||||
{ 10, 5, 0xf6f6f6ff }, // VALUEBOX_TEXT_COLOR_FOCUSED
|
||||
};
|
||||
|
||||
// WARNING: This style uses a custom font: "PixelOperator.ttf" (size: 16, spacing: 0)
|
||||
|
||||
#define DARK_STYLE_FONT_ATLAS_COMP_SIZE 2126
|
||||
|
||||
// Font atlas image pixels data: DEFLATE compressed
|
||||
static unsigned char darkFontData[DARK_STYLE_FONT_ATLAS_COMP_SIZE] = { 0xed,
|
||||
0xdd, 0xdb, 0x72, 0xa4, 0x3a, 0x12, 0x05, 0x50, 0xfd, 0xff, 0x4f, 0xe7, 0x3c, 0x4c, 0x4c, 0x4c, 0x74, 0x9c, 0xd3, 0x20,
|
||||
0xa5, 0x52, 0x17, 0xec, 0xd5, 0xeb, 0xcd, 0xe5, 0x76, 0x51, 0xa0, 0x94, 0x84, 0x28, 0x36, 0xd1, 0x00, 0x00, 0x00, 0x80,
|
||||
0x5f, 0x2f, 0xfe, 0xf5, 0x27, 0xf1, 0xd7, 0xdf, 0x8c, 0xee, 0xbf, 0xf3, 0xfc, 0xf3, 0xff, 0xbd, 0x1a, 0x0f, 0xef, 0xd5,
|
||||
0xb7, 0xad, 0xa3, 0xef, 0x1b, 0x03, 0x7b, 0xe2, 0xdf, 0xb7, 0x2f, 0xba, 0xff, 0xee, 0xdf, 0x3e, 0xdf, 0xf8, 0xef, 0x3f,
|
||||
0xfd, 0xa5, 0xe7, 0xad, 0x8f, 0xa1, 0xfd, 0x3e, 0xfe, 0x7f, 0xc6, 0x8e, 0x62, 0x2c, 0xd9, 0xf7, 0xef, 0x5b, 0x37, 0xbe,
|
||||
0xed, 0x95, 0xff, 0x27, 0x1e, 0x3e, 0x4f, 0xe6, 0x28, 0xf5, 0xd4, 0xd6, 0x0d, 0xf5, 0x1f, 0x5d, 0x95, 0x18, 0xa5, 0x2d,
|
||||
0xe7, 0xff, 0xef, 0x1a, 0x85, 0x3d, 0x55, 0x76, 0x4f, 0x3e, 0x55, 0xfa, 0xf8, 0xfe, 0x78, 0x6a, 0xfd, 0xe3, 0x3d, 0x60,
|
||||
0x94, 0x7c, 0x96, 0xf9, 0xd6, 0x18, 0xd3, 0xbf, 0xdd, 0xd7, 0x92, 0x6a, 0x3e, 0xd5, 0xcc, 0x2b, 0xad, 0xe4, 0x28, 0x9d,
|
||||
0xa8, 0xff, 0x48, 0xf7, 0x54, 0x31, 0x58, 0xd1, 0x15, 0x7b, 0x30, 0xd3, 0x0f, 0xb7, 0x8d, 0xf5, 0x1f, 0xa5, 0x73, 0x97,
|
||||
0x28, 0x6b, 0x73, 0x27, 0xea, 0xff, 0x79, 0xd4, 0x6e, 0x25, 0xed, 0x26, 0x5e, 0xf6, 0x51, 0x6d, 0x2d, 0xaf, 0x9d, 0xa7,
|
||||
0xae, 0xae, 0xff, 0xe7, 0xdf, 0x1c, 0x1d, 0x6f, 0x63, 0x70, 0xec, 0xae, 0xd8, 0x4f, 0xb9, 0xf1, 0xbf, 0x7e, 0x3f, 0xc6,
|
||||
0x5f, 0xc7, 0xe6, 0xec, 0x3c, 0x64, 0x64, 0x0f, 0xc7, 0xe0, 0xd9, 0xd5, 0xec, 0x08, 0x7b, 0x72, 0xfc, 0xef, 0x9b, 0x0b,
|
||||
0xaa, 0xff, 0xb5, 0xf5, 0x9f, 0xf9, 0x24, 0xd1, 0xb9, 0x05, 0x99, 0x31, 0xb1, 0x5d, 0x50, 0xff, 0xa3, 0xfd, 0xd0, 0xf3,
|
||||
0xbe, 0xaa, 0x9a, 0xcb, 0x8f, 0xae, 0x4b, 0xf4, 0x9d, 0x61, 0xef, 0x6b, 0x85, 0xe3, 0x73, 0xa3, 0xf1, 0xfa, 0x1f, 0xef,
|
||||
0x3d, 0xdf, 0xfe, 0xda, 0xe8, 0x5e, 0xfd, 0xfb, 0x99, 0xdd, 0xfc, 0x1e, 0xdf, 0x57, 0xff, 0x91, 0x18, 0x53, 0xce, 0xd7,
|
||||
0x73, 0x4d, 0xfd, 0x47, 0x62, 0xe5, 0xa2, 0x95, 0xad, 0xf2, 0xe5, 0xd6, 0x25, 0xea, 0xd6, 0x0c, 0xce, 0x1f, 0x81, 0xf7,
|
||||
0xfa, 0x7f, 0x3b, 0x1f, 0x3c, 0x3f, 0xfe, 0xc7, 0x15, 0xe3, 0x7f, 0xa4, 0xd7, 0x86, 0x5b, 0xa2, 0xf7, 0xfd, 0x5a, 0xfd,
|
||||
0x47, 0xa2, 0x66, 0xa2, 0xe4, 0xbc, 0xbc, 0x2d, 0x59, 0xcb, 0xab, 0x5d, 0x33, 0xdc, 0x73, 0xb4, 0xde, 0x46, 0xd1, 0xaa,
|
||||
0xb3, 0x9a, 0x9f, 0x55, 0xff, 0xad, 0x60, 0xfc, 0xef, 0x9b, 0x03, 0xcc, 0x7e, 0x8e, 0xf8, 0xd8, 0xe8, 0x5f, 0x59, 0xff,
|
||||
0xbb, 0x56, 0xec, 0xd7, 0xb7, 0xc6, 0xb8, 0xe2, 0xc8, 0x58, 0xff, 0xaf, 0x9c, 0xff, 0xe7, 0xd7, 0x00, 0xc6, 0xce, 0x63,
|
||||
0xe2, 0xd2, 0xea, 0xcf, 0x9c, 0x33, 0x57, 0x5d, 0xb1, 0xaf, 0xfd, 0x36, 0x41, 0x24, 0xbe, 0xab, 0x51, 0xb3, 0x8a, 0xb3,
|
||||
0xfa, 0x18, 0x8c, 0x8f, 0xff, 0xbb, 0xae, 0xff, 0xbf, 0xcf, 0xb9, 0xef, 0x18, 0xff, 0xdb, 0xeb, 0xe8, 0x7e, 0xcb, 0xf6,
|
||||
0x00, 0x7b, 0x7b, 0x80, 0x50, 0xfd, 0xe0, 0x7b, 0xc4, 0x80, 0xfa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0a, 0xbf, 0x9f, 0x5f, 0x9f, 0x63, 0x30, 0x9e, 0x84, 0xbd, 0x3e, 0x81, 0x7d, 0x26, 0x13, 0x38, 0xbb,
|
||||
0x87, 0xaa, 0xfe, 0xe2, 0x73, 0x76, 0xfc, 0x48, 0xd2, 0x42, 0x7f, 0xcb, 0x88, 0xe1, 0xa7, 0x1f, 0x54, 0x26, 0x0a, 0x64,
|
||||
0x32, 0x0d, 0xda, 0x60, 0x9b, 0xa8, 0xcd, 0x52, 0x1a, 0xdb, 0xfa, 0x3d, 0x2d, 0xfe, 0x0b, 0xf5, 0x7f, 0xfe, 0x95, 0x96,
|
||||
0xc8, 0xef, 0xd9, 0x59, 0xff, 0xa3, 0x6d, 0x2f, 0x97, 0x8f, 0x3b, 0x37, 0x96, 0xec, 0x4e, 0x14, 0x8b, 0xc2, 0x63, 0xb8,
|
||||
0x6f, 0x5c, 0xfd, 0x33, 0x43, 0x67, 0x47, 0xbb, 0x9e, 0xa9, 0xff, 0xd1, 0xec, 0xd3, 0x78, 0xe8, 0x85, 0xef, 0xa9, 0xff,
|
||||
0xb6, 0xa5, 0xfe, 0xe3, 0x23, 0xf5, 0x5f, 0x9d, 0x24, 0x53, 0x95, 0x42, 0x9e, 0x49, 0xbe, 0x19, 0x3f, 0x86, 0xf9, 0x84,
|
||||
0xdf, 0x6c, 0x8b, 0xfb, 0x4e, 0xfd, 0x67, 0xda, 0xd6, 0x73, 0xce, 0xaa, 0xfa, 0x7f, 0xdf, 0xb7, 0x99, 0xd1, 0x64, 0xfe,
|
||||
0xe7, 0x35, 0x95, 0xbf, 0x27, 0x47, 0xf7, 0xed, 0x39, 0x5a, 0x6b, 0xdb, 0xca, 0xec, 0x58, 0xf9, 0x95, 0xfa, 0x8f, 0xe4,
|
||||
0x5f, 0x89, 0x97, 0x1e, 0xa5, 0x36, 0x81, 0xbd, 0x26, 0xb5, 0x6d, 0x6f, 0xfd, 0x57, 0x3f, 0xf7, 0xe7, 0x8e, 0xfa, 0x3f,
|
||||
0x9f, 0xa3, 0xbb, 0xea, 0x1c, 0xae, 0x76, 0xac, 0xfc, 0xd9, 0xe3, 0xff, 0x7b, 0x2f, 0xb9, 0xa3, 0x7d, 0xcc, 0x8c, 0xf4,
|
||||
0x27, 0xc7, 0xff, 0x73, 0x3f, 0x3f, 0x5b, 0xff, 0x55, 0xad, 0x3d, 0x36, 0xce, 0x4c, 0xb2, 0x63, 0xe5, 0xce, 0x55, 0xb2,
|
||||
0xdd, 0xe7, 0xff, 0xab, 0x3e, 0x59, 0x1b, 0x9e, 0x4d, 0xc4, 0xb5, 0xf5, 0x3f, 0xb3, 0x0a, 0xb9, 0x6e, 0xbe, 0x70, 0x66,
|
||||
0xfe, 0x9f, 0x7b, 0xbe, 0x6d, 0xe6, 0xa9, 0x80, 0xb7, 0x8d, 0xff, 0xbb, 0xae, 0x92, 0xb5, 0xcd, 0x35, 0xb9, 0xf7, 0xbd,
|
||||
0x2a, 0x9f, 0x52, 0x37, 0x9e, 0xdf, 0x1f, 0xc5, 0x33, 0xbc, 0xaf, 0xd7, 0x7f, 0x7e, 0x95, 0xbf, 0x15, 0xad, 0x4a, 0x9e,
|
||||
0x9b, 0xff, 0xef, 0x7e, 0xd2, 0x49, 0xe6, 0x5d, 0x6a, 0xfa, 0xdf, 0xbe, 0xab, 0xc2, 0xb5, 0xa3, 0xc0, 0xdf, 0xaf, 0x36,
|
||||
0x44, 0xd1, 0xc8, 0x51, 0x95, 0xdf, 0xff, 0xe7, 0xb6, 0x8d, 0x3f, 0xf1, 0x6c, 0xfc, 0x4a, 0x7c, 0x0c, 0x3e, 0x4f, 0xff,
|
||||
0x44, 0xfd, 0x67, 0xde, 0x39, 0xf3, 0xbf, 0x46, 0x8f, 0x61, 0x65, 0xfd, 0x9f, 0xeb, 0x01, 0xe4, 0x6e, 0xc2, 0x8d, 0xb3,
|
||||
0x18, 0xe0, 0xe7, 0xf4, 0x00, 0x9e, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xec, 0xbe, 0x13, 0xfb, 0xef, 0xd9, 0x5c, 0x99, 0xd4, 0xf8, 0xf1, 0xfb, 0xa4, 0x77, 0x26, 0xe6, 0xb7, 0x97, 0x14, 0xb2,
|
||||
0xe7, 0xdf, 0xfa, 0xf3, 0x95, 0x8a, 0x3c, 0xde, 0x28, 0xbc, 0x6b, 0xfd, 0x29, 0x93, 0xe4, 0x39, 0x4b, 0x71, 0x34, 0x77,
|
||||
0xe0, 0x7d, 0x0f, 0x8f, 0x1f, 0x97, 0x99, 0xd7, 0x5a, 0x61, 0x9a, 0x42, 0x24, 0xd2, 0x5e, 0xde, 0xf6, 0x7a, 0x7f, 0x36,
|
||||
0x70, 0x94, 0x6d, 0xf1, 0x58, 0x1d, 0x55, 0x65, 0x27, 0xdf, 0x9e, 0x98, 0x3f, 0x9f, 0xbc, 0x13, 0x2f, 0xad, 0xae, 0xbf,
|
||||
0xfe, 0x7b, 0x92, 0x23, 0xd6, 0xe7, 0x18, 0xf5, 0xfc, 0x34, 0x93, 0x7a, 0x31, 0x96, 0xc1, 0x36, 0xd7, 0x06, 0x56, 0x8f,
|
||||
0x50, 0x6d, 0xb2, 0x42, 0x62, 0xaa, 0xa5, 0xcc, 0x67, 0xff, 0xbd, 0x6f, 0x69, 0x1b, 0x1c, 0xb9, 0x6e, 0x48, 0xcc, 0x8c,
|
||||
0xce, 0xfa, 0xaa, 0xfe, 0x69, 0x1b, 0xec, 0x6f, 0x32, 0x79, 0x75, 0x51, 0x9a, 0x44, 0x91, 0xff, 0x3f, 0x91, 0x48, 0x6d,
|
||||
0x6e, 0xc9, 0x2c, 0xbe, 0x7c, 0x46, 0x7c, 0x26, 0xa7, 0x2a, 0x16, 0xef, 0xd9, 0x4c, 0xfd, 0xb7, 0x43, 0xf5, 0x9f, 0x49,
|
||||
0x3d, 0x38, 0x9f, 0x98, 0x1d, 0xa9, 0xda, 0xdd, 0x5b, 0xff, 0xd1, 0xd1, 0x7f, 0x65, 0x66, 0xd7, 0x51, 0x78, 0xce, 0xf0,
|
||||
0x3e, 0xe3, 0xad, 0x1e, 0xff, 0xdb, 0xe3, 0x7e, 0x1a, 0x4f, 0x75, 0x5b, 0x3f, 0x42, 0x65, 0x7a, 0x93, 0xb1, 0xfa, 0x5f,
|
||||
0xdd, 0x63, 0xcd, 0x3c, 0x07, 0x29, 0x3e, 0x37, 0xfe, 0x9f, 0x49, 0xcc, 0x8e, 0xc4, 0xd9, 0x75, 0xe6, 0x7d, 0xeb, 0xd7,
|
||||
0x5e, 0xa2, 0xb0, 0xfe, 0x33, 0x3d, 0x40, 0xbe, 0xfe, 0x77, 0xce, 0xa6, 0xb3, 0x79, 0x93, 0x31, 0xdd, 0x86, 0xce, 0xd4,
|
||||
0x7f, 0xe5, 0xd3, 0x96, 0x56, 0x24, 0xe6, 0x8e, 0x3f, 0xd9, 0xf1, 0xd4, 0xf8, 0xdf, 0x52, 0xe3, 0x7f, 0x6e, 0x9c, 0xa8,
|
||||
0x3b, 0xf6, 0xb5, 0x73, 0xe5, 0xf7, 0xfa, 0x8f, 0x0d, 0xef, 0xb6, 0xaf, 0xfe, 0x33, 0x3d, 0x61, 0x2c, 0x9b, 0xff, 0x67,
|
||||
0xab, 0x25, 0x86, 0xe7, 0xd7, 0x3b, 0x13, 0x73, 0x33, 0xeb, 0xcc, 0xf7, 0xd7, 0x7f, 0xe5, 0x33, 0x4c, 0xda, 0x54, 0xfa,
|
||||
0x72, 0x94, 0x8e, 0xc8, 0xfb, 0xc6, 0xff, 0x15, 0xb3, 0xe9, 0x4c, 0xfa, 0xfe, 0x3d, 0xeb, 0x7f, 0xad, 0xf8, 0x88, 0xb5,
|
||||
0xe3, 0x79, 0x88, 0x2b, 0x66, 0x85, 0x27, 0xce, 0xff, 0xab, 0x12, 0xd8, 0x73, 0xe7, 0xff, 0xd5, 0x2b, 0xf2, 0x73, 0xc7,
|
||||
0xf2, 0xde, 0xf1, 0x3f, 0xd7, 0x42, 0x62, 0x68, 0x7c, 0x6e, 0x9f, 0xaa, 0xff, 0x5b, 0xbe, 0xd1, 0x50, 0xd1, 0x6f, 0x45,
|
||||
0x49, 0xef, 0x96, 0x79, 0x6e, 0x4b, 0xe5, 0x3c, 0xaa, 0x72, 0xfd, 0x6a, 0xe6, 0xfa, 0xff, 0xcc, 0xb7, 0x53, 0x56, 0xbf,
|
||||
0x5b, 0xfe, 0xfa, 0xff, 0xda, 0xfa, 0x8f, 0xe2, 0x2d, 0xe6, 0x9e, 0x5e, 0xea, 0xe6, 0xf7, 0xd3, 0x7e, 0xee, 0x38, 0x82,
|
||||
0x6a, 0x59, 0xeb, 0x39, 0x71, 0x3e, 0xc4, 0xef, 0x9a, 0x33, 0xf3, 0xd3, 0xbf, 0xe1, 0x6d, 0x3f, 0x18, 0x9b, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xef, 0xde, 0xc3, 0x14, 0xaf, 0x77, 0x38, 0xbc, 0x65, 0x4b,
|
||||
0x64, 0x72, 0x29, 0x5b, 0x69, 0xce, 0x5d, 0x4b, 0x24, 0xf3, 0x67, 0xb7, 0xae, 0x77, 0xaf, 0xac, 0xff, 0x64, 0xb3, 0x69,
|
||||
0xe6, 0x99, 0xc4, 0xf9, 0xcc, 0x3e, 0x3e, 0x7b, 0x34, 0xdf, 0x32, 0x3c, 0x22, 0x91, 0xc6, 0x5a, 0x79, 0xbc, 0x5a, 0x6a,
|
||||
0xdf, 0x65, 0x5b, 0x59, 0x6f, 0x0f, 0xd0, 0x9f, 0x0f, 0x53, 0x7f, 0x8f, 0x69, 0xa4, 0xf6, 0x79, 0x4d, 0x32, 0xff, 0x4c,
|
||||
0x5b, 0x6a, 0xe9, 0x04, 0xe2, 0x6c, 0xab, 0xe9, 0xfd, 0x5b, 0x31, 0xfd, 0x97, 0xdf, 0xb3, 0x5a, 0xe3, 0x73, 0x47, 0x33,
|
||||
0x9b, 0x17, 0x5f, 0x7d, 0xbc, 0x6a, 0xd3, 0xdb, 0x6a, 0x7a, 0x80, 0x8a, 0xfa, 0xaf, 0xdb, 0xca, 0xfd, 0xf7, 0xc6, 0x46,
|
||||
0xf2, 0x7e, 0xfa, 0xf8, 0xfc, 0xfd, 0xa7, 0xf1, 0xd1, 0x24, 0x81, 0x5c, 0xca, 0xe4, 0xae, 0x4f, 0x95, 0xcb, 0xe5, 0xca,
|
||||
0xa7, 0xb7, 0xed, 0x1c, 0xff, 0x33, 0x49, 0x52, 0x99, 0xb4, 0xd0, 0xea, 0x57, 0xb2, 0xbd, 0x65, 0xae, 0xfe, 0x33, 0x99,
|
||||
0x4d, 0x51, 0x94, 0x67, 0x5c, 0xf7, 0xdc, 0x93, 0x48, 0xce, 0xaf, 0x4f, 0x1e, 0xcd, 0x78, 0x4d, 0x25, 0xaf, 0xca, 0xd8,
|
||||
0xdd, 0xfb, 0x4a, 0x4c, 0x26, 0x3e, 0x44, 0xd7, 0xf1, 0x8e, 0xe9, 0xb1, 0x70, 0xd7, 0xd3, 0x02, 0x33, 0xcf, 0xa4, 0x68,
|
||||
0xc9, 0xd4, 0xcc, 0x28, 0x9b, 0xe1, 0x57, 0xbf, 0xb2, 0xa2, 0xfe, 0xe3, 0xe1, 0x3c, 0xb9, 0xfa, 0x99, 0x65, 0xd5, 0x47,
|
||||
0xb3, 0xa7, 0x67, 0xf8, 0x62, 0xfd, 0xaf, 0x9d, 0xa7, 0xd5, 0x9c, 0xff, 0x47, 0xfa, 0x59, 0x3c, 0x77, 0xb6, 0x98, 0xe8,
|
||||
0x4c, 0x77, 0xfe, 0x69, 0xf5, 0xbf, 0x77, 0x1f, 0x57, 0xf7, 0xe6, 0xcf, 0x33, 0xec, 0xf6, 0xd1, 0xfa, 0x9f, 0x49, 0x8b,
|
||||
0xaf, 0x39, 0x5f, 0x79, 0x5f, 0xff, 0xaf, 0x5c, 0xd9, 0xb8, 0xa3, 0xfe, 0x6f, 0xa9, 0xf2, 0xb1, 0x7d, 0xbe, 0xb6, 0xfe,
|
||||
0xcf, 0xd7, 0xd0, 0x6c, 0xf2, 0xfb, 0xf9, 0x6d, 0x8f, 0xb2, 0xf3, 0xff, 0x9a, 0x75, 0xa1, 0xea, 0x79, 0xc4, 0x6d, 0x3d,
|
||||
0xe8, 0xaa, 0xa7, 0xab, 0xbd, 0xcd, 0x1d, 0xaa, 0xcf, 0x77, 0xef, 0x18, 0xff, 0x43, 0xfd, 0x2f, 0x58, 0x0b, 0xaf, 0x1d,
|
||||
0x25, 0xf3, 0x2b, 0xcc, 0x33, 0xfd, 0xc9, 0xf8, 0xb3, 0xec, 0x6b, 0x57, 0xc9, 0x32, 0x7d, 0x68, 0xcf, 0x2b, 0xf9, 0x27,
|
||||
0x6e, 0x7c, 0x75, 0xfe, 0xdf, 0xf3, 0x54, 0xa0, 0x6f, 0xd5, 0x7f, 0x24, 0xd7, 0xb7, 0xee, 0xa8, 0xff, 0xb5, 0x57, 0x06,
|
||||
0xd6, 0x5f, 0xcb, 0xbf, 0x79, 0xfe, 0xbf, 0xa2, 0xcf, 0xfb, 0x76, 0xfd, 0x7f, 0x61, 0x0e, 0xbd, 0xe6, 0x5b, 0x28, 0xe7,
|
||||
0xea, 0x7f, 0x6e, 0xdc, 0x56, 0xff, 0x2b, 0x56, 0x8c, 0xf3, 0x9f, 0x7a, 0xc5, 0xf9, 0x7f, 0xef, 0x4c, 0xe3, 0xe7, 0xd7,
|
||||
0x7f, 0x7d, 0xd2, 0xf9, 0x9a, 0xf3, 0xcd, 0x76, 0xe9, 0x77, 0x61, 0xee, 0xfa, 0x4e, 0xf2, 0x9e, 0x16, 0xb3, 0x66, 0xed,
|
||||
0x23, 0xf3, 0x94, 0xde, 0xda, 0xa7, 0x39, 0xc5, 0xa2, 0x4a, 0xcf, 0x5d, 0xe5, 0xdd, 0x73, 0xfd, 0x7f, 0xef, 0x37, 0x8a,
|
||||
0xaa, 0xb7, 0x50, 0xfd, 0x7f, 0xa3, 0x0f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xdb,
|
||||
0xee, 0xd0, 0xdb, 0x9b, 0xa8, 0x5f, 0x9f, 0x82, 0x71, 0x7b, 0xa2, 0xfe, 0xdb, 0x5d, 0x33, 0xed, 0xda, 0x44, 0xfd, 0xd6,
|
||||
0x95, 0x4c, 0xf4, 0xbd, 0x44, 0xfd, 0xdf, 0x78, 0xc7, 0xc7, 0x6d, 0x89, 0xfa, 0x75, 0x77, 0x4e, 0xdf, 0x9e, 0xa8, 0xdf,
|
||||
0x5e, 0xf2, 0x87, 0x6e, 0x4e, 0xd4, 0xcf, 0xdf, 0x3b, 0x75, 0x6b, 0xa2, 0x3e, 0x6b, 0xef, 0x98, 0xec, 0xed, 0xfb, 0xe3,
|
||||
0xe0, 0x31, 0x5b, 0x75, 0x77, 0x69, 0x7c, 0xf4, 0xce, 0xcf, 0xf1, 0x8c, 0xa6, 0x15, 0x3d, 0x4a, 0xe5, 0x5d, 0x9a, 0xeb,
|
||||
0x13, 0xf5, 0x7f, 0x4a, 0xbd, 0xee, 0x4a, 0xd4, 0x7f, 0xcf, 0x19, 0x8b, 0x4d, 0xdb, 0x1f, 0x43, 0xf3, 0xc6, 0xb5, 0x89,
|
||||
0x5a, 0xcf, 0xfd, 0xe8, 0xbd, 0xcf, 0x47, 0xf8, 0x76, 0xa2, 0xf6, 0x6f, 0xab, 0xff, 0x55, 0xfb, 0x29, 0x8a, 0xaa, 0xae,
|
||||
0xf7, 0x95, 0x7d, 0x59, 0x41, 0x75, 0xf5, 0x1f, 0xe5, 0xaf, 0xed, 0x4d, 0xd4, 0xca, 0xae, 0x27, 0xa8, 0xff, 0xef, 0xac,
|
||||
0x01, 0xe4, 0xd6, 0xad, 0xe6, 0x12, 0x75, 0x4f, 0xb6, 0x80, 0x9d, 0x89, 0x5a, 0x5f, 0xaf, 0xff, 0xcc, 0xac, 0x5c, 0xfd,
|
||||
0xdf, 0x39, 0xff, 0x8f, 0xb2, 0x57, 0x32, 0xbd, 0x46, 0x7e, 0xfd, 0xff, 0xcb, 0x4f, 0xd4, 0xfa, 0x99, 0xf5, 0x7f, 0x47,
|
||||
0xa2, 0xae, 0xfa, 0x3f, 0x33, 0xff, 0x5f, 0xf7, 0x54, 0x82, 0x9d, 0x89, 0xba, 0xc6, 0xff, 0x55, 0x15, 0x71, 0x77, 0x95,
|
||||
0xdf, 0x95, 0x9b, 0xfb, 0xcd, 0xf3, 0xff, 0xdc, 0x93, 0x40, 0xb3, 0x3d, 0xc0, 0xbe, 0x84, 0xd6, 0x13, 0x89, 0xfa, 0x12,
|
||||
0x75, 0x67, 0x8e, 0xd7, 0xf3, 0xec, 0xef, 0x9b, 0xd7, 0x63, 0x6e, 0x9f, 0xff, 0xd7, 0x5e, 0xab, 0xf9, 0xe7, 0x9a, 0xd2,
|
||||
0xea, 0x15, 0xef, 0x55, 0xf3, 0xff, 0xda, 0x2b, 0x5b, 0x12, 0x75, 0xab, 0x8f, 0xda, 0x6f, 0x5f, 0xff, 0x3b, 0xdb, 0xd3,
|
||||
0xc0, 0xee, 0x79, 0xed, 0xf9, 0x9e, 0x10, 0xf8, 0xda, 0x37, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0xf9, 0xef, 0x3f, 0xfb, 0x01, 0xd4, 0x3f,
|
||||
0xf0, 0xeb, 0xea, 0xff, 0x3f };
|
||||
|
||||
// Font glyphs rectangles data (on atlas)
|
||||
static const Rectangle darkFontRecs[189] = {
|
||||
{ 4, 4, 4 , 16 },
|
||||
{ 16, 4, 1 , 9 },
|
||||
{ 25, 4, 3 , 3 },
|
||||
{ 36, 4, 6 , 9 },
|
||||
{ 50, 4, 5 , 13 },
|
||||
{ 63, 4, 7 , 9 },
|
||||
{ 78, 4, 5 , 9 },
|
||||
{ 91, 4, 1 , 3 },
|
||||
{ 100, 4, 3 , 9 },
|
||||
{ 111, 4, 3 , 9 },
|
||||
{ 122, 4, 5 , 5 },
|
||||
{ 135, 4, 5 , 5 },
|
||||
{ 148, 4, 2 , 3 },
|
||||
{ 158, 4, 4 , 1 },
|
||||
{ 170, 4, 1 , 1 },
|
||||
{ 179, 4, 3 , 9 },
|
||||
{ 190, 4, 5 , 9 },
|
||||
{ 203, 4, 3 , 9 },
|
||||
{ 214, 4, 5 , 9 },
|
||||
{ 227, 4, 5 , 9 },
|
||||
{ 240, 4, 5 , 9 },
|
||||
{ 253, 4, 5 , 9 },
|
||||
{ 266, 4, 5 , 9 },
|
||||
{ 279, 4, 5 , 9 },
|
||||
{ 292, 4, 5 , 9 },
|
||||
{ 305, 4, 5 , 9 },
|
||||
{ 318, 4, 1 , 7 },
|
||||
{ 327, 4, 2 , 9 },
|
||||
{ 337, 4, 3 , 5 },
|
||||
{ 348, 4, 4 , 3 },
|
||||
{ 360, 4, 3 , 5 },
|
||||
{ 371, 4, 5 , 9 },
|
||||
{ 384, 4, 7 , 9 },
|
||||
{ 399, 4, 5 , 9 },
|
||||
{ 412, 4, 5 , 9 },
|
||||
{ 425, 4, 5 , 9 },
|
||||
{ 438, 4, 5 , 9 },
|
||||
{ 451, 4, 5 , 9 },
|
||||
{ 464, 4, 5 , 9 },
|
||||
{ 477, 4, 5 , 9 },
|
||||
{ 490, 4, 5 , 9 },
|
||||
{ 4, 28, 1 , 9 },
|
||||
{ 13, 28, 5 , 9 },
|
||||
{ 26, 28, 5 , 9 },
|
||||
{ 39, 28, 5 , 9 },
|
||||
{ 52, 28, 7 , 9 },
|
||||
{ 67, 28, 5 , 9 },
|
||||
{ 80, 28, 5 , 9 },
|
||||
{ 93, 28, 5 , 9 },
|
||||
{ 106, 28, 5 , 9 },
|
||||
{ 119, 28, 5 , 9 },
|
||||
{ 132, 28, 5 , 9 },
|
||||
{ 145, 28, 5 , 9 },
|
||||
{ 158, 28, 5 , 9 },
|
||||
{ 171, 28, 5 , 9 },
|
||||
{ 184, 28, 7 , 9 },
|
||||
{ 199, 28, 5 , 9 },
|
||||
{ 212, 28, 5 , 9 },
|
||||
{ 225, 28, 5 , 9 },
|
||||
{ 238, 28, 3 , 9 },
|
||||
{ 249, 28, 3 , 9 },
|
||||
{ 260, 28, 3 , 9 },
|
||||
{ 271, 28, 5 , 3 },
|
||||
{ 284, 28, 5 , 1 },
|
||||
{ 297, 28, 2 , 2 },
|
||||
{ 307, 28, 5 , 7 },
|
||||
{ 320, 28, 5 , 9 },
|
||||
{ 333, 28, 5 , 7 },
|
||||
{ 346, 28, 5 , 9 },
|
||||
{ 359, 28, 5 , 7 },
|
||||
{ 372, 28, 4 , 9 },
|
||||
{ 384, 28, 5 , 9 },
|
||||
{ 397, 28, 5 , 9 },
|
||||
{ 410, 28, 1 , 9 },
|
||||
{ 419, 28, 5 , 11 },
|
||||
{ 432, 28, 5 , 9 },
|
||||
{ 445, 28, 2 , 9 },
|
||||
{ 455, 28, 7 , 7 },
|
||||
{ 470, 28, 5 , 7 },
|
||||
{ 483, 28, 5 , 7 },
|
||||
{ 496, 28, 5 , 9 },
|
||||
{ 4, 52, 5 , 9 },
|
||||
{ 17, 52, 5 , 7 },
|
||||
{ 30, 52, 5 , 7 },
|
||||
{ 43, 52, 4 , 8 },
|
||||
{ 55, 52, 5 , 7 },
|
||||
{ 68, 52, 5 , 7 },
|
||||
{ 81, 52, 7 , 7 },
|
||||
{ 96, 52, 5 , 7 },
|
||||
{ 109, 52, 5 , 9 },
|
||||
{ 122, 52, 5 , 7 },
|
||||
{ 135, 52, 4 , 9 },
|
||||
{ 147, 52, 1 , 9 },
|
||||
{ 156, 52, 4 , 9 },
|
||||
{ 168, 52, 6 , 2 },
|
||||
{ 182, 52, 1 , 9 },
|
||||
{ 191, 52, 5 , 11 },
|
||||
{ 204, 52, 6 , 9 },
|
||||
{ 218, 52, 6 , 9 },
|
||||
{ 232, 52, 5 , 9 },
|
||||
{ 245, 52, 5 , 12 },
|
||||
{ 258, 52, 5 , 9 },
|
||||
{ 271, 52, 5 , 10 },
|
||||
{ 284, 52, 7 , 9 },
|
||||
{ 299, 52, 5 , 9 },
|
||||
{ 312, 52, 6 , 5 },
|
||||
{ 326, 52, 5 , 3 },
|
||||
{ 339, 52, 7 , 9 },
|
||||
{ 354, 52, 5 , 9 },
|
||||
{ 367, 52, 4 , 4 },
|
||||
{ 379, 52, 5 , 7 },
|
||||
{ 392, 52, 5 , 9 },
|
||||
{ 405, 52, 5 , 9 },
|
||||
{ 418, 52, 5 , 12 },
|
||||
{ 431, 52, 5 , 9 },
|
||||
{ 444, 52, 7 , 9 },
|
||||
{ 459, 52, 1 , 1 },
|
||||
{ 468, 52, 5 , 10 },
|
||||
{ 481, 52, 5 , 9 },
|
||||
{ 494, 52, 5 , 9 },
|
||||
{ 4, 76, 6 , 5 },
|
||||
{ 18, 76, 9 , 9 },
|
||||
{ 35, 76, 9 , 7 },
|
||||
{ 52, 76, 5 , 11 },
|
||||
{ 65, 76, 5 , 9 },
|
||||
{ 78, 76, 5 , 12 },
|
||||
{ 91, 76, 5 , 12 },
|
||||
{ 104, 76, 5 , 12 },
|
||||
{ 117, 76, 6 , 12 },
|
||||
{ 131, 76, 5 , 11 },
|
||||
{ 144, 76, 5 , 13 },
|
||||
{ 157, 76, 9 , 9 },
|
||||
{ 174, 76, 5 , 12 },
|
||||
{ 187, 76, 5 , 12 },
|
||||
{ 200, 76, 5 , 12 },
|
||||
{ 213, 76, 5 , 12 },
|
||||
{ 226, 76, 5 , 11 },
|
||||
{ 239, 76, 2 , 12 },
|
||||
{ 249, 76, 2 , 12 },
|
||||
{ 259, 76, 3 , 12 },
|
||||
{ 270, 76, 3 , 11 },
|
||||
{ 281, 76, 6 , 9 },
|
||||
{ 295, 76, 6 , 12 },
|
||||
{ 309, 76, 5 , 12 },
|
||||
{ 322, 76, 5 , 12 },
|
||||
{ 335, 76, 5 , 12 },
|
||||
{ 348, 76, 6 , 12 },
|
||||
{ 362, 76, 5 , 11 },
|
||||
{ 375, 76, 5 , 5 },
|
||||
{ 388, 76, 7 , 9 },
|
||||
{ 403, 76, 5 , 12 },
|
||||
{ 416, 76, 5 , 12 },
|
||||
{ 429, 76, 5 , 12 },
|
||||
{ 442, 76, 5 , 11 },
|
||||
{ 455, 76, 5 , 12 },
|
||||
{ 468, 76, 5 , 9 },
|
||||
{ 481, 76, 5 , 9 },
|
||||
{ 494, 76, 5 , 10 },
|
||||
{ 4, 100, 5 , 10 },
|
||||
{ 17, 100, 5 , 10 },
|
||||
{ 30, 100, 6 , 10 },
|
||||
{ 44, 100, 5 , 9 },
|
||||
{ 57, 100, 5 , 11 },
|
||||
{ 70, 100, 9 , 7 },
|
||||
{ 87, 100, 5 , 10 },
|
||||
{ 100, 100, 5 , 10 },
|
||||
{ 113, 100, 5 , 10 },
|
||||
{ 126, 100, 5 , 10 },
|
||||
{ 139, 100, 5 , 9 },
|
||||
{ 152, 100, 2 , 10 },
|
||||
{ 162, 100, 2 , 10 },
|
||||
{ 172, 100, 3 , 10 },
|
||||
{ 183, 100, 3 , 9 },
|
||||
{ 194, 100, 6 , 9 },
|
||||
{ 208, 100, 6 , 10 },
|
||||
{ 222, 100, 5 , 10 },
|
||||
{ 235, 100, 5 , 10 },
|
||||
{ 248, 100, 5 , 10 },
|
||||
{ 261, 100, 6 , 10 },
|
||||
{ 275, 100, 5 , 9 },
|
||||
{ 288, 100, 5 , 5 },
|
||||
{ 301, 100, 7 , 7 },
|
||||
{ 316, 100, 5 , 10 },
|
||||
{ 329, 100, 5 , 10 },
|
||||
{ 342, 100, 5 , 10 },
|
||||
{ 355, 100, 5 , 9 },
|
||||
{ 368, 100, 5 , 12 },
|
||||
{ 381, 100, 5 , 11 },
|
||||
{ 394, 100, 5 , 11 },
|
||||
};
|
||||
|
||||
// Font glyphs info data
|
||||
// NOTE: No glyphs.image data provided
|
||||
static const GlyphInfo darkFontGlyphs[189] = {
|
||||
{ 32, 0, 13, 4, { 0 }},
|
||||
{ 33, 2, 4, 5, { 0 }},
|
||||
{ 34, 2, 4, 7, { 0 }},
|
||||
{ 35, 1, 4, 8, { 0 }},
|
||||
{ 36, 1, 2, 7, { 0 }},
|
||||
{ 37, 1, 4, 9, { 0 }},
|
||||
{ 38, 1, 4, 7, { 0 }},
|
||||
{ 39, 2, 4, 5, { 0 }},
|
||||
{ 40, 3, 4, 7, { 0 }},
|
||||
{ 41, 1, 4, 7, { 0 }},
|
||||
{ 42, 1, 4, 7, { 0 }},
|
||||
{ 43, 1, 6, 7, { 0 }},
|
||||
{ 44, 1, 12, 5, { 0 }},
|
||||
{ 45, 1, 8, 6, { 0 }},
|
||||
{ 46, 2, 12, 5, { 0 }},
|
||||
{ 47, 1, 4, 5, { 0 }},
|
||||
{ 48, 1, 4, 7, { 0 }},
|
||||
{ 49, 2, 4, 7, { 0 }},
|
||||
{ 50, 1, 4, 7, { 0 }},
|
||||
{ 51, 1, 4, 7, { 0 }},
|
||||
{ 52, 1, 4, 7, { 0 }},
|
||||
{ 53, 1, 4, 7, { 0 }},
|
||||
{ 54, 1, 4, 7, { 0 }},
|
||||
{ 55, 1, 4, 7, { 0 }},
|
||||
{ 56, 1, 4, 7, { 0 }},
|
||||
{ 57, 1, 4, 7, { 0 }},
|
||||
{ 58, 2, 6, 5, { 0 }},
|
||||
{ 59, 1, 6, 5, { 0 }},
|
||||
{ 60, 1, 6, 5, { 0 }},
|
||||
{ 61, 1, 7, 6, { 0 }},
|
||||
{ 62, 1, 6, 5, { 0 }},
|
||||
{ 63, 1, 4, 7, { 0 }},
|
||||
{ 64, 1, 4, 9, { 0 }},
|
||||
{ 65, 1, 4, 7, { 0 }},
|
||||
{ 66, 1, 4, 7, { 0 }},
|
||||
{ 67, 1, 4, 7, { 0 }},
|
||||
{ 68, 1, 4, 7, { 0 }},
|
||||
{ 69, 1, 4, 7, { 0 }},
|
||||
{ 70, 1, 4, 7, { 0 }},
|
||||
{ 71, 1, 4, 7, { 0 }},
|
||||
{ 72, 1, 4, 7, { 0 }},
|
||||
{ 73, 2, 4, 5, { 0 }},
|
||||
{ 74, 1, 4, 7, { 0 }},
|
||||
{ 75, 1, 4, 7, { 0 }},
|
||||
{ 76, 1, 4, 7, { 0 }},
|
||||
{ 77, 1, 4, 9, { 0 }},
|
||||
{ 78, 1, 4, 7, { 0 }},
|
||||
{ 79, 1, 4, 7, { 0 }},
|
||||
{ 80, 1, 4, 7, { 0 }},
|
||||
{ 81, 1, 4, 7, { 0 }},
|
||||
{ 82, 1, 4, 7, { 0 }},
|
||||
{ 83, 1, 4, 7, { 0 }},
|
||||
{ 84, 1, 4, 7, { 0 }},
|
||||
{ 85, 1, 4, 7, { 0 }},
|
||||
{ 86, 1, 4, 7, { 0 }},
|
||||
{ 87, 1, 4, 9, { 0 }},
|
||||
{ 88, 1, 4, 7, { 0 }},
|
||||
{ 89, 1, 4, 7, { 0 }},
|
||||
{ 90, 1, 4, 7, { 0 }},
|
||||
{ 91, 3, 4, 7, { 0 }},
|
||||
{ 92, 1, 4, 5, { 0 }},
|
||||
{ 93, 1, 4, 7, { 0 }},
|
||||
{ 94, 1, 4, 7, { 0 }},
|
||||
{ 95, 0, 14, 5, { 0 }},
|
||||
{ 96, 1, 4, 5, { 0 }},
|
||||
{ 97, 1, 6, 7, { 0 }},
|
||||
{ 98, 1, 4, 7, { 0 }},
|
||||
{ 99, 1, 6, 7, { 0 }},
|
||||
{ 100, 1, 4, 7, { 0 }},
|
||||
{ 101, 1, 6, 7, { 0 }},
|
||||
{ 102, 1, 4, 6, { 0 }},
|
||||
{ 103, 1, 6, 7, { 0 }},
|
||||
{ 104, 1, 4, 7, { 0 }},
|
||||
{ 105, 2, 4, 5, { 0 }},
|
||||
{ 106, 1, 4, 7, { 0 }},
|
||||
{ 107, 1, 4, 7, { 0 }},
|
||||
{ 108, 2, 4, 5, { 0 }},
|
||||
{ 109, 1, 6, 9, { 0 }},
|
||||
{ 110, 1, 6, 7, { 0 }},
|
||||
{ 111, 1, 6, 7, { 0 }},
|
||||
{ 112, 1, 6, 7, { 0 }},
|
||||
{ 113, 1, 6, 7, { 0 }},
|
||||
{ 114, 1, 6, 7, { 0 }},
|
||||
{ 115, 1, 6, 7, { 0 }},
|
||||
{ 116, 1, 5, 6, { 0 }},
|
||||
{ 117, 1, 6, 7, { 0 }},
|
||||
{ 118, 1, 6, 7, { 0 }},
|
||||
{ 119, 1, 6, 9, { 0 }},
|
||||
{ 120, 1, 6, 7, { 0 }},
|
||||
{ 121, 1, 6, 7, { 0 }},
|
||||
{ 122, 1, 6, 7, { 0 }},
|
||||
{ 123, 2, 4, 7, { 0 }},
|
||||
{ 124, 2, 4, 5, { 0 }},
|
||||
{ 125, 1, 4, 7, { 0 }},
|
||||
{ 126, 1, 4, 8, { 0 }},
|
||||
{ 161, 2, 6, 5, { 0 }},
|
||||
{ 162, 1, 4, 7, { 0 }},
|
||||
{ 163, 1, 4, 8, { 0 }},
|
||||
{ 8364, 1, 4, 8, { 0 }},
|
||||
{ 165, 1, 4, 7, { 0 }},
|
||||
{ 352, 1, 1, 7, { 0 }},
|
||||
{ 167, 2, 4, 9, { 0 }},
|
||||
{ 353, 1, 3, 7, { 0 }},
|
||||
{ 169, 1, 4, 9, { 0 }},
|
||||
{ 170, 2, 4, 9, { 0 }},
|
||||
{ 171, 1, 6, 8, { 0 }},
|
||||
{ 172, 1, 8, 7, { 0 }},
|
||||
{ 174, 1, 4, 9, { 0 }},
|
||||
{ 175, 2, 4, 9, { 0 }},
|
||||
{ 176, 1, 4, 6, { 0 }},
|
||||
{ 177, 1, 6, 7, { 0 }},
|
||||
{ 178, 2, 4, 9, { 0 }},
|
||||
{ 179, 2, 4, 9, { 0 }},
|
||||
{ 381, 1, 1, 7, { 0 }},
|
||||
{ 181, 1, 6, 7, { 0 }},
|
||||
{ 182, 1, 4, 9, { 0 }},
|
||||
{ 183, 2, 8, 5, { 0 }},
|
||||
{ 382, 1, 3, 7, { 0 }},
|
||||
{ 185, 2, 4, 9, { 0 }},
|
||||
{ 186, 2, 4, 9, { 0 }},
|
||||
{ 187, 1, 6, 8, { 0 }},
|
||||
{ 338, 1, 4, 11, { 0 }},
|
||||
{ 339, 1, 6, 11, { 0 }},
|
||||
{ 376, 1, 2, 7, { 0 }},
|
||||
{ 191, 1, 6, 7, { 0 }},
|
||||
{ 192, 1, 1, 7, { 0 }},
|
||||
{ 193, 1, 1, 7, { 0 }},
|
||||
{ 194, 1, 1, 7, { 0 }},
|
||||
{ 195, 1, 1, 7, { 0 }},
|
||||
{ 196, 1, 2, 7, { 0 }},
|
||||
{ 197, 1, 0, 7, { 0 }},
|
||||
{ 198, 1, 4, 11, { 0 }},
|
||||
{ 199, 1, 4, 7, { 0 }},
|
||||
{ 200, 1, 1, 7, { 0 }},
|
||||
{ 201, 1, 1, 7, { 0 }},
|
||||
{ 202, 1, 1, 7, { 0 }},
|
||||
{ 203, 1, 2, 7, { 0 }},
|
||||
{ 204, 1, 1, 5, { 0 }},
|
||||
{ 205, 2, 1, 5, { 0 }},
|
||||
{ 206, 1, 1, 5, { 0 }},
|
||||
{ 207, 1, 2, 5, { 0 }},
|
||||
{ 208, 0, 4, 7, { 0 }},
|
||||
{ 209, 1, 1, 7, { 0 }},
|
||||
{ 210, 1, 1, 7, { 0 }},
|
||||
{ 211, 1, 1, 7, { 0 }},
|
||||
{ 212, 1, 1, 7, { 0 }},
|
||||
{ 213, 1, 1, 7, { 0 }},
|
||||
{ 214, 1, 2, 7, { 0 }},
|
||||
{ 215, 1, 6, 7, { 0 }},
|
||||
{ 216, 0, 4, 7, { 0 }},
|
||||
{ 217, 1, 1, 7, { 0 }},
|
||||
{ 218, 1, 1, 7, { 0 }},
|
||||
{ 219, 1, 1, 7, { 0 }},
|
||||
{ 220, 1, 2, 7, { 0 }},
|
||||
{ 221, 1, 1, 7, { 0 }},
|
||||
{ 222, 1, 4, 7, { 0 }},
|
||||
{ 223, 1, 4, 7, { 0 }},
|
||||
{ 224, 1, 3, 7, { 0 }},
|
||||
{ 225, 1, 3, 7, { 0 }},
|
||||
{ 226, 1, 3, 7, { 0 }},
|
||||
{ 227, 1, 3, 7, { 0 }},
|
||||
{ 228, 1, 4, 7, { 0 }},
|
||||
{ 229, 1, 2, 7, { 0 }},
|
||||
{ 230, 1, 6, 11, { 0 }},
|
||||
{ 231, 1, 6, 7, { 0 }},
|
||||
{ 232, 1, 3, 7, { 0 }},
|
||||
{ 233, 1, 3, 7, { 0 }},
|
||||
{ 234, 1, 3, 7, { 0 }},
|
||||
{ 235, 1, 4, 7, { 0 }},
|
||||
{ 236, 1, 3, 5, { 0 }},
|
||||
{ 237, 2, 3, 5, { 0 }},
|
||||
{ 238, 1, 3, 5, { 0 }},
|
||||
{ 239, 1, 4, 5, { 0 }},
|
||||
{ 240, 1, 4, 7, { 0 }},
|
||||
{ 241, 1, 3, 7, { 0 }},
|
||||
{ 242, 1, 3, 7, { 0 }},
|
||||
{ 243, 1, 3, 7, { 0 }},
|
||||
{ 244, 1, 3, 7, { 0 }},
|
||||
{ 245, 1, 3, 7, { 0 }},
|
||||
{ 246, 1, 4, 7, { 0 }},
|
||||
{ 247, 1, 6, 7, { 0 }},
|
||||
{ 248, 0, 6, 7, { 0 }},
|
||||
{ 249, 1, 3, 7, { 0 }},
|
||||
{ 250, 1, 3, 7, { 0 }},
|
||||
{ 251, 1, 3, 7, { 0 }},
|
||||
{ 252, 1, 4, 7, { 0 }},
|
||||
{ 253, 1, 3, 7, { 0 }},
|
||||
{ 254, 1, 4, 7, { 0 }},
|
||||
{ 255, 1, 4, 7, { 0 }},
|
||||
};
|
||||
|
||||
// Style loading function: Dark
|
||||
static void GuiLoadStyleDark(void)
|
||||
{
|
||||
// Load style properties provided
|
||||
// NOTE: Default properties are propagated
|
||||
for (int i = 0; i < DARK_STYLE_PROPS_COUNT; i++)
|
||||
{
|
||||
GuiSetStyle(darkStyleProps[i].controlId, darkStyleProps[i].propertyId, darkStyleProps[i].propertyValue);
|
||||
}
|
||||
|
||||
// Custom font loading
|
||||
// NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function
|
||||
int darkFontDataSize = 0;
|
||||
unsigned char *data = DecompressData(darkFontData, DARK_STYLE_FONT_ATLAS_COMP_SIZE, &darkFontDataSize);
|
||||
Image imFont = { data, 512, 256, 1, 2 };
|
||||
|
||||
Font font = { 0 };
|
||||
font.baseSize = 16;
|
||||
font.glyphCount = 189;
|
||||
|
||||
// Load texture from image
|
||||
font.texture = LoadTextureFromImage(imFont);
|
||||
UnloadImage(imFont); // Uncompressed image data can be unloaded from memory
|
||||
|
||||
// Copy char recs data from global fontRecs
|
||||
// NOTE: Required to avoid issues if trying to free font
|
||||
font.recs = (Rectangle *)RAYGUI_MALLOC(font.glyphCount*sizeof(Rectangle));
|
||||
memcpy(font.recs, darkFontRecs, font.glyphCount*sizeof(Rectangle));
|
||||
|
||||
// Copy font char info data from global fontChars
|
||||
// NOTE: Required to avoid issues if trying to free font
|
||||
font.glyphs = (GlyphInfo *)RAYGUI_MALLOC(font.glyphCount*sizeof(GlyphInfo));
|
||||
memcpy(font.glyphs, darkFontGlyphs, font.glyphCount*sizeof(GlyphInfo));
|
||||
|
||||
GuiSetFont(font);
|
||||
|
||||
// Setup a white rectangle on the font to be used on shapes drawing,
|
||||
// it makes possible to draw shapes and text (full UI) in a single draw call
|
||||
Rectangle fontWhiteRec = { 510, 254, 1, 1 };
|
||||
SetShapesTexture(font.texture, fontWhiteRec);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
// TODO: Custom user style setup: Set specific properties here (if required)
|
||||
// i.e. Controls specific BORDER_WIDTH, TEXT_PADDING, TEXT_ALIGNMENT
|
||||
}
|
11
includes/raygui_helpers.hpp
Normal file
11
includes/raygui_helpers.hpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef _RAYGUI_HELPERS_HPP
|
||||
#define _RAYGUI_HELPERS_HPP
|
||||
#include <string>
|
||||
|
||||
/* Display the given text, centered on the screen, as a label.
|
||||
NEEDS RAYGUI LIBRARY. */
|
||||
void display_text_raygui(std::string to_disp);
|
||||
|
||||
/* Display the given string, and exit the game after 'time' seconds. */
|
||||
void display_and_exit_raygui(std::string to_disp, int time);
|
||||
#endif
|
@@ -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();
|
||||
|
@@ -1,8 +0,0 @@
|
||||
#ifndef _MATH_HELP
|
||||
#define _MATH_HELP
|
||||
int signum(int num) {
|
||||
int retval = 0;
|
||||
(num > 0) ? retval = 1 : retval = -1;
|
||||
return retval;
|
||||
}
|
||||
#endif
|
@@ -2,7 +2,7 @@
|
||||
#define _SOCK_CLASS
|
||||
|
||||
#include <string>
|
||||
#ifdef __unix__
|
||||
#if defined(__unix__) || defined(__unix) ||(defined(__APPLE__) && defined(__MACH__))
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
@@ -23,7 +23,7 @@ protected:
|
||||
int port;
|
||||
int sock_fd;
|
||||
std::string address;
|
||||
struct sockaddr* dest;
|
||||
struct sockaddr_storage* dest;
|
||||
socklen_t addrlen;
|
||||
int other_socket; // The peer socket (the client if this socket is a server, and the server if this socket is a client) */
|
||||
|
||||
@@ -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);
|
||||
@@ -49,7 +49,8 @@ public:
|
||||
/* Method to receive data sent to the 'other_socket' socket */
|
||||
char* recvAll();
|
||||
|
||||
/* Non-blocking receive method - calls the method above after polling for data */
|
||||
/* Non-blocking receive method - calls the method above after polling for data. Returns
|
||||
an empty string if there is nothing to read. */
|
||||
char* recvAllNB();
|
||||
|
||||
/* Returns socket identifier */
|
||||
|
30
includes/timer.h
Normal file
30
includes/timer.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifndef _TIMER_H
|
||||
#define _TIMER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* This file defines a simple timer Types, and declares functions to initialize it,
|
||||
and keep track of time elapsed. The actual definition of the Timer struct is in timer.c
|
||||
It was copied from https://github.com/raysan5/raylib/wiki/Frequently-Asked-Questions#how-do-i-make-a-timer */
|
||||
|
||||
typedef struct Timer_s {
|
||||
double start_time; // Start time (seconds)
|
||||
double lifetime; // Lifetime (seconds)
|
||||
} Timer;
|
||||
|
||||
/* Starts a timer for given number of seconds */
|
||||
Timer timer_init(double lifetime_secs);
|
||||
|
||||
/* Returns true when timer finishes, false if not */
|
||||
bool timer_done(Timer timer);
|
||||
|
||||
/* Returns amount of time elapsed since start of timer */
|
||||
double timer_get_elapsed(Timer timer);
|
||||
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
376
main.cpp
376
main.cpp
@@ -14,20 +14,28 @@
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <cerrno>
|
||||
#include <sstream>
|
||||
#include "includes/raylib-cpp/raylib-cpp.hpp"
|
||||
|
||||
#define RAYGUI_IMPLEMENTATION
|
||||
#include "includes/raygui/raygui.h"
|
||||
#include "includes/raygui/style_dark.h"
|
||||
#include "includes/paddle.hpp"
|
||||
#include "includes/ball.hpp"
|
||||
#include "includes/easysock.hpp"
|
||||
#include "includes/sign.hpp"
|
||||
#include "includes/connect_code.hpp"
|
||||
#include "includes/client.hpp"
|
||||
#include "includes/server.hpp"
|
||||
#include "includes/exception_consts.hpp"
|
||||
#include "includes/check_input.hpp"
|
||||
#include "includes/display_text.hpp"
|
||||
#include "includes/easysock.h"
|
||||
#include "includes/serialization.h"
|
||||
#include "includes/timer.h"
|
||||
|
||||
/* Global variables used to instantiate structs */
|
||||
const int WIDTH = 1500;
|
||||
@@ -38,21 +46,33 @@ const int PADDLE_SPEED = 8;
|
||||
const int CIRC_RAD = 10;
|
||||
const float BASE_BOUNCE_DEG = 45;
|
||||
const float BASE_BOUNCE_RAD = (BASE_BOUNCE_DEG / 180.0) * M_PI;
|
||||
const float BASE_SPEED_COMPONENTS = 18;
|
||||
const float BASE_SPEED_COMPONENTS = 15;
|
||||
const float BASE_SPEED = sqrt(powf(BASE_SPEED_COMPONENTS, 2) * 2);
|
||||
|
||||
typedef enum {M_SINGLE, M_CLIENT, M_SERVER} Mode;
|
||||
std::string HELP_TEXT = "\nnetpong - A networked pong game for the internet era.\n"
|
||||
"\n"
|
||||
"Usage: \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 and port must be specified.\n"
|
||||
"\n"
|
||||
"-C: Client mode. Connects to a server, using the provided connection code.\n"
|
||||
"\n"
|
||||
"If no mode is specified, single player mode is used as default.\n"
|
||||
"\n"
|
||||
"CONTROLS:"
|
||||
"\'W\' and \'S\' control left paddle (AKA client paddle)\n"
|
||||
"Up and Down arrow keys control right paddle (AKA server paddle)\n";
|
||||
|
||||
|
||||
/* This struct contains a Mode enum, which indicates the type of game we are
|
||||
playing (Single player, client mode or server mode). The netsock parameter is
|
||||
a 'Sock' object - Client and Server classes inherit from this object, so this
|
||||
parameter can be instantiated to either a client or server, depending on the
|
||||
game type. */
|
||||
|
||||
typedef struct {
|
||||
Mode mode;
|
||||
Sock* netsock;
|
||||
} GameType;
|
||||
/* Simple function to return 1 if a value is positive, and -1 if it is negative */
|
||||
int signum(int num) {
|
||||
int retval = 0;
|
||||
(num > 0) ? retval = 1 : retval = -1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
raylib::Vector2 changeVelocityAfterCollision(Paddle paddle, Ball ball) {
|
||||
float paddle_mid_y = (paddle.getRect().y + paddle.getRect().GetHeight()) / 2.0; /* Middle y value of rectangle */
|
||||
@@ -74,137 +94,68 @@ raylib::Vector2 changeVelocityAfterCollision(Paddle paddle, Ball ball) {
|
||||
return raylib::Vector2(new_x_vel, new_y_vel);
|
||||
}
|
||||
|
||||
/* This function checks the command-line arguments passed to the program.
|
||||
It then decides whether the game is in Server or Client mode (or neither), and
|
||||
instantiates the appropriate object. The (uninitialized) objects are passed to the
|
||||
function as pointers. It returns a GameType struct, that indicates whether the game
|
||||
is in server, client or single player mode, and contains the appropriate socket object. */
|
||||
|
||||
GameType check_server_client(int argc, char** argv) {
|
||||
std::string connect_code;
|
||||
std::vector<std::string> addr_port; /* Vector to store (IPv4) address and port */
|
||||
GameType type;
|
||||
|
||||
if (argc < 2) { /* Game was not started in client or server mode */
|
||||
type.mode = M_SINGLE;
|
||||
type.netsock = nullptr;
|
||||
return type;
|
||||
/* 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 > 4) {
|
||||
throw std::invalid_argument("ARGUMENT ERROR: Too many arguments. To view syntax, use -h or --help.");
|
||||
}
|
||||
|
||||
/* GAME STARTED IN CLIENT MODE */
|
||||
if (strcmp(argv[1],"-C") == 0) {
|
||||
if (argc < 3) { /* No address was provided */
|
||||
throw EXCEPT_TOOFEWARGS;
|
||||
}
|
||||
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]));
|
||||
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->recvAll();
|
||||
if (msg_from_server == "U2") {
|
||||
std::cout << "Connection made. Waiting for server to begin game..." << std::endl;
|
||||
} else {
|
||||
throw EXCEPT_WRONGRESPONSE;
|
||||
if (argc > 1) { // Either server or client mode
|
||||
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.");
|
||||
}
|
||||
type.mode = M_CLIENT;
|
||||
type.netsock = client;
|
||||
return type;
|
||||
} catch (int e) {
|
||||
throw;
|
||||
} catch (std::exception& e) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/* GAME STARTED IN SERVER MODE */
|
||||
else if (strcmp(argv[1],"-S") == 0) {
|
||||
std::string addr;
|
||||
uint16_t port;
|
||||
|
||||
/* No IP address or port specified */
|
||||
if (argc < 3) {
|
||||
throw EXCEPT_TOOFEWARGS;
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
/* IP address but no port */
|
||||
else if (argc < 4) {
|
||||
std::cout << "No port specified, using 6500..." << std::endl;
|
||||
addr = std::string(argv[2]);
|
||||
port = 6500;
|
||||
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 {
|
||||
addr = std::string(argv[2]);
|
||||
port = std::stoi(std::string(argv[3]));
|
||||
throw std::invalid_argument("Unrecognized argument.");
|
||||
}
|
||||
|
||||
/* Check if IP is valid */
|
||||
if (check_ip_ver(addr.data()) < 0) {
|
||||
throw EXCEPT_INVALIDIP;
|
||||
}
|
||||
|
||||
std::string code = connect_code::encode(addr, std::to_string(port));
|
||||
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->create_socket();
|
||||
std::cout << "Waiting for connection..." << std::endl;
|
||||
std::string response = "";
|
||||
char* temp_response = NULL;
|
||||
/* Wait for the right client to connect. Since recvAll returns a char*, we need to create a temporary variable to check for NULL. */
|
||||
do {
|
||||
temp_response = server->recvAll();
|
||||
} while (temp_response == NULL);
|
||||
response = std::string(temp_response);
|
||||
|
||||
std::cout << "Connection received from " << server->get_peer_addr() << std::endl;
|
||||
server->sendAll("U2");
|
||||
type.mode = M_SERVER;
|
||||
type.netsock = server;
|
||||
return type;
|
||||
}
|
||||
|
||||
else {
|
||||
throw EXCEPT_INVALIDARGS;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
/* 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 muilti-player mode, and
|
||||
/* 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) {
|
||||
std::cout << inv.what() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* From here on, we assume that:
|
||||
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. */
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
std::cout << inv.what() << std::endl;
|
||||
return -8;
|
||||
} catch (std::invalid_argument& inv) {
|
||||
std::cout << inv.what() << std::endl;
|
||||
return -1;
|
||||
} catch (int err) {
|
||||
std::cout << strerror(err) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize window and other variables */
|
||||
@@ -217,6 +168,154 @@ int main(int argc, char** argv) {
|
||||
bool game_started = false;
|
||||
srand(std::time(NULL));
|
||||
|
||||
/* If there were no command-line arguments, the user is prompted in the GUI */
|
||||
if (argc == 1) {
|
||||
/* Display a drop-down menu, to allow user to pick between Single player, server and client. This section of the code uses the raygui library, and is written in C. */
|
||||
|
||||
GuiLoadStyleDark(); // Load the dark theme style
|
||||
/* Modify the default style, by changing font size and spacing */
|
||||
int font_size = 25;
|
||||
int font_spacing = 2;
|
||||
GuiSetStyle(DEFAULT, TEXT_SIZE, font_size);
|
||||
GuiSetStyle(DEFAULT, TEXT_SPACING, font_spacing);
|
||||
|
||||
/* Set variables to position objects on screen */
|
||||
int selected_item = 0; // variable to hold the index of the selected item
|
||||
const char* text_to_display = "Select Game Mode"; // Text to display
|
||||
/* Size of the label, drop down box and button */
|
||||
Vector2 label_size = MeasureTextEx(GetFontDefault(), text_to_display, font_size, font_spacing); // Set the size based on the width of the string to print, the font size and the text spacing. I added 1 to font_size and font_spacing, to account for any possible rounding errors, since the function expects floats.
|
||||
Vector2 box_size = Vector2{label_size.x, HEIGHT / 20};
|
||||
bool is_being_edited = false; // Indicates whether the drop-down menu is being 'edited' i.e. whether an option is being selected
|
||||
bool button_pressed = false; // Indicates whether the submit button has been pressed
|
||||
|
||||
while (button_pressed == false) {
|
||||
if (WindowShouldClose()) {
|
||||
CloseWindow();
|
||||
return 0;
|
||||
}
|
||||
BeginDrawing();
|
||||
ClearBackground(BLACK);
|
||||
GuiLabel(Rectangle{(WIDTH/2)-(label_size.x/2), (HEIGHT/8), label_size.x, label_size.y}, text_to_display); // Label to display text on top
|
||||
|
||||
if (is_being_edited) {
|
||||
GuiLock(); // If the drop-down menu is being 'edited', we need to prevent the user from modifying any other aspect of the UI
|
||||
}
|
||||
|
||||
/* Button that allows user to proceed */
|
||||
button_pressed = GuiButton(Rectangle{(WIDTH/2)-(box_size.x/2), (HEIGHT/2) + (HEIGHT/8), box_size.x, box_size.y}, "Continue");
|
||||
|
||||
/* Drop-down menu, that allows user to select game mode */
|
||||
if (GuiDropdownBox(Rectangle{(WIDTH/2) - (box_size.x/2), (HEIGHT/2) - (HEIGHT/8), box_size.x, box_size.y}, "SINGLE;CLIENT;SERVER", &selected_item, is_being_edited)) { // This function returns != 0 if there was a mouse click inside the dropdown area
|
||||
is_being_edited = !is_being_edited; // If the dropdown menu was selected, then it is being edited (or not being edited, if it previously was).
|
||||
}
|
||||
|
||||
GuiUnlock();
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
/* Single player mode */
|
||||
if (selected_item == M_SINGLE) {
|
||||
GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // Enable text wrapping so that the long text, displayed below, will be wrapped
|
||||
BeginDrawing();
|
||||
ClearBackground(BLACK);
|
||||
GuiLabel(Rectangle{(WIDTH/2)-(WIDTH/8), (HEIGHT/2)-(HEIGHT/8), WIDTH/4, HEIGHT/4}, "W and S control left paddle, Up and Down arrow keys control right paddle. Good luck!");
|
||||
EndDrawing();
|
||||
Timer timer = timer_init(5);
|
||||
while (!timer_done(timer));
|
||||
}
|
||||
|
||||
/* Server mode, ask user to input IP address and port */
|
||||
if (selected_item == M_SERVER) {
|
||||
button_pressed = false; // Whether submit button is pressed
|
||||
char* ip_text = (char *)calloc(150, sizeof(char)); // Holds input of IP text box
|
||||
char* port_text = (char *)calloc(20, sizeof(char)); // Holds input of port text box
|
||||
const char* ip_label = "Local IP address";
|
||||
const char* port_label = "Port number (1024 - 65535)";
|
||||
int port_label_x_size = MeasureTextEx(GetFontDefault(), port_label, font_size, font_spacing).x; // Custom size for port label, because it's long
|
||||
bool editing_ip = false; // Indicates whether the IP address text box is being edited
|
||||
bool editing_port = false; // Indicates whether the port text box is being edited
|
||||
while (button_pressed == false || ((strlen(ip_text) == 0) || (strlen(port_text) == 0))) {
|
||||
if (WindowShouldClose()) {
|
||||
CloseWindow();
|
||||
return 0;
|
||||
}
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(BLACK);
|
||||
/* Label and text box for IP address */
|
||||
GuiLabel(Rectangle{(WIDTH/2)-(label_size.x/2), (HEIGHT/2) - (HEIGHT/6) - label_size.y - 10, label_size.x, label_size.y}, ip_label); // Label to display text on top
|
||||
/* The reason this if statement exists, is largely the same as the reasoning for the drop-down menu. We want to make the text box editable
|
||||
if it has been clicked. If it is already editable, we want to make it read-only if the user clicks outside the box. This functionality
|
||||
is mostly handled in the GuiTextBox function. If the text box is in edit mode, this function returns nonzero if the user clicks INSIDE
|
||||
the box. If the text box is in editable mode, this function returns nonzero if the user clicks OUTSIDE the box. */
|
||||
if (GuiTextBox(Rectangle{(WIDTH/2) - (box_size.x/2), (HEIGHT/2) - (HEIGHT/6), box_size.x, box_size.y}, ip_text, 100, editing_ip)) {
|
||||
editing_ip = !editing_ip;
|
||||
}
|
||||
|
||||
/* Label and text box for port. See above for explanation of if statement. */
|
||||
GuiLabel(Rectangle{(WIDTH/2)-(label_size.x/2), (HEIGHT/2) - label_size.y, port_label_x_size }, port_label); // Label to display text on top
|
||||
if (GuiTextBox(Rectangle{(WIDTH/2) - (box_size.x/2), (HEIGHT/2), box_size.x, box_size.y}, port_text, 100, editing_port)) {
|
||||
editing_port = !editing_port;
|
||||
}
|
||||
|
||||
button_pressed = GuiButton(Rectangle{(WIDTH/2) - (box_size.x/2), (HEIGHT/2) + (HEIGHT/6), box_size.x, box_size.y}, "Start Server");
|
||||
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
try {
|
||||
type = check_server(ip_text, port_text, IF_GUI);
|
||||
} catch (int e) {
|
||||
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_raygui(std::string(inv.what()) + "\nClosing game...", 2);
|
||||
free(ip_text);
|
||||
free(port_text);
|
||||
return -1;
|
||||
}
|
||||
free(ip_text);
|
||||
free(port_text);
|
||||
}
|
||||
|
||||
if (selected_item == M_CLIENT) {
|
||||
button_pressed = false; // Whether submit button is pressed
|
||||
char* code_text = (char *)calloc(150, sizeof(char)); // Holds the connect code
|
||||
const char* code_label = "Enter code:";
|
||||
bool editing_code = false; // Indicates whether the port text box is being edited
|
||||
while (button_pressed == false || ((strlen(code_text) == 0))) {
|
||||
if (WindowShouldClose()) {
|
||||
CloseWindow();
|
||||
return 0;
|
||||
}
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(BLACK);
|
||||
/* Label and text box for IP address */
|
||||
GuiLabel(Rectangle{(WIDTH/2)-(label_size.x/2), (HEIGHT/2) - (HEIGHT/6) - label_size.y - 10, label_size.x, label_size.y}, code_label);
|
||||
|
||||
if (GuiTextBox(Rectangle{(WIDTH/2) - (box_size.x/2), (HEIGHT/2) - (HEIGHT/6), box_size.x, box_size.y}, code_text, 100, editing_code)) {
|
||||
editing_code = !editing_code;
|
||||
}
|
||||
|
||||
button_pressed = GuiButton(Rectangle{(WIDTH/2) - (box_size.x/2), (HEIGHT/2) + (HEIGHT/6), box_size.x, box_size.y}, "Connect");
|
||||
EndDrawing();
|
||||
}
|
||||
try {
|
||||
type = check_client(code_text, IF_GUI);
|
||||
} catch (int e) {
|
||||
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_raygui(std::string(inv.what()) + "\nClosing game...", 2);
|
||||
return -1;
|
||||
}
|
||||
free(code_text);
|
||||
}
|
||||
}
|
||||
|
||||
/* Variable to store the response given by the other player */
|
||||
std::string response;
|
||||
Serial_Data response_data;
|
||||
@@ -233,6 +332,7 @@ int main(int argc, char** argv) {
|
||||
Ball ball = Ball(window.GetWidth()/2, window.GetHeight()/2, CIRC_RAD, BASE_SPEED, 0);
|
||||
|
||||
window.BeginDrawing();
|
||||
window.ClearBackground(BLACK);
|
||||
pad1.draw();
|
||||
pad2.draw();
|
||||
ball.draw();
|
||||
@@ -251,11 +351,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;
|
||||
}
|
||||
@@ -281,7 +388,6 @@ int main(int argc, char** argv) {
|
||||
uint8_t* response_array = (uint8_t *)(type.netsock->recvAll());
|
||||
if (response_array != NULL) {
|
||||
response_data = Serial_deserialize(response_array);
|
||||
std::cout << response_data.pad_x << "\t" << response_data.pad_y << "\t" << response_data.ball_x << "\t" << response_data.ball_y << std::endl;
|
||||
} else {
|
||||
/* If the response is NULL, that means it timed-out. In this case, there's no value to print */
|
||||
std::cout << "NOTHING RECEIVED" << std::endl;
|
||||
|
30
meson.build
30
meson.build
@@ -1,21 +1,25 @@
|
||||
project('Pong', ['cpp', 'c'], version: '0.1')
|
||||
add_global_arguments('-g', '-Wall', '-pedantic', '-Wno-unused-function', language : ['cpp', 'c'])
|
||||
add_global_arguments('-g', '-Wall', '-pedantic', '-Wno-unused-function', '-Wno-narrowing', language : ['cpp', 'c'])
|
||||
add_global_arguments('-std=c++11', language: ['cpp'])
|
||||
compiler = meson.get_compiler('cpp')
|
||||
cmake = import('cmake')
|
||||
|
||||
# if we are building a shared library
|
||||
if get_option('default_library') == 'shared'
|
||||
raylib = dependency('raylib', required: false) # Try to find dependency with pkg-config
|
||||
if not raylib.found()
|
||||
raylib = compiler.find_library('raylib', has_headers: ['raylib.h', 'raymath.h'], required: true) # Try to manually search for the dependency
|
||||
raylib = compiler.find_library('raylib', has_headers: ['raylib.h', 'raymath.h'], required: false) # Try to manually search for the dependency
|
||||
endif
|
||||
if not raylib.found()
|
||||
opt_var = cmake.subproject_options()
|
||||
opt_var.add_cmake_defines({'BUILD_SHARED_LIBS' : true})
|
||||
opt_var.add_cmake_defines({'CMAKE_SKIP_RPATH' : true})
|
||||
raylib_proj = cmake.subproject('raylib', options: opt_var)
|
||||
raylib = raylib_proj.dependency('raylib')
|
||||
endif
|
||||
# if not raylib.found()
|
||||
# opt_var = cmake.subproject_options()
|
||||
# opt_var.add_cmake_defines({'BUILD_SHARED_LIBS' : true})
|
||||
# opt_var.add_cmake_defines({'CMAKE_SKIP_RPATH' : true})
|
||||
# raylib_proj = cmake.subproject('raylib', options: opt_var)
|
||||
# raylib = raylib_proj.dependency('raylib')
|
||||
# endif
|
||||
endif
|
||||
|
||||
# I we are building a static library
|
||||
if get_option('default_library') == 'static'
|
||||
raylib_proj = cmake.subproject('raylib')
|
||||
raylib = raylib_proj.dependency('raylib')
|
||||
@@ -25,12 +29,12 @@ endif
|
||||
ws2_dep = compiler.find_library('ws2_32', required: false)
|
||||
winmm = compiler.find_library('winmm', required: false)
|
||||
if build_machine.system() == 'windows'
|
||||
add_global_arguments('-Wl,--subsystem,windows', '-mwindows', language: ['cpp', 'c']) # Prevent opening console when game is run
|
||||
add_project_arguments('-Wl,--subsystem,windows', '-mwindows', language: ['cpp', 'c']) # Prevent opening console when game is run
|
||||
|
||||
endif
|
||||
|
||||
executable('pong',
|
||||
'main.cpp', 'easysock.cpp', 'sock.cpp','paddle.cpp', 'ball.cpp', 'numeric_base.cpp', 'connect_code.cpp', 'server.cpp', 'client.cpp',
|
||||
'serialization.c',
|
||||
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', 'display_text.cpp',
|
||||
'serialization.c', 'timer.c', 'easysock.c',
|
||||
dependencies: [raylib, ws2_dep, winmm]
|
||||
)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
@@ -26,12 +27,17 @@ unsigned int to_decimal(std::string num, int from_base) {
|
||||
std::string from_decimal(unsigned int num, int to_base) {
|
||||
std::string return_val;
|
||||
int val = 0;
|
||||
while (num > 0) {
|
||||
val = num % to_base;
|
||||
return_val.push_back(possible_chars[val]);
|
||||
num /= to_base;
|
||||
/* Handle the special case of num being zero: In this case, the result is also zero */
|
||||
if (num == 0) {
|
||||
return_val = "0";
|
||||
} else {
|
||||
while (num > 0) {
|
||||
val = num % to_base;
|
||||
return_val.push_back(possible_chars[val]);
|
||||
num /= to_base;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Reverse the string, since we started from the right */
|
||||
std::reverse(return_val.begin(), return_val.end());
|
||||
|
||||
|
20
raygui_helpers.cpp
Normal file
20
raygui_helpers.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "includes/raygui_helpers.hpp"
|
||||
#include "includes/raygui/raygui.h"
|
||||
#include "includes/timer.h"
|
||||
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
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(BLACK);
|
||||
GuiLabel(Rectangle{(GetScreenWidth()/2) - (label_size.x/2), (GetScreenHeight()/2) - (label_size.y/2), label_size.x, label_size.y}, to_disp_cstr);
|
||||
EndDrawing();
|
||||
return;
|
||||
}
|
||||
|
||||
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,7 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#ifdef __unix__
|
||||
#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
|
26
server.cpp
26
server.cpp
@@ -1,4 +1,4 @@
|
||||
#ifdef __unix__
|
||||
#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
@@ -7,9 +7,8 @@
|
||||
#include <fcntl.h>
|
||||
#include "includes/sock.hpp"
|
||||
#include "includes/server.hpp"
|
||||
#include "includes/exception_consts.hpp"
|
||||
#include "includes/easysock.hpp"
|
||||
#include "includes/connect_code.hpp"
|
||||
#include "includes/easysock.h"
|
||||
|
||||
/* Destructor - closes any open sockets */
|
||||
Server::~Server() {
|
||||
@@ -44,11 +43,14 @@ char* Server::recvAll() {
|
||||
if (this->ip_ver == 4) {
|
||||
/* FOR IPv4 */
|
||||
struct sockaddr_in* temp_struct = (struct sockaddr_in*)this->dest;
|
||||
/* Convert the s_addr field of the caseted struct to host network-byte, and convert it to a dotted decimal */
|
||||
/* Convert the s_addr field of the casted struct to host network-byte, and convert it to a dotted decimal */
|
||||
peer_addr = connect_code::dec_to_dotted_dec(std::to_string(htonl(temp_struct->sin_addr.s_addr)));
|
||||
} else {
|
||||
/* FOR IPv6 */
|
||||
peer_addr = "IPV6 NOT SUPPORTED YET";
|
||||
/* FOR IPv6 - Use the inet_ntop function, and convert the struct's address into a string */
|
||||
struct sockaddr_in6* temp_struct = (struct sockaddr_in6*)this->dest;
|
||||
char* temp_buf = (char *)malloc(sizeof(char) * (INET6_ADDRSTRLEN + 1));
|
||||
peer_addr = std::string(inet_ntop(AF_INET6, temp_struct->sin6_addr.s6_addr, temp_buf, INET6_ADDRSTRLEN));
|
||||
free(temp_buf);
|
||||
}
|
||||
|
||||
return to_return;
|
||||
@@ -70,8 +72,11 @@ char* Server::recvAllNB() {
|
||||
/* Convert the s_addr field of the caseted struct to host network-byte, and convert it to a dotted decimal */
|
||||
peer_addr = connect_code::dec_to_dotted_dec(std::to_string(htonl(temp_struct->sin_addr.s_addr)));
|
||||
} else {
|
||||
/* FOR IPv6 */
|
||||
peer_addr = "IPV6 NOT SUPPORTED YET";
|
||||
/* FOR IPv6 - Use the inet_ntop function, and convert the struct's address into a string */
|
||||
struct sockaddr_in6* temp_struct = (struct sockaddr_in6*)this->dest;
|
||||
char* temp_buf = (char *)malloc(sizeof(char) * (INET6_ADDRSTRLEN + 1));
|
||||
peer_addr = std::string(inet_ntop(AF_INET6, temp_struct->sin6_addr.s6_addr, temp_buf, INET6_ADDRSTRLEN));
|
||||
free(temp_buf);
|
||||
}
|
||||
|
||||
return to_return;
|
||||
@@ -84,7 +89,7 @@ is thrown as an exception. */
|
||||
|
||||
void Server::wait_for_peer() {
|
||||
if (this->protocol == ES_TCP) {
|
||||
this->other_socket = accept(this->sock_fd, dest, &addrlen);
|
||||
this->other_socket = accept(this->sock_fd, (struct sockaddr *)dest, &addrlen);
|
||||
if (this->other_socket < 0) {
|
||||
throw errno;
|
||||
}
|
||||
@@ -96,8 +101,7 @@ called immediately after the constructor. If the socket is TCP, it also sets the
|
||||
socket to listen for incoming connections. This function throws an exception if
|
||||
the socket could not be created. The excpetion is an integer corresponding to the errno
|
||||
of the failing function, and enables the caller to print a corresponding error message by
|
||||
'catching' the thrown exception and using strerror().
|
||||
This function also sets a timeout of 100ms for UDP sockets */
|
||||
'catching' the thrown exception and using strerror().*/
|
||||
|
||||
void Server::create_socket() {
|
||||
Sock::create_socket();
|
||||
|
39
sock.cpp
39
sock.cpp
@@ -1,15 +1,14 @@
|
||||
#include <cerrno>
|
||||
#include <stdexcept>
|
||||
#include "includes/sock.hpp"
|
||||
#include "includes/exception_consts.hpp"
|
||||
#include "includes/easysock.hpp"
|
||||
#include "includes/easysock.h"
|
||||
|
||||
/* Function to create socket. This function doesn't actually create a socket
|
||||
(and isn't meant to be called directly). Instead, the client and server classes
|
||||
extend this function, and create the appropriate sockets. */
|
||||
|
||||
void Sock::create_socket() {
|
||||
dest = (struct sockaddr *)malloc(sizeof(struct sockaddr));
|
||||
dest = (struct sockaddr_storage *)malloc(sizeof(struct sockaddr_storage));
|
||||
addrlen = sizeof(*dest);
|
||||
}
|
||||
|
||||
@@ -18,11 +17,11 @@ 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) {
|
||||
/* Error checking */
|
||||
Sock::Sock(char protocol, const char* address, int port) {
|
||||
this->ip_ver = check_ip_ver(address);
|
||||
|
||||
if (ip_ver != 4 && ip_ver != 6) {
|
||||
throw std::invalid_argument("Invalid IP address type");
|
||||
}
|
||||
@@ -33,15 +32,9 @@ Sock::Sock(int ip_ver, char protocol, const char* address, int port) {
|
||||
throw std::invalid_argument("Invalid protocol");
|
||||
}
|
||||
|
||||
this->ip_ver = ip_ver;
|
||||
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
|
||||
@@ -55,7 +48,9 @@ void Sock::sendAll(std::string to_send) {
|
||||
|
||||
/* For UDP sockets */
|
||||
if (this->protocol == ES_UDP) {
|
||||
sendto(this->sock_fd, to_send.data(), str_length, 0, dest, addrlen);
|
||||
if (sendto(this->sock_fd, to_send.data(), str_length, 0, (struct sockaddr *)dest, addrlen) == -1) {
|
||||
throw errno;
|
||||
}
|
||||
}
|
||||
/* For TCP sockets */
|
||||
else {
|
||||
@@ -63,7 +58,7 @@ void Sock::sendAll(std::string to_send) {
|
||||
/* Send the data to the 'other_socket' variable, which should be set by the client and server methods */
|
||||
num_bytes_sent = send(this->other_socket, to_send.substr(total_bytes_sent).c_str(), str_length - total_bytes_sent, 0);
|
||||
if (num_bytes_sent < 0) {
|
||||
throw errno * -1;
|
||||
throw errno;
|
||||
}
|
||||
total_bytes_sent += num_bytes_sent;
|
||||
}
|
||||
@@ -86,14 +81,17 @@ This function also needs more testing for TCP. */
|
||||
char* Sock::recvAll() {
|
||||
int num_bytes_received = 0;
|
||||
int total_bytes_received = 0;
|
||||
char* buffer = (char *)malloc(100);
|
||||
char* buffer = (char *)malloc(150 * sizeof(char));
|
||||
bool has_been_read = false;
|
||||
|
||||
if (this->protocol == ES_UDP) {
|
||||
num_bytes_received = recvfrom(this->sock_fd, buffer, 99, 0, dest, &addrlen);
|
||||
num_bytes_received = recvfrom(this->sock_fd, buffer, 99, 0, (struct sockaddr *)dest, &addrlen);
|
||||
if (num_bytes_received == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (num_bytes_received < 0) {
|
||||
throw errno;
|
||||
}
|
||||
/* Null-terminate the string */
|
||||
*(buffer + num_bytes_received) = '\0';
|
||||
return buffer;
|
||||
@@ -111,7 +109,7 @@ char* Sock::recvAll() {
|
||||
}
|
||||
|
||||
if (num_bytes_received < 0) {
|
||||
throw errno * -1;
|
||||
throw errno;
|
||||
}
|
||||
total_bytes_received += num_bytes_received;
|
||||
has_been_read = true;
|
||||
@@ -122,7 +120,8 @@ char* Sock::recvAll() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* Non-blocking recv call - Uses 'select' to poll for data from the FD. */
|
||||
/* Non-blocking recv call - Uses 'select' to poll for data from the FD. Returns an empty string if there
|
||||
is nothing to read. */
|
||||
char* Sock::recvAllNB() {
|
||||
struct timeval tv;
|
||||
fd_set readfs;
|
||||
@@ -136,7 +135,7 @@ char* Sock::recvAllNB() {
|
||||
if (FD_ISSET(this->sock_fd, &readfs)) {
|
||||
return Sock::recvAll();
|
||||
} else {
|
||||
return NULL;
|
||||
return (char *)"";
|
||||
}
|
||||
}
|
||||
|
||||
|
19
timer.c
Normal file
19
timer.c
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <stdbool.h>
|
||||
#include "includes/timer.h"
|
||||
#include "includes/raygui/raygui.h"
|
||||
|
||||
Timer timer_init(double lifetime_secs) {
|
||||
Timer timer;
|
||||
timer.start_time = GetTime();
|
||||
timer.lifetime = lifetime_secs;
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
bool timer_done(Timer timer) {
|
||||
return GetTime() - timer.start_time >= timer.lifetime;
|
||||
}
|
||||
|
||||
double timer_get_elapsed(Timer timer) {
|
||||
return GetTime() - timer.start_time;
|
||||
}
|
12
todo.txt
12
todo.txt
@@ -1,2 +1,10 @@
|
||||
3. Try to make the ball go between screens.
|
||||
8. Have both client and server send a message if the game is quit.
|
||||
1. Sign Windows executable, to remove 'Unknown Publisher' warnings.
|
||||
2. Add 'install' target to Meson, to allow the user to install the game. This should also copy the .so files to the right locations.
|
||||
3. Use free() to free allocated memory.
|
||||
4. Use the struct to establish a connection, and to start each round (instead of sending strings).
|
||||
5. Figure out how to build statically-linked Mac binary, and create a build script for packaging it.
|
||||
6. Communicate the paddle reset position to the peer, after a round.
|
||||
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 specify which paddle they want to control, in multi-player mode.
|
||||
9. Try to make the ball go between screens.
|
||||
10. 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).
|
||||
|
Reference in New Issue
Block a user