Compare commits

...

12 Commits
v0.2 ... master

3
.gitmodules vendored

@ -1,3 +1,6 @@
[submodule "subprojects/raylib"] [submodule "subprojects/raylib"]
path = subprojects/raylib path = subprojects/raylib
url = https://github.com/raysan5/raylib.git url = https://github.com/raysan5/raylib.git
[submodule "subprojects/netpong-serialization"]
path = netpong-serialization
url = https://gitea.twomorecents.org/Rockingcool/netpong-serialization.git

@ -10,15 +10,23 @@ The game has only one runtime dependency: The [raylib](https://www.raylib.com/)
This application uses [Meson](https://mesonbuild.com/) as a build system. To build the application: This application uses [Meson](https://mesonbuild.com/) as a build system. To build the application:
1. Install meson from the link above. 1. Install meson from the link above.
2. Set up the build directory.
2. Clone the repository.
3. Update all submodules:
```
git submodule update --init --recursive
```
3. Set up the build directory.
``` ```
meson setup build 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. 4. 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 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: 5. 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/ meson configure -Ddefault_library=static build/

@ -5,6 +5,7 @@
/* Destructor - closes any open sockets */ /* Destructor - closes any open sockets */
Client::~Client() { Client::~Client() {
free(dest);
close(this->other_socket); close(this->other_socket);
close(this->sock_fd); close(this->sock_fd);
} }

@ -4,10 +4,10 @@
set -o errexit # Stop executing when a command fails set -o errexit # Stop executing when a command fails
BASE_DIR=$(dirname $0) BASE_DIR=$(dirname $0)
REL_DIR="$BASE_DIR/release/dist" REL_DIR="$BASE_DIR/release/dist/pong"
RAYLIB_DLL="$BASE_DIR/build/subprojects/raylib/libraylib.dll" RAYLIB_DLL="$BASE_DIR/build/subprojects/raylib/libraylib.dll"
mkdir -p "$REL_DIR" rm -r "$REL_DIR"; mkdir -p "$REL_DIR"
# Set up the build directory # Set up the build directory
meson setup build/ meson setup build/
@ -30,6 +30,9 @@ cp "$BASE_DIR/build/pong" "$REL_DIR"
# Remove the temporary file. # Remove the temporary file.
rm "$BASE_DIR/tmp_file.txt" rm "$BASE_DIR/tmp_file.txt"
#Zip the $REL_DIR folder # Go to the parent directory of $REL_DIR, and zip the $REL_DIR directory. This ensures
zip -r "$BASE_DIR/release/netpong-win.zip" "$REL_DIR" # that the parent directories aren't included in the zip file.
# The command is enclosed in parantheses, to ensure that the main shell's directory
# isn't changed.
(cd "$REL_DIR/.." && zip -r "./netpong-win.zip" "./pong")

@ -133,6 +133,7 @@ SOCKET create_remote (int network,char transport, const char* address,int port,s
} }
remote_addr_struct = (struct sockaddr_storage *)results->ai_addr; remote_addr_struct = (struct sockaddr_storage *)results->ai_addr;
network = inet_to_int(results->ai_family); network = inet_to_int(results->ai_family);
free(port_str);
} else { } else {
create_addr(network,address,port,remote_addr_struct); create_addr(network,address,port,remote_addr_struct);
} }

@ -1,33 +0,0 @@
#ifndef _SERIALIZATION_H
#define _SERIALIZATION_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
/* Struct used to hold the data that will be sent between sockets */
typedef struct {
uint16_t pad_x; // X-coordinate of sending paddle
uint16_t pad_y; // Y-coordinate of sending paddle
uint16_t ball_x; // X-coordinate of ball (only the server fills this in)
uint16_t ball_y; // Y-coordinate of ball (only the server fills this in)
bool should_quit; // Flag to indicate whether game should be quit or not
} Serial_Data;
/* Create a Serial_Data struct from float values */
Serial_Data Serial_create_data(float pad_x, float pad_y, float ball_x, float ball_y, bool should_quit);
/* Serialize a struct into a byte array, that can be sent through a socket */
uint8_t* Serial_serialize(Serial_Data data);
/* Deserialize a byte array into a struct, and return the struct */
Serial_Data Serial_deserialize(uint8_t* serialized);
#ifdef __cplusplus
}
#endif
#endif

@ -34,7 +34,7 @@
#include "includes/check_input.hpp" #include "includes/check_input.hpp"
#include "includes/display_text.hpp" #include "includes/display_text.hpp"
#include "includes/easysock.h" #include "includes/easysock.h"
#include "includes/serialization.h" #include "netpong-serialization/includes/serialization.h"
#include "includes/timer.h" #include "includes/timer.h"
/* Global variables used to instantiate structs */ /* Global variables used to instantiate structs */
@ -215,6 +215,9 @@ int main(int argc, char** argv) {
/* Single player mode */ /* Single player mode */
if (selected_item == M_SINGLE) { if (selected_item == M_SINGLE) {
type.mode = M_SINGLE;
type.netsock = NULL;
GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // Enable text wrapping so that the long text, displayed below, will be wrapped GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // Enable text wrapping so that the long text, displayed below, will be wrapped
BeginDrawing(); BeginDrawing();
ClearBackground(BLACK); ClearBackground(BLACK);
@ -312,7 +315,7 @@ int main(int argc, char** argv) {
display_and_exit_raygui(std::string(inv.what()) + "\nClosing game...", 2); display_and_exit_raygui(std::string(inv.what()) + "\nClosing game...", 2);
return -1; return -1;
} }
free(code_text); free(code_text);
} }
} }
@ -392,6 +395,7 @@ int main(int argc, char** argv) {
/* If the response is NULL, that means it timed-out. In this case, there's no value to print */ /* 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; std::cout << "NOTHING RECEIVED" << std::endl;
} }
free(response_array);
} }
/* Check to see if peer has quit the game */ /* Check to see if peer has quit the game */
@ -428,6 +432,7 @@ int main(int argc, char** argv) {
/* Up */ /* Up */
if (IsKeyPressed(KEY_UP) && type.mode != M_CLIENT) { if (IsKeyPressed(KEY_UP) && type.mode != M_CLIENT) {
pad2.velocity.y = (-1) * PADDLE_SPEED; pad2.velocity.y = (-1) * PADDLE_SPEED;
} }
/* Stop */ /* Stop */

@ -35,6 +35,6 @@ endif
executable('pong', 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', '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', 'netpong-serialization/serialization.c', 'timer.c', 'easysock.c',
dependencies: [raylib, ws2_dep, winmm] dependencies: [raylib, ws2_dep, winmm]
) )

@ -0,0 +1 @@
Subproject commit c0c7e14aa64ebffc334ad4f08e49bad2591050a4

@ -1,87 +0,0 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#include <arpa/inet.h>
#endif
#ifdef _WIN32
#include <winsock2.h>
#endif
#include "includes/serialization.h"
/* Takes in float values, casts them to uint16_t and creates a Serial_Data struct */
Serial_Data Serial_create_data(float pad_x, float pad_y, float ball_x, float ball_y, bool should_quit) {
Serial_Data data;
data.pad_x = (uint16_t)pad_x;
data.pad_y = (uint16_t)pad_y;
data.ball_x = (uint16_t)ball_x;
data.ball_y = (uint16_t)ball_y;
data.should_quit = should_quit;
return data;
}
/* Serializes a 'Data' struct into a byte array, converted to network-byte order */
uint8_t* Serial_serialize(Serial_Data data) {
/* Create a pointer that can fit the entire struct */
uint8_t* serialized = malloc(sizeof(Serial_Data) + 1);
uint8_t* pad_x_ptr;
uint8_t* pad_y_ptr;
uint8_t* ball_x_ptr;
uint8_t* ball_y_ptr;
uint8_t* should_quit_ptr;
memset(serialized, 0, sizeof(Serial_Data) + 1); // Zero out the memory
pad_x_ptr = serialized;
pad_y_ptr = pad_x_ptr + sizeof(uint16_t);
ball_x_ptr = pad_y_ptr + sizeof(uint16_t);
ball_y_ptr = ball_x_ptr + sizeof(uint16_t);
should_quit_ptr = ball_y_ptr + sizeof(uint16_t);
*((uint16_t *)pad_x_ptr) = data.pad_x;
*((uint16_t *)pad_x_ptr) = htons(*((uint16_t *)pad_x_ptr));
*((uint16_t *)pad_y_ptr) = data.pad_y;
*((uint16_t *)pad_y_ptr) = htons(*((uint16_t *)pad_y_ptr));
*((uint16_t *)ball_x_ptr) = data.ball_x;
*((uint16_t *)ball_x_ptr) = htons(*((uint16_t *)ball_x_ptr));
*((uint16_t *)ball_y_ptr) = data.ball_y;
*((uint16_t *)ball_y_ptr) = htons(*((uint16_t *)ball_y_ptr));
*((bool *)should_quit_ptr) = data.should_quit;
*(should_quit_ptr + sizeof(bool)) = '\0';
return serialized;
}
/* Deserialize a byte array into a 'Data' struct, converted to host byte order */
Serial_Data Serial_deserialize(uint8_t* serialized) {
Serial_Data deserialized;
/* Use successive chunks of memory address to create pointers to the data */
uint8_t* pad_x_ptr = serialized;
uint8_t* pad_y_ptr = serialized + sizeof(uint16_t);
uint8_t* ball_x_ptr = pad_y_ptr + sizeof(uint16_t);
uint8_t* ball_y_ptr = ball_x_ptr + sizeof(uint16_t);
uint8_t* should_quit_ptr = ball_y_ptr + sizeof(uint16_t);
/* Dereference (and cast) the pointers, and store them into the struct */
deserialized.pad_x = *((uint16_t *)pad_x_ptr);
deserialized.pad_x = ntohs(deserialized.pad_x);
deserialized.pad_y = *((uint16_t *)pad_y_ptr);
deserialized.pad_y = ntohs(deserialized.pad_y);
deserialized.ball_x = *((uint16_t *)ball_x_ptr);
deserialized.ball_x = ntohs(deserialized.ball_x);
deserialized.ball_y = *((uint16_t *)ball_y_ptr);
deserialized.ball_y = ntohs(deserialized.ball_y);
deserialized.should_quit = *((bool *)should_quit_ptr);
return deserialized;
}

@ -12,6 +12,7 @@
/* Destructor - closes any open sockets */ /* Destructor - closes any open sockets */
Server::~Server() { Server::~Server() {
free(dest);
close(this->other_socket); close(this->other_socket);
close(this->sock_fd); close(this->sock_fd);
} }

@ -1,10 +1,10 @@
1. Sign Windows executable, to remove 'Unknown Publisher' warnings. 1. Add 'install' target to Meson, to allow the user to install the game. This should also copy the .so files to the right locations.
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. 2. Use the struct to establish a connection, and to start each round (instead of sending strings).
3. Use free() to free allocated memory. 3. Figure out how to build statically-linked Mac binary, and create a build script for packaging it.
4. Use the struct to establish a connection, and to start each round (instead of sending strings). 4. Communicate the paddle reset position to the peer, after a round.
5. Figure out how to build statically-linked Mac binary, and create a build script for packaging it. 5. 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).
6. Communicate the paddle reset position to the peer, after a round. 6. Allow the user to specify which paddle they want to control, in multi-player mode.
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). 7. Try to make the ball go between screens.
8. Allow the user to specify which paddle they want to control, in multi-player mode. 8. 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).
9. Try to make the ball go between screens. 9. Create (or find) an icon for the application.
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). 10. [This can't really be fixed, since I'd need to purchase a developer certificate] Sign Windows executable, to remove 'Unknown Publisher' warnings.

Loading…
Cancel
Save