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"]
path = subprojects/raylib
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:
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
```
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
```
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/

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 */
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
is to be redefined by the children classes (client and server). */
virtual int get_type() = 0;

View File

@@ -34,7 +34,7 @@
#include "includes/check_input.hpp"
#include "includes/display_text.hpp"
#include "includes/easysock.h"
#include "includes/serialization.h"
#include "netpong-serialization/includes/serialization.h"
#include "includes/timer.h"
/* Global variables used to instantiate structs */
@@ -215,6 +215,9 @@ int main(int argc, char** argv) {
/* Single player mode */
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
BeginDrawing();
ClearBackground(BLACK);
@@ -429,6 +432,7 @@ int main(int argc, char** argv) {
/* Up */
if (IsKeyPressed(KEY_UP) && type.mode != M_CLIENT) {
pad2.velocity.y = (-1) * PADDLE_SPEED;
}
/* Stop */

View File

@@ -4,6 +4,45 @@ add_global_arguments('-std=c++11', language: ['cpp'])
compiler = meson.get_compiler('cpp')
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 get_option('default_library') == 'shared'
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 = raylib_proj.dependency('raylib')
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
# 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'
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
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]
'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',
'netpong-serialization/serialization.c', 'timer.c', 'easysock.c',
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 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
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. */
@@ -48,7 +55,13 @@ void Sock::sendAll(std::string to_send) {
/* For UDP sockets */
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;
}
}