Compare commits

..

12 Commits

9 changed files with 86 additions and 139 deletions

3
.gitmodules vendored
View File

@@ -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

View File

@@ -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/

View File

@@ -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

View File

@@ -56,6 +56,9 @@ public:
/* Returns socket identifier */ /* Returns socket identifier */
int getSockFD(); int getSockFD();
/* Returns whether or not the given socket is connected to a remote address */
bool has_remote_address();
/* This is a pure virtual function (AKA an abstract function). It's purpose /* This is a pure virtual function (AKA an abstract function). It's purpose
is to be redefined by the children classes (client and server). */ is to be redefined by the children classes (client and server). */
virtual int get_type() = 0; virtual int get_type() = 0;

View File

@@ -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);
@@ -429,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 */

View File

@@ -4,6 +4,45 @@ add_global_arguments('-std=c++11', language: ['cpp'])
compiler = meson.get_compiler('cpp') compiler = meson.get_compiler('cpp')
cmake = import('cmake') cmake = import('cmake')
# For macOS only - define extra dependencies early
if build_machine.system() == 'darwin'
objc_dep = dependency('objc', required: false)
if not objc_dep.found()
objc_dep = compiler.find_library('objc', required: true)
endif
# Add other macOS frameworks that might be needed
foundation_dep = dependency('Foundation', required: false)
if not foundation_dep.found()
foundation_dep = compiler.find_library('Foundation', required: false)
endif
cocoa_dep = dependency('Cocoa', required: false)
if not cocoa_dep.found()
cocoa_dep = compiler.find_library('Cocoa', required: false)
endif
iokit_dep = dependency('IOKit', required: false)
if not iokit_dep.found()
iokit_dep = compiler.find_library('IOKit', required: false)
endif
extra_deps = [objc_dep]
if foundation_dep.found()
extra_deps += [foundation_dep]
endif
if cocoa_dep.found()
extra_deps += [cocoa_dep]
endif
if iokit_dep.found()
extra_deps += [iokit_dep]
endif
else
extra_deps = []
endif
# For Windows only
ws2_dep = compiler.find_library('ws2_32', required: false)
winmm = compiler.find_library('winmm', required: false)
# Handle raylib dependency based on library type
# if we are building a shared library # if we are building a shared library
if get_option('default_library') == 'shared' if get_option('default_library') == 'shared'
raylib = dependency('raylib', required: false) # Try to find dependency with pkg-config raylib = dependency('raylib', required: false) # Try to find dependency with pkg-config
@@ -17,24 +56,20 @@ if get_option('default_library') == 'shared'
raylib_proj = cmake.subproject('raylib', options: opt_var) raylib_proj = cmake.subproject('raylib', options: opt_var)
raylib = raylib_proj.dependency('raylib') raylib = raylib_proj.dependency('raylib')
endif endif
else
# For static library (default case)
opt_var = cmake.subproject_options()
opt_var.add_cmake_defines({'BUILD_SHARED_LIBS' : false})
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')
endif
#For Windows only
ws2_dep = compiler.find_library('ws2_32', required: false)
winmm = compiler.find_library('winmm', required: false)
if build_machine.system() == 'windows' if build_machine.system() == 'windows'
add_project_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 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] + extra_deps
) )

1
netpong-serialization Submodule

Submodule netpong-serialization added at c0c7e14aa6

View File

@@ -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;
}

View File

@@ -37,6 +37,13 @@ Sock::Sock(char protocol, const char* address, int port) {
this->address = std::string(address); this->address = std::string(address);
} }
/* This method returns whether or not the socket is connected to a remote address */
bool Sock::has_remote_address() {
struct sockaddr_storage addr;
socklen_t len = sizeof(addr);
return getpeername(this->sock_fd, (struct sockaddr*)&addr, &len) == 0;
}
/* This method sends the given data, through the 'other_sockt' variable.. Client /* This method sends the given data, through the 'other_sockt' variable.. Client
and server classes extend this method, by setting this variable to different values. and server classes extend this method, by setting this variable to different values.
This function needs more testing for TCP, as it focuses on UDP right now. */ This function needs more testing for TCP, as it focuses on UDP right now. */
@@ -48,7 +55,13 @@ void Sock::sendAll(std::string to_send) {
/* For UDP sockets */ /* For UDP sockets */
if (this->protocol == ES_UDP) { if (this->protocol == ES_UDP) {
if (sendto(this->sock_fd, to_send.data(), str_length, 0, (struct sockaddr *)dest, addrlen) == -1) { int retval;
if (this->has_remote_address()) {
retval = send(this->sock_fd, to_send.data(), str_length, 0);
} else {
retval = sendto(this->sock_fd, to_send.data(), str_length, 0, (struct sockaddr *)dest, addrlen);
}
if (retval == -1) {
throw errno; throw errno;
} }
} }