Primitive type serialization

This commit is contained in:
2025-01-23 13:00:36 -05:00
parent 350e93da09
commit 71b95b2615
10 changed files with 264 additions and 122 deletions

View File

@@ -14,8 +14,8 @@ endif()
set(CMAKE_CXX_STANDARD 20)
# Set for profiling
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

View File

@@ -0,0 +1,63 @@
#pragma once
#include <cstdint>
#include <cstddef>
namespace CaveGame::Core
{
/// Primitive Serialization Functions.
/// A data container structure which keeps track of the current position.
struct Buffer {
uint8_t* data;
size_t size;
size_t index;
};
/// Writes a 1-byte unsigned int to the buffer, in network-byte-order, and advances the index by 1.
void write_u8(Buffer& buffer, uint8_t value);
/// Writes a 2-byte unsigned int to the buffer, in network-byte-order, and advances the index by 2.
void write_u16(Buffer& buffer, uint16_t value);
/// Writes a 4-byte unsigned int to the buffer, in network-byte-order, and advances the index by 4.
void write_u32(Buffer& buffer, uint32_t value);
/// Writes a 8-byte unsigned int to the buffer, in network-byte-order, and advances the index by 8.
void write_u64(Buffer& buffer, uint64_t value);
/// Reads a 1-byte unsigned int from the buffer, from network-byte-order, and advances the index by 1.
uint8_t read_u8(Buffer& buffer);
/// Reads a 2-byte unsigned int from the buffer, from network-byte-order, and advances the index by 2.
uint16_t read_u16(Buffer& buffer);
/// Reads a 4-byte unsigned int from the buffer, from network-byte-order, and advances the index by 4.
uint32_t read_u32(Buffer& buffer);
/// Reads a 8-byte unsigned int from the buffer, from network-byte-order, and advances the index by 8.
uint64_t read_u64(Buffer& buffer);
/// Writes a 1-byte signed int to the buffer, in network-byte-order, and advances the index by 1.
void write_s8(Buffer& buffer, int8_t value);
/// Writes a 2-byte signed int to the buffer, in network-byte-order, and advances the index by 2.
void write_s16(Buffer& buffer, int16_t value);
/// Writes a 4-byte signed int to the buffer, in network-byte-order, and advances the index by 4.
void write_s32(Buffer& buffer, int32_t value);
/// Writes a 8-byte signed int to the buffer, in network-byte-order, and advances the index by 8.
void write_s64(Buffer& buffer, int64_t value);
/// Reads a 1-byte signed int from the buffer, from network-byte-order, and advances the index by 1.
int8_t read_s8(Buffer& buffer);
/// Reads a 2-byte signed int from the buffer, from network-byte-order, and advances the index by 2.
int16_t read_s16(Buffer& buffer);
/// Reads a 4-byte signed int from the buffer, from network-byte-order, and advances the index by 4.
int32_t read_s32(Buffer& buffer);
/// Reads a 8-byte signed int from the buffer, from network-byte-order, and advances the index by 8.
int64_t read_s64(Buffer& buffer);
/// Writes a 4-byte float to the buffer, via reinterpreting as uint32_t, and advances the index by 4.
void write_f32(Buffer& buffer, float value);
/// Writes a 8-byte float to the buffer, via reinterpreting as uint64_t, and advances the index by 8.
void write_f64(Buffer& buffer, double value);
/// Reads a 4-byte float from the buffer, via reinterpreting from uint32_t, and advances the index by 4.
float read_f32(Buffer& buffer);
/// Reads a 8-byte float from the buffer, via reinterpreting from uint64_t, and advances the index by 8.
double read_f64(Buffer& buffer);
}

View File

@@ -99,6 +99,9 @@ namespace CaveGame::Core
/// Calculates the tile to be placed at a given x,y coordinates during the first terrain iteration.
TileID Generator::ComputeTile(int wx, int wy) {
// TODO: Pre-generate height maps instead of computing perlin noise samples at runtime.
float depth = ComputeDepth(wx, wy);
TileID base = HeightMap(depth, wx, wy);

View File

@@ -7,6 +7,8 @@ namespace CaveGame::Core {
bounding_box = {16, 24};
}
void Player::Draw() {}
void Player::Update(float elapsed) {
Humanoid::Update(elapsed);
}

View File

@@ -0,0 +1,145 @@
#include <Core/Serialization.hpp>
#include <cstdint>
#include <cassert>
#include <netinet/in.h>
#include <J3ML/Algorithm/Reinterpret.hpp>
namespace CaveGame::Core
{
void write_u8(Buffer &buffer, uint8_t value) {
assert(buffer.index + 1 <= buffer.size);
*((uint8_t*)(buffer.data + buffer.index)) = (value);
buffer.index += 1;
}
void write_u16(Buffer &buffer, uint16_t value) {
assert(buffer.index + 2 <= buffer.size);
*((uint16_t*)(buffer.data + buffer.index)) = htons(value);
buffer.index += 2;
}
void write_u32(Buffer &buffer, uint32_t value) {
assert(buffer.index + 4 <= buffer.size);
*((uint32_t*)(buffer.data + buffer.index)) = htonl(value);
buffer.index += 4;
}
void write_u64(Buffer &buffer, uint64_t value) {
assert(buffer.index + 8 <= buffer.size);
*((uint64_t*)(buffer.data + buffer.index)) = htonl(value);
buffer.index += 8;
}
uint8_t read_u8(Buffer &buffer) {
assert(buffer.index + 1 <= buffer.size);
uint8_t value;
value = (*((uint8_t*)(buffer.data + buffer.index)));
buffer.index += 1;
return value;
}
uint16_t read_u16(Buffer &buffer) {
assert(buffer.index + 2 <= buffer.size);
uint16_t value;
value = ntohs(*((uint16_t*)(buffer.data + buffer.index)));
buffer.index += 2;
return value;
}
uint32_t read_u32(Buffer &buffer) {
assert(buffer.index + 4 <= buffer.size);
uint32_t value;
value = ntohl(*((uint32_t*)(buffer.data + buffer.index)));
buffer.index += 4;
return value;
}
uint64_t read_u64(Buffer &buffer) {
assert(buffer.index + 8 <= buffer.size);
uint64_t value;
value = ntohl(*((uint64_t*)(buffer.data + buffer.index)));
buffer.index += 8;
return value;
}
void write_s8(Buffer& buffer, int8_t value)
{
assert(buffer.index + 1 <= buffer.size);
*((int8_t*)(buffer.data + buffer.index)) = (value);
buffer.index += 1;
}
void write_s16(Buffer& buffer, int16_t value)
{
assert(buffer.index + 2 <= buffer.size);
*((int16_t*)(buffer.data + buffer.index)) = htons(value);
buffer.index += 2;
}
void write_s32(Buffer& buffer, int32_t value)
{
assert(buffer.index + 3 <= buffer.size);
*((int32_t*)(buffer.data + buffer.index)) = htons(value);
buffer.index += 3;
}
void write_s64(Buffer& buffer, int64_t value)
{
assert(buffer.index + 4 <= buffer.size);
*((int64_t*)(buffer.data + buffer.index)) = htons(value);
buffer.index += 3;
}
int8_t read_s8(Buffer& buffer)
{
assert(buffer.index + 1 <= buffer.size);
int8_t value;
value = (*((int8_t*)(buffer.data + buffer.index)));
buffer.index += 1;
return value;
}
int16_t read_s16(Buffer& buffer)
{
assert(buffer.index + 2 <= buffer.size);
int16_t value;
value = ntohs(*((int16_t*)(buffer.data + buffer.index)));
buffer.index += 2;
return value;
}
int32_t read_s32(Buffer& buffer)
{
assert(buffer.index + 4 <= buffer.size);
int32_t value;
value = ntohs(*((int32_t*)(buffer.data + buffer.index)));
buffer.index += 4;
return value;
}
int64_t read_s64(Buffer& buffer)
{
assert(buffer.index + 8 <= buffer.size);
int64_t value;
value = ntohs(*((int64_t*)(buffer.data + buffer.index)));
buffer.index += 8;
return value;
}
using J3ML::ReinterpretAs;
void write_f32(Buffer &buffer, float value) {
write_u32(buffer, ReinterpretAs<uint32_t>(value));
}
void write_f64(Buffer &buffer, double value) {
write_u64(buffer, ReinterpretAs<uint64_t>(value));
}
float read_f32(Buffer &buffer) {
return ReinterpretAs<float>(read_u32(buffer));
}
double read_f64(Buffer &buffer) {
return ReinterpretAs<float>(read_u64(buffer));
}
}

View File

@@ -8,8 +8,7 @@ if (UNIX)
endif()
if (WIN32)
add_library(CaveServer SHARED ${CaveServer_SRC}
include/Server/ServerGameWorld.hpp)
add_library(CaveServer SHARED ${CaveServer_SRC})
endif()
target_include_directories(CaveServer PUBLIC

View File

@@ -9,35 +9,15 @@
namespace CaveGame::Server
{
struct Buffer {
uint8_t* data;
size_t size;
size_t index;
struct ServerInfoPacket
{
};
void write_u8(Buffer& buffer, uint8_t value);
void write_u16(Buffer& buffer, uint16_t value);
void write_u32(Buffer& buffer, uint32_t value);
void write_u64(Buffer& buffer, uint64_t value);
uint8_t read_u8(Buffer& buffer);
uint16_t read_u16(Buffer& buffer);
uint32_t read_u32(Buffer& buffer);
uint64_t read_u64(Buffer& buffer);
void write_s8(Buffer& buffer, int8_t value);
void write_s16(Buffer& buffer, int16_t value);
void write_s32(Buffer& buffer, int32_t value);
void write_s64(Buffer& buffer, int64_t value);
int8_t read_s8(Buffer& buffer);
int16_t read_s16(Buffer& buffer);
int32_t read_s32(Buffer& buffer);
int64_t read_s64(Buffer& buffer);
class Peer
{
public:

View File

@@ -3,93 +3,6 @@
namespace CaveGame::Server
{
void write_u8(Buffer &buffer, uint8_t value) {
assert(buffer.index + 1 <= buffer.size);
*((uint8_t*)(buffer.data + buffer.index)) = htons(value);
buffer.index += 1;
}
void write_u16(Buffer &buffer, uint16_t value) {
assert(buffer.index + 2 <= buffer.size);
*((uint16_t*)(buffer.data + buffer.index)) = htons(value);
buffer.index += 2;
}
void write_u32(Buffer &buffer, uint32_t value) {
assert(buffer.index + 4 <= buffer.size);
*((uint32_t*)(buffer.data + buffer.index)) = htonl(value);
buffer.index += 4;
}
void write_u64(Buffer &buffer, uint64_t value) {
assert(buffer.index + 8 <= buffer.size);
*((uint64_t*)(buffer.data + buffer.index)) = htonl(value);
buffer.index += 8;
}
uint8_t read_u8(Buffer &buffer) {
assert(buffer.index + 1 <= buffer.size);
uint32_t value;
value = ntohs(*((uint32_t*)(buffer.data + buffer.index)));
buffer.index += 1;
return value;
}
uint16_t read_u16(Buffer &buffer) {
assert(buffer.index + 2 <= buffer.size);
uint32_t value;
value = ntohs(*((uint32_t*)(buffer.data + buffer.index)));
buffer.index += 2;
return value;
}
uint32_t read_u32(Buffer &buffer) {
assert(buffer.index + 4 <= buffer.size);
uint32_t value;
value = ntohl(*((uint32_t*)(buffer.data + buffer.index)));
buffer.index += 4;
return value;
}
uint64_t read_u64(Buffer &buffer) {
assert(buffer.index + 8 <= buffer.size);
uint64_t value;
value = ntohl(*((uint64_t*)(buffer.data + buffer.index)));
buffer.index += 8;
return value;
}
void write_s8(Buffer& buffer, int8_t value)
{
assert(buffer.index + 1 <= buffer.size);
*((int8_t*)(buffer.data + buffer.index)) = htons(value);
buffer.index += 1;
}
void write_s16(Buffer& buffer, int16_t value)
{
assert(buffer.index + 2 <= buffer.size);
*((int16_t*)(buffer.data + buffer.index)) = htons(value);
buffer.index += 2;
}
void write_s32(Buffer& buffer, int32_t value)
{
assert(buffer.index + 3 <= buffer.size);
*((int32_t*)(buffer.data + buffer.index)) = htons(value);
buffer.index += 3;
}
void write_s64(Buffer& buffer, int64_t value)
{
assert(buffer.index + 4 <= buffer.size);
*((int64_t*)(buffer.data + buffer.index)) = htons(value);
buffer.index += 3;
}
int8_t read_s8(Buffer& buffer);
int16_t read_s16(Buffer& buffer);

View File

@@ -6,13 +6,14 @@ file(GLOB_RECURSE CaveServerApp_SRC "src/*.cpp")
add_executable(CaveServerApp main.cpp ${CaveServerApp_SRC})
target_include_directories(CaveServerApp PUBLIC
${CaveServer_SOURCE_DIR}/include
${CaveCore_SOURCE_DIR}/include
${CaveServer_SOURCE_DIR}/include
${mcolor_SOURCE_DIR}/include
${jlog_SOURCE_DIR}/include
${J3ML_SOURCE_DIR}/include
${Sockets_SOURCE_DIR}/include)
target_include_directories(CaveClientApp PUBLIC "include")
target_include_directories(CaveServerApp PUBLIC "include")
target_link_libraries(CaveClientApp PUBLIC mcolor jlog CaveServer J3ML Sockets)
target_link_libraries(CaveServerApp PUBLIC mcolor jlog CaveCore CaveServer J3ML Sockets)

View File

@@ -3,6 +3,7 @@
#include <iostream>
#include <Sockets/UdpServer.hpp>
#include <Core/Serialization.hpp>
/* Networking Design Notes
*
@@ -70,7 +71,7 @@ void RunServer() {
//std::string input;
//getline(std::cin, input);
// while (input != "exit") {
//while (input != "exit") {
// getline(std::cin, input);
//}
@@ -111,8 +112,43 @@ void RunClient() {
std::cout << "Client closing." << std::endl;
}
void roundtrip_test()
{
using namespace CaveGame::Core;
uint8_t a = 128;
uint16_t b = 32000;
uint32_t c = 666420;
int8_t d = -64;
float e = 3.14159f;
Buffer test;
test.index = 0;
test.size = 32;
//test.data = ;
write_u8(test, a);
write_u16(test, b);
write_u32(test, c);
write_s8(test, d);
write_f32(test, e);
test.index = 0;
a = read_u8(test);
b = read_u16(test);
c = read_u32(test);
d = read_s8(test);
e = read_f32(test);
}
int main(int argc, char** argv) {
roundtrip_test();
std::cout << "Running Program" << std::endl;