diff --git a/Deer/Build-Service.lua b/Deer/Build-Service.lua index c6df4cc..7026a66 100644 --- a/Deer/Build-Service.lua +++ b/Deer/Build-Service.lua @@ -19,8 +19,11 @@ project "DeerService" "vendor/entt/include", "vendor/cereal/include", "vendor/angelScript/include", - "vendor/smallVector" + "vendor/smallVector", + "vendor/enet/include" } + + links {"enet"} targetdir ("../bin/" .. OutputDir .. "/%{prj.name}") objdir ("../bin/int/" .. OutputDir .. "/%{prj.name}") @@ -55,4 +58,4 @@ project "DeerService" defines { "DIST" } runtime "Release" optimize "On" - symbols "Off" \ No newline at end of file + symbols "Off" diff --git a/Deer/Build.lua b/Deer/Build.lua index 11f85fe..bd5696e 100755 --- a/Deer/Build.lua +++ b/Deer/Build.lua @@ -6,8 +6,8 @@ project "Deer" staticruntime "off" files { - "src/Deer/**.h", - "src/Deer/**.cpp", + "src/DeerCore/**.h", + "src/DeerCore/**.cpp", "src/DeerRender/**.h", "src/DeerRender/**.cpp", "src/Plattform/OpenGL/**.h", @@ -35,7 +35,8 @@ project "Deer" "vendor/cereal/include", "vendor/objload/include/objload", "vendor/angelScript/include", - "vendor/smallVector" + "vendor/smallVector", + "vendor/enet/include" } targetdir ("../bin/" .. OutputDir .. "/%{prj.name}") @@ -81,7 +82,8 @@ project "Deer" "gdk_pixbuf-2.0", -- GDK Pixbuf library "gio-2.0", -- GIO library "gobject-2.0", -- GObject library - "pthread" -- POSIX threads library + "pthread", -- POSIX threads library + "enet" } @@ -109,4 +111,4 @@ project "Deer" defines { "DIST" } runtime "Release" optimize "On" - symbols "Off" \ No newline at end of file + symbols "Off" diff --git a/Deer/Include/Deer/Voxel.h b/Deer/Include/Deer/Voxel.h deleted file mode 100755 index c1ef093..0000000 --- a/Deer/Include/Deer/Voxel.h +++ /dev/null @@ -1,296 +0,0 @@ -// Structure definition for voxel and voxel manipulation -// copyright Copyright (c) 2025 Deer -#pragma once -#include - -#include -#include -#include - -#include "Deer/Tools/Memory.h" - -#ifdef DEER_RENDER -#include "DeerRender/VoxelAspect.h" - -namespace Deer { - class Texture2D; - class Shader; -} // namespace Deer -#endif - -#define VOXEL_INFO_TYPE_AIR "air" -#define VOXEL_INFO_TYPE_VOXEL "voxel" -#define VOXEL_INFO_TYPE_TRANSPARENT_VOXEL "transparentVoxel" -#define VOXEL_INFO_TYPE_CUSTOM "custom" - -#define CHUNK_SIZE_X 32 -#define CHUNK_SIZE_Y 32 -#define CHUNK_SIZE_Z 32 -#define CHUNK_SIZE(axis) \ - ((axis == 0) ? CHUNK_SIZE_X : (axis == 1) ? CHUNK_SIZE_Y \ - : CHUNK_SIZE_Z) - -#define LAYER_VOXELS CHUNK_SIZE_X* CHUNK_SIZE_Z -#define CHUNK_VOXELS CHUNK_SIZE_X* CHUNK_SIZE_Y* CHUNK_SIZE_Z - -// TODO: Change this to be a inline function -#define VOXEL_POSITION(id) \ - id.z + id.y* CHUNK_SIZE_Z + id.x* CHUNK_SIZE_Z* CHUNK_SIZE_Y -#define LAYER_VOXEL_POSITION(id) id.z + id.x* CHUNK_SIZE_Z - -#define X_AXIS 0 -#define Y_AXIS 1 -#define Z_AXIS 2 - -// TODO: Change this to be a inline function -#define NORMAL_DIR(axis, normal) normalDirs[axis + normal * 3] - -namespace Deer { - struct Voxel; - struct LayerVoxel; - - extern Voxel nullVoxel; - extern Voxel emptyVoxel; - extern LayerVoxel nullLayerVoxel; - extern int normalDirs[3 * 6]; - - enum NormalDirection : uint8_t { - NORMAL_LEFT = 0, - NORMAL_RIGHT = 1, - NORMAL_DOWN = 2, - NORMAL_UP = 3, - NORMAL_BACK = 4, - NORMAL_FRONT = 5 - }; - - enum class VoxelInfoType : uint8_t { - Air = 0, - Voxel = 1, - TransparentVoxel = 2, - Custom = 3 - }; - - // Defines the general data of a voxel id stored in the array - // DataStore::voxelsInfo - struct VoxelInfo { - std::string name; - VoxelInfoType type = VoxelInfoType::Air; - }; - - // Namespace to load and manage voxel data - namespace DataStore { - // List of the voxels loaded with loadVoxelsData() - extern std::vector voxelsInfo; - - // Loads basic voxel data from folder DEER_VOXEL_DATA_PATH defined in - // DataStore.h - void loadVoxelsData(); - void createExampleVoxelData(); - - int32_t getVoxelID(const std::string&); - -#ifdef DEER_RENDER - // List of the voxels Aspect loaded with loadVoxelsAspect() - extern std::vector voxelsAspect; - - // Loads voxel aspect from folder DEER_VOXEL_ASPECT_PATH defined in - // DataStore.h - void loadVoxelsAspect(); - void createExampleVoxelAspect(); - - // Generates the texture atlas that the voxels demanded from folder - // DEER_VOXEL_TEXTURE_PATH defined in DataStore.h Warning : This - // function must be called with a render context, otherwise this will - // crash - void generateTextureAtlas(); - // Loads the shaders for rendering chunks from folder - // DEER_VOXEL_SHADER_PATH defined in DataStore.h - void loadVoxelsShaders(); - - // Returns with & height of the texture atlas generated - // Warning: If you call this before generate Texture Atlas the return - // value will be 0 - int getVoxelTextureAtlasSize(); - // Texture atlas created with generateTextureAtlas() call - // Warning: You must have called generateTextureAtlas() in order to work - /// Ref& getVoxelColorTextureAtlas(); - // Returns the shader created with loadVoxelsShaders() - // Warning: You must have called loadVoxelsShaders() in order to work - /// Ref& getSolidVoxelShader(); - -#endif - } // namespace DataStore - - // Structure to define what a voxel inside a world must have - struct Voxel { - // Reference to the voxel id - uint16_t id = 0; - - Voxel() = default; - Voxel(uint16_t _id) : id(_id) {} - - inline bool operator==(const Voxel& b) const { return id == b.id; } - inline bool isVoxelType() const { - return DataStore::voxelsInfo[id].type == VoxelInfoType::Voxel; - } - }; - - // Structure to define the general cordinates of a voxel in the world - struct VoxelCordinates { - union { - struct { - int32_t x, y, z; - }; - std::array data; - }; - - VoxelCordinates(int32_t _x = 0, int32_t _y = 0, int32_t _z = 0) - : x(_x), y(_y), z(_z) {} - - inline int32_t& operator[](int id) { return data[id]; } - inline bool operator==(const VoxelCordinates& b) const { - return x == b.x && y == b.y && z == b.z; - } - inline bool isNull() const { return x < 0 || y < 0 || z < 0; } - inline void makeNull() { x = -1; } - }; - - // Stucture that defines the info of a layer voxel - struct LayerVoxel { - uint16_t height = 0; -#ifdef DEER_RENDER - uint16_t ambient_light_height = 0; -#endif - - LayerVoxel() = default; - LayerVoxel(uint16_t _height) : height(_height) {} - }; - - // Returning info of a raycast - struct VoxelRayResult { - float distance = 0; - VoxelCordinates hitPos; - uint8_t face = 0; - }; - - // Coordinates of a chunk - struct ChunkID { - union { - struct { - uint16_t x; - uint16_t y; - uint16_t z; - }; - std::array axis; - }; - - ChunkID(uint16_t _x = 0, uint16_t _y = 0, uint16_t _z = 0) - : x(_x), y(_y), z(_z) {} - - inline bool operator==(const ChunkID& b) const { - return x == b.x && y == b.y && z == b.z; - } - inline uint16_t& operator[](size_t i) { return axis[i]; } - }; - - struct ChunkIDHash { - size_t operator()(const ChunkID& chunk) const { - size_t h1 = std::hash{}(chunk.x); - size_t h2 = std::hash{}(chunk.y); - size_t h3 = std::hash{}(chunk.z); - - size_t result = h1; - result = result * 31 + h2; - result = result * 31 + h3; - return result; - } - }; - - // Cordinates of a Layer - struct LayerID { - uint16_t x = 0; - uint16_t z = 0; - - LayerID() = default; - LayerID(uint16_t _x, uint16_t _z) : x(_x), z(_z) {} - inline bool operator==(const LayerID& b) const { - return x == b.x && z == b.z; - } - }; - - // Coordinates of a layer voxel relative to the Layer Chunk - struct LayerVoxelID { - uint8_t x = 0; - uint8_t z = 0; - - LayerVoxelID() = default; - LayerVoxelID(uint8_t _x, uint8_t _z = 0) : x(_x), z(_z) {} - }; - - // Coordinates of a voxel inside a Chunk - struct ChunkVoxelID { - union { - struct { - uint8_t x; - uint8_t y; - uint8_t z; - }; - std::array axis; - }; - - ChunkVoxelID(uint8_t _x = 0, uint8_t _y = 0, uint8_t _z = 0) - : x(_x), y(_y), z(_z) {} - inline uint8_t& operator[](size_t i) { return axis[i]; } - }; - - // Extracts the chunk coordinaes and the chunk voxel coordinates from a - // world position - inline void extractChunkCordinates(uint32_t x, uint32_t y, uint32_t z, - ChunkID& _chunkID, - ChunkVoxelID& _chunkVoxelID) { - uint16_t posX = x; - uint16_t posY = y; - uint16_t posZ = z; - - _chunkID.x = posX >> 5; - _chunkID.y = posY >> 5; - _chunkID.z = posZ >> 5; - - _chunkVoxelID.x = posX & 31; - _chunkVoxelID.y = posY & 31; - _chunkVoxelID.z = posZ & 31; - } - - // Extracts the chunk coordinaes and the chunk voxel chunk coordinates from - // a world position - inline void extractChunkCordinates(VoxelCordinates coords, - ChunkID& _chunkID, - ChunkVoxelID& _chunkVoxelID) { - uint16_t posX = coords.x; - uint16_t posY = coords.y; - uint16_t posZ = coords.z; - - _chunkID.x = posX >> 5; - _chunkID.y = posY >> 5; - _chunkID.z = posZ >> 5; - - _chunkVoxelID.x = posX & 31; - _chunkVoxelID.y = posY & 31; - _chunkVoxelID.z = posZ & 31; - } - - // Extracts the layer chunk coordinaes and the layer chunk voxel coordinates - // from a world position - inline void extractLayerCordinates(uint32_t x, uint32_t z, - LayerID& _layerID, - LayerVoxelID& _layerVoxelID) { - uint16_t posX = x; - uint16_t posZ = z; - - _layerID.x = posX >> 5; - _layerID.z = posZ >> 5; - - _layerVoxelID.x = posX & 31; - _layerVoxelID.z = posZ & 31; - } -} // namespace Deer diff --git a/Deer/Include/Deer/VoxelWorld.h b/Deer/Include/Deer/VoxelWorld.h deleted file mode 100755 index 5007a1f..0000000 --- a/Deer/Include/Deer/VoxelWorld.h +++ /dev/null @@ -1,209 +0,0 @@ -// copyright Copyright (c) 2025 Deer -#pragma once -#include - -#include "Deer/Tools/Memory.h" -#include "Deer/Voxel.h" - -#ifdef DEER_RENDER -#include "DeerRender/Voxel.h" -#endif - -#include "glm/glm.hpp" - -namespace Deer { - class Chunk; - class Layer; - struct SceneCamera; - struct VoxelWorldProps; - struct VoxelWorldRenderData; - - // Properties of a Voxel World - struct VoxelWorldProps { - union { - struct { - uint8_t chunkSizeX; - uint8_t chunkSizeY; - uint8_t chunkSizeZ; - }; - std::array axis; - }; - - VoxelWorldProps() = default; - VoxelWorldProps(uint8_t _chunkSizeX, uint8_t _chunkSizeY, - uint8_t _chunkSizeZ) - : chunkSizeX(_chunkSizeX), - chunkSizeY(_chunkSizeY), - chunkSizeZ(_chunkSizeZ) {} - - inline uint8_t& operator[](size_t i) { return axis[i]; } - - // Returns the count of chunks - inline int getChunkCount() const { - return chunkSizeX * chunkSizeY * chunkSizeZ; - } - // Returns the count of layers - inline int getLayerCount() const { return chunkSizeX * chunkSizeZ; } - // Returns the internal id of a chunk relative to a Voxel World Props - // from a chunk id - inline int getWorldChunkID(ChunkID chunkID) const { - return chunkID.z + chunkID.y * chunkSizeZ + - chunkID.x * chunkSizeZ * chunkSizeY; - } - // Returns the internal id of a layer relative to a Voxel World Props - // from a Layer id - inline int getWorldLayerID(LayerID layerID) const { - return layerID.z + layerID.x * chunkSizeZ; - } - - // Extracts the LayerID from a internal Layer id relative to Voxel World - // Props - inline LayerID getLayerID(int id) const { - LayerID l_id; - - l_id.x = id / chunkSizeZ; - id -= l_id.x * chunkSizeZ; - - l_id.z = id; - return l_id; - } - // Extracts the ChunkID from a internal Chunk id relative to Voxel World - // Props - inline ChunkID getChunkID(int id) const { - ChunkID c_id; - - c_id.x = id / (chunkSizeZ * chunkSizeY); - id -= c_id.x * (chunkSizeZ * chunkSizeY); - - c_id.y = id / chunkSizeZ; - id -= c_id.y * chunkSizeZ; - - c_id.z = id; - return c_id; - } - - // Checks if the Chunk id is inside the voxel World bounds - inline bool isValid(ChunkID chunkID) const { - return chunkID.x >= 0 && chunkID.x < chunkSizeX && chunkID.y >= 0 && - chunkID.y < chunkSizeY && chunkID.z >= 0 && - chunkID.z < chunkSizeZ; - } - - // Checks if the Layer id is inside the voxel World bounds - inline bool isValid(LayerID layerID) const { - return layerID.x >= 0 && layerID.x < chunkSizeX && layerID.z >= 0 && - layerID.z < chunkSizeZ; - } - - // Returns the max amount of voxels in the Voxel World Props - inline int getMaxVoxelCount() const { - return getChunkCount() * CHUNK_VOXELS; - } - - // Clamps the coordinates of a Voxel World Coordinates to be inside the - // voxel world props - inline void clampCordinates(VoxelCordinates& coords) const { - if (coords.x < 0) - coords.x = 0; - else if (coords.x >= chunkSizeX * CHUNK_SIZE_X) - coords.x = chunkSizeX * CHUNK_SIZE_X - 1; - - if (coords.y < 0) - coords.y = 0; - else if (coords.y >= chunkSizeY * CHUNK_SIZE_Y) - coords.y = chunkSizeY * CHUNK_SIZE_Y - 1; - - if (coords.z < 0) - coords.z = 0; - else if (coords.z >= chunkSizeZ * CHUNK_SIZE_Z) - coords.z = chunkSizeZ * CHUNK_SIZE_Z - 1; - } - - // Takes 2 Voxel coordinates and outputs them in the same variables - // being the min with the min values and the max with the max This is - // useful for loops - inline void clampAndSetMinMax(VoxelCordinates& min, - VoxelCordinates& max) const { - VoxelCordinates a_cache = min; - VoxelCordinates b_cache = max; - - for (int x = 0; x < 3; x++) { - if (a_cache[x] > b_cache[x]) { - max[x] = a_cache[x]; - min[x] = b_cache[x]; - } else { - min[x] = a_cache[x]; - max[x] = b_cache[x]; - } - } - - clampCordinates(min); - clampCordinates(max); - } - }; - - // Class to manage the voxels - namespace VoxelWorld { - void initialize(const VoxelWorldProps&); - void clear(); - - // Returns the voxel in a voxel coordinates - Voxel readVoxel(VoxelCordinates); - // Sets the voxel in the coordinates to the value - void setVoxel(VoxelCordinates, Voxel value); - - // Fills a space with the voxel value inside the 2 coordinates - // Note that you don't have to give then ordeered by min and max - void fillVoxels(VoxelCordinates, VoxelCordinates, Voxel value); - // Remplaces the ref voxel with the value of a space inside the 2 coordinates - // Note that you don't have to give then ordeered by min and max - void remplaceVoxels(VoxelCordinates, VoxelCordinates, Voxel ref, Voxel value); - - // Returns the layer data of a woorld coordinates - // Note out of bounds will return a default Layer Voxel - LayerVoxel readLayerVoxel(int x, int z); - // Calculates the max height of a layer in a space - // Note out of bounds will return a 0 of height - // Tip: this will calculate, you should use the cached height in a layer voxel - uint16_t calculateLayerVoxelHeight(int x, int z); - - // Raycast a ray from a source and dir - VoxelRayResult rayCast(glm::vec3 position, glm::vec3 dir, - float maxDistance = 10.0f); - // Raycast a ray from a source and dir ignoring if the ray stats inside a voxel - VoxelRayResult rayCast_editor(glm::vec3 position, glm::vec3 dir, - float maxDistance = 10.0f); - - bool isInitialized(); - - // Returns the voxel world props used in the voxel world - // Note that you can't change the world size unless you create a new Voxel World - const VoxelWorldProps& getWorldProps(); -#ifdef DEER_RENDER - // Renders the current voxel world with a specified scene camera - void render(const SceneCamera&); - // Generates the next chunk mesh - void bakeNextChunk(); - - // Light data - VoxelLight readLight(VoxelCordinates); - VoxelLight& modLight(VoxelCordinates); - - // Chunk vertex creation - void genSolidVoxel(ChunkID chunkID, ChunkVoxelID chunkVoxelID); - - // --- Light propagation --- - // Warning: This function is private and needs to have min and max - // clamped and in order - void bakeVoxelLight(VoxelCordinates min, VoxelCordinates max); - void bakeVoxelLightFromPoint(VoxelCordinates); - void bakeAmbientLight(int minX, int maxX, int minZ, int maxZ); - void bakeAmbientLightFromPoint(int x, int z); - - void resolveNextAmbientLightPropagation(); - void resolveNextVoxelLightPropagation(); -#endif - - LayerVoxel& modLayerVoxel(int x, int z); - } // namespace VoxelWorld -} // namespace Deer diff --git a/Deer/Include/Deer/Application.h b/Deer/Include/DeerCore/Application.h similarity index 93% rename from Deer/Include/Deer/Application.h rename to Deer/Include/DeerCore/Application.h index 3e4e44c..b7bff53 100755 --- a/Deer/Include/Deer/Application.h +++ b/Deer/Include/DeerCore/Application.h @@ -1,5 +1,5 @@ #pragma once -#include "Deer/Tools/Memory.h" +#include "DeerCore/Tools/Memory.h" namespace Deer { class ImGuiLayer; diff --git a/Deer/Include/Deer/Components.h b/Deer/Include/DeerCore/Components.h similarity index 95% rename from Deer/Include/Deer/Components.h rename to Deer/Include/DeerCore/Components.h index 1b1e765..1bb3524 100755 --- a/Deer/Include/Deer/Components.h +++ b/Deer/Include/DeerCore/Components.h @@ -1,6 +1,6 @@ #pragma once -#include "Deer/Tools/Memory.h" -#include "Deer/Tools/SmallVector.h" +#include "DeerCore/Tools/Memory.h" +#include "DeerCore/Tools/SmallVector.h" #define GLM_ENABLE_EXPERIMENTAL #include @@ -9,7 +9,7 @@ #include #include -#include "Deer/Log.h" +#include "DeerCore/Log.h" #include "glm/glm.hpp" #include "glm/gtc/quaternion.hpp" diff --git a/Deer/Include/Deer/DataManagment.h b/Deer/Include/DeerCore/DataManagment.h similarity index 97% rename from Deer/Include/Deer/DataManagment.h rename to Deer/Include/DeerCore/DataManagment.h index 30dd66f..a0460b8 100644 --- a/Deer/Include/Deer/DataManagment.h +++ b/Deer/Include/DeerCore/DataManagment.h @@ -1,6 +1,6 @@ #pragma once -#include "Deer/Tools/Memory.h" -#include "Deer/Tools/TypeDefs.h" +#include "DeerCore/Tools/Memory.h" +#include "DeerCore/Tools/TypeDefs.h" #include #include diff --git a/Deer/Include/Deer/DataStore.h b/Deer/Include/DeerCore/DataStore.h similarity index 98% rename from Deer/Include/Deer/DataStore.h rename to Deer/Include/DeerCore/DataStore.h index 9b8f0de..7db6fdf 100755 --- a/Deer/Include/Deer/DataStore.h +++ b/Deer/Include/DeerCore/DataStore.h @@ -3,7 +3,7 @@ #include #include -#include "Deer/Tools/Path.h" +#include "DeerCore/Tools/Path.h" #define DEER_RESOURCE_PATH "Assets" diff --git a/Deer/Include/Deer/Enviroment.h b/Deer/Include/DeerCore/Enviroment.h similarity index 96% rename from Deer/Include/Deer/Enviroment.h rename to Deer/Include/DeerCore/Enviroment.h index f781d2e..6019841 100755 --- a/Deer/Include/Deer/Enviroment.h +++ b/Deer/Include/DeerCore/Enviroment.h @@ -1,8 +1,8 @@ #pragma once -#include "Deer/Components.h" -#include "Deer/Log.h" -#include "Deer/Tools/Memory.h" -#include "Deer/Resource.h" +#include "DeerCore/Components.h" +#include "DeerCore/Log.h" +#include "DeerCore/Resource.h" +#include "DeerCore/Tools/Memory.h" #include "entt/entt.hpp" @@ -63,7 +63,7 @@ namespace Deer { // Obtains the entity that is on the root of the environment inline Entity& getRoot() { return getEntity(0); } #ifdef DEER_RENDER - void render(SceneCamera& camera); + void render(const SceneCamera& camera); #endif Scope m_registry; diff --git a/Deer/Include/Deer/Log.h b/Deer/Include/DeerCore/Log.h similarity index 98% rename from Deer/Include/Deer/Log.h rename to Deer/Include/DeerCore/Log.h index ca9194b..3824d9f 100755 --- a/Deer/Include/Deer/Log.h +++ b/Deer/Include/DeerCore/Log.h @@ -1,5 +1,5 @@ #pragma once -#include "Deer/Tools/Memory.h" +#include "DeerCore/Tools/Memory.h" #include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/spdlog.h" diff --git a/Deer/Include/DeerCore/Network.h b/Deer/Include/DeerCore/Network.h new file mode 100644 index 0000000..1808e52 --- /dev/null +++ b/Deer/Include/DeerCore/Network.h @@ -0,0 +1,35 @@ +#pragma once +#include "DeerCore/Tools/Memory.h" +#include "DeerCore/Tools/TypeDefs.h" + +typedef struct _ENetPeer ENetPeer; + +namespace Deer { + namespace Network { + struct ServerSettings; + struct DeerClient; + + void initServer(const ServerSettings&); + void shutdownServer(); + + void flushServerEvents(); + + enum class DeerClientState : int { + NotConnected = 0, + Connected = 1 + }; + + struct DeerClient { + DeerClientState clientState = DeerClientState::NotConnected; + ENetPeer* internalPeer = nullptr; + }; + + struct ServerSettings { + uint32_t port = 500; + uint32_t maxClients = 32; + uint32_t maxOutgoingBand = 0; + uint32_t maxIncomingBand = 0; + }; + + } // namespace Network +} // namespace Deer \ No newline at end of file diff --git a/Deer/Include/Deer/Resource.h b/Deer/Include/DeerCore/Resource.h similarity index 95% rename from Deer/Include/Deer/Resource.h rename to Deer/Include/DeerCore/Resource.h index 1a84845..6e57b3b 100644 --- a/Deer/Include/Deer/Resource.h +++ b/Deer/Include/DeerCore/Resource.h @@ -1,9 +1,9 @@ #pragma once -#include "Deer/DataManagment.h" -#include "Deer/Log.h" -#include "Deer/Tools/Memory.h" -#include "Deer/Tools/Path.h" -#include "Deer/Tools/TypeDefs.h" +#include "DeerCore/DataManagment.h" +#include "DeerCore/Log.h" +#include "DeerCore/Tools/Memory.h" +#include "DeerCore/Tools/Path.h" +#include "DeerCore/Tools/TypeDefs.h" #include #include @@ -94,7 +94,7 @@ namespace Deer { static Resource loadResourceFromData(const typename ResourceBuilder::BaseDataType& resourceData, const std::string& storageId) { if (resourceCache.contains(storageId)) return resourceCache[storageId]; - + Scope data = ResourceBuilder::buildResource(resourceData); Resource resource = Resource::unsafeFromId(resources.size()); diff --git a/Deer/Include/Deer/Scene.h b/Deer/Include/DeerCore/Scene.h similarity index 59% rename from Deer/Include/Deer/Scene.h rename to Deer/Include/DeerCore/Scene.h index 16abd5b..168ff5c 100755 --- a/Deer/Include/Deer/Scene.h +++ b/Deer/Include/DeerCore/Scene.h @@ -1,19 +1,9 @@ #pragma once -#include "Deer/DataStore.h" -#include "Deer/Tools/Memory.h" -#include "Deer/Tools/Path.h" - -#ifdef DEER_RENDER -#include "DeerRender/GizmoRenderer.h" -#endif - -#include -#include -#include -#include +#include "DeerCore/Tools/TypeDefs.h" namespace Deer { class Environment; + class SceneCamera; class GizmoRenderer; // A scene is a 3d simulation with its environment and voxel world in case @@ -33,19 +23,10 @@ namespace Deer { #ifdef DEER_RENDER // This function renders with the default camera in the environment void render(); - void render(SceneCamera); + void render(const SceneCamera&); extern GizmoRenderer gizmoRenderer; #endif extern Environment environment; } // namespace Scene - - // Namespace to manage scenes in memory - namespace DataStore { - void loadScene(const Path& name); - void exportScene(const Path& name); - - void exportRuntimeScene(); - void importRuntimeScene(); - } // namespace DataStore } // namespace Deer diff --git a/Deer/Include/Deer/Tools/Memory.h b/Deer/Include/DeerCore/Tools/Memory.h similarity index 100% rename from Deer/Include/Deer/Tools/Memory.h rename to Deer/Include/DeerCore/Tools/Memory.h diff --git a/Deer/Include/Deer/Tools/Path.h b/Deer/Include/DeerCore/Tools/Path.h similarity index 100% rename from Deer/Include/Deer/Tools/Path.h rename to Deer/Include/DeerCore/Tools/Path.h diff --git a/Deer/Include/Deer/Tools/SmallVector.h b/Deer/Include/DeerCore/Tools/SmallVector.h similarity index 100% rename from Deer/Include/Deer/Tools/SmallVector.h rename to Deer/Include/DeerCore/Tools/SmallVector.h diff --git a/Deer/Include/Deer/Tools/TypeDefs.h b/Deer/Include/DeerCore/Tools/TypeDefs.h similarity index 100% rename from Deer/Include/Deer/Tools/TypeDefs.h rename to Deer/Include/DeerCore/Tools/TypeDefs.h diff --git a/Deer/Include/DeerRender/Application.h b/Deer/Include/DeerRender/Application.h index 0ef5071..56d5107 100644 --- a/Deer/Include/DeerRender/Application.h +++ b/Deer/Include/DeerRender/Application.h @@ -1,4 +1,4 @@ -#include "Deer/Application.h" +#include "DeerCore/Application.h" #ifdef DEER_RENDER #include "DeerRender/Events/ApplicationEvent.h" @@ -7,8 +7,8 @@ #endif namespace Deer { - namespace Application { - using EventFunction = void(*)(Event&); + namespace Application { + using EventFunction = void (*)(Event&); void initWindow(); void shutdownWindow(); @@ -17,5 +17,5 @@ namespace Deer { void setEventCallback(EventFunction); Window& getWindow(); - } -} \ No newline at end of file + } // namespace Application +} // namespace Deer \ No newline at end of file diff --git a/Deer/Include/DeerRender/Components.h b/Deer/Include/DeerRender/Components.h index 9064eb3..f10e57a 100755 --- a/Deer/Include/DeerRender/Components.h +++ b/Deer/Include/DeerRender/Components.h @@ -1,5 +1,5 @@ #pragma once -#include "Deer/Components.h" +#include "DeerCore/Components.h" #include "DeerRender/Mesh.h" #include "DeerRender/Shader.h" diff --git a/Deer/Include/DeerRender/DataManagment.h b/Deer/Include/DeerRender/DataManagment.h index 37079ef..125a73b 100644 --- a/Deer/Include/DeerRender/DataManagment.h +++ b/Deer/Include/DeerRender/DataManagment.h @@ -1,2 +1,2 @@ #pragma once -#include "Deer/DataManagment.h" \ No newline at end of file +#include "DeerCore/DataManagment.h" \ No newline at end of file diff --git a/Deer/Include/DeerRender/DataStore.h b/Deer/Include/DeerRender/DataStore.h index ab2d871..97b9aca 100644 --- a/Deer/Include/DeerRender/DataStore.h +++ b/Deer/Include/DeerRender/DataStore.h @@ -1,2 +1,2 @@ #pragma once -#include "Deer/DataStore.h" \ No newline at end of file +#include "DeerCore/DataStore.h" \ No newline at end of file diff --git a/Deer/Include/DeerRender/Enviroment.h b/Deer/Include/DeerRender/Enviroment.h index 937f805..6870c0e 100644 --- a/Deer/Include/DeerRender/Enviroment.h +++ b/Deer/Include/DeerRender/Enviroment.h @@ -1,2 +1,2 @@ #pragma once -#include "Deer/Enviroment.h" \ No newline at end of file +#include "DeerCore/Enviroment.h" \ No newline at end of file diff --git a/Deer/Include/DeerRender/GizmoRenderer.h b/Deer/Include/DeerRender/GizmoRenderer.h deleted file mode 100755 index c72c8e2..0000000 --- a/Deer/Include/DeerRender/GizmoRenderer.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include "glm/glm.hpp" - -#include -#include - -#define GIZMO_DEPTH 8 - -namespace Deer { - struct SceneCamera; - struct GizmoFace { - glm::vec3 positions[4]; - uint16_t textureID; - uint8_t face; - }; - - class GizmoRenderer { - public: - void drawLine(glm::vec3 a, glm::vec3 b, glm::vec3 color = glm::vec3(1.0f, 1.0f, 1.0f)); - void drawVoxelLine(int x, int y, int z, glm::vec3 color = glm::vec3(1.0f, 1.0f, 1.0f)); - void drawVoxelLineFace(int x, int y, int z, uint8_t face, glm::vec3 color = glm::vec3(1.0f, 1.0f, 1.0f)); - - void drawVoxelFace(int x, int y, int z, uint16_t voxelID, uint8_t face, uint8_t priority = 0); - void drawVoxelFaceInverted(int x, int y, int z, uint16_t voxelID, uint8_t face, uint8_t priority = 0); - - void render(const SceneCamera& camera); - void refresh(); - private: - std::vector> m_lines; - std::array, GIZMO_DEPTH> m_faces; - }; -} - diff --git a/Deer/Include/DeerRender/Input.h b/Deer/Include/DeerRender/Input.h index 247b0fd..45e4760 100755 --- a/Deer/Include/DeerRender/Input.h +++ b/Deer/Include/DeerRender/Input.h @@ -1,14 +1,14 @@ #pragma once -#include "Deer/Application.h" +#include "DeerCore/Application.h" namespace Deer { class Input { - public: + public: static bool isKeyPressed(unsigned int key); static bool isMouseButtonPressed(int button); static void getMousePos(float& x, float& y); }; -} // namespace Deer +} // namespace Deer // From GLFW #define DEER_KEY_SPACE 32 diff --git a/Deer/Include/DeerRender/Log.h b/Deer/Include/DeerRender/Log.h index 645582f..3ab6dce 100644 --- a/Deer/Include/DeerRender/Log.h +++ b/Deer/Include/DeerRender/Log.h @@ -1,2 +1,2 @@ #pragma once -#include "Deer/Log.h" \ No newline at end of file +#include "DeerCore/Log.h" \ No newline at end of file diff --git a/Deer/Include/DeerRender/Render/Buffer.h b/Deer/Include/DeerRender/Render/Buffer.h index d7de23c..517b384 100755 --- a/Deer/Include/DeerRender/Render/Buffer.h +++ b/Deer/Include/DeerRender/Render/Buffer.h @@ -1,5 +1,5 @@ #pragma once -#include "Deer/Tools/Memory.h" +#include "DeerCore/Tools/Memory.h" #include #include diff --git a/Deer/Include/DeerRender/Render/FrameBuffer.h b/Deer/Include/DeerRender/Render/FrameBuffer.h index 81ac883..6d4447a 100755 --- a/Deer/Include/DeerRender/Render/FrameBuffer.h +++ b/Deer/Include/DeerRender/Render/FrameBuffer.h @@ -1,9 +1,9 @@ #pragma once -#include "Deer/Log.h" +#include "DeerCore/Log.h" -#include #include +#include namespace Deer { enum class TextureBufferType { @@ -15,15 +15,15 @@ namespace Deer { unsigned int width, height; unsigned int samples; std::vector frameBufferTextures; - + bool swapChainTarget = false; FrameBufferSpecification(unsigned int _width, unsigned int _height, std::initializer_list _frameBufferTextures, unsigned int _samples = 1, bool _swapChainTarget = false) - : width(_width), height(_height), samples(_samples), frameBufferTextures(_frameBufferTextures), swapChainTarget(_swapChainTarget) { + : width(_width), height(_height), samples(_samples), frameBufferTextures(_frameBufferTextures), swapChainTarget(_swapChainTarget) { } }; class FrameBuffer { - public: + public: virtual ~FrameBuffer() = default; virtual const FrameBufferSpecification& getSpecification() = 0; @@ -32,7 +32,7 @@ namespace Deer { virtual void clear() = 0; virtual void resize(unsigned int width, unsigned int height) = 0; - + virtual unsigned int getTextureBufferID(int id = 0) = 0; virtual void clearBuffer(unsigned int bufferId, void* data) = 0; @@ -40,5 +40,4 @@ namespace Deer { static FrameBuffer* create(const FrameBufferSpecification& spec); }; -} - +} // namespace Deer diff --git a/Deer/Include/DeerRender/Render/Shader.h b/Deer/Include/DeerRender/Render/Shader.h index 7a86d3d..d6e4d66 100755 --- a/Deer/Include/DeerRender/Render/Shader.h +++ b/Deer/Include/DeerRender/Render/Shader.h @@ -1,5 +1,5 @@ #pragma once -#include "Deer/Tools/Memory.h" +#include "DeerCore/Tools/Memory.h" #include "glm/glm.hpp" diff --git a/Deer/Include/DeerRender/Render/Texture.h b/Deer/Include/DeerRender/Render/Texture.h index 98dfb88..1875baa 100755 --- a/Deer/Include/DeerRender/Render/Texture.h +++ b/Deer/Include/DeerRender/Render/Texture.h @@ -1,5 +1,5 @@ #pragma once -#include "Deer/Tools/Memory.h" +#include "DeerCore/Tools/Memory.h" #include diff --git a/Deer/Include/DeerRender/Resource.h b/Deer/Include/DeerRender/Resource.h index c2be576..fd6b8c1 100644 --- a/Deer/Include/DeerRender/Resource.h +++ b/Deer/Include/DeerRender/Resource.h @@ -1,2 +1,2 @@ #pragma once -#include "Deer/Resource.h" \ No newline at end of file +#include "DeerCore/Resource.h" \ No newline at end of file diff --git a/Deer/Include/DeerRender/Scene.h b/Deer/Include/DeerRender/Scene.h index 1a40dae..c1dd6b6 100755 --- a/Deer/Include/DeerRender/Scene.h +++ b/Deer/Include/DeerRender/Scene.h @@ -1,5 +1,5 @@ #pragma once -#include "Deer/Scene.h" +#include "DeerCore/Scene.h" #include "DeerRender/Components.h" namespace Deer { diff --git a/Deer/Include/DeerRender/Shader.h b/Deer/Include/DeerRender/Shader.h index 19d9495..ed8e63e 100644 --- a/Deer/Include/DeerRender/Shader.h +++ b/Deer/Include/DeerRender/Shader.h @@ -1,5 +1,5 @@ #pragma once -#include "Deer/Tools/Path.h" +#include "DeerCore/Tools/Path.h" #include "DeerRender/Render/Shader.h" #include "DeerRender/Resource.h" @@ -22,6 +22,11 @@ namespace Deer { } }; + namespace RenderUtils { + void initializeRenderUtils(); + void deinitializeRenderUtils(); + } // namespace RenderUtils + template <> class ResourceBuilder { public: diff --git a/Deer/Include/DeerRender/Tools/Memory.h b/Deer/Include/DeerRender/Tools/Memory.h index afda165..4026d04 100644 --- a/Deer/Include/DeerRender/Tools/Memory.h +++ b/Deer/Include/DeerRender/Tools/Memory.h @@ -1,2 +1,2 @@ #pragma once -#include "Deer/Tools/Memory.h" \ No newline at end of file +#include "DeerCore/Tools/Memory.h" \ No newline at end of file diff --git a/Deer/Include/DeerRender/Tools/Path.h b/Deer/Include/DeerRender/Tools/Path.h index a978697..ee68898 100644 --- a/Deer/Include/DeerRender/Tools/Path.h +++ b/Deer/Include/DeerRender/Tools/Path.h @@ -1,2 +1,2 @@ #pragma once -#include "Deer/Tools/Path.h" \ No newline at end of file +#include "DeerCore/Tools/Path.h" \ No newline at end of file diff --git a/Deer/Include/DeerRender/Tools/SmallVector.h b/Deer/Include/DeerRender/Tools/SmallVector.h index 4e29c66..ad0fe25 100644 --- a/Deer/Include/DeerRender/Tools/SmallVector.h +++ b/Deer/Include/DeerRender/Tools/SmallVector.h @@ -1,2 +1,2 @@ #pragma once -#include "Deer/Tools/SmallVector.h" \ No newline at end of file +#include "DeerCore/Tools/SmallVector.h" \ No newline at end of file diff --git a/Deer/Include/DeerRender/Tools/TypeDefs.h b/Deer/Include/DeerRender/Tools/TypeDefs.h index d16a559..b1c9d03 100644 --- a/Deer/Include/DeerRender/Tools/TypeDefs.h +++ b/Deer/Include/DeerRender/Tools/TypeDefs.h @@ -1,2 +1,2 @@ #pragma once -#include "Deer/Tools/TypeDefs.h" \ No newline at end of file +#include "DeerCore/Tools/TypeDefs.h" \ No newline at end of file diff --git a/Deer/Include/DeerRender/Voxel.h b/Deer/Include/DeerRender/Voxel.h deleted file mode 100755 index 38c8709..0000000 --- a/Deer/Include/DeerRender/Voxel.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include "Deer/Voxel.h" - -#define LIGHT_PROPAGATION_COMPLEX_DIRS 18 -#define LIGHT_PROPAGATION_COMPLEX_DIR(id, dir) lightPropagationComplexDir[id + dir * 2] -#define LIGHT_PROPAGATION_SIMPLE_FALL 16 -#define LIGHT_PROPAGATION_COMPLEX_FALL 23 - -#define NORMAL_VERTEX_POS(axis, id, normal) normalFacePositions[axis + id * 3 + normal * 3 * 4] -#define VERTEX_UV(axis, id) uvFace[axis + id * 2] -#define AMBIENT_OCCLUSION_VERTEX(axis, id, vertex, normal) ambientOcclusionVertex[axis + id * 3 + vertex * 3 * 2 + normal * 3 * 2 * 4] -#define LAYER_CHECK_DIRS(axis, id) layerCheckDirections[axis + id * 2] - -namespace Deer { - struct VoxelLight; - extern VoxelLight lightVoxel; - - extern int lightPropagationComplexDir[12 * 2]; - extern int normalFacePositions[3 * 4 * 6]; - extern int uvFace[2 * 4]; - // 6 Dirs * 4 vertices * 2 checks * 3 dirs - extern int ambientOcclusionVertex[6 * 4 * 2 * 3]; - extern int layerCheckDirections[2 * 8]; - - struct VoxelLight { - uint8_t r_light; - uint8_t g_light; - uint8_t b_light; - uint8_t ambient_light; - - VoxelLight(uint8_t _ambient_light = 0) : r_light(0), g_light(0), b_light(0), ambient_light(_ambient_light) {} - }; -} // namespace Deer \ No newline at end of file diff --git a/Deer/Include/DeerRender/VoxelAspect.h b/Deer/Include/DeerRender/VoxelAspect.h deleted file mode 100644 index 90ea5e7..0000000 --- a/Deer/Include/DeerRender/VoxelAspect.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file VoxelAspect.h - * @author chewico@frostdeer.com - * @brief File to save the voxel aspect data - * - * @copyright Copyright (c) 2025 - */ -#pragma once -#include "Deer/Voxel.h" - -// TEMP -#define VOXEL_TEXTURE_SIZE_X 128 -#define VOXEL_TEXTURE_SIZE_Y 128 - -namespace Deer { - struct VoxelTextureFaceDefinition { - std::string textureFaces[6]; - - inline std::string& operator[](size_t index) { - return textureFaces[index]; - } - }; - - struct VoxelColorEmission { - uint8_t r_value = 0; - uint8_t g_value = 0; - uint8_t b_value = 0; - }; - - struct VoxelAspectDefinition { - std::string voxelName; - VoxelTextureFaceDefinition textureFaces; - VoxelColorEmission colorEmission; - - VoxelAspectDefinition() = default; - }; - - struct VoxelAspect { - VoxelAspectDefinition definition; - uint16_t textureFacesIDs[6]{}; - - inline bool isLightSource() { - return definition.colorEmission.r_value || definition.colorEmission.g_value || definition.colorEmission.b_value; - } - - /** - * @brief Get the texture id for the voxel face - * - * @param face face of the texture defined in the enum NormalDirection of Voxel.h - * @return uint16_t texture id in the texture atlas - */ - inline uint16_t getTextureID(uint8_t face) { return textureFacesIDs[face]; } - }; -} \ No newline at end of file diff --git a/Deer/Include/DeerRender/VoxelWorld.h b/Deer/Include/DeerRender/VoxelWorld.h deleted file mode 100644 index 8ca640f..0000000 --- a/Deer/Include/DeerRender/VoxelWorld.h +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "Deer/VoxelWorld.h" \ No newline at end of file diff --git a/Deer/Include/DeerRender/Window.h b/Deer/Include/DeerRender/Window.h index 21873fe..f794666 100755 --- a/Deer/Include/DeerRender/Window.h +++ b/Deer/Include/DeerRender/Window.h @@ -1,5 +1,5 @@ #pragma once -#include "Deer/Tools/Path.h" +#include "DeerCore/Tools/Path.h" #include "DeerRender/Events/Event.h" #include diff --git a/Deer/src/Deer/Core/Application.cpp b/Deer/src/Deer/Core/Application.cpp deleted file mode 100644 index 1ac2ec5..0000000 --- a/Deer/src/Deer/Core/Application.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "Deer/Application.h" -#include -#include - -namespace Deer { - namespace Application { - // Implemented in DeerRender/Application - void runRender(float deltaTime); - void resolveEvents(); - - Function tickCallback; - bool running; - - const double targetUpdateTime = 1.0 / 60.0; // Fixed 60 FPS update - double targetRenderTime = 1.0 / 160.0; // User-defined render FPS - - void setTickCallback(Function _tick) { - tickCallback = _tick; - } - - void run() { - running = true; - - auto previousTime = std::chrono::high_resolution_clock::now(); - double accumulatedUpdateTime = 0.0; - double accumulatedRenderTime = 0.0; - - while (running) { - // Time handling - auto currentTime = std::chrono::high_resolution_clock::now(); - std::chrono::duration deltaTime = currentTime - previousTime; - previousTime = currentTime; - - accumulatedUpdateTime += deltaTime.count(); - accumulatedRenderTime += deltaTime.count(); - - // Fixed Update loop (60 FPS) - while (accumulatedUpdateTime >= targetUpdateTime) { - Timestep timestep = (float)targetUpdateTime; - accumulatedUpdateTime -= targetUpdateTime; - - if (tickCallback) - tickCallback(); - - } -#ifdef DEER_RENDER - if (accumulatedRenderTime >= targetRenderTime) { - runRender((float)targetRenderTime); - accumulatedRenderTime -= targetRenderTime; - } - resolveEvents(); -#endif - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - } - - void shutdown() { - running = false; - } - } -} \ No newline at end of file diff --git a/Deer/src/Deer/Scene/Components.cpp b/Deer/src/Deer/Scene/Components.cpp deleted file mode 100755 index 9f36e72..0000000 --- a/Deer/src/Deer/Scene/Components.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "Deer/Components.h" -#include "glm/gtc/matrix_transform.hpp" -#include "Deer/Log.h" - -namespace Deer { - glm::mat4 TransformComponent::getMatrix() const{ - glm::mat4 scaleMat = glm::scale(glm::mat4(1.0f), scale); - glm::mat4 roatationMat = glm::mat4(rotation); - glm::mat4 positionMat = glm::translate(glm::mat4(1.0f), position); - - return positionMat * roatationMat * scaleMat; - } - -} diff --git a/Deer/src/Deer/Scene/EnvironmentBuilder.cpp b/Deer/src/Deer/Scene/EnvironmentBuilder.cpp deleted file mode 100644 index e70261a..0000000 --- a/Deer/src/Deer/Scene/EnvironmentBuilder.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "Deer/Enviroment.h" - -namespace Deer { - Scope ResourceBuilder::buildResource(const BaseDataType& baseData) { - Scope env = MakeScope(); - return env; - } -} \ No newline at end of file diff --git a/Deer/src/Deer/Scene/SceneData.cpp b/Deer/src/Deer/Scene/SceneData.cpp deleted file mode 100644 index b8d4053..0000000 --- a/Deer/src/Deer/Scene/SceneData.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "Deer/Enviroment.h" -#include "Deer/Tools/Memory.h" - -#ifdef DEER_RENDER -#include "DeerRender/GizmoRenderer.h" -#endif - -namespace Deer { - namespace Scene { - Environment environment; - bool isExecuting = false; - -#ifdef DEER_RENDER - GizmoRenderer gizmoRenderer; -#endif - } // namespace Scene - -} // namespace Deer diff --git a/Deer/src/Deer/Scene/Serialization/Components/TransformComponentSerialization.h b/Deer/src/Deer/Scene/Serialization/Components/TransformComponentSerialization.h deleted file mode 100755 index 8eb4c5c..0000000 --- a/Deer/src/Deer/Scene/Serialization/Components/TransformComponentSerialization.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "Deer/Components.h" - -namespace Deer { - - // TRANSFORM COMPONENT - template - void serialize(Archive& archive, - TransformComponent& transform) { - - archive(cereal::make_nvp("position", transform.position)); - archive(cereal::make_nvp("scale", transform.scale)); - archive(cereal::make_nvp("rotation", transform.rotation)); - } - -} \ No newline at end of file diff --git a/Deer/src/Deer/Voxels/Chunk.cpp b/Deer/src/Deer/Voxels/Chunk.cpp deleted file mode 100755 index 789c2e7..0000000 --- a/Deer/src/Deer/Voxels/Chunk.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "Chunk.h" - -namespace Deer { - Chunk::~Chunk() { - if (m_voxels) { - delete[] m_voxels; -#ifdef DEER_RENDER - delete[] m_lightInfo; -#endif - } - } - - void Chunk::loadVoxels() { - if (!m_voxels) { - m_voxels = new Voxel[CHUNK_VOXELS](); -#ifdef DEER_RENDER - m_lightInfo = new VoxelLight[CHUNK_VOXELS](); -#endif - } - } -} diff --git a/Deer/src/Deer/Voxels/Chunk.h b/Deer/src/Deer/Voxels/Chunk.h deleted file mode 100755 index 80a2b94..0000000 --- a/Deer/src/Deer/Voxels/Chunk.h +++ /dev/null @@ -1,143 +0,0 @@ -#pragma once -#include "Deer/Voxel.h" - -#ifdef DEER_RENDER -#include - -#include "DeerRender/Voxel.h" -#include "DeerRender/VoxelAspect.h" -#endif - -#include - -namespace Deer { - class Chunk { - public: - Chunk() = default; - ~Chunk(); - - inline Voxel readVoxel(ChunkVoxelID id) { - if (m_voxels) - return m_voxels[VOXEL_POSITION(id)]; - return emptyVoxel; - } - - inline Voxel& modVoxel(ChunkVoxelID id) { - if (!m_voxels) - loadVoxels(); - return m_voxels[VOXEL_POSITION(id)]; - } - - inline void fillVoxels(ChunkVoxelID min, ChunkVoxelID max, Voxel info) { - if (!m_voxels) - loadVoxels(); - - ChunkVoxelID voxelID; - for (voxelID.x = min.x; voxelID.x <= max.x; voxelID.x++) { - for (voxelID.y = min.y; voxelID.y <= max.y; voxelID.y++) { - for (voxelID.z = min.z; voxelID.z <= max.x; voxelID.z++) { - m_voxels[VOXEL_POSITION(voxelID)] = info; - } - } - } - } - - inline void remplaceVoxels(ChunkVoxelID min, ChunkVoxelID max, - Voxel ref, Voxel value) { - if (!m_voxels) - loadVoxels(); - - ChunkVoxelID voxelID; - for (voxelID.x = min.x; voxelID.x <= max.x; voxelID.x++) { - for (voxelID.y = min.y; voxelID.y <= max.y; voxelID.y++) { - for (voxelID.z = min.z; voxelID.z <= max.z; voxelID.z++) { - Voxel& currentVoxel = m_voxels[VOXEL_POSITION(voxelID)]; - - if (currentVoxel.id == ref.id) - currentVoxel = value; - } - } - } - } - - inline uint8_t calculateLayerVoxelHeight(LayerVoxelID layerVoxelID) { - if (!m_voxels) - return 0; - - ChunkVoxelID voxelID(layerVoxelID.x, CHUNK_SIZE_Y - 1, - layerVoxelID.z); - for (int y = CHUNK_SIZE_Y - 1; y >= 0; y--) { - voxelID.y = y; - - if (m_voxels[VOXEL_POSITION(voxelID)].id != 0) - return voxelID.y + 1; - } - return 0; - } - - private: - Voxel* m_voxels = nullptr; - - void loadVoxels(); -#ifdef DEER_RENDER - public: - inline VoxelLight readLight(ChunkVoxelID id) { - if (m_voxels) - return m_lightInfo[VOXEL_POSITION(id)]; - return VoxelLight(); - } - - inline VoxelLight& modLight(ChunkVoxelID id) { - if (!m_voxels) - loadVoxels(); - return m_lightInfo[VOXEL_POSITION(id)]; - } - - inline void clearVoxelLight(ChunkVoxelID min, ChunkVoxelID max) { - ChunkVoxelID voxelID; - for (voxelID.x = min.x; voxelID.x <= max.x; voxelID.x++) { - for (voxelID.y = min.y; voxelID.y <= max.y; voxelID.y++) { - for (voxelID.z = min.z; voxelID.z <= max.z; voxelID.z++) { - m_lightInfo[VOXEL_POSITION(voxelID)].b_light = 0; - m_lightInfo[VOXEL_POSITION(voxelID)].r_light = 0; - m_lightInfo[VOXEL_POSITION(voxelID)].g_light = 0; - } - } - } - } - - // This function is the same as clear Voxel Light but it also checks if - // there is a source of light - inline void clearVoxelLightAndSaveSources( - ChunkVoxelID min, ChunkVoxelID max, ChunkID chunkID, - std::vector& sources) { - if (!m_voxels) - return; - - ChunkVoxelID voxelID; - for (voxelID.x = min.x; voxelID.x <= max.x; voxelID.x++) { - for (voxelID.y = min.y; voxelID.y <= max.y; voxelID.y++) { - for (voxelID.z = min.z; voxelID.z <= max.z; voxelID.z++) { - Voxel voxel = m_voxels[VOXEL_POSITION(voxelID)]; - VoxelAspect& voxelAspect = - DataStore::voxelsAspect[voxel.id]; - if (voxelAspect.isLightSource()) { - sources.push_back(VoxelCordinates( - voxelID.x + chunkID.x * CHUNK_SIZE_X, - voxelID.y + chunkID.y * CHUNK_SIZE_Y, - voxelID.z + chunkID.z * CHUNK_SIZE_Z)); - } - - m_lightInfo[VOXEL_POSITION(voxelID)].b_light = 0; - m_lightInfo[VOXEL_POSITION(voxelID)].r_light = 0; - m_lightInfo[VOXEL_POSITION(voxelID)].g_light = 0; - } - } - } - } - - private: - VoxelLight* m_lightInfo = nullptr; -#endif - }; -} // namespace Deer diff --git a/Deer/src/Deer/Voxels/Layer.cpp b/Deer/src/Deer/Voxels/Layer.cpp deleted file mode 100755 index 9df256e..0000000 --- a/Deer/src/Deer/Voxels/Layer.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "Layer.h" - -namespace Deer { - Layer::~Layer() { - if (m_layerInfo) - delete[] m_layerInfo; - } - - void Layer::loadData() { - m_layerInfo = new LayerVoxel[LAYER_VOXELS](); - } -} \ No newline at end of file diff --git a/Deer/src/Deer/Voxels/Layer.h b/Deer/src/Deer/Voxels/Layer.h deleted file mode 100755 index 0d2c17c..0000000 --- a/Deer/src/Deer/Voxels/Layer.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include "Deer/Voxel.h" - -namespace Deer { - class Layer { - public: - Layer() = default; - ~Layer(); - - inline LayerVoxel readLayerVoxel(LayerVoxelID id) { - if (!m_layerInfo) - return LayerVoxel(); - return m_layerInfo[LAYER_VOXEL_POSITION(id)]; - } - - inline LayerVoxel& modLayerVoxel(LayerVoxelID id) { - if (!m_layerInfo) - loadData(); - return m_layerInfo[LAYER_VOXEL_POSITION(id)]; - } - - inline void fillVoxelLayerMaxHeight(LayerVoxelID min, LayerVoxelID max, uint8_t maxHeight) { - if (!m_layerInfo) - loadData(); - - LayerVoxelID layerVoxelID; - for (layerVoxelID.x = min.x; layerVoxelID.x <= max.x; layerVoxelID.x++) { - for (layerVoxelID.z = min.x; layerVoxelID.z <= max.z; layerVoxelID.z++) { - int id = LAYER_VOXEL_POSITION(layerVoxelID); - if (m_layerInfo[id].height <= maxHeight) - m_layerInfo[id].height = maxHeight + 1; - } - } - } - private: - void loadData(); - - LayerVoxel* m_layerInfo = nullptr; - }; -} \ No newline at end of file diff --git a/Deer/src/Deer/Voxels/Serialization/VoxelInfoSerialization.h b/Deer/src/Deer/Voxels/Serialization/VoxelInfoSerialization.h deleted file mode 100644 index a346f74..0000000 --- a/Deer/src/Deer/Voxels/Serialization/VoxelInfoSerialization.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -#include "Deer/Voxel.h" -#include "Deer/Log.h" - -#include "cereal/cereal.hpp" -#include "cereal/types/string.hpp" - -namespace Deer{ - template - void save(Archive & archive, VoxelInfo const & block) { - archive(cereal::make_nvp("name", block.name)); - - // To avoid breaking things we set it up to Air - const char* blockTypeChar = VOXEL_INFO_TYPE_AIR; - switch (block.type) - { - case VoxelInfoType::Air : - blockTypeChar = VOXEL_INFO_TYPE_AIR; - break; - case VoxelInfoType::Voxel : - blockTypeChar = VOXEL_INFO_TYPE_VOXEL; - break; - case VoxelInfoType::TransparentVoxel : - blockTypeChar = VOXEL_INFO_TYPE_TRANSPARENT_VOXEL; - break; - case VoxelInfoType::Custom : - blockTypeChar = VOXEL_INFO_TYPE_CUSTOM; - break; - } - - std::string blockTypeString(blockTypeChar); - archive(cereal::make_nvp("type", blockTypeString)); - } - - template - void load(Archive & archive, VoxelInfo & block) {archive(cereal::make_nvp("name", block.name)); - std::string blockTypeString; - - archive(cereal::make_nvp("name", block.name)); - archive(cereal::make_nvp("type", blockTypeString)); - - if (blockTypeString == VOXEL_INFO_TYPE_AIR) - block.type = VoxelInfoType::Air; - else if (blockTypeString == VOXEL_INFO_TYPE_VOXEL) - block.type = VoxelInfoType::Voxel; - else if (blockTypeString == VOXEL_INFO_TYPE_TRANSPARENT_VOXEL) - block.type = VoxelInfoType::TransparentVoxel; - else if (blockTypeString == VOXEL_INFO_TYPE_CUSTOM) - block.type = VoxelInfoType::Custom; - else { - block.type = VoxelInfoType::Air; - DEER_CORE_ERROR("Failed to resolve voxel type for {0}, unknown type : {1}", - block.name.c_str(), blockTypeString.c_str()); - } - } -} \ No newline at end of file diff --git a/Deer/src/Deer/Voxels/Voxel.cpp b/Deer/src/Deer/Voxels/Voxel.cpp deleted file mode 100755 index 058abd5..0000000 --- a/Deer/src/Deer/Voxels/Voxel.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "Deer/Voxel.h" - -namespace Deer { - // This means the voxel is null - Voxel nullVoxel(65535); - Voxel emptyVoxel; - - LayerVoxel nullLayerVoxel(65535); - - int normalDirs[3 * 6] = { - -1, 0, 0, - 1, 0, 0, - 0, -1, 0, - 0, 1, 0, - 0, 0, -1, - 0, 0, 1 - }; - -} diff --git a/Deer/src/Deer/Voxels/VoxelData.cpp b/Deer/src/Deer/Voxels/VoxelData.cpp deleted file mode 100644 index bb57d1b..0000000 --- a/Deer/src/Deer/Voxels/VoxelData.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include -#include -#include - -#include "Deer/DataStore.h" -#include "Deer/Log.h" -#include "Deer/Voxel.h" -#include "Deer/Voxels/Serialization/VoxelInfoSerialization.h" -#include "cereal/archives/json.hpp" - -namespace Deer { - namespace DataStore { - std::vector voxelsInfo; - std::unordered_map blockIDMap; - } // namespace DataStore - - int32_t DataStore::getVoxelID(const std::string& name) { - if (blockIDMap.contains(name)) - return blockIDMap[name]; - DEER_CORE_WARN("Voxel Info {0} Not Found!", name.c_str()); - return -1; - } - - void DataStore::loadVoxelsData() { - voxelsInfo.clear(); - blockIDMap.clear(); - - VoxelInfo airVoxelInfo; - airVoxelInfo.name = VOXEL_INFO_TYPE_AIR; - - voxelsInfo.push_back(airVoxelInfo); - blockIDMap[VOXEL_INFO_TYPE_AIR] = 0; - - std::vector voxelsData; - voxelsData = DataStore::getFiles(DEER_VOXEL_DATA_PATH, ".voxel"); - - DEER_CORE_TRACE("Loading voxels"); - for (Path& voxel : voxelsData) { - VoxelInfo voxelData; - - uint32_t dataSize; - uint8_t* data = DataStore::readFile(voxel, &dataSize); - - std::string dataString((char*)data, dataSize); - std::istringstream dataInputStream(dataString); - { - cereal::JSONInputArchive archive(dataInputStream); - archive(cereal::make_nvp("voxel", voxelData)); - } - - if (voxelData.name.empty()) { - DEER_CORE_ERROR("{0} has an empty name", - voxel.generic_string().c_str()); - continue; - } - - if (blockIDMap.contains(voxelData.name)) { - DEER_CORE_ERROR("{0} with name {1} has dupplicated name id", - voxel.generic_string().c_str(), - voxelData.name.c_str()); - continue; - } - - uint32_t id = voxelsInfo.size(); - - voxelsInfo.push_back(voxelData); - blockIDMap[voxelData.name] = id; - - delete data; - } - } - - void DataStore::createExampleVoxelData() { - VoxelInfo block; - - std::stringstream data; - { - cereal::JSONOutputArchive archive(data); - archive(cereal::make_nvp("voxel", block)); - } - - DataStore::saveFile(Path(DEER_VOXEL_PATH) / "voxel.example", - (uint8_t*)(data.str().c_str()), data.str().size()); - } -} // namespace Deer \ No newline at end of file diff --git a/Deer/src/Deer/Voxels/VoxelWorld.cpp b/Deer/src/Deer/Voxels/VoxelWorld.cpp deleted file mode 100755 index 61c1ac0..0000000 --- a/Deer/src/Deer/Voxels/VoxelWorld.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "Deer/VoxelWorld.h" -#include "Deer/Voxels/VoxelWorldData.h" - -#include "Deer/Log.h" -#include "Deer/Voxels/Chunk.h" -#include "Deer/Voxels/Layer.h" - -#ifdef DEER_RENDER -#include "DeerRender/Voxels/VoxelWorldRenderData.h" -#endif - -#include - -#include -#include - -namespace Deer { - void VoxelWorld::initialize(const VoxelWorldProps& props) { - clear(); - - worldProps = props; - - chunks = MakeScope(worldProps.getChunkCount()); - layers = MakeScope(worldProps.getLayerCount()); - -#ifdef DEER_RENDER - initializeRenderVars(props); -#endif - initialized = true; - } - - void VoxelWorld::clear() { - chunks.reset(); - layers.reset(); - - initialized = false; -#ifdef DEER_RENDER - clearRenderVars(); -#endif - } - - const VoxelWorldProps& VoxelWorld::getWorldProps() { - return worldProps; - } - - uint16_t VoxelWorld::calculateLayerVoxelHeight(int x, int z) { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - LayerVoxelID layerVoxelID; - LayerID layerID; - - extractLayerCordinates(x, z, layerID, layerVoxelID); - ChunkID chunkID(layerID.x, 0, layerID.z); - - for (int y = worldProps.chunkSizeY - 1; y >= 0; y--) { - chunkID.y = y; - - Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)]; - uint8_t chunkVoxelHeight = - chunk.calculateLayerVoxelHeight(layerVoxelID); - - if (chunkVoxelHeight != 0) { - return chunkVoxelHeight + chunkID.y * CHUNK_SIZE_Y; - } - } - - return 0; - } -} // namespace Deer diff --git a/Deer/src/Deer/Voxels/VoxelWorldData.cpp b/Deer/src/Deer/Voxels/VoxelWorldData.cpp deleted file mode 100644 index 2ff9604..0000000 --- a/Deer/src/Deer/Voxels/VoxelWorldData.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "Deer/Voxels/VoxelWorldData.h" -#include "Deer/Voxels/Chunk.h" -#include "Deer/Voxels/Layer.h" - -namespace Deer { - namespace VoxelWorld { - VoxelWorldProps worldProps; - - Scope chunks; - Scope layers; - - bool initialized; - } - - bool VoxelWorld::isInitialized() { - return initialized; - } -} \ No newline at end of file diff --git a/Deer/src/Deer/Voxels/VoxelWorldData.h b/Deer/src/Deer/Voxels/VoxelWorldData.h deleted file mode 100644 index c183050..0000000 --- a/Deer/src/Deer/Voxels/VoxelWorldData.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "Deer/Tools/Memory.h" -#include "Deer/VoxelWorld.h" - -namespace Deer { - namespace VoxelWorld { - extern VoxelWorldProps worldProps; - - extern Scope chunks; - extern Scope layers; - extern bool initialized; - } // namespace VoxelWorld -} // namespace Deer \ No newline at end of file diff --git a/Deer/src/Deer/Voxels/VoxelWorld_Raycast.cpp b/Deer/src/Deer/Voxels/VoxelWorld_Raycast.cpp deleted file mode 100644 index 123abe6..0000000 --- a/Deer/src/Deer/Voxels/VoxelWorld_Raycast.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "Deer/VoxelWorld.h" -#include "Deer/Log.h" -#include "Deer/Voxels/Chunk.h" -#include "Deer/Voxels/Layer.h" -#include "Deer/Voxels/VoxelWorldData.h" - -#include -#include -#include - -namespace Deer { - VoxelRayResult VoxelWorld::rayCast(glm::vec3 position, glm::vec3 dir, float maxDistance) { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - VoxelRayResult result; - - result.hitPos.x = (int32_t)std::floor(position.x); - result.hitPos.y = (int32_t)std::floor(position.y); - result.hitPos.z = (int32_t)std::floor(position.z); - - result.distance = 0; - - if (dir.x == 0 && dir.y == 0 && dir.z == 0) { - return result; - } - - dir = glm::normalize(dir); - - glm::vec3 stepAxis = glm::vec3(maxDistance, maxDistance, maxDistance); - glm::vec3 distanceAxis = glm::vec3(maxDistance, maxDistance, maxDistance); - - int8_t directionAxis[3] = { 1, 1, 1 }; - - for (int i = 0; i < 3; i++) { - if (dir[i] < 0) { - stepAxis[i] = -1.0f / dir[i]; - directionAxis[i] = -1; - distanceAxis[i] = stepAxis[i] * ((float)position[i] - (float)(&result.hitPos.x)[i]); - } - else if (dir[i] > 0) { - stepAxis[i] = 1.0f / dir[i]; - distanceAxis[i] = stepAxis[i] * (1 - (float)position[i] + (float)(&result.hitPos.x)[i]); - } - } - - while (result.distance < maxDistance) { - float minDistance = distanceAxis[0]; - for (int i = 1; i < 3; i++) { - if (distanceAxis[i] < minDistance) - minDistance = distanceAxis[i]; - } - - result.distance = minDistance; - if (result.distance > maxDistance) - break; - - for (int i = 0; i < 3; i++) { - if (minDistance == distanceAxis[i]) { - result.hitPos[i] += directionAxis[i]; - distanceAxis[i] = minDistance + stepAxis[i]; - - Voxel hitVoxel = readVoxel(result.hitPos); - - if (hitVoxel == nullVoxel) - continue; - - if (hitVoxel != 0) { - result.face = i * 2; - - if (directionAxis[i] == -1) - result.face++; - - return result; - } - } - } - } - - result.distance = maxDistance; - return result; - } - - VoxelRayResult VoxelWorld::rayCast_editor(glm::vec3 position, glm::vec3 dir, float maxDistance) { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - VoxelRayResult result; - - result.hitPos.x = (int32_t)std::floor(position.x); - result.hitPos.y = (int32_t)std::floor(position.y); - result.hitPos.z = (int32_t)std::floor(position.z); - - result.distance = 0; - - if (dir.x == 0 && dir.y == 0 && dir.z == 0) { - return result; - } - - dir = glm::normalize(dir); - - glm::vec3 stepAxis = glm::vec3(maxDistance, maxDistance, maxDistance); - glm::vec3 distanceAxis = glm::vec3(maxDistance, maxDistance, maxDistance); - - int8_t directionAxis[3] = { 1, 1, 1 }; - - for (int i = 0; i < 3; i++) { - if (dir[i] < 0) { - stepAxis[i] = -1.0f / dir[i]; - directionAxis[i] = -1; - distanceAxis[i] = stepAxis[i] * ((float)position[i] - (float)result.hitPos[i]); - } - else if (dir[i] > 0) { - stepAxis[i] = 1.0f / dir[i]; - distanceAxis[i] = stepAxis[i] * (1 - (float)position[i] + (float)result.hitPos[i]); - } - } - - Voxel hitVoxel = readVoxel(result.hitPos); - bool has_exit_inner_walls = hitVoxel.id == 0; - while (result.distance < maxDistance) { - float minDistance = distanceAxis[0]; - for (int i = 1; i < 3; i++) { - if (distanceAxis[i] < minDistance) - minDistance = distanceAxis[i]; - } - - result.distance = minDistance; - if (result.distance > maxDistance) - break; - - for (int i = 0; i < 3; i++) { - if (minDistance == distanceAxis[i]) { - result.hitPos[i] += directionAxis[i]; - distanceAxis[i] = minDistance + stepAxis[i]; - - Voxel hitVoxel = readVoxel(result.hitPos); - - if (hitVoxel.id == 0) { - if (has_exit_inner_walls && result.hitPos.y == -1 && directionAxis[1] == -1 && i == 1) { - result.face = NORMAL_UP; - return result; - } - - has_exit_inner_walls = true; - } else if (hitVoxel.id != 0 && has_exit_inner_walls) { - result.face = i * 2; - - if (directionAxis[i] == -1) - result.face++; - - return result; - } - } - } - } - - result.distance = maxDistance; - return result; - } -} diff --git a/Deer/src/Deer/Voxels/VoxelWorld_VoxelManipultation.cpp b/Deer/src/Deer/Voxels/VoxelWorld_VoxelManipultation.cpp deleted file mode 100644 index 5ea5403..0000000 --- a/Deer/src/Deer/Voxels/VoxelWorld_VoxelManipultation.cpp +++ /dev/null @@ -1,255 +0,0 @@ -#include "Deer/Log.h" -#include "Deer/VoxelWorld.h" -#include "Deer/Voxels/Chunk.h" -#include "Deer/Voxels/Layer.h" - -#include "Deer/Voxels/VoxelWorldData.h" - -#ifdef DEER_RENDER -#include "DeerRender/Voxels/VoxelWorldRenderData.h" -#endif - -#include - -#include -#include - -namespace Deer { - Voxel VoxelWorld::readVoxel(VoxelCordinates coords) { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - ChunkID chunkID; - ChunkVoxelID chunkVoxelID; - - extractChunkCordinates(coords, chunkID, chunkVoxelID); - if (!worldProps.isValid(chunkID)) return emptyVoxel; - - Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)]; - return chunk.readVoxel(chunkVoxelID); - } - - void VoxelWorld::setVoxel(VoxelCordinates coords, Voxel info) { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - ChunkID chunkID; - ChunkVoxelID chunkVoxelID; - - extractChunkCordinates(coords, chunkID, chunkVoxelID); - if (!worldProps.isValid(chunkID)) return; - - Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)]; - chunk.modVoxel(chunkVoxelID) = info; - - LayerID layerID; - LayerVoxelID layerVoxelID; - - extractLayerCordinates(coords.x, coords.z, layerID, layerVoxelID); - - Layer& layer = layers[worldProps.getWorldLayerID(layerID)]; - LayerVoxel& layerVoxel = layer.modLayerVoxel(layerVoxelID); - - if (!info.isVoxelType()) - layerVoxel.height = calculateLayerVoxelHeight(coords.x, coords.z); - else if (coords.y >= layerVoxel.height) - layerVoxel.height = coords.y + 1; - -#ifdef DEER_RENDER - chunkQueue.addChunk(chunkID); - // For every axis, X & Y & Z - for (int i = 0; i < 3; i++) { - if (chunkVoxelID[i] == 0 && chunkID[i] != 0) { - ChunkID nextChunk = chunkID; - nextChunk[i]--; - chunkQueue.addChunk(nextChunk); - } - - if (chunkVoxelID[i] == CHUNK_SIZE(i) && - chunkID[i] != worldProps[i] - 1) { - ChunkID nextChunk = chunkID; - nextChunk[i]++; - chunkQueue.addChunk(nextChunk); - } - } - - // Check if we should update the lighting - bakeAmbientLightFromPoint(coords.x, coords.z); - bakeVoxelLightFromPoint(coords); -#endif - } - - void VoxelWorld::fillVoxels(VoxelCordinates min, VoxelCordinates max, Voxel info) { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - ChunkID minChunkID; - ChunkID maxChunkID; - ChunkVoxelID minChunkVoxelID; - ChunkVoxelID maxChunkVoxelID; - - worldProps.clampAndSetMinMax(min, max); - - extractChunkCordinates(min, minChunkID, minChunkVoxelID); - extractChunkCordinates(max, maxChunkID, maxChunkVoxelID); - for (int chunkX = minChunkID.x; chunkX <= maxChunkID.x; chunkX++) { - for (int chunkY = minChunkID.y; chunkY <= maxChunkID.y; chunkY++) { - for (int chunkZ = minChunkID.z; chunkZ <= maxChunkID.z; - chunkZ++) { - ChunkID workingChunkID(chunkX, chunkY, chunkZ); - LayerID workingLayerID(chunkX, chunkZ); - Chunk& workingChunk = - chunks[worldProps.getWorldChunkID(workingChunkID)]; - Layer& workingLayer = - layers[worldProps.getWorldLayerID(workingLayerID)]; - - ChunkVoxelID workingMin(0, 0, 0); - ChunkVoxelID workingMax(CHUNK_SIZE_X - 1, CHUNK_SIZE_Y - 1, - CHUNK_SIZE_Z - 1); - - if (chunkX == minChunkID.x) - workingMin.x = minChunkVoxelID.x; - if (chunkY == minChunkID.y) - workingMin.y = minChunkVoxelID.y; - if (chunkZ == minChunkID.z) - workingMin.z = minChunkVoxelID.z; - - if (chunkX == maxChunkID.x) - workingMax.x = maxChunkVoxelID.x; - if (chunkY == maxChunkID.y) - workingMax.y = maxChunkVoxelID.y; - if (chunkZ == maxChunkID.z) - workingMax.z = maxChunkVoxelID.z; - - LayerVoxelID workingMinLayer(workingMin.x, workingMin.z); - LayerVoxelID workingMaxLayer(workingMax.x, workingMax.z); - - workingChunk.fillVoxels(workingMin, workingMax, info); - workingLayer.fillVoxelLayerMaxHeight( - workingMinLayer, workingMaxLayer, max.y); - -#ifdef DEER_RENDER - chunkQueue.addChunk(workingChunkID); -#endif - } - } - } - -#ifdef DEER_RENDER - VoxelCordinates minLightModification = min; - VoxelCordinates maxLightModification = max; - // We want to add a 16 layer border - for (int i = 0; i < 3; i++) { - minLightModification[i] -= 16; - maxLightModification[i] += 16; - } - - worldProps.clampCordinates(minLightModification); - worldProps.clampCordinates(maxLightModification); - - bakeAmbientLight(minLightModification.x, maxLightModification.x, - minLightModification.z, maxLightModification.z); - bakeVoxelLight(minLightModification, maxLightModification); -#endif - } - - void VoxelWorld::remplaceVoxels(VoxelCordinates min, VoxelCordinates max, - Voxel ref, Voxel value) { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - ChunkID minChunkID; - ChunkID maxChunkID; - ChunkVoxelID minChunkVoxelID; - ChunkVoxelID maxChunkVoxelID; - - worldProps.clampAndSetMinMax(min, max); - - extractChunkCordinates(min, minChunkID, minChunkVoxelID); - extractChunkCordinates(max, maxChunkID, maxChunkVoxelID); - for (int chunkX = minChunkID.x; chunkX <= maxChunkID.x; chunkX++) { - for (int chunkY = minChunkID.y; chunkY <= maxChunkID.y; chunkY++) { - for (int chunkZ = minChunkID.z; chunkZ <= maxChunkID.z; - chunkZ++) { - ChunkID workingChunkID(chunkX, chunkY, chunkZ); - Chunk& workingChunk = - chunks[worldProps.getWorldChunkID(workingChunkID)]; - - ChunkVoxelID workingMin(0, 0, 0); - ChunkVoxelID workingMax(CHUNK_SIZE_X - 1, CHUNK_SIZE_Y - 1, - CHUNK_SIZE_Z - 1); - - if (chunkX == minChunkID.x) - workingMin.x = minChunkVoxelID.x; - if (chunkY == minChunkID.y) - workingMin.y = minChunkVoxelID.y; - if (chunkZ == minChunkID.z) - workingMin.z = minChunkVoxelID.z; - - if (chunkX == maxChunkID.x) - workingMax.x = maxChunkVoxelID.x; - if (chunkY == maxChunkID.y) - workingMax.y = maxChunkVoxelID.y; - if (chunkZ == maxChunkID.z) - workingMax.z = maxChunkVoxelID.z; - - workingChunk.remplaceVoxels(workingMin, workingMax, ref, - value); - -#ifdef DEER_RENDER - chunkQueue.addChunk(workingChunkID); -#endif - } - } - } - - for (int xPos = min.x; xPos <= max.x; xPos++) { - for (int zPos = min.z; zPos <= max.z; zPos++) { - LayerID layerID; - LayerVoxelID layerVoxelID; - - extractLayerCordinates(xPos, zPos, layerID, layerVoxelID); - int worldLayerID = worldProps.getWorldLayerID(layerID); - - layers[worldLayerID].modLayerVoxel(layerVoxelID).height = - calculateLayerVoxelHeight(xPos, zPos); - } - } - -#ifdef DEER_RENDER - VoxelCordinates minLightModification = min; - VoxelCordinates maxLightModification = max; - // We want to add a 16 layer border - for (int i = 0; i < 3; i++) { - minLightModification[i] -= 16; - maxLightModification[i] += 16; - } - - worldProps.clampCordinates(minLightModification); - worldProps.clampCordinates(maxLightModification); - - bakeAmbientLight(minLightModification.x, maxLightModification.x, - minLightModification.z, maxLightModification.z); - bakeVoxelLight(minLightModification, maxLightModification); -#endif - } - - LayerVoxel VoxelWorld::readLayerVoxel(int x, int z) { - LayerID layerID; - LayerVoxelID layerVoxelID; - - extractLayerCordinates(x, z, layerID, layerVoxelID); - if (!worldProps.isValid(layerID)) return LayerVoxel(); - - Layer& layer = layers[worldProps.getWorldLayerID(layerID)]; - return layer.readLayerVoxel(layerVoxelID); - } - - LayerVoxel& VoxelWorld::modLayerVoxel(int x, int z) { - LayerID layerID; - LayerVoxelID layerVoxelID; - - extractLayerCordinates(x, z, layerID, layerVoxelID); - if (!worldProps.isValid(layerID)) return nullLayerVoxel; - - Layer& layer = layers[worldProps.getWorldLayerID(layerID)]; - return layer.modLayerVoxel(layerVoxelID); - } - -} // namespace Deer diff --git a/Deer/src/DeerCore/Core/Application.cpp b/Deer/src/DeerCore/Core/Application.cpp new file mode 100644 index 0000000..70ef871 --- /dev/null +++ b/Deer/src/DeerCore/Core/Application.cpp @@ -0,0 +1,59 @@ +#include "DeerCore/Application.h" +#include +#include + +namespace Deer { + namespace Application { + // Implemented in DeerRender/Application + void runRender(float deltaTime); + void resolveEvents(); + + Function tickCallback; + bool running; + + const double targetUpdateTime = 1.0 / 60.0; // Fixed 60 FPS update + double targetRenderTime = 1.0 / 160.0; // User-defined render FPS + + void setTickCallback(Function _tick) { + tickCallback = _tick; + } + void run() { + running = true; + + auto previousTime = std::chrono::high_resolution_clock::now(); + double accumulatedUpdateTime = 0.0; + double accumulatedRenderTime = 0.0; + + while (running) { + // Time handling + auto currentTime = std::chrono::high_resolution_clock::now(); + std::chrono::duration deltaTime = currentTime - previousTime; + previousTime = currentTime; + + accumulatedUpdateTime += deltaTime.count(); + accumulatedRenderTime += deltaTime.count(); + + // Fixed Update loop (60 FPS) + while (accumulatedUpdateTime >= targetUpdateTime) { + Timestep timestep = (float)targetUpdateTime; + accumulatedUpdateTime -= targetUpdateTime; + + if (tickCallback) + tickCallback(); + } +#ifdef DEER_RENDER + if (accumulatedRenderTime >= targetRenderTime) { + runRender((float)targetRenderTime); + accumulatedRenderTime -= targetRenderTime; + } + resolveEvents(); +#endif + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } + + void shutdown() { + running = false; + } + } // namespace Application +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/Deer/Core/Log.cpp b/Deer/src/DeerCore/Core/Log.cpp similarity index 97% rename from Deer/src/Deer/Core/Log.cpp rename to Deer/src/DeerCore/Core/Log.cpp index fbe068e..1ee04fd 100755 --- a/Deer/src/Deer/Core/Log.cpp +++ b/Deer/src/DeerCore/Core/Log.cpp @@ -1,4 +1,4 @@ -#include "Deer/Log.h" +#include "DeerCore/Log.h" namespace Deer { std::shared_ptr Log::coreLogger; diff --git a/Deer/src/Deer/DataStore/DataStore.cpp b/Deer/src/DeerCore/DataStore/DataStore.cpp similarity index 96% rename from Deer/src/Deer/DataStore/DataStore.cpp rename to Deer/src/DeerCore/DataStore/DataStore.cpp index 949cb39..51f24fa 100755 --- a/Deer/src/Deer/DataStore/DataStore.cpp +++ b/Deer/src/DeerCore/DataStore/DataStore.cpp @@ -1,13 +1,13 @@ -#include "Deer/DataStore.h" -#include "Deer/Log.h" -#include "Deer/Tools/Path.h" +#include "DeerCore/DataStore.h" +#include "DeerCore/Log.h" +#include "DeerCore/Tools/Path.h" #include "cereal/archives/portable_binary.hpp" #include "cereal/cereal.hpp" #include "cereal/types/unordered_map.hpp" -#include "Deer/DataStore/DataStructure.h" -#include "Deer/DataStore/DataStructureSerialization.h" +#include "DeerCore/DataStore/DataStructure.h" +#include "DeerCore/DataStore/DataStructureSerialization.h" #include #include diff --git a/Deer/src/Deer/DataStore/DataStructure.h b/Deer/src/DeerCore/DataStore/DataStructure.h similarity index 78% rename from Deer/src/Deer/DataStore/DataStructure.h rename to Deer/src/DeerCore/DataStore/DataStructure.h index 83060d8..3c1f276 100755 --- a/Deer/src/Deer/DataStore/DataStructure.h +++ b/Deer/src/DeerCore/DataStore/DataStructure.h @@ -1,6 +1,6 @@ #pragma once -#include "Deer/Tools/Path.h" +#include "DeerCore/Tools/Path.h" namespace Deer { struct DataStructure { diff --git a/Deer/src/Deer/DataStore/DataStructureSerialization.h b/Deer/src/DeerCore/DataStore/DataStructureSerialization.h similarity index 89% rename from Deer/src/Deer/DataStore/DataStructureSerialization.h rename to Deer/src/DeerCore/DataStore/DataStructureSerialization.h index f588b20..633fb8f 100755 --- a/Deer/src/Deer/DataStore/DataStructureSerialization.h +++ b/Deer/src/DeerCore/DataStore/DataStructureSerialization.h @@ -1,6 +1,6 @@ #pragma once -#include "Deer/DataStore/DataStructure.h" -#include "Deer/Tools/Path.h" +#include "DeerCore/DataStore/DataStructure.h" +#include "DeerCore/Tools/Path.h" #include "cereal/cereal.hpp" #include "cereal/types/string.hpp" diff --git a/Deer/src/Deer/DataStore/Path.cpp b/Deer/src/DeerCore/DataStore/Path.cpp similarity index 89% rename from Deer/src/Deer/DataStore/Path.cpp rename to Deer/src/DeerCore/DataStore/Path.cpp index e1aa599..bd93791 100644 --- a/Deer/src/Deer/DataStore/Path.cpp +++ b/Deer/src/DeerCore/DataStore/Path.cpp @@ -1,4 +1,4 @@ -#include "Deer/Tools/Path.h" +#include "DeerCore/Tools/Path.h" #include Deer::Path Deer::toLowerCasePath(const Path& inputPath) { diff --git a/Deer/src/DeerCore/Network/Server.cpp b/Deer/src/DeerCore/Network/Server.cpp new file mode 100644 index 0000000..6c69b67 --- /dev/null +++ b/Deer/src/DeerCore/Network/Server.cpp @@ -0,0 +1,96 @@ +#include "DeerCore/Log.h" +#include "DeerCore/Network.h" + +#include "enet/enet.h" +#include +#include + +namespace Deer { + namespace Network { + ServerSettings serverSettings; + ENetHost* enetServer; + + void clientConnect(ENetPeer* refPeer); + void clientDisconnect(ENetPeer* refPeer); + void clientData(ENetPeer* peer, ENetPacket* packet); + + // Fixed array of clients, defined by max player count + Scope clients; + } // namespace Network + + void Network::initServer(const ServerSettings& config) { + serverSettings = config; + if (enet_initialize() != 0) { + DEER_CORE_ERROR("An error ocurred while initing enet"); + return; + } + ENetAddress serverAddress; + + serverAddress.host = ENET_HOST_ANY; + serverAddress.port = config.port; + + enetServer = enet_host_create(&serverAddress, config.maxClients, 2, config.maxOutgoingBand, config.maxIncomingBand); + if (!enetServer) { + DEER_CORE_ERROR("An error ocurred while initing server"); + return; + } + + clients = MakeScope(serverSettings.maxClients); + } + + void Network::shutdownServer() { + enet_deinitialize(); + } + + void Network::flushServerEvents() { + ENetEvent event; + while (enet_host_service(enetServer, &event, 0) > 0) { + switch (event.type) { + case ENET_EVENT_TYPE_CONNECT: + clientConnect(event.peer); + break; + + case ENET_EVENT_TYPE_RECEIVE: + clientData(event.peer, event.packet); + break; + + case ENET_EVENT_TYPE_DISCONNECT: + clientDisconnect(event.peer); + break; + case ENET_EVENT_TYPE_NONE: + break; + } + } + } + + void Network::clientConnect(ENetPeer* peer) { + DeerClient* client = nullptr; + int clientId = -1; + for (int i = 0; i < serverSettings.maxClients; i++) { + if (clients[i].clientState == DeerClientState::NotConnected) { + client = &client[i]; + clientId = i; + break; + } + } + + if (!client) { + DEER_CORE_ERROR("Server full, critical error"); + enet_peer_disconnect(peer, 0); + return; + } + + client->clientState = DeerClientState::Connected; + client->internalPeer = peer; + peer->data = client; + } + + void Network::clientDisconnect(ENetPeer* peer) { + DeerClient& client = *(DeerClient*)peer->data; + client.clientState = DeerClientState::NotConnected; + client.internalPeer = nullptr; + } + + void Network::clientData(ENetPeer* peer, ENetPacket* packetData) { + } +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerCore/Scene/Components.cpp b/Deer/src/DeerCore/Scene/Components.cpp new file mode 100755 index 0000000..0e59fe9 --- /dev/null +++ b/Deer/src/DeerCore/Scene/Components.cpp @@ -0,0 +1,14 @@ +#include "DeerCore/Components.h" +#include "DeerCore/Log.h" +#include "glm/gtc/matrix_transform.hpp" + +namespace Deer { + glm::mat4 TransformComponent::getMatrix() const { + glm::mat4 scaleMat = glm::scale(glm::mat4(1.0f), scale); + glm::mat4 roatationMat = glm::mat4(rotation); + glm::mat4 positionMat = glm::translate(glm::mat4(1.0f), position); + + return positionMat * roatationMat * scaleMat; + } + +} // namespace Deer diff --git a/Deer/src/Deer/Scene/Entity.cpp b/Deer/src/DeerCore/Scene/Entity.cpp similarity index 97% rename from Deer/src/Deer/Scene/Entity.cpp rename to Deer/src/DeerCore/Scene/Entity.cpp index 11f4d87..f4e9573 100755 --- a/Deer/src/Deer/Scene/Entity.cpp +++ b/Deer/src/DeerCore/Scene/Entity.cpp @@ -1,6 +1,6 @@ -#include "Deer/Components.h" -#include "Deer/Enviroment.h" -#include "Deer/Log.h" +#include "DeerCore/Components.h" +#include "DeerCore/Enviroment.h" +#include "DeerCore/Log.h" namespace Deer { Entity::Entity(entt::entity handle, Environment* scene, uint16_t entityID) diff --git a/Deer/src/Deer/Scene/Enviroment.cpp b/Deer/src/DeerCore/Scene/Enviroment.cpp similarity index 96% rename from Deer/src/Deer/Scene/Enviroment.cpp rename to Deer/src/DeerCore/Scene/Enviroment.cpp index f1d399b..5e52ac8 100755 --- a/Deer/src/Deer/Scene/Enviroment.cpp +++ b/Deer/src/DeerCore/Scene/Enviroment.cpp @@ -1,10 +1,9 @@ -#include "Deer/Enviroment.h" +#include "DeerCore/Enviroment.h" -#include "Deer/Application.h" -#include "Deer/Components.h" -#include "Deer/Log.h" +#include "DeerCore/Application.h" +#include "DeerCore/Components.h" +#include "DeerCore/Log.h" #include "DeerRender/Render/Render.h" -#include "DeerRender/Render/RenderUtils.h" #include "DeerRender/Render/Texture.h" namespace Deer { diff --git a/Deer/src/DeerCore/Scene/EnvironmentBuilder.cpp b/Deer/src/DeerCore/Scene/EnvironmentBuilder.cpp new file mode 100644 index 0000000..7fe6106 --- /dev/null +++ b/Deer/src/DeerCore/Scene/EnvironmentBuilder.cpp @@ -0,0 +1,8 @@ +#include "DeerCore/Enviroment.h" + +namespace Deer { + Scope ResourceBuilder::buildResource(const BaseDataType& baseData) { + Scope env = MakeScope(); + return env; + } +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/Deer/Scene/Scene.cpp b/Deer/src/DeerCore/Scene/Scene.cpp similarity index 64% rename from Deer/src/Deer/Scene/Scene.cpp rename to Deer/src/DeerCore/Scene/Scene.cpp index b52868b..a5f1f1c 100755 --- a/Deer/src/Deer/Scene/Scene.cpp +++ b/Deer/src/DeerCore/Scene/Scene.cpp @@ -1,28 +1,20 @@ -#include "Deer/Scene.h" +#include "DeerCore/Scene.h" -#include "Deer/Components.h" -#include "Deer/Enviroment.h" -#include "Deer/Log.h" -#include "Deer/Tools/Memory.h" -#include "Deer/VoxelWorld.h" -#include "Deer/Voxels/Chunk.h" -#include "Deer/Voxels/Layer.h" -#include "Deer/Voxels/VoxelWorldData.h" - -#include "Deer/Enviroment.h" -#include "Deer/Scene/SceneData.h" +#include "DeerCore/Components.h" +#include "DeerCore/Enviroment.h" +#include "DeerCore/Log.h" +#include "DeerCore/Scene/SceneData.h" +#include "DeerCore/Tools/Memory.h" #ifdef DEER_RENDER #include "DeerRender/FrameBuffer.h" #include "DeerRender/Mesh.h" #include "DeerRender/Shader.h" -#include "DeerRender/Voxels/VoxelWorldRenderData.h" #endif namespace Deer { void Scene::clear() { environment.clear(); - VoxelWorld::clear(); #ifdef DEER_RENDER ResourceManager::unloadResources(); diff --git a/Deer/src/DeerCore/Scene/SceneData.cpp b/Deer/src/DeerCore/Scene/SceneData.cpp new file mode 100644 index 0000000..4fa1bb2 --- /dev/null +++ b/Deer/src/DeerCore/Scene/SceneData.cpp @@ -0,0 +1,10 @@ +#include "DeerCore/Enviroment.h" +#include "DeerCore/Tools/Memory.h" + +namespace Deer { + namespace Scene { + Environment environment; + bool isExecuting = false; + } // namespace Scene + +} // namespace Deer diff --git a/Deer/src/Deer/Scene/SceneData.h b/Deer/src/DeerCore/Scene/SceneData.h similarity index 52% rename from Deer/src/Deer/Scene/SceneData.h rename to Deer/src/DeerCore/Scene/SceneData.h index 057aef4..9c14b57 100644 --- a/Deer/src/Deer/Scene/SceneData.h +++ b/Deer/src/DeerCore/Scene/SceneData.h @@ -1,9 +1,5 @@ #pragma once -#include "Deer/Tools/Memory.h" - -#ifdef DEER_RENDER -#include "DeerRender/GizmoRenderer.h" -#endif +#include "DeerCore/Tools/Memory.h" namespace Deer { class Environment; @@ -11,10 +7,6 @@ namespace Deer { namespace Scene { extern Environment environment; extern bool isExecuting; - -#ifdef DEER_RENDER - extern GizmoRenderer gizmoRenderer; -#endif } // namespace Scene } // namespace Deer diff --git a/Deer/src/Deer/Scene/Serialization/Components/RelationshipComponentSerialization.h b/Deer/src/DeerCore/Scene/Serialization/Components/RelationshipComponentSerialization.h similarity index 93% rename from Deer/src/Deer/Scene/Serialization/Components/RelationshipComponentSerialization.h rename to Deer/src/DeerCore/Scene/Serialization/Components/RelationshipComponentSerialization.h index 5143430..1fba667 100755 --- a/Deer/src/Deer/Scene/Serialization/Components/RelationshipComponentSerialization.h +++ b/Deer/src/DeerCore/Scene/Serialization/Components/RelationshipComponentSerialization.h @@ -1,5 +1,5 @@ #pragma once -#include "Deer/Components.h" +#include "DeerCore/Components.h" namespace Deer { // RELATIONSHIP COMPONENT diff --git a/Deer/src/DeerCore/Scene/Serialization/Components/TransformComponentSerialization.h b/Deer/src/DeerCore/Scene/Serialization/Components/TransformComponentSerialization.h new file mode 100755 index 0000000..4098327 --- /dev/null +++ b/Deer/src/DeerCore/Scene/Serialization/Components/TransformComponentSerialization.h @@ -0,0 +1,16 @@ +#pragma once +#include "DeerCore/Components.h" + +namespace Deer { + + // TRANSFORM COMPONENT + template + void serialize(Archive& archive, + TransformComponent& transform) { + + archive(cereal::make_nvp("position", transform.position)); + archive(cereal::make_nvp("scale", transform.scale)); + archive(cereal::make_nvp("rotation", transform.rotation)); + } + +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/Deer/Scene/Serialization/EntitySerialization.h b/Deer/src/DeerCore/Scene/Serialization/EntitySerialization.h similarity index 94% rename from Deer/src/Deer/Scene/Serialization/EntitySerialization.h rename to Deer/src/DeerCore/Scene/Serialization/EntitySerialization.h index 61c472f..991f91f 100755 --- a/Deer/src/Deer/Scene/Serialization/EntitySerialization.h +++ b/Deer/src/DeerCore/Scene/Serialization/EntitySerialization.h @@ -1,8 +1,8 @@ #pragma once -#include "Deer/Components.h" -#include "Deer/Enviroment.h" -#include "Deer/Scene/Serialization/SerializationGlobalVars.h" +#include "DeerCore/Components.h" +#include "DeerCore/Enviroment.h" +#include "DeerCore/Scene/Serialization/SerializationGlobalVars.h" #include "EntitySerializationStruct.h" namespace Deer { diff --git a/Deer/src/Deer/Scene/Serialization/EntitySerializationStruct.h b/Deer/src/DeerCore/Scene/Serialization/EntitySerializationStruct.h similarity index 100% rename from Deer/src/Deer/Scene/Serialization/EntitySerializationStruct.h rename to Deer/src/DeerCore/Scene/Serialization/EntitySerializationStruct.h diff --git a/Deer/src/Deer/Scene/Serialization/EnvironmentSerialization.h b/Deer/src/DeerCore/Scene/Serialization/EnvironmentSerialization.h similarity index 96% rename from Deer/src/Deer/Scene/Serialization/EnvironmentSerialization.h rename to Deer/src/DeerCore/Scene/Serialization/EnvironmentSerialization.h index 973250a..c16fd5a 100755 --- a/Deer/src/Deer/Scene/Serialization/EnvironmentSerialization.h +++ b/Deer/src/DeerCore/Scene/Serialization/EnvironmentSerialization.h @@ -2,7 +2,7 @@ #include #include -#include "Deer/Enviroment.h" +#include "DeerCore/Enviroment.h" #include "EntitySerializationStruct.h" namespace Deer { @@ -54,4 +54,4 @@ namespace Deer { archive(serializationStruct); } } -} // namespace Deer \ No newline at end of file +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/Deer/Scene/Serialization/QuatSerialization.h b/Deer/src/DeerCore/Scene/Serialization/QuatSerialization.h similarity index 100% rename from Deer/src/Deer/Scene/Serialization/QuatSerialization.h rename to Deer/src/DeerCore/Scene/Serialization/QuatSerialization.h diff --git a/Deer/src/Deer/Scene/Serialization/Serialization.cpp b/Deer/src/DeerCore/Scene/Serialization/Serialization.cpp similarity index 100% rename from Deer/src/Deer/Scene/Serialization/Serialization.cpp rename to Deer/src/DeerCore/Scene/Serialization/Serialization.cpp diff --git a/Deer/src/Deer/Scene/Serialization/Serialization.h b/Deer/src/DeerCore/Scene/Serialization/Serialization.h similarity index 50% rename from Deer/src/Deer/Scene/Serialization/Serialization.h rename to Deer/src/DeerCore/Scene/Serialization/Serialization.h index 9d03d59..af1c1fc 100755 --- a/Deer/src/Deer/Scene/Serialization/Serialization.h +++ b/Deer/src/DeerCore/Scene/Serialization/Serialization.h @@ -5,19 +5,19 @@ #include "cereal/types/vector.hpp" // Serialization Vars -#include "Deer/Scene/Serialization/SerializationGlobalVars.h" +#include "DeerCore/Scene/Serialization/SerializationGlobalVars.h" // GENERICS -#include "Deer/Scene/Serialization/QuatSerialization.h" -#include "Deer/Scene/Serialization/Vec3Serialization.h" +#include "DeerCore/Scene/Serialization/QuatSerialization.h" +#include "DeerCore/Scene/Serialization/Vec3Serialization.h" // SCENE SPECIFIC -#include "Deer/Scene/Serialization/EntitySerialization.h" -#include "Deer/Scene/Serialization/EnvironmentSerialization.h" +#include "DeerCore/Scene/Serialization/EntitySerialization.h" +#include "DeerCore/Scene/Serialization/EnvironmentSerialization.h" // COMPONENTS SPECIFIC -#include "Deer/Scene/Serialization/Components/RelationshipComponentSerialization.h" -#include "Deer/Scene/Serialization/Components/TransformComponentSerialization.h" +#include "DeerCore/Scene/Serialization/Components/RelationshipComponentSerialization.h" +#include "DeerCore/Scene/Serialization/Components/TransformComponentSerialization.h" // RENDER SPECIFIC #ifdef DEER_RENDER diff --git a/Deer/src/Deer/Scene/Serialization/SerializationGlobalVars.cpp b/Deer/src/DeerCore/Scene/Serialization/SerializationGlobalVars.cpp similarity index 100% rename from Deer/src/Deer/Scene/Serialization/SerializationGlobalVars.cpp rename to Deer/src/DeerCore/Scene/Serialization/SerializationGlobalVars.cpp diff --git a/Deer/src/Deer/Scene/Serialization/SerializationGlobalVars.h b/Deer/src/DeerCore/Scene/Serialization/SerializationGlobalVars.h similarity index 100% rename from Deer/src/Deer/Scene/Serialization/SerializationGlobalVars.h rename to Deer/src/DeerCore/Scene/Serialization/SerializationGlobalVars.h diff --git a/Deer/src/Deer/Scene/Serialization/Vec3Serialization.h b/Deer/src/DeerCore/Scene/Serialization/Vec3Serialization.h similarity index 100% rename from Deer/src/Deer/Scene/Serialization/Vec3Serialization.h rename to Deer/src/DeerCore/Scene/Serialization/Vec3Serialization.h diff --git a/Deer/src/DeerRender/Core/Application.cpp b/Deer/src/DeerRender/Core/Application.cpp index 4892f5a..6c1685d 100644 --- a/Deer/src/DeerRender/Core/Application.cpp +++ b/Deer/src/DeerRender/Core/Application.cpp @@ -4,7 +4,6 @@ #include "DeerRender/Render/Render.h" #include "DeerRender/Render/RenderCommand.h" -#include "DeerRender/Render/RenderUtils.h" #include "DeerRender/Log.h" @@ -46,7 +45,6 @@ namespace Deer { imGuiLayer = MakeScope(); imGuiLayer->onAttach(); - RenderUtils::initializeRenderUtils(); RenderCommand::init(); } diff --git a/Deer/src/DeerRender/Render/RenderUtils.cpp b/Deer/src/DeerRender/Render/RenderUtils.cpp index 14de635..856f545 100755 --- a/Deer/src/DeerRender/Render/RenderUtils.cpp +++ b/Deer/src/DeerRender/Render/RenderUtils.cpp @@ -1,7 +1,7 @@ #include "RenderUtils.h" -#include "DeerRender/Render/VertexArray.h" #include "DeerRender/Render/Buffer.h" #include "DeerRender/Render/Shader.h" +#include "DeerRender/Render/VertexArray.h" #ifdef DEER_RENDER @@ -16,7 +16,7 @@ namespace Deer { Scope genFaceVertexArray(); Scope getLineShader(); Scope getFaceShader(); - } + } // namespace RenderUtils void RenderUtils::initializeRenderUtils() { m_lineVertexArray = genLineVertexArray(); @@ -25,18 +25,23 @@ namespace Deer { m_faceShader = getFaceShader(); } + void RenderUtils::deinitializeRenderUtils() { + m_lineVertexArray.reset(); + m_lineShader.reset(); + m_faceVertexArray.reset(); + m_faceShader.reset(); + } + Scope RenderUtils::genLineVertexArray() { - unsigned int vertices[2] = { 0, 1 }; + unsigned int vertices[2] = {0, 1}; Scope vertexArray = Scope(VertexArray::create()); vertexArray->bind(); - + Ref vertexBuffer = VertexBuffer::create(vertices, sizeof(vertices)); Ref indexBuffer = IndexBuffer::create(vertices, sizeof(vertices), IndexDataType::Unsigned_Int); - BufferLayout layout({ - {"a_vertexID", DataType::Unsigned_Int, ShaderDataType::Integer} - }); + BufferLayout layout({{"a_vertexID", DataType::Unsigned_Int, ShaderDataType::Integer}}); vertexBuffer->setLayout(layout); vertexArray->addVertexBuffer(vertexBuffer); @@ -87,11 +92,9 @@ void main() Scope RenderUtils::genFaceVertexArray() { unsigned int vertices[4] = { - 0, 1, 2, 3 - }; + 0, 1, 2, 3}; unsigned int indices[6] = { - 0, 2, 1, 1, 2, 3 - }; + 0, 2, 1, 1, 2, 3}; Scope vertexArray = Scope(VertexArray::create()); vertexArray->bind(); @@ -99,9 +102,7 @@ void main() Ref vertexBuffer = VertexBuffer::create(vertices, sizeof(vertices)); Ref indexBuffer = IndexBuffer::create(indices, sizeof(indices), IndexDataType::Unsigned_Int); - BufferLayout layout({ - {"a_vertexID", DataType::Unsigned_Int, ShaderDataType::Integer} - }); + BufferLayout layout({{"a_vertexID", DataType::Unsigned_Int, ShaderDataType::Integer}}); vertexBuffer->setLayout(layout); vertexArray->addVertexBuffer(vertexBuffer); @@ -178,5 +179,5 @@ void main() return Scope(Shader::create(vertexSrc, fragmentSrc)); } -} -#endif +} // namespace Deer +#endif diff --git a/Deer/src/DeerRender/Render/RenderUtils.h b/Deer/src/DeerRender/Render/RenderUtils.h index fd75bf8..ac46ba7 100755 --- a/Deer/src/DeerRender/Render/RenderUtils.h +++ b/Deer/src/DeerRender/Render/RenderUtils.h @@ -12,5 +12,6 @@ namespace Deer { extern Scope m_faceShader; void initializeRenderUtils(); + void deinitializeRenderUtils(); } // namespace RenderUtils } // namespace Deer diff --git a/Deer/src/DeerRender/Scene/Environment.cpp b/Deer/src/DeerRender/Scene/Environment.cpp index 4f8cb53..a3b67ac 100755 --- a/Deer/src/DeerRender/Scene/Environment.cpp +++ b/Deer/src/DeerRender/Scene/Environment.cpp @@ -3,7 +3,6 @@ #include "DeerRender/Application.h" #include "DeerRender/Components.h" -#include "DeerRender/Voxel.h" #include "DeerRender/Mesh.h" #include "DeerRender/Render/Render.h" @@ -14,7 +13,7 @@ #include "DeerRender/Log.h" namespace Deer { - void Environment::render(SceneCamera& camera) { + void Environment::render(const SceneCamera& camera) { glm::mat4 camMatrix = glm::inverse(camera.transform.getMatrix()); glm::mat4 projectionMatrix = camera.camera.getMatrix(); glm::mat4 invertZ = glm::scale(glm::mat4(1.0f), glm::vec3(1, 1, -1)); diff --git a/Deer/src/DeerRender/Scene/GizmoRenderer.cpp b/Deer/src/DeerRender/Scene/GizmoRenderer.cpp deleted file mode 100755 index 892858f..0000000 --- a/Deer/src/DeerRender/Scene/GizmoRenderer.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include "DeerRender/GizmoRenderer.h" - -#include "DeerRender/Components.h" -#include "DeerRender/Render/Render.h" -#include "DeerRender/Render/RenderCommand.h" -#include "DeerRender/Render/RenderUtils.h" -#include "DeerRender/Render/Texture.h" -#include "DeerRender/Scene.h" -#include "DeerRender/Voxel.h" - -namespace Deer { - void GizmoRenderer::drawLine(glm::vec3 a, glm::vec3 b, glm::vec3 color) { - m_lines.push_back({a, b, color}); - } - - void GizmoRenderer::drawVoxelLine(int _x, int _y, int _z, glm::vec3 color) { - for (int x = 0; x < 2; x++) { - for (int y = 0; y < 2; y++) { - glm::vec3 a = glm::vec3(x + _x, y + _y, 0 + _z); - glm::vec3 b = glm::vec3(x + _x, y + _y, 1 + _z); - - drawLine(a, b, color); - } - } - for (int z = 0; z < 2; z++) { - for (int y = 0; y < 2; y++) { - glm::vec3 a = glm::vec3(0 + _x, y + _y, z + _z); - glm::vec3 b = glm::vec3(1 + _x, y + _y, z + _z); - - drawLine(a, b, color); - } - } - for (int x = 0; x < 2; x++) { - for (int z = 0; z < 2; z++) { - glm::vec3 a = glm::vec3(x + _x, 0 + _y, z + _z); - glm::vec3 b = glm::vec3(x + _x, 1 + _y, z + _z); - - drawLine(a, b, color); - } - } - } - - void GizmoRenderer::drawVoxelLineFace(int x, int y, int z, uint8_t face, - glm::vec3 color) { - glm::vec3 points[4]; - - for (int i = 0; i < 4; i++) { - points[i] = {x + NORMAL_VERTEX_POS(X_AXIS, i, face), - y + NORMAL_VERTEX_POS(Y_AXIS, i, face), - z + NORMAL_VERTEX_POS(Z_AXIS, i, face)}; - } - - drawLine(points[0], points[1], color); - drawLine(points[2], points[3], color); - drawLine(points[0], points[2], color); - drawLine(points[1], points[3], color); - } - - void GizmoRenderer::drawVoxelFace(int x, int y, int z, uint16_t voxelID, - uint8_t faceID, uint8_t priority) { - glm::vec3 points[4]; - VoxelAspect& aspect = DataStore::voxelsAspect[voxelID]; - GizmoFace face; - face.textureID = aspect.textureFacesIDs[faceID]; - face.face = faceID; - - for (int i = 0; i < 4; i++) { - face.positions[i] = {x + NORMAL_VERTEX_POS(X_AXIS, i, faceID), - y + NORMAL_VERTEX_POS(Y_AXIS, i, faceID), - z + NORMAL_VERTEX_POS(Z_AXIS, i, faceID)}; - } - - m_faces[priority].push_back(face); - } - - void GizmoRenderer::drawVoxelFaceInverted(int x, int y, int z, - uint16_t voxelID, uint8_t faceID, - uint8_t priority) { - glm::vec3 points[4]; - VoxelAspect& aspect = DataStore::voxelsAspect[voxelID]; - GizmoFace face; - face.textureID = aspect.textureFacesIDs[faceID]; - face.face = faceID; - - face.positions[0] = {x + NORMAL_VERTEX_POS(X_AXIS, 0, faceID), - y + NORMAL_VERTEX_POS(Y_AXIS, 0, faceID), - z + NORMAL_VERTEX_POS(Z_AXIS, 0, faceID)}; - - face.positions[2] = {x + NORMAL_VERTEX_POS(X_AXIS, 1, faceID), - y + NORMAL_VERTEX_POS(Y_AXIS, 1, faceID), - z + NORMAL_VERTEX_POS(Z_AXIS, 1, faceID)}; - - face.positions[1] = {x + NORMAL_VERTEX_POS(X_AXIS, 2, faceID), - y + NORMAL_VERTEX_POS(Y_AXIS, 2, faceID), - z + NORMAL_VERTEX_POS(Z_AXIS, 2, faceID)}; - - face.positions[3] = {x + NORMAL_VERTEX_POS(X_AXIS, 3, faceID), - y + NORMAL_VERTEX_POS(Y_AXIS, 3, faceID), - z + NORMAL_VERTEX_POS(Z_AXIS, 3, faceID)}; - - m_faces[priority].push_back(face); - } - - void GizmoRenderer::render(const SceneCamera& camera) { - RenderCommand::setDepthBuffer(true); - - // We make a exact camera but with less far clip to give priority in the - // depht test - CameraComponent camera_lessDistance = camera.camera; - camera_lessDistance.farZ *= 1.1f; - - glm::mat4 camMatrix = glm::inverse(camera.transform.getMatrix()); - glm::mat4 projectionMatrix = camera_lessDistance.getMatrix(); - glm::mat4 invertZ = glm::scale(glm::mat4(1.0f), glm::vec3(1, 1, -1)); - - glm::mat4 cameraProjectionMatrix = - projectionMatrix * invertZ * camMatrix; - - // DataStore::getVoxelColorTextureAtlas()->bind(0); - RenderUtils::m_faceShader->bind(); - RenderUtils::m_faceShader->uploadUniformMat4("u_viewMatrix", cameraProjectionMatrix); - RenderUtils::m_faceShader->uploadUniformInt("u_texture", 0); - // RenderUtils::m_faceShader->uploadUniformInt("u_textureSize", DataStore::getVoxelTextureAtlasSize()); - - for (int i = 0; i < GIZMO_DEPTH; i++) { - for (GizmoFace& face : m_faces[i]) { - RenderUtils::m_faceShader->uploadUniformInt("u_textureID", - face.textureID); - - RenderUtils::m_faceShader->uploadUniformFloat3( - "u_posA", face.positions[0]); - RenderUtils::m_faceShader->uploadUniformFloat3( - "u_posB", face.positions[1]); - RenderUtils::m_faceShader->uploadUniformFloat3( - "u_posC", face.positions[2]); - RenderUtils::m_faceShader->uploadUniformFloat3( - "u_posD", face.positions[3]); - - Render::submit(*RenderUtils::m_faceVertexArray); - } - } - - RenderCommand::setDepthBuffer(false); - - for (std::array& line : m_lines) { - RenderUtils::m_lineShader->bind(); - RenderUtils::m_lineShader->uploadUniformMat4( - "u_viewMatrix", cameraProjectionMatrix); - RenderUtils::m_lineShader->uploadUniformFloat3("u_color", line[2]); - - RenderUtils::m_lineShader->uploadUniformFloat3("u_posA", line[0]); - RenderUtils::m_lineShader->uploadUniformFloat3("u_posB", line[1]); - - Render::submitLine(*RenderUtils::m_lineVertexArray); - } - } - - void GizmoRenderer::refresh() { - m_lines.clear(); - for (int i = 0; i < GIZMO_DEPTH; i++) - m_faces[i].clear(); - } -} // namespace Deer diff --git a/Deer/src/DeerRender/Scene/Scene.cpp b/Deer/src/DeerRender/Scene/Scene.cpp index 8e637bd..dd66bde 100755 --- a/Deer/src/DeerRender/Scene/Scene.cpp +++ b/Deer/src/DeerRender/Scene/Scene.cpp @@ -3,7 +3,7 @@ #include "DeerRender/Components.h" #include "DeerRender/Enviroment.h" #include "DeerRender/Render/RenderCommand.h" -#include "DeerRender/VoxelWorld.h" +#include "DeerRender/Scene.h" namespace Deer { void Scene::render() { @@ -19,15 +19,11 @@ namespace Deer { Scene::render(sceneCamera); } - void Scene::render(SceneCamera sceneCamera) { + void Scene::render(const SceneCamera& sceneCamera) { RenderCommand::setDepthBuffer(true); environment.render(sceneCamera); - if (VoxelWorld::isInitialized()) - VoxelWorld::render(sceneCamera); - RenderCommand::setDepthBuffer(false); - gizmoRenderer.render(sceneCamera); } } // namespace Deer diff --git a/Deer/src/DeerRender/Voxels/ChunkUpdateQueue.cpp b/Deer/src/DeerRender/Voxels/ChunkUpdateQueue.cpp deleted file mode 100755 index f2d5578..0000000 --- a/Deer/src/DeerRender/Voxels/ChunkUpdateQueue.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "DeerRender/Voxels/VoxelWorldRenderData.h" - -namespace Deer { - void ChunkUpdateQueue::addChunk(ChunkID chunkID) { - if (m_containingChunks.contains(chunkID)) - return; - - m_containingChunks.insert(chunkID); - m_updateOrder.push(chunkID); - } - - ChunkID ChunkUpdateQueue::pullChunk() { - ChunkID chunkID = m_updateOrder.front(); - m_updateOrder.pop(); - m_containingChunks.erase(chunkID); - return chunkID; - } - - void ChunkUpdateQueue::reset() { - while (!m_updateOrder.empty()) { - m_updateOrder.pop(); - } - - m_containingChunks.clear(); - } - - bool ChunkUpdateQueue::hasChunk() { - return m_updateOrder.size() > 0; - } -} diff --git a/Deer/src/DeerRender/Voxels/Serialization/VoxelAspect_Serialization.h b/Deer/src/DeerRender/Voxels/Serialization/VoxelAspect_Serialization.h deleted file mode 100644 index 98bf922..0000000 --- a/Deer/src/DeerRender/Voxels/Serialization/VoxelAspect_Serialization.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include "DeerRender/Log.h" -#include "DeerRender/Voxel.h" -#include "DeerRender/VoxelAspect.h" - -#include "cereal/cereal.hpp" -#include "cereal/types/string.hpp" - -namespace Deer { - template - void serialize(Archive& archive, VoxelTextureFaceDefinition& textureFaceDefinitions) { - archive(cereal::make_nvp("left", textureFaceDefinitions.textureFaces[NORMAL_LEFT])); - archive(cereal::make_nvp("right", textureFaceDefinitions.textureFaces[NORMAL_RIGHT])); - archive(cereal::make_nvp("down", textureFaceDefinitions.textureFaces[NORMAL_DOWN])); - archive(cereal::make_nvp("up", textureFaceDefinitions.textureFaces[NORMAL_UP])); - archive(cereal::make_nvp("front", textureFaceDefinitions.textureFaces[NORMAL_FRONT])); - archive(cereal::make_nvp("back", textureFaceDefinitions.textureFaces[NORMAL_BACK])); - } - - template - void serialize(Archive& archive, VoxelColorEmission& voxelEmission) { - archive(cereal::make_nvp("red", voxelEmission.r_value)); - archive(cereal::make_nvp("green", voxelEmission.g_value)); - archive(cereal::make_nvp("blue", voxelEmission.b_value)); - } - - template - void serialize(Archive& archive, VoxelAspectDefinition& voxelAspectDefinition) { - archive(cereal::make_nvp("name", voxelAspectDefinition.voxelName)); - archive(cereal::make_nvp("textureFaces", voxelAspectDefinition.textureFaces)); - archive(cereal::make_nvp("emission", voxelAspectDefinition.colorEmission)); - } -} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Voxels/Voxel.cpp b/Deer/src/DeerRender/Voxels/Voxel.cpp deleted file mode 100755 index 61136b2..0000000 --- a/Deer/src/DeerRender/Voxels/Voxel.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include "DeerRender/Voxel.h" - -#include -#include - -namespace Deer { - VoxelLight lightVoxel(255); - - int lightPropagationComplexDir[12 * 2] = { - NORMAL_LEFT, NORMAL_DOWN, - NORMAL_RIGHT, NORMAL_DOWN, - NORMAL_LEFT, NORMAL_UP, - NORMAL_RIGHT, NORMAL_UP, - NORMAL_LEFT, NORMAL_BACK, - NORMAL_RIGHT, NORMAL_BACK, - NORMAL_LEFT, NORMAL_FRONT, - NORMAL_RIGHT, NORMAL_FRONT, - NORMAL_DOWN, NORMAL_BACK, - NORMAL_UP, NORMAL_BACK, - NORMAL_DOWN, NORMAL_FRONT, - NORMAL_UP, NORMAL_FRONT}; - - int normalFacePositions[3 * 4 * 6] = { - // Left - 0, 0, 1, - 0, 0, 0, - 0, 1, 1, - 0, 1, 0, - // Right - 1, 0, 0, - 1, 0, 1, - 1, 1, 0, - 1, 1, 1, - // Down - 0, 0, 1, - 1, 0, 1, - 0, 0, 0, - 1, 0, 0, - // Up - 0, 1, 0, - 1, 1, 0, - 0, 1, 1, - 1, 1, 1, - // Back - 0, 0, 0, - 1, 0, 0, - 0, 1, 0, - 1, 1, 0, - // Front - 1, 0, 1, - 0, 0, 1, - 1, 1, 1, - 0, 1, 1}; - - int uvFace[2 * 4] = { - 0, 0, - 1, 0, - 0, 1, - 1, 1}; - - int ambientOcclusionVertex[6 * 2 * 4 * 3]{ - 0, -1, 0, 0, 0, 1, - 0, -1, 0, 0, 0, -1, - 0, 1, 0, 0, 0, 1, - 0, 1, 0, 0, 0, -1, - 0, -1, 0, 0, 0, -1, - 0, -1, 0, 0, 0, 1, - 0, 1, 0, 0, 0, -1, - 0, 1, 0, 0, 0, 1, - -1, 0, 0, 0, 0, 1, - 1, 0, 0, 0, 0, 1, - -1, 0, 0, 0, 0, -1, - 1, 0, 0, 0, 0, -1, - -1, 0, 0, 0, 0, -1, - 1, 0, 0, 0, 0, -1, - -1, 0, 0, 0, 0, 1, - 1, 0, 0, 0, 0, 1, - -1, 0, 0, 0, -1, 0, - 1, 0, 0, 0, -1, 0, - -1, 0, 0, 0, 1, 0, - 1, 0, 0, 0, 1, 0, - 1, 0, 0, 0, -1, 0, - -1, 0, 0, 0, -1, 0, - 1, 0, 0, 0, 1, 0, - -1, 0, 0, 0, 1, 0}; - - int layerCheckDirections[2 * 8]{ - -1, 0, - -1, 1, - 0, 1, - 1, 1, - 1, 0, - 1, -1, - 0, -1, - -1, -1}; - - void calcFaces() { - std::string out; - - for (int f = 0; f < 6; f++) { - int normalDirX = NORMAL_DIR(X_AXIS, f); - int normalDirY = NORMAL_DIR(Y_AXIS, f); - int normalDirZ = NORMAL_DIR(Z_AXIS, f); - - for (int vertex = 0; vertex < 4; vertex++) { - int xPos = NORMAL_VERTEX_POS(X_AXIS, vertex, f); - int yPos = NORMAL_VERTEX_POS(Y_AXIS, vertex, f); - int zPos = NORMAL_VERTEX_POS(Z_AXIS, vertex, f); - - int sideX = (xPos == 1) ? 1 : -1; - int sideY = (yPos == 1) ? 1 : -1; - int sideZ = (zPos == 1) ? 1 : -1; - - if (normalDirX == 1 || normalDirX == -1) { - out += std::to_string(0) + ", "; - out += std::to_string(sideY) + ", "; - out += std::to_string(0) + ",\t"; - - out += std::to_string(0) + ", "; - out += std::to_string(0) + ", "; - out += std::to_string(sideZ) + ",\n"; - } - - if (normalDirY == 1 || normalDirY == -1) { - out += std::to_string(sideX) + ", "; - out += std::to_string(0) + ", "; - out += std::to_string(0) + ",\t"; - - out += std::to_string(0) + ", "; - out += std::to_string(0) + ", "; - out += std::to_string(sideZ) + ",\n"; - } - - if (normalDirZ == 1 || normalDirZ == -1) { - out += std::to_string(sideX) + ", "; - out += std::to_string(0) + ", "; - out += std::to_string(0) + ",\t"; - - out += std::to_string(0) + ", "; - out += std::to_string(sideY) + ", "; - out += std::to_string(0) + ",\n"; - } - } - } - - std::cout << out; - } /**/ -} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Voxels/VoxelData.cpp b/Deer/src/DeerRender/Voxels/VoxelData.cpp deleted file mode 100644 index 23ea158..0000000 --- a/Deer/src/DeerRender/Voxels/VoxelData.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include -#include -#include - -#include "DeerRender/DataStore.h" -#include "DeerRender/Log.h" -#include "DeerRender/Render/Shader.h" -#include "DeerRender/Voxel.h" -#include "DeerRender/VoxelAspect.h" -#include "DeerRender/Voxels/Serialization/VoxelAspect_Serialization.h" -#include "cereal/archives/json.hpp" - -namespace Deer { - namespace DataStore { - std::vector voxelsAspect; - std::unordered_map texturesIDs; - Ref solidVoxelShader; - } // namespace DataStore - - void DataStore::loadVoxelsAspect() { - std::vector voxelsAspectPath = - DataStore::getFiles(DEER_VOXEL_ASPECT_PATH, ".vaspect"); - voxelsAspect.clear(); - voxelsAspect.resize(voxelsInfo.size()); - - voxelsAspect[0].definition.voxelName = VOXEL_INFO_TYPE_AIR; - - DEER_CORE_TRACE("Loading voxel aspect "); - // DEER_CORE_TRACE(" default - air"); - for (Path& voxelAspectPath : voxelsAspectPath) { - uint32_t size; - uint8_t* data = DataStore::readFile(voxelAspectPath, &size); - - std::string dataString((char*)data, size); - std::istringstream inputStream(dataString); - - VoxelAspectDefinition aspectDefinition; - { - cereal::JSONInputArchive archive(inputStream); - archive(cereal::make_nvp("voxelAspect", aspectDefinition)); - } - - if (aspectDefinition.voxelName.empty()) { - DEER_CORE_ERROR("{0} has an empty name", - voxelAspectPath.generic_string().c_str()); - continue; - } - - int16_t voxelID = getVoxelID(aspectDefinition.voxelName); - if (voxelID == -1) { - DEER_CORE_ERROR( - "Voxel aspect {0} references {1} but it does not exist", - voxelAspectPath.generic_string().c_str(), - aspectDefinition.voxelName.c_str()); - - continue; - } - - voxelsAspect[voxelID].definition = aspectDefinition; - } - - DEER_CORE_TRACE("Extracting textures "); - for (VoxelAspect& voxelAspect : voxelsAspect) { - if (voxelsInfo[DataStore::getVoxelID( - voxelAspect.definition.voxelName)] - .type != VoxelInfoType::Voxel) - continue; - - for (int i = 0; i < 6; i++) { - std::string& faceTextureString = - voxelAspect.definition.textureFaces[i]; - - if (faceTextureString.empty()) { - DEER_CORE_WARN( - "{0} has an empty texture at position {1} this could " - "cause unwanted behaviour!", - voxelAspect.definition.voxelName.c_str(), i); - - voxelAspect.textureFacesIDs[i] = 0; - continue; - } - - if (texturesIDs.contains(faceTextureString)) - voxelAspect.textureFacesIDs[i] = - texturesIDs[faceTextureString]; - else { - uint16_t textureID = texturesIDs.size(); - - texturesIDs[faceTextureString] = textureID; - voxelAspect.textureFacesIDs[i] = textureID; - } - } - } - } - - void DataStore::createExampleVoxelAspect() { - VoxelAspectDefinition voxelAspectDefinition; - - std::ostringstream outputStream; - { - cereal::JSONOutputArchive archive(outputStream); - archive(cereal::make_nvp("voxelAspect", voxelAspectDefinition)); - } - - std::string restultString = outputStream.str(); - DataStore::saveFile(Path(DEER_VOXEL_PATH) / "vaspect.example", - (uint8_t*)restultString.c_str(), - restultString.size()); - } - - void DataStore::loadVoxelsShaders() { - uint32_t size; - uint8_t* data = DataStore::readFile( - Path(DEER_VOXEL_SHADER_PATH) / "solid_voxel.glsl", &size); - - solidVoxelShader = Shader::create(data, size); - - delete[] data; - } - - // Ref& DataStore::getSolidVoxelShader() { return solidVoxelShader; } -} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Voxels/VoxelData_TextureAtlas.cpp b/Deer/src/DeerRender/Voxels/VoxelData_TextureAtlas.cpp deleted file mode 100644 index 830392a..0000000 --- a/Deer/src/DeerRender/Voxels/VoxelData_TextureAtlas.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* -#include -#include - -#include "DeerRender/DataStore.h" -#include "DeerRender/Log.h" -#include "DeerRender/Render/Texture.h" -#include "DeerRender/Voxel.h" -#include "DeerRender/VoxelAspect.h" - -namespace Deer { - namespace DataStore { - extern std::unordered_map texturesIDs; - - int squareTextureSize = 0; - uint8_t* voxelColorTextureAtlasData = nullptr; - Ref voxelColorTextureAtlas = nullptr; - } // namespace DataStore - - void DataStore::generateTextureAtlas() { - if (voxelColorTextureAtlasData != nullptr) { - delete[] voxelColorTextureAtlasData; - voxelColorTextureAtlasData = nullptr; - } - - squareTextureSize = 1; - int textureCount = texturesIDs.size(); - while (squareTextureSize * squareTextureSize < textureCount) - squareTextureSize++; - - int textureAtlasSize = squareTextureSize * VOXEL_TEXTURE_SIZE_X * - squareTextureSize * VOXEL_TEXTURE_SIZE_Y * 4; - voxelColorTextureAtlasData = new uint8_t[textureAtlasSize]{}; - - DEER_CORE_TRACE("Creating Texture Atlas "); - for (auto& texture : texturesIDs) { - uint32_t size; - uint8_t* fileData = DataStore::readFile( - Path(DEER_VOXEL_TEXTURE_PATH) / (texture.first + ".png"), - &size); - - // DEER_CORE_TRACE(" {0}.png - {1}", texture.first.c_str(), - // texture.second); - if (fileData == nullptr) { - DEER_CORE_ERROR("{0}.png does not exists", - texture.first.c_str()); - continue; - } - - int width, height, channels; - uint8_t* textureData = stbi_load_from_memory(fileData, size, &width, - &height, &channels, 4); - - if (channels < 3) { - DEER_CORE_ERROR( - "{0}.png has {1} channels and it must be bigger than {2}", - texture.first.c_str(), channels, 3); - } else if (width != VOXEL_TEXTURE_SIZE_X) { - DEER_CORE_ERROR("{0}.png has a width of {1} and it must be {2}", - texture.first.c_str(), width, - VOXEL_TEXTURE_SIZE_X); - } else if (height != VOXEL_TEXTURE_SIZE_Y) { - DEER_CORE_ERROR( - "{0}.png has a height of {1} and it must be {2}", - texture.first.c_str(), height, VOXEL_TEXTURE_SIZE_Y); - } else { - int yOffset = (int)(texture.second / squareTextureSize); - int xOffset = texture.second - yOffset * squareTextureSize; - - int yOffsetPixels = yOffset * VOXEL_TEXTURE_SIZE_Y; - int xOffsetPixels = xOffset * VOXEL_TEXTURE_SIZE_X; - - for (int y = 0; y < VOXEL_TEXTURE_SIZE_Y; y++) { - for (int x = 0; x < VOXEL_TEXTURE_SIZE_X; x++) { - int inputTextureIndex = (x + y * width) * 4; - int outputTextureIndex = - (x + xOffsetPixels + - (y + yOffsetPixels) * VOXEL_TEXTURE_SIZE_X * - squareTextureSize) * - 4; - - voxelColorTextureAtlasData[outputTextureIndex + 0] = - textureData[inputTextureIndex + 0]; - voxelColorTextureAtlasData[outputTextureIndex + 1] = - textureData[inputTextureIndex + 1]; - voxelColorTextureAtlasData[outputTextureIndex + 2] = - textureData[inputTextureIndex + 2]; - voxelColorTextureAtlasData[outputTextureIndex + 3] = - textureData[inputTextureIndex + 3]; - } - } - } - - stbi_image_free(textureData); - delete[] fileData; - } - - voxelColorTextureAtlas = - Texture2D::create(voxelColorTextureAtlasData, - squareTextureSize * VOXEL_TEXTURE_SIZE_X, - squareTextureSize * VOXEL_TEXTURE_SIZE_Y, 4); - - // temp - // Path savePath = DataStore::rootPath / DEER_TEMP_PATH / "voxel_texture_atlas.png"; - // DataStore::createFolder(DataStore::rootPath / DEER_TEMP_PATH); - // stbi_write_png(savePath.generic_string().c_str(), squareTextureSize * VOXEL_TEXTURE_SIZE_X, squareTextureSize * VOXEL_TEXTURE_SIZE_Y, 4, voxelColorTextureAtlasData, squareTextureSize * VOXEL_TEXTURE_SIZE_X * 4); - } - - int DataStore::getVoxelTextureAtlasSize() { return squareTextureSize; } - - Ref& DataStore::getVoxelColorTextureAtlas() { - return voxelColorTextureAtlas; - } -} // namespace Deer - */ \ No newline at end of file diff --git a/Deer/src/DeerRender/Voxels/VoxelWorld.cpp b/Deer/src/DeerRender/Voxels/VoxelWorld.cpp deleted file mode 100755 index 770f16b..0000000 --- a/Deer/src/DeerRender/Voxels/VoxelWorld.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "DeerRender/VoxelWorld.h" - -#include "Deer/Voxels/Chunk.h" -#include "Deer/Voxels/VoxelWorldData.h" -#include "DeerRender/Application.h" -#include "DeerRender/Components.h" -#include "DeerRender/Log.h" -#include "DeerRender/Tools/Memory.h" -#include "DeerRender/Voxel.h" - -#include "DeerRender/Render/Render.h" -#include "DeerRender/Render/RenderUtils.h" -#include "DeerRender/Render/Texture.h" -#include "DeerRender/Scene.h" -#include "DeerRender/Voxels/VoxelWorldRenderData.h" -#include "glm/glm.hpp" -#include "glm/gtc/matrix_inverse.hpp" -#include "glm/gtc/matrix_transform.hpp" - -namespace Deer { - VoxelLight VoxelWorld::readLight(VoxelCordinates coords) { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - ChunkID chunkID; - ChunkVoxelID chunkVoxelID; - - extractChunkCordinates(coords, chunkID, chunkVoxelID); - if (!worldProps.isValid(chunkID)) - return lightVoxel; - - Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)]; - return chunk.readLight(chunkVoxelID); - } - - VoxelLight& VoxelWorld::modLight(VoxelCordinates coords) { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - ChunkID chunkID; - ChunkVoxelID chunkVoxelID; - - extractChunkCordinates(coords, chunkID, chunkVoxelID); - if (!worldProps.isValid(chunkID)) - return lightVoxel; - - chunkQueue.addChunk(chunkID); - - Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)]; - return chunk.modLight(chunkVoxelID); - } - - void VoxelWorld::render(const SceneCamera& camera) { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - glm::mat4 camMatrix = glm::inverse(camera.transform.getMatrix()); - glm::mat4 projectionMatrix = camera.camera.getMatrix(); - glm::mat4 invertZ = glm::scale(glm::mat4(1.0f), glm::vec3(1, 1, -1)); - - // Lets invert the z axis for engine convenience - glm::mat4 cameraProjectionMatrix = - projectionMatrix * invertZ * camMatrix; - - // DataStore::getVoxelColorTextureAtlas()->bind(0); - - // Ref& shader = DataStore::getSolidVoxelShader(); - // shader->bind(); - - // shader->uploadUniformMat4("u_viewMatrix", cameraProjectionMatrix); - // shader->uploadUniformMat4("u_worldMatrix", glm::mat4(1.0f)); - // shader->uploadUniformInt("u_texture", 0); - // shader->uploadUniformInt("u_textureSize", - // DataStore::getVoxelTextureAtlasSize()); - - for (int x = 0; x < worldProps.getChunkCount(); x++) { - ChunkRender& chunkRender = chunksRender[x]; - if (!chunkRender.hasData) - continue; - - ChunkID chunkID = worldProps.getChunkID(x); - chunkRender.solidVoxel->bind(); - - // shader->uploadUniformInt("u_chunkID_x", chunkID.x); - // shader->uploadUniformInt("u_chunkID_y", chunkID.y); - // shader->uploadUniformInt("u_chunkID_z", chunkID.z); - - Render::submit(*chunkRender.solidVoxel); - } - } -} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Voxels/VoxelWorldRenderData.cpp b/Deer/src/DeerRender/Voxels/VoxelWorldRenderData.cpp deleted file mode 100644 index e07e37f..0000000 --- a/Deer/src/DeerRender/Voxels/VoxelWorldRenderData.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "DeerRender/Voxels/VoxelWorldRenderData.h" -#include "Deer/Voxels/Chunk.h" -#include "DeerRender/VoxelWorld.h" - -namespace Deer { - namespace VoxelWorld { - // Chunk render data - Scope chunksRender; - ChunkUpdateQueue chunkQueue; - - // Voxel creation data - std::vector indices; - std::vector vertexData; - std::queue ambientLightPropagation; - std::queue voxelLightPropagation; - std::vector tmp_voxelLightSource; - } // namespace VoxelWorld - - void VoxelWorld::clearRenderVars() { - chunksRender.reset(); - chunkQueue.reset(); - - indices.clear(); - vertexData.clear(); - - while (!ambientLightPropagation.empty()) { - ambientLightPropagation.pop(); - } - while (!voxelLightPropagation.empty()) { - voxelLightPropagation.pop(); - } - - tmp_voxelLightSource.clear(); - } - - void VoxelWorld::initializeRenderVars(const VoxelWorldProps& props) { - chunksRender = MakeScope(props.getChunkCount()); - } -} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Voxels/VoxelWorldRenderData.h b/Deer/src/DeerRender/Voxels/VoxelWorldRenderData.h deleted file mode 100644 index 8ac1449..0000000 --- a/Deer/src/DeerRender/Voxels/VoxelWorldRenderData.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once -#include -#include -#include - -#include "DeerRender/Render/VertexArray.h" -#include "DeerRender/Tools/Memory.h" -#include "DeerRender/Voxel.h" -#include "DeerRender/VoxelWorld.h" - -namespace Deer { - struct ChunkRender { - Scope solidVoxel; - bool hasData = false; - }; - - struct SolidVoxelVertexData { - uint16_t textureID = 0; - uint8_t ambient_occlusion = 0; - - uint8_t xPos = 0; - uint8_t yPos = 0; - uint8_t zPos = 0; - - uint8_t a_light = 0; - uint8_t r_light = 0; - uint8_t g_light = 0; - uint8_t b_light = 0; - - uint8_t normal = 0; - - uint8_t u = 0; - uint8_t v = 0; - - SolidVoxelVertexData() = default; - }; - - class ChunkUpdateQueue { - public: - // TODO: Add priority - void addChunk(ChunkID); - void reset(); - ChunkID pullChunk(); - bool hasChunk(); - - private: - std::queue m_updateOrder; - std::unordered_set m_containingChunks; - }; - - namespace VoxelWorld { - // Chunk render data - extern Scope chunksRender; - extern ChunkUpdateQueue chunkQueue; - - // Voxel creation data - extern std::vector indices; - extern std::vector vertexData; - - // Voxel temp light variables - extern std::queue ambientLightPropagation; - extern std::queue voxelLightPropagation; - extern std::vector tmp_voxelLightSource; - - void clearRenderVars(); - void initializeRenderVars(const VoxelWorldProps& props); - } // namespace VoxelWorld -} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Voxels/VoxelWorld_AmbientLightPropagation.cpp b/Deer/src/DeerRender/Voxels/VoxelWorld_AmbientLightPropagation.cpp deleted file mode 100755 index 65a7aa0..0000000 --- a/Deer/src/DeerRender/Voxels/VoxelWorld_AmbientLightPropagation.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "Deer/Voxels/Chunk.h" -#include "DeerRender/Application.h" -#include "DeerRender/VoxelWorld.h" - -#include "Deer/Voxels/VoxelWorldData.h" -#include "DeerRender/Components.h" - -#include "DeerRender/Render/Render.h" -#include "DeerRender/Render/RenderUtils.h" -#include "DeerRender/Render/Texture.h" -#include "DeerRender/Voxels/VoxelWorldRenderData.h" - -#include "DeerRender/Log.h" -#include "glm/glm.hpp" -#include "glm/gtc/matrix_inverse.hpp" -#include "glm/gtc/matrix_transform.hpp" - -namespace Deer { - void VoxelWorld::bakeAmbientLight(int minX, int maxX, int minZ, int maxZ) { - int xPos = minX; - for (; xPos <= maxX; xPos++) { - int zPos = minZ; - for (; zPos <= maxZ; zPos++) { - LayerVoxel layer = readLayerVoxel(xPos, zPos); - uint16_t maxHeight = layer.height; - uint16_t minHeight = layer.ambient_light_height; - - if (minHeight > layer.height) - minHeight = layer.height; - - uint16_t maxHeightSorroundings = maxHeight; - for (int i = 0; i < 8; i++) { - int checkX = xPos + LAYER_CHECK_DIRS(X_AXIS, i); - int checkZ = zPos + LAYER_CHECK_DIRS(Y_AXIS, i); - - LayerVoxel layer = readLayerVoxel(checkX, checkZ); - if (layer.height > maxHeightSorroundings) - maxHeightSorroundings = layer.height; - } - - maxHeightSorroundings++; - if (maxHeightSorroundings >= CHUNK_SIZE_Y * worldProps.chunkSizeY) - maxHeightSorroundings = CHUNK_SIZE_Y * worldProps.chunkSizeY - 1; - - ChunkID chunkID; - ChunkVoxelID chunkVoxelID; - - // Depending if it's an edge we will add to queue to propagate the light - bool isPositionEdge = - (xPos == minX) || (xPos == maxX) || - (zPos == minZ) || (zPos == maxZ); - - if (xPos == 0 || zPos == 0 || xPos == CHUNK_SIZE_X * worldProps.chunkSizeX - 1 || zPos == CHUNK_SIZE_Z * worldProps.chunkSizeZ - 1) - isPositionEdge = false; - - // All light voxelsInfo under the max height must be put to 0 ambient light and above to 255 - // I think this is optional - - int yPos = minHeight; - if (!isPositionEdge) { - // Empty the ilumination - for (; yPos < maxHeight; yPos++) { - extractChunkCordinates(xPos, yPos, zPos, chunkID, chunkVoxelID); - Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)]; - VoxelLight& voxelLight = chunk.modLight(chunkVoxelID); - - voxelLight.ambient_light = 0; - } - } else { - // Add to queue - for (; yPos < maxHeight; yPos++) { - extractChunkCordinates(xPos, yPos, zPos, chunkID, chunkVoxelID); - Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)]; - VoxelLight voxelLight = chunk.readLight(chunkVoxelID); - - if (voxelLight.ambient_light > 0) - ambientLightPropagation.push(VoxelCordinates(xPos, yPos, zPos)); - } - } - - // Fill with light voxelsInfo and add queue to update light propagation - for (; yPos < maxHeightSorroundings; yPos++) { - extractChunkCordinates(xPos, yPos, zPos, chunkID, chunkVoxelID); - Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)]; - VoxelLight& voxelLight = chunk.modLight(chunkVoxelID); - - voxelLight.ambient_light = 255; - ambientLightPropagation.push(VoxelCordinates(xPos, yPos, zPos)); - } - - modLayerVoxel(xPos, zPos).ambient_light_height = CHUNK_SIZE_Y * worldProps.chunkSizeY; - } - } - - // Resolve ambient light propagation - while (!ambientLightPropagation.empty()) { - resolveNextAmbientLightPropagation(); - } - } - - void VoxelWorld::bakeAmbientLightFromPoint(int x, int z) { - int minX = x - 16; - int maxX = x + 16; - - int minZ = z - 16; - int maxZ = z + 16; - - minX = (minX < 0) ? 0 : minX; - maxX = (maxX >= worldProps.chunkSizeX * CHUNK_SIZE_X) ? worldProps.chunkSizeX * CHUNK_SIZE_X - 1 : maxX; - - minZ = (minZ < 0) ? 0 : minZ; - maxZ = (maxZ >= worldProps.chunkSizeZ * CHUNK_SIZE_Z) ? worldProps.chunkSizeZ * CHUNK_SIZE_Z - 1 : maxZ; - - bakeAmbientLight(minX, maxX, minZ, maxZ); - } - - void VoxelWorld::resolveNextAmbientLightPropagation() { - VoxelCordinates position = ambientLightPropagation.front(); - ambientLightPropagation.pop(); - - LayerVoxel& layerVoxel = modLayerVoxel(position.x, position.z); - - if (layerVoxel.ambient_light_height > position.y) - layerVoxel.ambient_light_height = position.y; - - VoxelLight currentLight = readLight(position); - bool solidCheck[6] = {false}; - // Check for every simple dir - for (int i = 0; i < 6; i++) { - VoxelCordinates next( - position.x + NORMAL_DIR(X_AXIS, i), - position.y + NORMAL_DIR(Y_AXIS, i), - position.z + NORMAL_DIR(Z_AXIS, i)); - - Voxel nextVoxel = readVoxel(next); - solidCheck[i] = nextVoxel.isVoxelType(); - if (solidCheck[i]) - continue; - - VoxelLight& nextLight = modLight(next); - int nextLightMinValue = currentLight.ambient_light - LIGHT_PROPAGATION_SIMPLE_FALL; - - if (nextLight.ambient_light < nextLightMinValue) { - nextLight.ambient_light = nextLightMinValue; - ambientLightPropagation.push(next); - } - } - - return; - // TODO - // Check for every complex dir - for (int i = 0; i < 6; i++) { - int cDir0 = LIGHT_PROPAGATION_COMPLEX_DIR(0, i); - int cDir1 = LIGHT_PROPAGATION_COMPLEX_DIR(1, i); - - if (solidCheck[cDir0] || solidCheck[cDir1]) - continue; - - VoxelCordinates next( - NORMAL_DIR(X_AXIS, cDir0) + NORMAL_DIR(X_AXIS, cDir1), - NORMAL_DIR(Y_AXIS, cDir0) + NORMAL_DIR(Y_AXIS, cDir1), - NORMAL_DIR(Z_AXIS, cDir0) + NORMAL_DIR(Z_AXIS, cDir1)); - - Voxel nextVoxel = readVoxel(next); - if (nextVoxel.isVoxelType()) - continue; - - VoxelLight& nextLight = modLight(next); - int nextLightMinValue = currentLight.ambient_light - LIGHT_PROPAGATION_COMPLEX_FALL; - - if (nextLight.ambient_light < nextLightMinValue) { - nextLight.ambient_light = nextLightMinValue; - ambientLightPropagation.push(next); - } - } - } -} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Voxels/VoxelWorld_SolidVoxelGeneration.cpp b/Deer/src/DeerRender/Voxels/VoxelWorld_SolidVoxelGeneration.cpp deleted file mode 100755 index 8ecd779..0000000 --- a/Deer/src/DeerRender/Voxels/VoxelWorld_SolidVoxelGeneration.cpp +++ /dev/null @@ -1,263 +0,0 @@ -#include "Deer/Voxels/Chunk.h" -#include "Deer/Voxels/VoxelWorldData.h" -#include "DeerRender/Application.h" -#include "DeerRender/Components.h" -#include "DeerRender/VoxelWorld.h" - -#include "DeerRender/Render/Render.h" -#include "DeerRender/Render/RenderUtils.h" -#include "DeerRender/Render/Texture.h" -#include "DeerRender/Voxels/VoxelWorldRenderData.h" -#include "glm/glm.hpp" -#include "glm/gtc/matrix_inverse.hpp" -#include "glm/gtc/matrix_transform.hpp" - -namespace Deer { - void VoxelWorld::bakeNextChunk() { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - if (!chunkQueue.hasChunk()) - return; - - // Pull the next chunk to render - ChunkID nextChunk = chunkQueue.pullChunk(); - vertexData.clear(); - indices.clear(); - - // For each voxel - for (int x = 0; x < CHUNK_SIZE_X; x++) { - for (int y = 0; y < CHUNK_SIZE_Y; y++) { - for (int z = 0; z < CHUNK_SIZE_Z; z++) { - genSolidVoxel(nextChunk, ChunkVoxelID(x, y, z)); - } - } - } - - // Pass the data to the GPU - Scope va = Scope(VertexArray::create()); - va->bind(); - Ref vb = VertexBuffer::create( - vertexData.data(), - vertexData.size() * sizeof(SolidVoxelVertexData)); - Ref ib = - IndexBuffer::create(indices.data(), - indices.size() * sizeof(uint32_t), - IndexDataType::Unsigned_Int); - - BufferLayout layout( - {{"a_textureID", DataType::Unsigned_Short2, ShaderDataType::Integer, - offsetof(SolidVoxelVertexData, textureID)}, - {"a_ambient_occlusion", DataType::Unsigned_Byte, - ShaderDataType::FloatingPoint, - offsetof(SolidVoxelVertexData, ambient_occlusion)}, - - {"a_xPos", DataType::Unsigned_Byte, ShaderDataType::FloatingPoint, - offsetof(SolidVoxelVertexData, xPos)}, - {"a_yPos", DataType::Unsigned_Byte, ShaderDataType::FloatingPoint, - offsetof(SolidVoxelVertexData, yPos)}, - {"a_zPos", DataType::Unsigned_Byte, ShaderDataType::FloatingPoint, - offsetof(SolidVoxelVertexData, zPos)}, - - {"a_a_light", DataType::Unsigned_Byte, - ShaderDataType::FloatingPoint, - offsetof(SolidVoxelVertexData, a_light)}, - {"a_r_light", DataType::Unsigned_Byte, - ShaderDataType::FloatingPoint, - offsetof(SolidVoxelVertexData, r_light)}, - {"a_g_light", DataType::Unsigned_Byte, - ShaderDataType::FloatingPoint, - offsetof(SolidVoxelVertexData, g_light)}, - {"a_b_light", DataType::Unsigned_Byte, - ShaderDataType::FloatingPoint, - offsetof(SolidVoxelVertexData, b_light)}, - - {"a_normal", DataType::Unsigned_Byte, ShaderDataType::Integer, - offsetof(SolidVoxelVertexData, normal)}, - - {"a_u", DataType::Unsigned_Byte, ShaderDataType::FloatingPoint, - offsetof(SolidVoxelVertexData, u)}, - {"a_v", DataType::Unsigned_Byte, ShaderDataType::FloatingPoint, - offsetof(SolidVoxelVertexData, v)}}, - sizeof(SolidVoxelVertexData)); - - vb->setLayout(layout); - va->addVertexBuffer(vb); - va->setIndexBuffer(ib); - - // Update the data to the chunk render - int id = worldProps.getWorldChunkID(nextChunk); - ChunkRender& chunkRender = chunksRender[id]; - chunkRender.solidVoxel = std::move(va); - chunkRender.hasData = true; - } - - void VoxelWorld::genSolidVoxel(ChunkID chunkID, ChunkVoxelID chunkVoxelID) { - Chunk& workingChunk = chunks[worldProps.getWorldChunkID(chunkID)]; - Voxel voxel = workingChunk.readVoxel(chunkVoxelID); - - if (!voxel.isVoxelType()) - return; - - for (int i = 0; i < 6; i++) { - // front means the front voxel of the face - VoxelCordinates frontID(NORMAL_DIR(X_AXIS, i) + chunkVoxelID.x + - CHUNK_SIZE_X * chunkID.x, - NORMAL_DIR(Y_AXIS, i) + chunkVoxelID.y + - CHUNK_SIZE_Y * chunkID.y, - NORMAL_DIR(Z_AXIS, i) + chunkVoxelID.z + - CHUNK_SIZE_Z * chunkID.z); - - Voxel frontVoxel = readVoxel(frontID); - // If the face is inside 2 Voxels we will not render it - if (frontVoxel.isVoxelType()) - continue; - - VoxelLight frontVoxelLight = readLight(frontID); - - // front2ID means the front voxel in 2 voxels apart - VoxelCordinates front2ID( - NORMAL_DIR(X_AXIS, i) * 2 + chunkVoxelID.x + - CHUNK_SIZE_X * chunkID.x, - NORMAL_DIR(Y_AXIS, i) * 2 + chunkVoxelID.y + - CHUNK_SIZE_Y * chunkID.y, - NORMAL_DIR(Z_AXIS, i) * 2 + chunkVoxelID.z + - CHUNK_SIZE_Z * chunkID.z); - - Voxel front2Voxel = readVoxel(frontID); - VoxelLight front2VoxelLight = readLight(frontID); - - // Face Shadow means that face is not in the direction of the light - bool isFaceShadow = frontVoxelLight.ambient_light != 255 && - (frontVoxel.isVoxelType() || - frontVoxelLight.ambient_light > - front2VoxelLight.ambient_light); - - // Save the vertex id for later - int vertexID = vertexData.size(); - - int voxel_count[4]; - - // For every vertex - for (int v = 0; v < 4; v++) { - // This var takes the count of the voxels that where added in - // voxel_light - int sample_count = 1; - // Count the blocks to calculate the ambient occlusion, min - // value 0 max value 2 - voxel_count[v] = 0; - - // col 0 -> ambient oclusion - // col 1 -> red light - // col 2 -> green light - // col 3 -> blue light - int voxel_light[4]; - - voxel_light[0] = frontVoxelLight.ambient_light; - voxel_light[1] = frontVoxelLight.r_light; - voxel_light[2] = frontVoxelLight.g_light; - voxel_light[3] = frontVoxelLight.b_light; - - // Checks if there is air on the blocks of the side - bool airEdge[2]; - - // Calculate ambient occlusion and light difusion - for (int a = 0; a < 2; a++) { - VoxelCordinates checkChordsID( - frontID.x + AMBIENT_OCCLUSION_VERTEX(X_AXIS, a, v, i), - frontID.y + AMBIENT_OCCLUSION_VERTEX(Y_AXIS, a, v, i), - frontID.z + AMBIENT_OCCLUSION_VERTEX(Z_AXIS, a, v, i)); - - Voxel checkChordsVoxel = readVoxel(checkChordsID); - VoxelLight checkChordsVoxelLight = readLight(checkChordsID); - - // Check for the same chords but 2 voxels apart - airEdge[a] = !checkChordsVoxel.isVoxelType(); - if (airEdge[a]) { - sample_count++; - - voxel_light[0] += checkChordsVoxelLight.ambient_light; - voxel_light[1] += checkChordsVoxelLight.r_light; - voxel_light[2] += checkChordsVoxelLight.g_light; - voxel_light[3] += checkChordsVoxelLight.b_light; - } else { - voxel_count[v]++; - } - } - - if (airEdge[0] || airEdge[1]) { - VoxelCordinates checkChordsID( - frontID.x + AMBIENT_OCCLUSION_VERTEX(X_AXIS, 0, v, i) + - AMBIENT_OCCLUSION_VERTEX(X_AXIS, 1, v, i), - frontID.y + AMBIENT_OCCLUSION_VERTEX(Y_AXIS, 0, v, i) + - AMBIENT_OCCLUSION_VERTEX(Y_AXIS, 1, v, i), - frontID.z + AMBIENT_OCCLUSION_VERTEX(Z_AXIS, 0, v, i) + - AMBIENT_OCCLUSION_VERTEX(Z_AXIS, 1, v, i)); - - Voxel checkChordsVoxel = readVoxel(checkChordsID); - VoxelLight checkChordsVoxelLight = readLight(checkChordsID); - - if (!checkChordsVoxel.isVoxelType()) { - sample_count++; - - voxel_light[0] += checkChordsVoxelLight.ambient_light; - voxel_light[1] += checkChordsVoxelLight.r_light; - voxel_light[2] += checkChordsVoxelLight.g_light; - voxel_light[3] += checkChordsVoxelLight.b_light; - } else { - voxel_count[v]++; - } - } - - for (int xi = 0; xi < 4; xi++) { - voxel_light[xi] = (voxel_light[xi]) / sample_count; - voxel_light[xi] = - (voxel_light[xi] > 255) ? 255 : voxel_light[xi]; - } - - SolidVoxelVertexData vertex_data; - vertex_data.textureID = - DataStore::voxelsAspect[voxel.id].getTextureID(i); - vertex_data.ambient_occlusion = voxel_count[v]; - - vertex_data.xPos = - chunkVoxelID.x + NORMAL_VERTEX_POS(X_AXIS, v, i); - vertex_data.yPos = - chunkVoxelID.y + NORMAL_VERTEX_POS(Y_AXIS, v, i); - vertex_data.zPos = - chunkVoxelID.z + NORMAL_VERTEX_POS(Z_AXIS, v, i); - - vertex_data.a_light = voxel_light[0]; - vertex_data.r_light = voxel_light[1]; - vertex_data.g_light = voxel_light[2]; - vertex_data.b_light = voxel_light[3]; - - vertex_data.normal = i; - - vertex_data.u = VERTEX_UV(X_AXIS, v); - vertex_data.v = VERTEX_UV(Y_AXIS, v); - - vertexData.push_back(vertex_data); - } - - if (voxel_count[0] + voxel_count[3] > - voxel_count[1] + voxel_count[2]) { - indices.push_back(vertexID); - indices.push_back(vertexID + 2); - indices.push_back(vertexID + 1); - - indices.push_back(vertexID + 1); - indices.push_back(vertexID + 2); - indices.push_back(vertexID + 3); - } else { - indices.push_back(vertexID); - indices.push_back(vertexID + 3); - indices.push_back(vertexID + 1); - - indices.push_back(vertexID + 2); - indices.push_back(vertexID + 3); - indices.push_back(vertexID); - } - } - } - -} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Voxels/VoxelWorld_VoxelLightPropagation.cpp b/Deer/src/DeerRender/Voxels/VoxelWorld_VoxelLightPropagation.cpp deleted file mode 100644 index 43f3564..0000000 --- a/Deer/src/DeerRender/Voxels/VoxelWorld_VoxelLightPropagation.cpp +++ /dev/null @@ -1,250 +0,0 @@ -#include "Deer/Voxels/Chunk.h" -#include "Deer/Voxels/VoxelWorldData.h" -#include "DeerRender/Log.h" -#include "DeerRender/VoxelWorld.h" -#include "DeerRender/Voxels/VoxelWorldRenderData.h" - -namespace Deer { - void VoxelWorld::bakeVoxelLightFromPoint(VoxelCordinates coords) { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - VoxelCordinates min = VoxelCordinates(coords.x - 16, coords.y - 16, coords.z - 16); - VoxelCordinates max = VoxelCordinates(coords.x + 16, coords.y + 16, coords.z + 16); - - worldProps.clampCordinates(min); - worldProps.clampCordinates(max); - - bakeVoxelLight(min, max); - } - - void VoxelWorld::bakeVoxelLight(VoxelCordinates min, VoxelCordinates max) { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - // We want to make the box 1 layer smaller - // For every axis, X & Y & Z - for (int i = 0; i < 3; i++) { - min[i]++; - max[i]--; - } - ChunkID minChunkID; - ChunkID maxChunkID; - ChunkVoxelID minChunkVoxelID; - ChunkVoxelID maxChunkVoxelID; - - extractChunkCordinates(min, minChunkID, minChunkVoxelID); - extractChunkCordinates(max, maxChunkID, maxChunkVoxelID); - - tmp_voxelLightSource.clear(); - - // We want to empty the voxel light of the section first - ChunkID workingChunkID; - for (workingChunkID.x = minChunkID.x; workingChunkID.x <= maxChunkID.x; - workingChunkID.x++) { - for (workingChunkID.y = minChunkID.y; - workingChunkID.y <= maxChunkID.y; workingChunkID.y++) { - for (workingChunkID.z = minChunkID.z; - workingChunkID.z <= maxChunkID.z; workingChunkID.z++) { - ChunkVoxelID workingMinVoxelID( - (workingChunkID.x == minChunkID.x) ? minChunkVoxelID.x - : 0, - (workingChunkID.y == minChunkID.y) ? minChunkVoxelID.y - : 0, - (workingChunkID.z == minChunkID.z) ? minChunkVoxelID.z - : 0); - ChunkVoxelID workingMaxVoxelID( - (workingChunkID.x == maxChunkID.x) ? maxChunkVoxelID.x - : CHUNK_SIZE_X - 1, - (workingChunkID.y == maxChunkID.y) ? maxChunkVoxelID.y - : CHUNK_SIZE_Y - 1, - (workingChunkID.z == maxChunkID.z) ? maxChunkVoxelID.z - : CHUNK_SIZE_Z - 1); - - Chunk& workingChunk = - chunks[worldProps.getWorldChunkID(workingChunkID)]; - workingChunk.clearVoxelLightAndSaveSources( - workingMinVoxelID, workingMaxVoxelID, workingChunkID, - tmp_voxelLightSource); - } - } - } - - // Cover all 6 edges with light propagation - for (int x = min.x; x <= max.x; x++) { - for (int y = min.y; y <= max.y; y++) { - VoxelCordinates minZEdge(x, y, min.z - 1); - VoxelCordinates maxZEdge(x, y, max.z + 1); - - VoxelLight minZEdgeLight = readLight(minZEdge); - VoxelLight maxZEdgeLight = readLight(maxZEdge); - - if (minZEdgeLight.b_light || minZEdgeLight.g_light || - minZEdgeLight.b_light) - voxelLightPropagation.push(minZEdge); - if (maxZEdgeLight.b_light || maxZEdgeLight.g_light || - maxZEdgeLight.b_light) - voxelLightPropagation.push(maxZEdge); - } - } - - for (int x = min.x; x <= max.x; x++) { - for (int z = min.z; z <= max.z; z++) { - VoxelCordinates minYEdge(x, min.y - 1, z); - VoxelCordinates maxYEdge(x, max.y + 1, z); - - VoxelLight minYEdgeLight = readLight(minYEdge); - VoxelLight maxYEdgeLight = readLight(maxYEdge); - - if (minYEdgeLight.b_light || minYEdgeLight.g_light || - minYEdgeLight.b_light) - voxelLightPropagation.push(minYEdge); - if (maxYEdgeLight.b_light || maxYEdgeLight.g_light || - maxYEdgeLight.b_light) - voxelLightPropagation.push(maxYEdge); - } - } - - for (int y = min.y; y <= max.y; y++) { - for (int z = min.z; z <= max.z; z++) { - VoxelCordinates minXEdge(min.x - 1, y, z); - VoxelCordinates maxXEdge(max.x + 1, y, z); - - VoxelLight minXEdgeLight = readLight(minXEdge); - VoxelLight maxXEdgeLight = readLight(maxXEdge); - - if (minXEdgeLight.b_light || minXEdgeLight.g_light || - minXEdgeLight.b_light) - voxelLightPropagation.push(minXEdge); - if (maxXEdgeLight.b_light || maxXEdgeLight.g_light || - maxXEdgeLight.b_light) - voxelLightPropagation.push(maxXEdge); - } - } - - for (VoxelCordinates& cordinates : tmp_voxelLightSource) { - VoxelLight& voxelLight = modLight(cordinates); - Voxel voxel = readVoxel(cordinates); - - VoxelAspect& voxelAspect = DataStore::voxelsAspect[voxel.id]; - voxelLight.r_light = voxelAspect.definition.colorEmission.r_value; - voxelLight.g_light = voxelAspect.definition.colorEmission.g_value; - voxelLight.b_light = voxelAspect.definition.colorEmission.b_value; - - voxelLightPropagation.push(cordinates); - } - - while (!voxelLightPropagation.empty()) { - resolveNextVoxelLightPropagation(); - } - } - - void VoxelWorld::resolveNextVoxelLightPropagation() { - DEER_CORE_ASSERT(initialized, "Voxel World is not initialized"); - - VoxelCordinates position = voxelLightPropagation.front(); - voxelLightPropagation.pop(); - - VoxelLight currentLight = readLight(position); - bool voxelCheck[6] = {false}; - - int highestRGBValue = currentLight.r_light; - if (highestRGBValue < currentLight.g_light) - highestRGBValue = currentLight.g_light; - if (highestRGBValue < currentLight.b_light) - highestRGBValue = currentLight.b_light; - - int proportionalDecrease = - (LIGHT_PROPAGATION_SIMPLE_FALL * 100) / highestRGBValue; - - int nextLightRedMinValue = - currentLight.r_light - - (proportionalDecrease * currentLight.r_light) / 100; - int nextLightGreenMinValue = - currentLight.g_light - - (proportionalDecrease * currentLight.g_light) / 100; - int nextLightBlueMinValue = - currentLight.b_light - - (proportionalDecrease * currentLight.b_light) / 100; - - // Check for every simple dir - for (int i = 0; i < 6; i++) { - VoxelCordinates next(position.x + NORMAL_DIR(X_AXIS, i), - position.y + NORMAL_DIR(Y_AXIS, i), - position.z + NORMAL_DIR(Z_AXIS, i)); - - Voxel nextVoxel = readVoxel(next); - voxelCheck[i] = nextVoxel.isVoxelType(); - if (voxelCheck[i]) - continue; - - VoxelLight& nextLight = modLight(next); - - bool nextVoxelModified = false; - if (nextLight.r_light < nextLightRedMinValue) { - nextLight.r_light = nextLightRedMinValue; - nextVoxelModified = true; - } - - if (nextLight.g_light < nextLightGreenMinValue) { - nextLight.g_light = nextLightGreenMinValue; - nextVoxelModified = true; - } - - if (nextLight.b_light < nextLightBlueMinValue) { - nextLight.b_light = nextLightBlueMinValue; - nextVoxelModified = true; - } - - if (nextVoxelModified) - voxelLightPropagation.push(next); - } - - return; - // TODO - // Check for every complex dir - for (int i = 0; i < 6; i++) { - int cDir0 = LIGHT_PROPAGATION_COMPLEX_DIR(0, i); - int cDir1 = LIGHT_PROPAGATION_COMPLEX_DIR(1, i); - - if (voxelCheck[cDir0] || voxelCheck[cDir1]) - continue; - - VoxelCordinates next(position.x + NORMAL_DIR(X_AXIS, cDir0) + - NORMAL_DIR(X_AXIS, cDir1), - position.y + NORMAL_DIR(Y_AXIS, cDir0) + - NORMAL_DIR(Y_AXIS, cDir1), - position.z + NORMAL_DIR(Z_AXIS, cDir0) + - NORMAL_DIR(Z_AXIS, cDir1)); - - Voxel nextVoxel = readVoxel(next); - if (nextVoxel.isVoxelType()) - continue; - - VoxelLight& nextLight = modLight(next); - int nextLightRedMinValue = - currentLight.r_light - LIGHT_PROPAGATION_COMPLEX_FALL; - int nextLightGreenMinValue = - currentLight.g_light - LIGHT_PROPAGATION_COMPLEX_FALL; - int nextLightBlueMinValue = - currentLight.b_light - LIGHT_PROPAGATION_COMPLEX_FALL; - - bool nextVoxelModified = false; - if (nextLight.r_light < nextLightRedMinValue) { - nextLight.r_light = nextLightRedMinValue; - nextVoxelModified = true; - } - - if (nextLight.g_light < nextLightGreenMinValue) { - nextLight.g_light = nextLightGreenMinValue; - nextVoxelModified = true; - } - - if (nextLight.b_light < nextLightBlueMinValue) { - nextLight.b_light = nextLightBlueMinValue; - nextVoxelModified = true; - } - - if (nextVoxelModified) - voxelLightPropagation.push(next); - } - } -} // namespace Deer \ No newline at end of file diff --git a/Deer/src/Plattform/Linux/LinuxWindow.cpp b/Deer/src/Plattform/Linux/LinuxWindow.cpp index b3f44ed..b82a928 100755 --- a/Deer/src/Plattform/Linux/LinuxWindow.cpp +++ b/Deer/src/Plattform/Linux/LinuxWindow.cpp @@ -1,6 +1,6 @@ #include "LinuxWindow.h" -#include "Deer/Application.h" -#include "Deer/Log.h" +#include "DeerCore/Application.h" +#include "DeerCore/Log.h" #include "glad/glad.h" diff --git a/Deer/vendor/cereal/include/cereal/external/rapidjson/document.h b/Deer/vendor/cereal/include/cereal/external/rapidjson/document.h index 91c4be8..f34cdd1 100755 --- a/Deer/vendor/cereal/include/cereal/external/rapidjson/document.h +++ b/Deer/vendor/cereal/include/cereal/external/rapidjson/document.h @@ -17,13 +17,13 @@ /*! \file document.h */ -#include "reader.h" +#include "encodedstream.h" #include "internal/meta.h" #include "internal/strfunc.h" #include "memorystream.h" -#include "encodedstream.h" -#include // placement new +#include "reader.h" #include +#include // placement new #ifdef __cpp_lib_three_way_comparison #include #endif @@ -31,8 +31,8 @@ CEREAL_RAPIDJSON_DIAG_PUSH #ifdef __clang__ CEREAL_RAPIDJSON_DIAG_OFF(padded) -CEREAL_RAPIDJSON_DIAG_OFF(switch-enum) -CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat) +CEREAL_RAPIDJSON_DIAG_OFF(switch - enum) +CEREAL_RAPIDJSON_DIAG_OFF(c++ 98 - compat) #elif defined(_MSC_VER) CEREAL_RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant CEREAL_RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data @@ -67,14 +67,14 @@ class GenericDocument; */ template struct GenericMember { - GenericValue name; //!< name of member (must be a string) - GenericValue value; //!< value of member. + GenericValue name; //!< name of member (must be a string) + GenericValue value; //!< value of member. - // swap() for std::sort() and other potential use in STL. - friend inline void swap(GenericMember& a, GenericMember& b) CEREAL_RAPIDJSON_NOEXCEPT { - a.name.Swap(b.name); - a.value.Swap(b.value); - } + // swap() for std::sort() and other potential use in STL. + friend inline void swap(GenericMember& a, GenericMember& b) CEREAL_RAPIDJSON_NOEXCEPT { + a.name.Swap(b.name); + a.value.Swap(b.value); + } }; /////////////////////////////////////////////////////////////////////////////// @@ -104,107 +104,138 @@ struct GenericMember { template class GenericMemberIterator { - friend class GenericValue; - template friend class GenericMemberIterator; + friend class GenericValue; + template + friend class GenericMemberIterator; - typedef GenericMember PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; + typedef GenericMember PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; -public: - //! Iterator type itself - typedef GenericMemberIterator Iterator; - //! Constant iterator type - typedef GenericMemberIterator ConstIterator; - //! Non-constant iterator type - typedef GenericMemberIterator NonConstIterator; + public: + //! Iterator type itself + typedef GenericMemberIterator Iterator; + //! Constant iterator type + typedef GenericMemberIterator ConstIterator; + //! Non-constant iterator type + typedef GenericMemberIterator NonConstIterator; - /** \name std::iterator_traits support */ - //@{ - typedef ValueType value_type; - typedef ValueType * pointer; - typedef ValueType & reference; - typedef std::ptrdiff_t difference_type; - typedef std::random_access_iterator_tag iterator_category; - //@} + /** \name std::iterator_traits support */ + //@{ + typedef ValueType value_type; + typedef ValueType* pointer; + typedef ValueType& reference; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; + //@} - //! Pointer to (const) GenericMember - typedef pointer Pointer; - //! Reference to (const) GenericMember - typedef reference Reference; - //! Signed integer type (e.g. \c ptrdiff_t) - typedef difference_type DifferenceType; + //! Pointer to (const) GenericMember + typedef pointer Pointer; + //! Reference to (const) GenericMember + typedef reference Reference; + //! Signed integer type (e.g. \c ptrdiff_t) + typedef difference_type DifferenceType; - //! Default constructor (singular value) - /*! Creates an iterator pointing to no element. - \note All operations, except for comparisons, are undefined on such values. - */ - GenericMemberIterator() : ptr_() {} + //! Default constructor (singular value) + /*! Creates an iterator pointing to no element. + \note All operations, except for comparisons, are undefined on such values. + */ + GenericMemberIterator() : ptr_() {} - //! Iterator conversions to more const - /*! - \param it (Non-const) iterator to copy from + //! Iterator conversions to more const + /*! + \param it (Non-const) iterator to copy from - Allows the creation of an iterator from another GenericMemberIterator - that is "less const". Especially, creating a non-constant iterator - from a constant iterator are disabled: - \li const -> non-const (not ok) - \li const -> const (ok) - \li non-const -> const (ok) - \li non-const -> non-const (ok) + Allows the creation of an iterator from another GenericMemberIterator + that is "less const". Especially, creating a non-constant iterator + from a constant iterator are disabled: + \li const -> non-const (not ok) + \li const -> const (ok) + \li non-const -> const (ok) + \li non-const -> non-const (ok) - \note If the \c Const template parameter is already \c false, this - constructor effectively defines a regular copy-constructor. - Otherwise, the copy constructor is implicitly defined. - */ - GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} - Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; } + \note If the \c Const template parameter is already \c false, this + constructor effectively defines a regular copy-constructor. + Otherwise, the copy constructor is implicitly defined. + */ + GenericMemberIterator(const NonConstIterator& it) : ptr_(it.ptr_) {} + Iterator& operator=(const NonConstIterator& it) { + ptr_ = it.ptr_; + return *this; + } - //! @name stepping - //@{ - Iterator& operator++(){ ++ptr_; return *this; } - Iterator& operator--(){ --ptr_; return *this; } - Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } - Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } - //@} + //! @name stepping + //@{ + Iterator& operator++() { + ++ptr_; + return *this; + } + Iterator& operator--() { + --ptr_; + return *this; + } + Iterator operator++(int) { + Iterator old(*this); + ++ptr_; + return old; + } + Iterator operator--(int) { + Iterator old(*this); + --ptr_; + return old; + } + //@} - //! @name increment/decrement - //@{ - Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } - Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } + //! @name increment/decrement + //@{ + Iterator operator+(DifferenceType n) const { return Iterator(ptr_ + n); } + Iterator operator-(DifferenceType n) const { return Iterator(ptr_ - n); } - Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } - Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } - //@} + Iterator& operator+=(DifferenceType n) { + ptr_ += n; + return *this; + } + Iterator& operator-=(DifferenceType n) { + ptr_ -= n; + return *this; + } + //@} - //! @name relations - //@{ - template bool operator==(const GenericMemberIterator& that) const { return ptr_ == that.ptr_; } - template bool operator!=(const GenericMemberIterator& that) const { return ptr_ != that.ptr_; } - template bool operator<=(const GenericMemberIterator& that) const { return ptr_ <= that.ptr_; } - template bool operator>=(const GenericMemberIterator& that) const { return ptr_ >= that.ptr_; } - template bool operator< (const GenericMemberIterator& that) const { return ptr_ < that.ptr_; } - template bool operator> (const GenericMemberIterator& that) const { return ptr_ > that.ptr_; } + //! @name relations + //@{ + template + bool operator==(const GenericMemberIterator& that) const { return ptr_ == that.ptr_; } + template + bool operator!=(const GenericMemberIterator& that) const { return ptr_ != that.ptr_; } + template + bool operator<=(const GenericMemberIterator& that) const { return ptr_ <= that.ptr_; } + template + bool operator>=(const GenericMemberIterator& that) const { return ptr_ >= that.ptr_; } + template + bool operator<(const GenericMemberIterator& that) const { return ptr_ < that.ptr_; } + template + bool operator>(const GenericMemberIterator& that) const { return ptr_ > that.ptr_; } #ifdef __cpp_lib_three_way_comparison - template std::strong_ordering operator<=>(const GenericMemberIterator& that) const { return ptr_ <=> that.ptr_; } + template + std::strong_ordering operator<=>(const GenericMemberIterator& that) const { return ptr_ <=> that.ptr_; } #endif - //@} + //@} - //! @name dereference - //@{ - Reference operator*() const { return *ptr_; } - Pointer operator->() const { return ptr_; } - Reference operator[](DifferenceType n) const { return ptr_[n]; } - //@} + //! @name dereference + //@{ + Reference operator*() const { return *ptr_; } + Pointer operator->() const { return ptr_; } + Reference operator[](DifferenceType n) const { return ptr_[n]; } + //@} - //! Distance - DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } + //! Distance + DifferenceType operator-(ConstIterator that) const { return ptr_ - that.ptr_; } -private: - //! Internal constructor from plain pointer - explicit GenericMemberIterator(Pointer p) : ptr_(p) {} + private: + //! Internal constructor from plain pointer + explicit GenericMemberIterator(Pointer p) : ptr_(p) {} - Pointer ptr_; //!< raw pointer + Pointer ptr_; //!< raw pointer }; #else // CEREAL_RAPIDJSON_NOMEMBERITERATORCLASS @@ -216,15 +247,15 @@ class GenericMemberIterator; //! non-const GenericMemberIterator template -class GenericMemberIterator { - //! use plain pointer as iterator type - typedef GenericMember* Iterator; +class GenericMemberIterator { + //! use plain pointer as iterator type + typedef GenericMember* Iterator; }; //! const GenericMemberIterator template -class GenericMemberIterator { - //! use plain const pointer as iterator type - typedef const GenericMember* Iterator; +class GenericMemberIterator { + //! use plain const pointer as iterator type + typedef const GenericMember* Iterator; }; #endif // CEREAL_RAPIDJSON_NOMEMBERITERATORCLASS @@ -259,101 +290,102 @@ class GenericMemberIterator { \see StringRef, GenericValue::SetString */ -template +template struct GenericStringRef { - typedef CharType Ch; //!< character type of the string + typedef CharType Ch; //!< character type of the string - //! Create string reference from \c const character array + //! Create string reference from \c const character array #ifndef __clang__ // -Wdocumentation - /*! - This constructor implicitly creates a constant string reference from - a \c const character array. It has better performance than - \ref StringRef(const CharType*) by inferring the string \ref length - from the array length, and also supports strings containing null - characters. + /*! + This constructor implicitly creates a constant string reference from + a \c const character array. It has better performance than + \ref StringRef(const CharType*) by inferring the string \ref length + from the array length, and also supports strings containing null + characters. - \tparam N length of the string, automatically inferred + \tparam N length of the string, automatically inferred - \param str Constant character array, lifetime assumed to be longer - than the use of the string in e.g. a GenericValue + \param str Constant character array, lifetime assumed to be longer + than the use of the string in e.g. a GenericValue - \post \ref s == str + \post \ref s == str - \note Constant complexity. - \note There is a hidden, private overload to disallow references to - non-const character arrays to be created via this constructor. - By this, e.g. function-scope arrays used to be filled via - \c snprintf are excluded from consideration. - In such cases, the referenced string should be \b copied to the - GenericValue instead. - */ + \note Constant complexity. + \note There is a hidden, private overload to disallow references to + non-const character arrays to be created via this constructor. + By this, e.g. function-scope arrays used to be filled via + \c snprintf are excluded from consideration. + In such cases, the referenced string should be \b copied to the + GenericValue instead. + */ #endif - template - GenericStringRef(const CharType (&str)[N]) CEREAL_RAPIDJSON_NOEXCEPT - : s(str), length(N-1) {} + template + GenericStringRef(const CharType (&str)[N]) CEREAL_RAPIDJSON_NOEXCEPT + : s(str), + length(N - 1) {} - //! Explicitly create string reference from \c const character pointer + //! Explicitly create string reference from \c const character pointer #ifndef __clang__ // -Wdocumentation - /*! - This constructor can be used to \b explicitly create a reference to - a constant string pointer. + /*! + This constructor can be used to \b explicitly create a reference to + a constant string pointer. - \see StringRef(const CharType*) + \see StringRef(const CharType*) - \param str Constant character pointer, lifetime assumed to be longer - than the use of the string in e.g. a GenericValue + \param str Constant character pointer, lifetime assumed to be longer + than the use of the string in e.g. a GenericValue - \post \ref s == str + \post \ref s == str - \note There is a hidden, private overload to disallow references to - non-const character arrays to be created via this constructor. - By this, e.g. function-scope arrays used to be filled via - \c snprintf are excluded from consideration. - In such cases, the referenced string should be \b copied to the - GenericValue instead. - */ + \note There is a hidden, private overload to disallow references to + non-const character arrays to be created via this constructor. + By this, e.g. function-scope arrays used to be filled via + \c snprintf are excluded from consideration. + In such cases, the referenced string should be \b copied to the + GenericValue instead. + */ #endif - explicit GenericStringRef(const CharType* str) - : s(str), length(NotNullStrLen(str)) {} + explicit GenericStringRef(const CharType* str) + : s(str), length(NotNullStrLen(str)) {} - //! Create constant string reference from pointer and length + //! Create constant string reference from pointer and length #ifndef __clang__ // -Wdocumentation - /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \param len length of the string, excluding the trailing NULL terminator + /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \param len length of the string, excluding the trailing NULL terminator - \post \ref s == str && \ref length == len - \note Constant complexity. - */ + \post \ref s == str && \ref length == len + \note Constant complexity. + */ #endif - GenericStringRef(const CharType* str, SizeType len) - : s(CEREAL_RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { CEREAL_RAPIDJSON_ASSERT(str != 0 || len == 0u); } + GenericStringRef(const CharType* str, SizeType len) + : s(CEREAL_RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { CEREAL_RAPIDJSON_ASSERT(str != 0 || len == 0u); } - GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} + GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} - //! implicit conversion to plain CharType pointer - operator const Ch *() const { return s; } + //! implicit conversion to plain CharType pointer + operator const Ch*() const { return s; } - const Ch* const s; //!< plain CharType pointer - const SizeType length; //!< length of the string (excluding the trailing NULL terminator) + const Ch* const s; //!< plain CharType pointer + const SizeType length; //!< length of the string (excluding the trailing NULL terminator) -private: - SizeType NotNullStrLen(const CharType* str) { - CEREAL_RAPIDJSON_ASSERT(str != 0); - return internal::StrLen(str); - } + private: + SizeType NotNullStrLen(const CharType* str) { + CEREAL_RAPIDJSON_ASSERT(str != 0); + return internal::StrLen(str); + } - /// Empty string - used when passing in a NULL pointer - static const Ch emptyString[]; + /// Empty string - used when passing in a NULL pointer + static const Ch emptyString[]; - //! Disallow construction from non-const array - template - GenericStringRef(CharType (&str)[N]) /* = delete */; - //! Copy assignment operator not permitted - immutable type - GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */; + //! Disallow construction from non-const array + template + GenericStringRef(CharType (&str)[N]) /* = delete */; + //! Copy assignment operator not permitted - immutable type + GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */; }; -template -const CharType GenericStringRef::emptyString[] = { CharType() }; +template +const CharType GenericStringRef::emptyString[] = {CharType()}; //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function @@ -367,9 +399,9 @@ const CharType GenericStringRef::emptyString[] = { CharType() }; \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember */ -template +template inline GenericStringRef StringRef(const CharType* str) { - return GenericStringRef(str); + return GenericStringRef(str); } //! Mark a character pointer as constant string @@ -387,9 +419,9 @@ inline GenericStringRef StringRef(const CharType* str) { \return GenericStringRef string reference object \relatesalso GenericStringRef */ -template +template inline GenericStringRef StringRef(const CharType* str, size_t length) { - return GenericStringRef(str, SizeType(length)); + return GenericStringRef(str, SizeType(length)); } #if CEREAL_RAPIDJSON_HAS_STDSTRING @@ -405,9 +437,9 @@ inline GenericStringRef StringRef(const CharType* str, size_t length) \relatesalso GenericStringRef \note Requires the definition of the preprocessor symbol \ref CEREAL_RAPIDJSON_HAS_STDSTRING. */ -template +template inline GenericStringRef StringRef(const std::basic_string& str) { - return GenericStringRef(str.data(), SizeType(str.size())); + return GenericStringRef(str.data(), SizeType(str.size())); } #endif @@ -415,15 +447,17 @@ inline GenericStringRef StringRef(const std::basic_string& s // GenericValue type traits namespace internal { -template -struct IsGenericValueImpl : FalseType {}; + template + struct IsGenericValueImpl : FalseType {}; -// select candidates according to nested encoding and allocator types -template struct IsGenericValueImpl::Type, typename Void::Type> - : IsBaseOf, T>::Type {}; + // select candidates according to nested encoding and allocator types + template + struct IsGenericValueImpl::Type, typename Void::Type> + : IsBaseOf, T>::Type {}; -// helper to match arbitrary GenericValue instantiations, including derived classes -template struct IsGenericValue : IsGenericValueImpl::Type {}; + // helper to match arbitrary GenericValue instantiations, including derived classes + template + struct IsGenericValue : IsGenericValueImpl::Type {}; } // namespace internal @@ -432,141 +466,143 @@ template struct IsGenericValue : IsGenericValueImpl::Type {}; namespace internal { -template -struct TypeHelper {}; + template + struct TypeHelper {}; -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsBool(); } - static bool Get(const ValueType& v) { return v.GetBool(); } - static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } - static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } -}; + template + struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsBool(); } + static bool Get(const ValueType& v) { return v.GetBool(); } + static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } + static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } + }; -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsInt(); } - static int Get(const ValueType& v) { return v.GetInt(); } - static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } - static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } -}; + template + struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt(); } + static int Get(const ValueType& v) { return v.GetInt(); } + static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } + static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } + }; -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsUint(); } - static unsigned Get(const ValueType& v) { return v.GetUint(); } - static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } - static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } -}; + template + struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint(); } + static unsigned Get(const ValueType& v) { return v.GetUint(); } + static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } + static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } + }; #ifdef _MSC_VER -CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int)); -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsInt(); } - static long Get(const ValueType& v) { return v.GetInt(); } - static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); } - static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); } -}; + CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int)); + template + struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt(); } + static long Get(const ValueType& v) { return v.GetInt(); } + static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); } + static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); } + }; -CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned)); -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsUint(); } - static unsigned long Get(const ValueType& v) { return v.GetUint(); } - static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); } - static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); } -}; + CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned)); + template + struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint(); } + static unsigned long Get(const ValueType& v) { return v.GetUint(); } + static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); } + static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); } + }; #endif -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsInt64(); } - static int64_t Get(const ValueType& v) { return v.GetInt64(); } - static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } - static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } -}; + template + struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt64(); } + static int64_t Get(const ValueType& v) { return v.GetInt64(); } + static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } + static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } + }; -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsUint64(); } - static uint64_t Get(const ValueType& v) { return v.GetUint64(); } - static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } - static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } -}; + template + struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint64(); } + static uint64_t Get(const ValueType& v) { return v.GetUint64(); } + static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } + static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } + }; -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsDouble(); } - static double Get(const ValueType& v) { return v.GetDouble(); } - static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } - static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } -}; + template + struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsDouble(); } + static double Get(const ValueType& v) { return v.GetDouble(); } + static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } + static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } + }; -template -struct TypeHelper { - static bool Is(const ValueType& v) { return v.IsFloat(); } - static float Get(const ValueType& v) { return v.GetFloat(); } - static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } - static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } -}; + template + struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsFloat(); } + static float Get(const ValueType& v) { return v.GetFloat(); } + static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } + static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } + }; -template -struct TypeHelper { - typedef const typename ValueType::Ch* StringType; - static bool Is(const ValueType& v) { return v.IsString(); } - static StringType Get(const ValueType& v) { return v.GetString(); } - static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } - static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } -}; + template + struct TypeHelper { + typedef const typename ValueType::Ch* StringType; + static bool Is(const ValueType& v) { return v.IsString(); } + static StringType Get(const ValueType& v) { return v.GetString(); } + static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } + static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } + }; #if CEREAL_RAPIDJSON_HAS_STDSTRING -template -struct TypeHelper > { - typedef std::basic_string StringType; - static bool Is(const ValueType& v) { return v.IsString(); } - static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); } - static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } -}; + template + struct TypeHelper> { + typedef std::basic_string StringType; + static bool Is(const ValueType& v) { return v.IsString(); } + static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); } + static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } + }; #endif -template -struct TypeHelper { - typedef typename ValueType::Array ArrayType; - static bool Is(const ValueType& v) { return v.IsArray(); } - static ArrayType Get(ValueType& v) { return v.GetArray(); } - static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } - static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } -}; + template + struct TypeHelper { + typedef typename ValueType::Array ArrayType; + static bool Is(const ValueType& v) { return v.IsArray(); } + static ArrayType Get(ValueType& v) { return v.GetArray(); } + static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } + static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } + }; -template -struct TypeHelper { - typedef typename ValueType::ConstArray ArrayType; - static bool Is(const ValueType& v) { return v.IsArray(); } - static ArrayType Get(const ValueType& v) { return v.GetArray(); } -}; + template + struct TypeHelper { + typedef typename ValueType::ConstArray ArrayType; + static bool Is(const ValueType& v) { return v.IsArray(); } + static ArrayType Get(const ValueType& v) { return v.GetArray(); } + }; -template -struct TypeHelper { - typedef typename ValueType::Object ObjectType; - static bool Is(const ValueType& v) { return v.IsObject(); } - static ObjectType Get(ValueType& v) { return v.GetObject(); } - static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } - static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } -}; + template + struct TypeHelper { + typedef typename ValueType::Object ObjectType; + static bool Is(const ValueType& v) { return v.IsObject(); } + static ObjectType Get(ValueType& v) { return v.GetObject(); } + static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } + static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } + }; -template -struct TypeHelper { - typedef typename ValueType::ConstObject ObjectType; - static bool Is(const ValueType& v) { return v.IsObject(); } - static ObjectType Get(const ValueType& v) { return v.GetObject(); } -}; + template + struct TypeHelper { + typedef typename ValueType::ConstObject ObjectType; + static bool Is(const ValueType& v) { return v.IsObject(); } + static ObjectType Get(const ValueType& v) { return v.GetObject(); } + }; } // namespace internal // Forward declarations -template class GenericArray; -template class GenericObject; +template +class GenericArray; +template +class GenericObject; /////////////////////////////////////////////////////////////////////////////// // GenericValue @@ -581,1540 +617,1676 @@ template class GenericObject; \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. */ -template > +template > class GenericValue { -public: - //! Name-value pair in an object. - typedef GenericMember Member; - typedef Encoding EncodingType; //!< Encoding type from template parameter. - typedef Allocator AllocatorType; //!< Allocator type from template parameter. - typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. - typedef GenericStringRef StringRefType; //!< Reference to a constant string - typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. - typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. - typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. - typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. - typedef GenericValue ValueType; //!< Value type of itself. - typedef GenericArray Array; - typedef GenericArray ConstArray; - typedef GenericObject Object; - typedef GenericObject ConstObject; + public: + //! Name-value pair in an object. + typedef GenericMember Member; + typedef Encoding EncodingType; //!< Encoding type from template parameter. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericStringRef StringRefType; //!< Reference to a constant string + typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. + typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. + typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. + typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. + typedef GenericValue ValueType; //!< Value type of itself. + typedef GenericArray Array; + typedef GenericArray ConstArray; + typedef GenericObject Object; + typedef GenericObject ConstObject; - //!@name Constructors and destructor. - //@{ + //!@name Constructors and destructor. + //@{ - //! Default constructor creates a null value. - GenericValue() CEREAL_RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } + //! Default constructor creates a null value. + GenericValue() CEREAL_RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericValue(GenericValue&& rhs) CEREAL_RAPIDJSON_NOEXCEPT : data_(rhs.data_) { - rhs.data_.f.flags = kNullFlag; // give up contents - } + //! Move constructor in C++11 + GenericValue(GenericValue&& rhs) CEREAL_RAPIDJSON_NOEXCEPT : data_(rhs.data_) { + rhs.data_.f.flags = kNullFlag; // give up contents + } #endif -private: - //! Copy constructor is not permitted. - GenericValue(const GenericValue& rhs); + private: + //! Copy constructor is not permitted. + GenericValue(const GenericValue& rhs); #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Moving from a GenericDocument is not permitted. - template - GenericValue(GenericDocument&& rhs); + //! Moving from a GenericDocument is not permitted. + template + GenericValue(GenericDocument&& rhs); - //! Move assignment from a GenericDocument is not permitted. - template - GenericValue& operator=(GenericDocument&& rhs); + //! Move assignment from a GenericDocument is not permitted. + template + GenericValue& operator=(GenericDocument&& rhs); #endif -public: + public: + //! Constructor with JSON value type. + /*! This creates a Value of specified type with default content. + \param type Type of the value. + \note Default content for number is zero. + */ + explicit GenericValue(Type type) CEREAL_RAPIDJSON_NOEXCEPT : data_() { + static const uint16_t defaultFlags[] = { + kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, + kNumberAnyFlag}; + CEREAL_RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType); + data_.f.flags = defaultFlags[type]; - //! Constructor with JSON value type. - /*! This creates a Value of specified type with default content. - \param type Type of the value. - \note Default content for number is zero. - */ - explicit GenericValue(Type type) CEREAL_RAPIDJSON_NOEXCEPT : data_() { - static const uint16_t defaultFlags[] = { - kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, - kNumberAnyFlag - }; - CEREAL_RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType); - data_.f.flags = defaultFlags[type]; + // Use ShortString to store empty string. + if (type == kStringType) + data_.ss.SetLength(0); + } - // Use ShortString to store empty string. - if (type == kStringType) - data_.ss.SetLength(0); - } + //! Explicit copy constructor (with allocator) + /*! Creates a copy of a Value by using the given Allocator + \tparam SourceAllocator allocator of \c rhs + \param rhs Value to copy from (read-only) + \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) + \see CopyFrom() + */ + template + GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { + switch (rhs.GetType()) { + case kObjectType: { + SizeType count = rhs.data_.o.size; + Member* lm = reinterpret_cast(allocator.Malloc(count * sizeof(Member))); + const typename GenericValue::Member* rm = rhs.GetMembersPointer(); + for (SizeType i = 0; i < count; i++) { + new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); + new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); + } + data_.f.flags = kObjectFlag; + data_.o.size = data_.o.capacity = count; + SetMembersPointer(lm); + } break; + case kArrayType: { + SizeType count = rhs.data_.a.size; + GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue))); + const GenericValue* re = rhs.GetElementsPointer(); + for (SizeType i = 0; i < count; i++) + new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); + data_.f.flags = kArrayFlag; + data_.a.size = data_.a.capacity = count; + SetElementsPointer(le); + } break; + case kStringType: + if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) { + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + } else + SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); + break; + default: + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + break; + } + } - //! Explicit copy constructor (with allocator) - /*! Creates a copy of a Value by using the given Allocator - \tparam SourceAllocator allocator of \c rhs - \param rhs Value to copy from (read-only) - \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). - \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) - \see CopyFrom() - */ - template - GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { - switch (rhs.GetType()) { - case kObjectType: { - SizeType count = rhs.data_.o.size; - Member* lm = reinterpret_cast(allocator.Malloc(count * sizeof(Member))); - const typename GenericValue::Member* rm = rhs.GetMembersPointer(); - for (SizeType i = 0; i < count; i++) { - new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); - new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); - } - data_.f.flags = kObjectFlag; - data_.o.size = data_.o.capacity = count; - SetMembersPointer(lm); - } - break; - case kArrayType: { - SizeType count = rhs.data_.a.size; - GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue))); - const GenericValue* re = rhs.GetElementsPointer(); - for (SizeType i = 0; i < count; i++) - new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); - data_.f.flags = kArrayFlag; - data_.a.size = data_.a.capacity = count; - SetElementsPointer(le); - } - break; - case kStringType: - if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) { - data_.f.flags = rhs.data_.f.flags; - data_ = *reinterpret_cast(&rhs.data_); - } - else - SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); - break; - default: - data_.f.flags = rhs.data_.f.flags; - data_ = *reinterpret_cast(&rhs.data_); - break; - } - } - - //! Constructor for boolean value. - /*! \param b Boolean value - \note This constructor is limited to \em real boolean values and rejects - implicitly converted types like arbitrary pointers. Use an explicit cast - to \c bool, if you want to construct a boolean JSON value in such cases. - */ + //! Constructor for boolean value. + /*! \param b Boolean value + \note This constructor is limited to \em real boolean values and rejects + implicitly converted types like arbitrary pointers. Use an explicit cast + to \c bool, if you want to construct a boolean JSON value in such cases. + */ #ifndef CEREAL_RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen - template - explicit GenericValue(T b, CEREAL_RAPIDJSON_ENABLEIF((internal::IsSame))) CEREAL_RAPIDJSON_NOEXCEPT // See #472 + template + explicit GenericValue(T b, CEREAL_RAPIDJSON_ENABLEIF((internal::IsSame))) CEREAL_RAPIDJSON_NOEXCEPT // See #472 #else - explicit GenericValue(bool b) CEREAL_RAPIDJSON_NOEXCEPT + explicit GenericValue(bool b) CEREAL_RAPIDJSON_NOEXCEPT #endif - : data_() { - // safe-guard against failing SFINAE - CEREAL_RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); - data_.f.flags = b ? kTrueFlag : kFalseFlag; - } + : data_() { + // safe-guard against failing SFINAE + CEREAL_RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); + data_.f.flags = b ? kTrueFlag : kFalseFlag; + } - //! Constructor for int value. - explicit GenericValue(int i) CEREAL_RAPIDJSON_NOEXCEPT : data_() { - data_.n.i64 = i; - data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag; - } + //! Constructor for int value. + explicit GenericValue(int i) CEREAL_RAPIDJSON_NOEXCEPT : data_() { + data_.n.i64 = i; + data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag; + } - //! Constructor for unsigned value. - explicit GenericValue(unsigned u) CEREAL_RAPIDJSON_NOEXCEPT : data_() { - data_.n.u64 = u; - data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag); - } + //! Constructor for unsigned value. + explicit GenericValue(unsigned u) CEREAL_RAPIDJSON_NOEXCEPT : data_() { + data_.n.u64 = u; + data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag); + } - //! Constructor for int64_t value. - explicit GenericValue(int64_t i64) CEREAL_RAPIDJSON_NOEXCEPT : data_() { - data_.n.i64 = i64; - data_.f.flags = kNumberInt64Flag; - if (i64 >= 0) { - data_.f.flags |= kNumberUint64Flag; - if (!(static_cast(i64) & CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) - data_.f.flags |= kUintFlag; - if (!(static_cast(i64) & CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - data_.f.flags |= kIntFlag; - } - else if (i64 >= static_cast(CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - data_.f.flags |= kIntFlag; - } + //! Constructor for int64_t value. + explicit GenericValue(int64_t i64) CEREAL_RAPIDJSON_NOEXCEPT : data_() { + data_.n.i64 = i64; + data_.f.flags = kNumberInt64Flag; + if (i64 >= 0) { + data_.f.flags |= kNumberUint64Flag; + if (!(static_cast(i64) & CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + data_.f.flags |= kUintFlag; + if (!(static_cast(i64) & CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + data_.f.flags |= kIntFlag; + } else if (i64 >= static_cast(CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + data_.f.flags |= kIntFlag; + } - //! Constructor for uint64_t value. - explicit GenericValue(uint64_t u64) CEREAL_RAPIDJSON_NOEXCEPT : data_() { - data_.n.u64 = u64; - data_.f.flags = kNumberUint64Flag; - if (!(u64 & CEREAL_RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) - data_.f.flags |= kInt64Flag; - if (!(u64 & CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) - data_.f.flags |= kUintFlag; - if (!(u64 & CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - data_.f.flags |= kIntFlag; - } + //! Constructor for uint64_t value. + explicit GenericValue(uint64_t u64) CEREAL_RAPIDJSON_NOEXCEPT : data_() { + data_.n.u64 = u64; + data_.f.flags = kNumberUint64Flag; + if (!(u64 & CEREAL_RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) + data_.f.flags |= kInt64Flag; + if (!(u64 & CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + data_.f.flags |= kUintFlag; + if (!(u64 & CEREAL_RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + data_.f.flags |= kIntFlag; + } - //! Constructor for double value. - explicit GenericValue(double d) CEREAL_RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } + //! Constructor for double value. + explicit GenericValue(double d) CEREAL_RAPIDJSON_NOEXCEPT : data_() { + data_.n.d = d; + data_.f.flags = kNumberDoubleFlag; + } - //! Constructor for float value. - explicit GenericValue(float f) CEREAL_RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast(f); data_.f.flags = kNumberDoubleFlag; } + //! Constructor for float value. + explicit GenericValue(float f) CEREAL_RAPIDJSON_NOEXCEPT : data_() { + data_.n.d = static_cast(f); + data_.f.flags = kNumberDoubleFlag; + } - //! Constructor for constant string (i.e. do not make a copy of string) - GenericValue(const Ch* s, SizeType length) CEREAL_RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } + //! Constructor for constant string (i.e. do not make a copy of string) + GenericValue(const Ch* s, SizeType length) CEREAL_RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } - //! Constructor for constant string (i.e. do not make a copy of string) - explicit GenericValue(StringRefType s) CEREAL_RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } + //! Constructor for constant string (i.e. do not make a copy of string) + explicit GenericValue(StringRefType s) CEREAL_RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } - //! Constructor for copy-string (i.e. do make a copy of string) - GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } - //! Constructor for copy-string (i.e. do make a copy of string) - GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch* s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } #if CEREAL_RAPIDJSON_HAS_STDSTRING - //! Constructor for copy-string from a string object (i.e. do make a copy of string) - /*! \note Requires the definition of the preprocessor symbol \ref CEREAL_RAPIDJSON_HAS_STDSTRING. - */ - GenericValue(const std::basic_string& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } + //! Constructor for copy-string from a string object (i.e. do make a copy of string) + /*! \note Requires the definition of the preprocessor symbol \ref CEREAL_RAPIDJSON_HAS_STDSTRING. + */ + GenericValue(const std::basic_string& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } #endif - //! Constructor for Array. - /*! - \param a An array obtained by \c GetArray(). - \note \c Array is always pass-by-value. - \note the source array is moved into this value and the sourec array becomes empty. - */ - GenericValue(Array a) CEREAL_RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { - a.value_.data_ = Data(); - a.value_.data_.f.flags = kArrayFlag; - } + //! Constructor for Array. + /*! + \param a An array obtained by \c GetArray(). + \note \c Array is always pass-by-value. + \note the source array is moved into this value and the sourec array becomes empty. + */ + GenericValue(Array a) CEREAL_RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { + a.value_.data_ = Data(); + a.value_.data_.f.flags = kArrayFlag; + } - //! Constructor for Object. - /*! - \param o An object obtained by \c GetObject(). - \note \c Object is always pass-by-value. - \note the source object is moved into this value and the sourec object becomes empty. - */ - GenericValue(Object o) CEREAL_RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { - o.value_.data_ = Data(); - o.value_.data_.f.flags = kObjectFlag; - } + //! Constructor for Object. + /*! + \param o An object obtained by \c GetObject(). + \note \c Object is always pass-by-value. + \note the source object is moved into this value and the sourec object becomes empty. + */ + GenericValue(Object o) CEREAL_RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { + o.value_.data_ = Data(); + o.value_.data_.f.flags = kObjectFlag; + } - //! Destructor. - /*! Need to destruct elements of array, members of object, or copy-string. - */ - ~GenericValue() { - if (Allocator::kNeedFree) { // Shortcut by Allocator's trait - switch(data_.f.flags) { - case kArrayFlag: - { - GenericValue* e = GetElementsPointer(); - for (GenericValue* v = e; v != e + data_.a.size; ++v) - v->~GenericValue(); - Allocator::Free(e); - } - break; + //! Destructor. + /*! Need to destruct elements of array, members of object, or copy-string. + */ + ~GenericValue() { + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + switch (data_.f.flags) { + case kArrayFlag: { + GenericValue* e = GetElementsPointer(); + for (GenericValue* v = e; v != e + data_.a.size; ++v) + v->~GenericValue(); + Allocator::Free(e); + } break; - case kObjectFlag: - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - Allocator::Free(GetMembersPointer()); - break; + case kObjectFlag: + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + Allocator::Free(GetMembersPointer()); + break; - case kCopyStringFlag: - Allocator::Free(const_cast(GetStringPointer())); - break; + case kCopyStringFlag: + Allocator::Free(const_cast(GetStringPointer())); + break; - default: - break; // Do nothing for other types. - } - } - } + default: + break; // Do nothing for other types. + } + } + } - //@} + //@} - //!@name Assignment operators - //@{ + //!@name Assignment operators + //@{ - //! Assignment with move semantics. - /*! \param rhs Source of the assignment. It will become a null value after assignment. - */ - GenericValue& operator=(GenericValue& rhs) CEREAL_RAPIDJSON_NOEXCEPT { - if (CEREAL_RAPIDJSON_LIKELY(this != &rhs)) { - this->~GenericValue(); - RawAssign(rhs); - } - return *this; - } + //! Assignment with move semantics. + /*! \param rhs Source of the assignment. It will become a null value after assignment. + */ + GenericValue& operator=(GenericValue& rhs) CEREAL_RAPIDJSON_NOEXCEPT { + if (CEREAL_RAPIDJSON_LIKELY(this != &rhs)) { + this->~GenericValue(); + RawAssign(rhs); + } + return *this; + } #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move assignment in C++11 - GenericValue& operator=(GenericValue&& rhs) CEREAL_RAPIDJSON_NOEXCEPT { - return *this = rhs.Move(); - } + //! Move assignment in C++11 + GenericValue& operator=(GenericValue&& rhs) CEREAL_RAPIDJSON_NOEXCEPT { + return *this = rhs.Move(); + } #endif - //! Assignment of constant string reference (no copy) - /*! \param str Constant string reference to be assigned - \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. - \see GenericStringRef, operator=(T) - */ - GenericValue& operator=(StringRefType str) CEREAL_RAPIDJSON_NOEXCEPT { - GenericValue s(str); - return *this = s; - } + //! Assignment of constant string reference (no copy) + /*! \param str Constant string reference to be assigned + \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. + \see GenericStringRef, operator=(T) + */ + GenericValue& operator=(StringRefType str) CEREAL_RAPIDJSON_NOEXCEPT { + GenericValue s(str); + return *this = s; + } - //! Assignment with primitive types. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param value The value to be assigned. + //! Assignment with primitive types. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param value The value to be assigned. - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref SetString(const Ch*, Allocator&) (for copying) or - \ref StringRef() (to explicitly mark the pointer as constant) instead. - All other pointer types would implicitly convert to \c bool, - use \ref SetBool() instead. - */ - template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) - operator=(T value) { - GenericValue v(value); - return *this = v; - } + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref SetString(const Ch*, Allocator&) (for copying) or + \ref StringRef() (to explicitly mark the pointer as constant) instead. + All other pointer types would implicitly convert to \c bool, + use \ref SetBool() instead. + */ + template + CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) + operator=(T value) { + GenericValue v(value); + return *this = v; + } - //! Deep-copy assignment from Value - /*! Assigns a \b copy of the Value to the current Value object - \tparam SourceAllocator Allocator type of \c rhs - \param rhs Value to copy from (read-only) - \param allocator Allocator to use for copying - \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) - */ - template - GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { - CEREAL_RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); - this->~GenericValue(); - new (this) GenericValue(rhs, allocator, copyConstStrings); - return *this; - } + //! Deep-copy assignment from Value + /*! Assigns a \b copy of the Value to the current Value object + \tparam SourceAllocator Allocator type of \c rhs + \param rhs Value to copy from (read-only) + \param allocator Allocator to use for copying + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) + */ + template + GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { + CEREAL_RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); + this->~GenericValue(); + new (this) GenericValue(rhs, allocator, copyConstStrings); + return *this; + } - //! Exchange the contents of this value with those of other. - /*! - \param other Another value. - \note Constant complexity. - */ - GenericValue& Swap(GenericValue& other) CEREAL_RAPIDJSON_NOEXCEPT { - GenericValue temp; - temp.RawAssign(*this); - RawAssign(other); - other.RawAssign(temp); - return *this; - } + //! Exchange the contents of this value with those of other. + /*! + \param other Another value. + \note Constant complexity. + */ + GenericValue& Swap(GenericValue& other) CEREAL_RAPIDJSON_NOEXCEPT { + GenericValue temp; + temp.RawAssign(*this); + RawAssign(other); + other.RawAssign(temp); + return *this; + } - //! free-standing swap function helper - /*! - Helper function to enable support for common swap implementation pattern based on \c std::swap: - \code - void swap(MyClass& a, MyClass& b) { - using std::swap; - swap(a.value, b.value); - // ... - } - \endcode - \see Swap() - */ - friend inline void swap(GenericValue& a, GenericValue& b) CEREAL_RAPIDJSON_NOEXCEPT { a.Swap(b); } + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.value, b.value); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericValue& a, GenericValue& b) CEREAL_RAPIDJSON_NOEXCEPT { a.Swap(b); } - //! Prepare Value for move semantics - /*! \return *this */ - GenericValue& Move() CEREAL_RAPIDJSON_NOEXCEPT { return *this; } - //@} + //! Prepare Value for move semantics + /*! \return *this */ + GenericValue& Move() CEREAL_RAPIDJSON_NOEXCEPT { return *this; } + //@} - //!@name Equal-to and not-equal-to operators - //@{ - //! Equal-to operator - /*! - \note If an object contains duplicated named member, comparing equality with any object is always \c false. - \note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings). - */ - template - bool operator==(const GenericValue& rhs) const { - typedef GenericValue RhsType; - if (GetType() != rhs.GetType()) - return false; + //!@name Equal-to and not-equal-to operators + //@{ + //! Equal-to operator + /*! + \note If an object contains duplicated named member, comparing equality with any object is always \c false. + \note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings). + */ + template + bool operator==(const GenericValue& rhs) const { + typedef GenericValue RhsType; + if (GetType() != rhs.GetType()) + return false; - switch (GetType()) { - case kObjectType: // Warning: O(n^2) inner-loop - if (data_.o.size != rhs.data_.o.size) - return false; - for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { - typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); - if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) - return false; - } - return true; + switch (GetType()) { + case kObjectType: // Warning: O(n^2) inner-loop + if (data_.o.size != rhs.data_.o.size) + return false; + for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { + typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); + if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) + return false; + } + return true; - case kArrayType: - if (data_.a.size != rhs.data_.a.size) - return false; - for (SizeType i = 0; i < data_.a.size; i++) - if ((*this)[i] != rhs[i]) - return false; - return true; + case kArrayType: + if (data_.a.size != rhs.data_.a.size) + return false; + for (SizeType i = 0; i < data_.a.size; i++) + if ((*this)[i] != rhs[i]) + return false; + return true; - case kStringType: - return StringEqual(rhs); + case kStringType: + return StringEqual(rhs); - case kNumberType: - if (IsDouble() || rhs.IsDouble()) { - double a = GetDouble(); // May convert from integer to double. - double b = rhs.GetDouble(); // Ditto - return a >= b && a <= b; // Prevent -Wfloat-equal - } - else - return data_.n.u64 == rhs.data_.n.u64; + case kNumberType: + if (IsDouble() || rhs.IsDouble()) { + double a = GetDouble(); // May convert from integer to double. + double b = rhs.GetDouble(); // Ditto + return a >= b && a <= b; // Prevent -Wfloat-equal + } else + return data_.n.u64 == rhs.data_.n.u64; - default: - return true; - } - } + default: + return true; + } + } - //! Equal-to operator with const C-string pointer - bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } + //! Equal-to operator with const C-string pointer + bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } #if CEREAL_RAPIDJSON_HAS_STDSTRING - //! Equal-to operator with string object - /*! \note Requires the definition of the preprocessor symbol \ref CEREAL_RAPIDJSON_HAS_STDSTRING. - */ - bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } + //! Equal-to operator with string object + /*! \note Requires the definition of the preprocessor symbol \ref CEREAL_RAPIDJSON_HAS_STDSTRING. + */ + bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } #endif - //! Equal-to operator with primitive types - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false - */ - template CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } + //! Equal-to operator with primitive types + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false + */ + template + CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue>), (bool)) + operator==(const T & rhs) const { return *this == GenericValue(rhs); } - //! Not-equal-to operator - /*! \return !(*this == rhs) - */ - template - bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } + //! Not-equal-to operator + /*! \return !(*this == rhs) + */ + template + bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } - //! Not-equal-to operator with const C-string pointer - bool operator!=(const Ch* rhs) const { return !(*this == rhs); } + //! Not-equal-to operator with const C-string pointer + bool operator!=(const Ch* rhs) const { return !(*this == rhs); } - //! Not-equal-to operator with arbitrary types - /*! \return !(*this == rhs) - */ - template CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } + //! Not-equal-to operator with arbitrary types + /*! \return !(*this == rhs) + */ + template + CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) + operator!=(const T & rhs) const { return !(*this == rhs); } - //! Equal-to operator with arbitrary types (symmetric version) - /*! \return (rhs == lhs) - */ - template friend CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } + //! Equal-to operator with arbitrary types (symmetric version) + /*! \return (rhs == lhs) + */ + template + friend CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T & lhs, const GenericValue & rhs) { return rhs == lhs; } - //! Not-Equal-to operator with arbitrary types (symmetric version) - /*! \return !(rhs == lhs) - */ - template friend CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } - //@} + //! Not-Equal-to operator with arbitrary types (symmetric version) + /*! \return !(rhs == lhs) + */ + template + friend CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T & lhs, const GenericValue & rhs) { return !(rhs == lhs); } + //@} - //!@name Type - //@{ + //!@name Type + //@{ - Type GetType() const { return static_cast(data_.f.flags & kTypeMask); } - bool IsNull() const { return data_.f.flags == kNullFlag; } - bool IsFalse() const { return data_.f.flags == kFalseFlag; } - bool IsTrue() const { return data_.f.flags == kTrueFlag; } - bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } - bool IsObject() const { return data_.f.flags == kObjectFlag; } - bool IsArray() const { return data_.f.flags == kArrayFlag; } - bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } - bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } - bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } - bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } - bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } - bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } - bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } + Type GetType() const { return static_cast(data_.f.flags & kTypeMask); } + bool IsNull() const { return data_.f.flags == kNullFlag; } + bool IsFalse() const { return data_.f.flags == kFalseFlag; } + bool IsTrue() const { return data_.f.flags == kTrueFlag; } + bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } + bool IsObject() const { return data_.f.flags == kObjectFlag; } + bool IsArray() const { return data_.f.flags == kArrayFlag; } + bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } + bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } + bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } + bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } + bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } + bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } + bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } - // Checks whether a number can be losslessly converted to a double. - bool IsLosslessDouble() const { - if (!IsNumber()) return false; - if (IsUint64()) { - uint64_t u = GetUint64(); - volatile double d = static_cast(u); - return (d >= 0.0) - && (d < static_cast((std::numeric_limits::max)())) - && (u == static_cast(d)); - } - if (IsInt64()) { - int64_t i = GetInt64(); - volatile double d = static_cast(i); - return (d >= static_cast((std::numeric_limits::min)())) - && (d < static_cast((std::numeric_limits::max)())) - && (i == static_cast(d)); - } - return true; // double, int, uint are always lossless - } + // Checks whether a number can be losslessly converted to a double. + bool IsLosslessDouble() const { + if (!IsNumber()) + return false; + if (IsUint64()) { + uint64_t u = GetUint64(); + volatile double d = static_cast(u); + return (d >= 0.0) && (d < static_cast((std::numeric_limits::max)())) && (u == static_cast(d)); + } + if (IsInt64()) { + int64_t i = GetInt64(); + volatile double d = static_cast(i); + return (d >= static_cast((std::numeric_limits::min)())) && (d < static_cast((std::numeric_limits::max)())) && (i == static_cast(d)); + } + return true; // double, int, uint are always lossless + } - // Checks whether a number is a float (possible lossy). - bool IsFloat() const { - if ((data_.f.flags & kDoubleFlag) == 0) - return false; - double d = GetDouble(); - return d >= -3.4028234e38 && d <= 3.4028234e38; - } - // Checks whether a number can be losslessly converted to a float. - bool IsLosslessFloat() const { - if (!IsNumber()) return false; - double a = GetDouble(); - if (a < static_cast(-(std::numeric_limits::max)()) - || a > static_cast((std::numeric_limits::max)())) - return false; - double b = static_cast(static_cast(a)); - return a >= b && a <= b; // Prevent -Wfloat-equal - } + // Checks whether a number is a float (possible lossy). + bool IsFloat() const { + if ((data_.f.flags & kDoubleFlag) == 0) + return false; + double d = GetDouble(); + return d >= -3.4028234e38 && d <= 3.4028234e38; + } + // Checks whether a number can be losslessly converted to a float. + bool IsLosslessFloat() const { + if (!IsNumber()) + return false; + double a = GetDouble(); + if (a < static_cast(-(std::numeric_limits::max)()) || a > static_cast((std::numeric_limits::max)())) + return false; + double b = static_cast(static_cast(a)); + return a >= b && a <= b; // Prevent -Wfloat-equal + } - //@} + //@} - //!@name Null - //@{ + //!@name Null + //@{ - GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } + GenericValue& SetNull() { + this->~GenericValue(); + new (this) GenericValue(); + return *this; + } - //@} + //@} - //!@name Bool - //@{ + //!@name Bool + //@{ - bool GetBool() const { CEREAL_RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; } - //!< Set boolean value - /*! \post IsBool() == true */ - GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } + bool GetBool() const { + CEREAL_RAPIDJSON_ASSERT(IsBool()); + return data_.f.flags == kTrueFlag; + } + //!< Set boolean value + /*! \post IsBool() == true */ + GenericValue& SetBool(bool b) { + this->~GenericValue(); + new (this) GenericValue(b); + return *this; + } - //@} + //@} - //!@name Object - //@{ + //!@name Object + //@{ - //! Set this value as an empty object. - /*! \post IsObject() == true */ - GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } + //! Set this value as an empty object. + /*! \post IsObject() == true */ + GenericValue& SetObject() { + this->~GenericValue(); + new (this) GenericValue(kObjectType); + return *this; + } - //! Get the number of members in the object. - SizeType MemberCount() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } + //! Get the number of members in the object. + SizeType MemberCount() const { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + return data_.o.size; + } - //! Get the capacity of object. - SizeType MemberCapacity() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; } + //! Get the capacity of object. + SizeType MemberCapacity() const { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + return data_.o.capacity; + } - //! Check whether the object is empty. - bool ObjectEmpty() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } + //! Check whether the object is empty. + bool ObjectEmpty() const { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + return data_.o.size == 0; + } - //! Get a value from an object associated with the name. - /*! \pre IsObject() == true - \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) - \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. - Since 0.2, if the name is not correct, it will assert. - If user is unsure whether a member exists, user should use HasMember() first. - A better approach is to use FindMember(). - \note Linear time complexity. - */ - template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { - GenericValue n(StringRef(name)); - return (*this)[n]; - } - template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } + //! Get a value from an object associated with the name. + /*! \pre IsObject() == true + \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) + \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. + Since 0.2, if the name is not correct, it will assert. + If user is unsure whether a member exists, user should use HasMember() first. + A better approach is to use FindMember(). + \note Linear time complexity. + */ + template + CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch>>), (GenericValue&)) + operator[](T * name) { + GenericValue n(StringRef(name)); + return (*this)[n]; + } + template + CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch>>), (const GenericValue&)) + operator[](T * name) const { return const_cast(*this)[name]; } - //! Get a value from an object associated with the name. - /*! \pre IsObject() == true - \tparam SourceAllocator Allocator of the \c name value + //! Get a value from an object associated with the name. + /*! \pre IsObject() == true + \tparam SourceAllocator Allocator of the \c name value - \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). - And it can also handle strings with embedded null characters. + \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). + And it can also handle strings with embedded null characters. - \note Linear time complexity. - */ - template - GenericValue& operator[](const GenericValue& name) { - MemberIterator member = FindMember(name); - if (member != MemberEnd()) - return member->value; - else { - CEREAL_RAPIDJSON_ASSERT(false); // see above note + \note Linear time complexity. + */ + template + GenericValue& operator[](const GenericValue& name) { + MemberIterator member = FindMember(name); + if (member != MemberEnd()) + return member->value; + else { + CEREAL_RAPIDJSON_ASSERT(false); // see above note - // This will generate -Wexit-time-destructors in clang - // static GenericValue NullValue; - // return NullValue; + // This will generate -Wexit-time-destructors in clang + // static GenericValue NullValue; + // return NullValue; - // Use static buffer and placement-new to prevent destruction - static char buffer[sizeof(GenericValue)]; - return *new (buffer) GenericValue(); - } - } - template - const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } + // Use static buffer and placement-new to prevent destruction + static char buffer[sizeof(GenericValue)]; + return *new (buffer) GenericValue(); + } + } + template + const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } #if CEREAL_RAPIDJSON_HAS_STDSTRING - //! Get a value from an object associated with name (string object). - GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } - const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } + //! Get a value from an object associated with name (string object). + GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } + const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } #endif - //! Const member iterator - /*! \pre IsObject() == true */ - ConstMemberIterator MemberBegin() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } - //! Const \em past-the-end member iterator - /*! \pre IsObject() == true */ - ConstMemberIterator MemberEnd() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } - //! Member iterator - /*! \pre IsObject() == true */ - MemberIterator MemberBegin() { CEREAL_RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } - //! \em Past-the-end member iterator - /*! \pre IsObject() == true */ - MemberIterator MemberEnd() { CEREAL_RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } + //! Const member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberBegin() const { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + return ConstMemberIterator(GetMembersPointer()); + } + //! Const \em past-the-end member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberEnd() const { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + return ConstMemberIterator(GetMembersPointer() + data_.o.size); + } + //! Member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberBegin() { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + return MemberIterator(GetMembersPointer()); + } + //! \em Past-the-end member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberEnd() { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + return MemberIterator(GetMembersPointer() + data_.o.size); + } - //! Request the object to have enough capacity to store members. - /*! \param newCapacity The capacity that the object at least need to have. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note Linear time complexity. - */ - GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { - CEREAL_RAPIDJSON_ASSERT(IsObject()); - if (newCapacity > data_.o.capacity) { - SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member)))); - data_.o.capacity = newCapacity; - } - return *this; - } + //! Request the object to have enough capacity to store members. + /*! \param newCapacity The capacity that the object at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& MemberReserve(SizeType newCapacity, Allocator& allocator) { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + if (newCapacity > data_.o.capacity) { + SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member)))); + data_.o.capacity = newCapacity; + } + return *this; + } - //! Check whether a member exists in the object. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } + //! Check whether a member exists in the object. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } #if CEREAL_RAPIDJSON_HAS_STDSTRING - //! Check whether a member exists in the object with string object. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } + //! Check whether a member exists in the object with string object. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } #endif - //! Check whether a member exists in the object with GenericValue name. - /*! - This version is faster because it does not need a StrLen(). It can also handle string with null character. - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - template - bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } + //! Check whether a member exists in the object with GenericValue name. + /*! + This version is faster because it does not need a StrLen(). It can also handle string with null character. + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + template + bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } - //! Find member by name. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). + //! Find member by name. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). - \note Earlier versions of Rapidjson returned a \c NULL pointer, in case - the requested member doesn't exist. For consistency with e.g. - \c std::map, this has been changed to MemberEnd() now. - \note Linear time complexity. - */ - MemberIterator FindMember(const Ch* name) { - GenericValue n(StringRef(name)); - return FindMember(n); - } + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. + \note Linear time complexity. + */ + MemberIterator FindMember(const Ch* name) { + GenericValue n(StringRef(name)); + return FindMember(n); + } - ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } + ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } - //! Find member by name. - /*! - This version is faster because it does not need a StrLen(). It can also handle string with null character. - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). + //! Find member by name. + /*! + This version is faster because it does not need a StrLen(). It can also handle string with null character. + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). - \note Earlier versions of Rapidjson returned a \c NULL pointer, in case - the requested member doesn't exist. For consistency with e.g. - \c std::map, this has been changed to MemberEnd() now. - \note Linear time complexity. - */ - template - MemberIterator FindMember(const GenericValue& name) { - CEREAL_RAPIDJSON_ASSERT(IsObject()); - CEREAL_RAPIDJSON_ASSERT(name.IsString()); - MemberIterator member = MemberBegin(); - for ( ; member != MemberEnd(); ++member) - if (name.StringEqual(member->name)) - break; - return member; - } - template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. + \note Linear time complexity. + */ + template + MemberIterator FindMember(const GenericValue& name) { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + CEREAL_RAPIDJSON_ASSERT(name.IsString()); + MemberIterator member = MemberBegin(); + for (; member != MemberEnd(); ++member) + if (name.StringEqual(member->name)) + break; + return member; + } + template + ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } #if CEREAL_RAPIDJSON_HAS_STDSTRING - //! Find member by string object name. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). - */ - MemberIterator FindMember(const std::basic_string& name) { return FindMember(GenericValue(StringRef(name))); } - ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(GenericValue(StringRef(name))); } + //! Find member by string object name. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + */ + MemberIterator FindMember(const std::basic_string& name) { return FindMember(GenericValue(StringRef(name))); } + ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(GenericValue(StringRef(name))); } #endif - //! Add a member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value Value of any type. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note The ownership of \c name and \c value will be transferred to this object on success. - \pre IsObject() && name.IsString() - \post name.IsNull() && value.IsNull() - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { - CEREAL_RAPIDJSON_ASSERT(IsObject()); - CEREAL_RAPIDJSON_ASSERT(name.IsString()); + //! Add a member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note The ownership of \c name and \c value will be transferred to this object on success. + \pre IsObject() && name.IsString() + \post name.IsNull() && value.IsNull() + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + CEREAL_RAPIDJSON_ASSERT(name.IsString()); - ObjectData& o = data_.o; - if (o.size >= o.capacity) - MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator); - Member* members = GetMembersPointer(); - members[o.size].name.RawAssign(name); - members[o.size].value.RawAssign(value); - o.size++; - return *this; - } + ObjectData& o = data_.o; + if (o.size >= o.capacity) + MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator); + Member* members = GetMembersPointer(); + members[o.size].name.RawAssign(name); + members[o.size].value.RawAssign(value); + o.size++; + return *this; + } - //! Add a constant string value as member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } + //! Add a constant string value as member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } #if CEREAL_RAPIDJSON_HAS_STDSTRING - //! Add a string object as member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { - GenericValue v(value, allocator); - return AddMember(name, v, allocator); - } + //! Add a string object as member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { + GenericValue v(value, allocator); + return AddMember(name, v, allocator); + } #endif - //! Add any primitive value as member (name-value pair) to the object. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param name A string value as name of member. - \param value Value of primitive type \c T as value of member - \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() + //! Add any primitive value as member (name-value pair) to the object. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param name A string value as name of member. + \param value Value of primitive type \c T as value of member + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref - AddMember(StringRefType, StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized Constant time complexity. - */ - template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) - AddMember(GenericValue& name, T value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref + AddMember(StringRefType, StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized Constant time complexity. + */ + template + CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue>), (GenericValue&)) + AddMember(GenericValue& name, T value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { - return AddMember(name, value, allocator); - } - GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { - return AddMember(name, value, allocator); - } - GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { - return AddMember(name, value, allocator); - } - GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } + GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } #endif // CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Add a member (name-value pair) to the object. + /*! \param name A constant string reference as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note The ownership of \c value will be transferred to this object on success. + \pre IsObject() + \post value.IsNull() + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } - //! Add a member (name-value pair) to the object. - /*! \param name A constant string reference as name of member. - \param value Value of any type. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note The ownership of \c value will be transferred to this object on success. - \pre IsObject() - \post value.IsNull() - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } + //! Add a constant string value as member (name-value pair) to the object. + /*! \param name A constant string reference as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } - //! Add a constant string value as member (name-value pair) to the object. - /*! \param name A constant string reference as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } + //! Add any primitive value as member (name-value pair) to the object. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param name A constant string reference as name of member. + \param value Value of primitive type \c T as value of member + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() - //! Add any primitive value as member (name-value pair) to the object. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param name A constant string reference as name of member. - \param value Value of primitive type \c T as value of member - \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref + AddMember(StringRefType, StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized Constant time complexity. + */ + template + CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue>), (GenericValue&)) + AddMember(StringRefType name, T value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref - AddMember(StringRefType, StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized Constant time complexity. - */ - template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) - AddMember(StringRefType name, T value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } + //! Remove all members in the object. + /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. + \note Linear time complexity. + */ + void RemoveAllMembers() { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + data_.o.size = 0; + } - //! Remove all members in the object. - /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. - \note Linear time complexity. - */ - void RemoveAllMembers() { - CEREAL_RAPIDJSON_ASSERT(IsObject()); - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - data_.o.size = 0; - } - - //! Remove a member in object by its name. - /*! \param name Name of member to be removed. - \return Whether the member existed. - \note This function may reorder the object members. Use \ref - EraseMember(ConstMemberIterator) if you need to preserve the - relative order of the remaining members. - \note Linear time complexity. - */ - bool RemoveMember(const Ch* name) { - GenericValue n(StringRef(name)); - return RemoveMember(n); - } + //! Remove a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note This function may reorder the object members. Use \ref + EraseMember(ConstMemberIterator) if you need to preserve the + relative order of the remaining members. + \note Linear time complexity. + */ + bool RemoveMember(const Ch* name) { + GenericValue n(StringRef(name)); + return RemoveMember(n); + } #if CEREAL_RAPIDJSON_HAS_STDSTRING - bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } + bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } #endif - template - bool RemoveMember(const GenericValue& name) { - MemberIterator m = FindMember(name); - if (m != MemberEnd()) { - RemoveMember(m); - return true; - } - else - return false; - } + template + bool RemoveMember(const GenericValue& name) { + MemberIterator m = FindMember(name); + if (m != MemberEnd()) { + RemoveMember(m); + return true; + } else + return false; + } - //! Remove a member in object by iterator. - /*! \param m member iterator (obtained by FindMember() or MemberBegin()). - \return the new iterator after removal. - \note This function may reorder the object members. Use \ref - EraseMember(ConstMemberIterator) if you need to preserve the - relative order of the remaining members. - \note Constant time complexity. - */ - MemberIterator RemoveMember(MemberIterator m) { - CEREAL_RAPIDJSON_ASSERT(IsObject()); - CEREAL_RAPIDJSON_ASSERT(data_.o.size > 0); - CEREAL_RAPIDJSON_ASSERT(GetMembersPointer() != 0); - CEREAL_RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); + //! Remove a member in object by iterator. + /*! \param m member iterator (obtained by FindMember() or MemberBegin()). + \return the new iterator after removal. + \note This function may reorder the object members. Use \ref + EraseMember(ConstMemberIterator) if you need to preserve the + relative order of the remaining members. + \note Constant time complexity. + */ + MemberIterator RemoveMember(MemberIterator m) { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + CEREAL_RAPIDJSON_ASSERT(data_.o.size > 0); + CEREAL_RAPIDJSON_ASSERT(GetMembersPointer() != 0); + CEREAL_RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); - MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); - if (data_.o.size > 1 && m != last) - *m = *last; // Move the last one to this place - else - m->~Member(); // Only one left, just destroy - --data_.o.size; - return m; - } + MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); + if (data_.o.size > 1 && m != last) + *m = *last; // Move the last one to this place + else + m->~Member(); // Only one left, just destroy + --data_.o.size; + return m; + } - //! Remove a member from an object by iterator. - /*! \param pos iterator to the member to remove - \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() - \return Iterator following the removed element. - If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. - \note This function preserves the relative order of the remaining object - members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). - \note Linear time complexity. - */ - MemberIterator EraseMember(ConstMemberIterator pos) { - return EraseMember(pos, pos +1); - } + //! Remove a member from an object by iterator. + /*! \param pos iterator to the member to remove + \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() + \return Iterator following the removed element. + If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. + \note This function preserves the relative order of the remaining object + members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). + \note Linear time complexity. + */ + MemberIterator EraseMember(ConstMemberIterator pos) { + return EraseMember(pos, pos + 1); + } - //! Remove members in the range [first, last) from an object. - /*! \param first iterator to the first member to remove - \param last iterator following the last member to remove - \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() - \return Iterator following the last removed element. - \note This function preserves the relative order of the remaining object - members. - \note Linear time complexity. - */ - MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { - CEREAL_RAPIDJSON_ASSERT(IsObject()); - CEREAL_RAPIDJSON_ASSERT(data_.o.size > 0); - CEREAL_RAPIDJSON_ASSERT(GetMembersPointer() != 0); - CEREAL_RAPIDJSON_ASSERT(first >= MemberBegin()); - CEREAL_RAPIDJSON_ASSERT(first <= last); - CEREAL_RAPIDJSON_ASSERT(last <= MemberEnd()); + //! Remove members in the range [first, last) from an object. + /*! \param first iterator to the first member to remove + \param last iterator following the last member to remove + \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() + \return Iterator following the last removed element. + \note This function preserves the relative order of the remaining object + members. + \note Linear time complexity. + */ + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + CEREAL_RAPIDJSON_ASSERT(data_.o.size > 0); + CEREAL_RAPIDJSON_ASSERT(GetMembersPointer() != 0); + CEREAL_RAPIDJSON_ASSERT(first >= MemberBegin()); + CEREAL_RAPIDJSON_ASSERT(first <= last); + CEREAL_RAPIDJSON_ASSERT(last <= MemberEnd()); - MemberIterator pos = MemberBegin() + (first - MemberBegin()); - for (MemberIterator itr = pos; itr != last; ++itr) - itr->~Member(); - std::memmove(static_cast(&*pos), &*last, static_cast(MemberEnd() - last) * sizeof(Member)); - data_.o.size -= static_cast(last - first); - return pos; - } + MemberIterator pos = MemberBegin() + (first - MemberBegin()); + for (MemberIterator itr = pos; itr != last; ++itr) + itr->~Member(); + std::memmove(static_cast(&*pos), &*last, static_cast(MemberEnd() - last) * sizeof(Member)); + data_.o.size -= static_cast(last - first); + return pos; + } - //! Erase a member in object by its name. - /*! \param name Name of member to be removed. - \return Whether the member existed. - \note Linear time complexity. - */ - bool EraseMember(const Ch* name) { - GenericValue n(StringRef(name)); - return EraseMember(n); - } + //! Erase a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note Linear time complexity. + */ + bool EraseMember(const Ch* name) { + GenericValue n(StringRef(name)); + return EraseMember(n); + } #if CEREAL_RAPIDJSON_HAS_STDSTRING - bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } + bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } #endif - template - bool EraseMember(const GenericValue& name) { - MemberIterator m = FindMember(name); - if (m != MemberEnd()) { - EraseMember(m); - return true; - } - else - return false; - } + template + bool EraseMember(const GenericValue& name) { + MemberIterator m = FindMember(name); + if (m != MemberEnd()) { + EraseMember(m); + return true; + } else + return false; + } - Object GetObject() { CEREAL_RAPIDJSON_ASSERT(IsObject()); return Object(*this); } - ConstObject GetObject() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } + Object GetObject() { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + return Object(*this); + } + ConstObject GetObject() const { + CEREAL_RAPIDJSON_ASSERT(IsObject()); + return ConstObject(*this); + } - //@} + //@} - //!@name Array - //@{ + //!@name Array + //@{ - //! Set this value as an empty array. - /*! \post IsArray == true */ - GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } + //! Set this value as an empty array. + /*! \post IsArray == true */ + GenericValue& SetArray() { + this->~GenericValue(); + new (this) GenericValue(kArrayType); + return *this; + } - //! Get the number of elements in array. - SizeType Size() const { CEREAL_RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } + //! Get the number of elements in array. + SizeType Size() const { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + return data_.a.size; + } - //! Get the capacity of array. - SizeType Capacity() const { CEREAL_RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } + //! Get the capacity of array. + SizeType Capacity() const { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + return data_.a.capacity; + } - //! Check whether the array is empty. - bool Empty() const { CEREAL_RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } + //! Check whether the array is empty. + bool Empty() const { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + return data_.a.size == 0; + } - //! Remove all elements in the array. - /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. - \note Linear time complexity. - */ - void Clear() { - CEREAL_RAPIDJSON_ASSERT(IsArray()); - GenericValue* e = GetElementsPointer(); - for (GenericValue* v = e; v != e + data_.a.size; ++v) - v->~GenericValue(); - data_.a.size = 0; - } + //! Remove all elements in the array. + /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. + \note Linear time complexity. + */ + void Clear() { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + GenericValue* e = GetElementsPointer(); + for (GenericValue* v = e; v != e + data_.a.size; ++v) + v->~GenericValue(); + data_.a.size = 0; + } - //! Get an element from array by index. - /*! \pre IsArray() == true - \param index Zero-based index of element. - \see operator[](T*) - */ - GenericValue& operator[](SizeType index) { - CEREAL_RAPIDJSON_ASSERT(IsArray()); - CEREAL_RAPIDJSON_ASSERT(index < data_.a.size); - return GetElementsPointer()[index]; - } - const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } + //! Get an element from array by index. + /*! \pre IsArray() == true + \param index Zero-based index of element. + \see operator[](T*) + */ + GenericValue& operator[](SizeType index) { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + CEREAL_RAPIDJSON_ASSERT(index < data_.a.size); + return GetElementsPointer()[index]; + } + const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } - //! Element iterator - /*! \pre IsArray() == true */ - ValueIterator Begin() { CEREAL_RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } - //! \em Past-the-end element iterator - /*! \pre IsArray() == true */ - ValueIterator End() { CEREAL_RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } - //! Constant element iterator - /*! \pre IsArray() == true */ - ConstValueIterator Begin() const { return const_cast(*this).Begin(); } - //! Constant \em past-the-end element iterator - /*! \pre IsArray() == true */ - ConstValueIterator End() const { return const_cast(*this).End(); } + //! Element iterator + /*! \pre IsArray() == true */ + ValueIterator Begin() { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + return GetElementsPointer(); + } + //! \em Past-the-end element iterator + /*! \pre IsArray() == true */ + ValueIterator End() { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + return GetElementsPointer() + data_.a.size; + } + //! Constant element iterator + /*! \pre IsArray() == true */ + ConstValueIterator Begin() const { return const_cast(*this).Begin(); } + //! Constant \em past-the-end element iterator + /*! \pre IsArray() == true */ + ConstValueIterator End() const { return const_cast(*this).End(); } - //! Request the array to have enough capacity to store elements. - /*! \param newCapacity The capacity that the array at least need to have. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note Linear time complexity. - */ - GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { - CEREAL_RAPIDJSON_ASSERT(IsArray()); - if (newCapacity > data_.a.capacity) { - SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); - data_.a.capacity = newCapacity; - } - return *this; - } + //! Request the array to have enough capacity to store elements. + /*! \param newCapacity The capacity that the array at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& Reserve(SizeType newCapacity, Allocator& allocator) { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + if (newCapacity > data_.a.capacity) { + SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); + data_.a.capacity = newCapacity; + } + return *this; + } - //! Append a GenericValue at the end of the array. - /*! \param value Value to be appended. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \post value.IsNull() == true - \return The value itself for fluent API. - \note The ownership of \c value will be transferred to this array on success. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - \note Amortized constant time complexity. - */ - GenericValue& PushBack(GenericValue& value, Allocator& allocator) { - CEREAL_RAPIDJSON_ASSERT(IsArray()); - if (data_.a.size >= data_.a.capacity) - Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); - GetElementsPointer()[data_.a.size++].RawAssign(value); - return *this; - } + //! Append a GenericValue at the end of the array. + /*! \param value Value to be appended. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \post value.IsNull() == true + \return The value itself for fluent API. + \note The ownership of \c value will be transferred to this array on success. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + \note Amortized constant time complexity. + */ + GenericValue& PushBack(GenericValue& value, Allocator& allocator) { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + if (data_.a.size >= data_.a.capacity) + Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); + GetElementsPointer()[data_.a.size++].RawAssign(value); + return *this; + } #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { - return PushBack(value, allocator); - } + GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { + return PushBack(value, allocator); + } #endif // CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Append a constant string reference at the end of the array. - /*! \param value Constant string reference to be appended. - \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \return The value itself for fluent API. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - \note Amortized constant time complexity. - \see GenericStringRef - */ - GenericValue& PushBack(StringRefType value, Allocator& allocator) { - return (*this).template PushBack(value, allocator); - } + //! Append a constant string reference at the end of the array. + /*! \param value Constant string reference to be appended. + \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \return The value itself for fluent API. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + \note Amortized constant time complexity. + \see GenericStringRef + */ + GenericValue& PushBack(StringRefType value, Allocator& allocator) { + return (*this).template PushBack(value, allocator); + } - //! Append a primitive value at the end of the array. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param value Value of primitive type T to be appended. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \return The value itself for fluent API. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + //! Append a primitive value at the end of the array. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param value Value of primitive type T to be appended. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \return The value itself for fluent API. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref PushBack(GenericValue&, Allocator&) or \ref - PushBack(StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized constant time complexity. - */ - template - CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) - PushBack(T value, Allocator& allocator) { - GenericValue v(value); - return PushBack(v, allocator); - } + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref PushBack(GenericValue&, Allocator&) or \ref + PushBack(StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized constant time complexity. + */ + template + CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue>), (GenericValue&)) + PushBack(T value, Allocator& allocator) { + GenericValue v(value); + return PushBack(v, allocator); + } - //! Remove the last element in the array. - /*! - \note Constant time complexity. - */ - GenericValue& PopBack() { - CEREAL_RAPIDJSON_ASSERT(IsArray()); - CEREAL_RAPIDJSON_ASSERT(!Empty()); - GetElementsPointer()[--data_.a.size].~GenericValue(); - return *this; - } + //! Remove the last element in the array. + /*! + \note Constant time complexity. + */ + GenericValue& PopBack() { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + CEREAL_RAPIDJSON_ASSERT(!Empty()); + GetElementsPointer()[--data_.a.size].~GenericValue(); + return *this; + } - //! Remove an element of array by iterator. - /*! - \param pos iterator to the element to remove - \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() - \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. - \note Linear time complexity. - */ - ValueIterator Erase(ConstValueIterator pos) { - return Erase(pos, pos + 1); - } + //! Remove an element of array by iterator. + /*! + \param pos iterator to the element to remove + \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() + \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. + \note Linear time complexity. + */ + ValueIterator Erase(ConstValueIterator pos) { + return Erase(pos, pos + 1); + } - //! Remove elements in the range [first, last) of the array. - /*! - \param first iterator to the first element to remove - \param last iterator following the last element to remove - \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() - \return Iterator following the last removed element. - \note Linear time complexity. - */ - ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { - CEREAL_RAPIDJSON_ASSERT(IsArray()); - CEREAL_RAPIDJSON_ASSERT(data_.a.size > 0); - CEREAL_RAPIDJSON_ASSERT(GetElementsPointer() != 0); - CEREAL_RAPIDJSON_ASSERT(first >= Begin()); - CEREAL_RAPIDJSON_ASSERT(first <= last); - CEREAL_RAPIDJSON_ASSERT(last <= End()); - ValueIterator pos = Begin() + (first - Begin()); - for (ValueIterator itr = pos; itr != last; ++itr) - itr->~GenericValue(); - std::memmove(static_cast(pos), last, static_cast(End() - last) * sizeof(GenericValue)); - data_.a.size -= static_cast(last - first); - return pos; - } + //! Remove elements in the range [first, last) of the array. + /*! + \param first iterator to the first element to remove + \param last iterator following the last element to remove + \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() + \return Iterator following the last removed element. + \note Linear time complexity. + */ + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + CEREAL_RAPIDJSON_ASSERT(data_.a.size > 0); + CEREAL_RAPIDJSON_ASSERT(GetElementsPointer() != 0); + CEREAL_RAPIDJSON_ASSERT(first >= Begin()); + CEREAL_RAPIDJSON_ASSERT(first <= last); + CEREAL_RAPIDJSON_ASSERT(last <= End()); + ValueIterator pos = Begin() + (first - Begin()); + for (ValueIterator itr = pos; itr != last; ++itr) + itr->~GenericValue(); + std::memmove(static_cast(pos), last, static_cast(End() - last) * sizeof(GenericValue)); + data_.a.size -= static_cast(last - first); + return pos; + } - Array GetArray() { CEREAL_RAPIDJSON_ASSERT(IsArray()); return Array(*this); } - ConstArray GetArray() const { CEREAL_RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } + Array GetArray() { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + return Array(*this); + } + ConstArray GetArray() const { + CEREAL_RAPIDJSON_ASSERT(IsArray()); + return ConstArray(*this); + } - //@} + //@} - //!@name Number - //@{ + //!@name Number + //@{ - int GetInt() const { CEREAL_RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; } - unsigned GetUint() const { CEREAL_RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; } - int64_t GetInt64() const { CEREAL_RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; } - uint64_t GetUint64() const { CEREAL_RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; } + int GetInt() const { + CEREAL_RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); + return data_.n.i.i; + } + unsigned GetUint() const { + CEREAL_RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); + return data_.n.u.u; + } + int64_t GetInt64() const { + CEREAL_RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); + return data_.n.i64; + } + uint64_t GetUint64() const { + CEREAL_RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); + return data_.n.u64; + } - //! Get the value as double type. - /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless. - */ - double GetDouble() const { - CEREAL_RAPIDJSON_ASSERT(IsNumber()); - if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. - if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double - if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double - if ((data_.f.flags & kInt64Flag) != 0) return static_cast(data_.n.i64); // int64_t -> double (may lose precision) - CEREAL_RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_t -> double (may lose precision) - } + //! Get the value as double type. + /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless. + */ + double GetDouble() const { + CEREAL_RAPIDJSON_ASSERT(IsNumber()); + if ((data_.f.flags & kDoubleFlag) != 0) + return data_.n.d; // exact type, no conversion. + if ((data_.f.flags & kIntFlag) != 0) + return data_.n.i.i; // int -> double + if ((data_.f.flags & kUintFlag) != 0) + return data_.n.u.u; // unsigned -> double + if ((data_.f.flags & kInt64Flag) != 0) + return static_cast(data_.n.i64); // int64_t -> double (may lose precision) + CEREAL_RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); + return static_cast(data_.n.u64); // uint64_t -> double (may lose precision) + } - //! Get the value as float type. - /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless. - */ - float GetFloat() const { - return static_cast(GetDouble()); - } + //! Get the value as float type. + /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless. + */ + float GetFloat() const { + return static_cast(GetDouble()); + } - GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } - GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } - GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } - GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } - GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } - GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast(f)); return *this; } + GenericValue& SetInt(int i) { + this->~GenericValue(); + new (this) GenericValue(i); + return *this; + } + GenericValue& SetUint(unsigned u) { + this->~GenericValue(); + new (this) GenericValue(u); + return *this; + } + GenericValue& SetInt64(int64_t i64) { + this->~GenericValue(); + new (this) GenericValue(i64); + return *this; + } + GenericValue& SetUint64(uint64_t u64) { + this->~GenericValue(); + new (this) GenericValue(u64); + return *this; + } + GenericValue& SetDouble(double d) { + this->~GenericValue(); + new (this) GenericValue(d); + return *this; + } + GenericValue& SetFloat(float f) { + this->~GenericValue(); + new (this) GenericValue(static_cast(f)); + return *this; + } - //@} + //@} - //!@name String - //@{ + //!@name String + //@{ - const Ch* GetString() const { CEREAL_RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } + const Ch* GetString() const { + CEREAL_RAPIDJSON_ASSERT(IsString()); + return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); + } - //! Get the length of string. - /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). - */ - SizeType GetStringLength() const { CEREAL_RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } + //! Get the length of string. + /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). + */ + SizeType GetStringLength() const { + CEREAL_RAPIDJSON_ASSERT(IsString()); + return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); + } - //! Set this value as a string without copying source string. - /*! This version has better performance with supplied length, and also support string containing null character. - \param s source string pointer. - \param length The length of source string, excluding the trailing null terminator. - \return The value itself for fluent API. - \post IsString() == true && GetString() == s && GetStringLength() == length - \see SetString(StringRefType) - */ - GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } + //! Set this value as a string without copying source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string pointer. + \param length The length of source string, excluding the trailing null terminator. + \return The value itself for fluent API. + \post IsString() == true && GetString() == s && GetStringLength() == length + \see SetString(StringRefType) + */ + GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } - //! Set this value as a string without copying source string. - /*! \param s source string reference - \return The value itself for fluent API. - \post IsString() == true && GetString() == s && GetStringLength() == s.length - */ - GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } + //! Set this value as a string without copying source string. + /*! \param s source string reference + \return The value itself for fluent API. + \post IsString() == true && GetString() == s && GetStringLength() == s.length + */ + GenericValue& SetString(StringRefType s) { + this->~GenericValue(); + SetStringRaw(s); + return *this; + } - //! Set this value as a string by copying from source string. - /*! This version has better performance with supplied length, and also support string containing null character. - \param s source string. - \param length The length of source string, excluding the trailing null terminator. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); } + //! Set this value as a string by copying from source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string. + \param length The length of source string, excluding the trailing null terminator. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); } - //! Set this value as a string by copying from source string. - /*! \param s source string. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } - //! Set this value as a string by copying from source string. - /*! \param s source string reference - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; } + //! Set this value as a string by copying from source string. + /*! \param s source string reference + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(StringRefType s, Allocator& allocator) { + this->~GenericValue(); + SetStringRaw(s, allocator); + return *this; + } #if CEREAL_RAPIDJSON_HAS_STDSTRING - //! Set this value as a string by copying from source string. - /*! \param s source string. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() - \note Requires the definition of the preprocessor symbol \ref CEREAL_RAPIDJSON_HAS_STDSTRING. - */ - GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() + \note Requires the definition of the preprocessor symbol \ref CEREAL_RAPIDJSON_HAS_STDSTRING. + */ + GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } #endif - //@} + //@} - //!@name Array - //@{ + //!@name Array + //@{ - //! Templated version for checking whether this value is type T. - /*! - \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string - */ - template - bool Is() const { return internal::TypeHelper::Is(*this); } + //! Templated version for checking whether this value is type T. + /*! + \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string + */ + template + bool Is() const { return internal::TypeHelper::Is(*this); } - template - T Get() const { return internal::TypeHelper::Get(*this); } + template + T Get() const { return internal::TypeHelper::Get(*this); } - template - T Get() { return internal::TypeHelper::Get(*this); } + template + T Get() { return internal::TypeHelper::Get(*this); } - template - ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } + template + ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } - template - ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } + template + ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } - //@} + //@} - //! Generate events of this value to a Handler. - /*! This function adopts the GoF visitor pattern. - Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. - It can also be used to deep clone this value via GenericDocument, which is also a Handler. - \tparam Handler type of handler. - \param handler An object implementing concept Handler. - */ - template - bool Accept(Handler& handler) const { - switch(GetType()) { - case kNullType: return handler.Null(); - case kFalseType: return handler.Bool(false); - case kTrueType: return handler.Bool(true); + //! Generate events of this value to a Handler. + /*! This function adopts the GoF visitor pattern. + Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. + It can also be used to deep clone this value via GenericDocument, which is also a Handler. + \tparam Handler type of handler. + \param handler An object implementing concept Handler. + */ + template + bool Accept(Handler& handler) const { + switch (GetType()) { + case kNullType: + return handler.Null(); + case kFalseType: + return handler.Bool(false); + case kTrueType: + return handler.Bool(true); - case kObjectType: - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.StartObject())) - return false; - for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { - CEREAL_RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) - return false; - if (CEREAL_RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) - return false; - } - return handler.EndObject(data_.o.size); + case kObjectType: + if (CEREAL_RAPIDJSON_UNLIKELY(!handler.StartObject())) + return false; + for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { + CEREAL_RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. + if (CEREAL_RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) + return false; + if (CEREAL_RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) + return false; + } + return handler.EndObject(data_.o.size); - case kArrayType: - if (CEREAL_RAPIDJSON_UNLIKELY(!handler.StartArray())) - return false; - for (const GenericValue* v = Begin(); v != End(); ++v) - if (CEREAL_RAPIDJSON_UNLIKELY(!v->Accept(handler))) - return false; - return handler.EndArray(data_.a.size); + case kArrayType: + if (CEREAL_RAPIDJSON_UNLIKELY(!handler.StartArray())) + return false; + for (const GenericValue* v = Begin(); v != End(); ++v) + if (CEREAL_RAPIDJSON_UNLIKELY(!v->Accept(handler))) + return false; + return handler.EndArray(data_.a.size); - case kStringType: - return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); + case kStringType: + return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); - default: - CEREAL_RAPIDJSON_ASSERT(GetType() == kNumberType); - if (IsDouble()) return handler.Double(data_.n.d); - else if (IsInt()) return handler.Int(data_.n.i.i); - else if (IsUint()) return handler.Uint(data_.n.u.u); - else if (IsInt64()) return handler.Int64(data_.n.i64); - else return handler.Uint64(data_.n.u64); - } - } + default: + CEREAL_RAPIDJSON_ASSERT(GetType() == kNumberType); + if (IsDouble()) + return handler.Double(data_.n.d); + else if (IsInt()) + return handler.Int(data_.n.i.i); + else if (IsUint()) + return handler.Uint(data_.n.u.u); + else if (IsInt64()) + return handler.Int64(data_.n.i64); + else + return handler.Uint64(data_.n.u64); + } + } -private: - template friend class GenericValue; - template friend class GenericDocument; + private: + template + friend class GenericValue; + template + friend class GenericDocument; - enum { - kBoolFlag = 0x0008, - kNumberFlag = 0x0010, - kIntFlag = 0x0020, - kUintFlag = 0x0040, - kInt64Flag = 0x0080, - kUint64Flag = 0x0100, - kDoubleFlag = 0x0200, - kStringFlag = 0x0400, - kCopyFlag = 0x0800, - kInlineStrFlag = 0x1000, + enum { + kBoolFlag = 0x0008, + kNumberFlag = 0x0010, + kIntFlag = 0x0020, + kUintFlag = 0x0040, + kInt64Flag = 0x0080, + kUint64Flag = 0x0100, + kDoubleFlag = 0x0200, + kStringFlag = 0x0400, + kCopyFlag = 0x0800, + kInlineStrFlag = 0x1000, - // Initial flags of different types. - kNullFlag = kNullType, - kTrueFlag = kTrueType | kBoolFlag, - kFalseFlag = kFalseType | kBoolFlag, - kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, - kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, - kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, - kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, - kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, - kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, - kConstStringFlag = kStringType | kStringFlag, - kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, - kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag, - kObjectFlag = kObjectType, - kArrayFlag = kArrayType, + // Initial flags of different types. + kNullFlag = kNullType, + kTrueFlag = kTrueType | kBoolFlag, + kFalseFlag = kFalseType | kBoolFlag, + kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, + kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, + kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, + kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, + kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, + kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, + kConstStringFlag = kStringType | kStringFlag, + kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, + kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag, + kObjectFlag = kObjectType, + kArrayFlag = kArrayType, - kTypeMask = 0x07 - }; + kTypeMask = 0x07 + }; - static const SizeType kDefaultArrayCapacity = 16; - static const SizeType kDefaultObjectCapacity = 16; + static const SizeType kDefaultArrayCapacity = 16; + static const SizeType kDefaultObjectCapacity = 16; - struct Flag { + struct Flag { #if CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION - char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer + char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer #elif CEREAL_RAPIDJSON_64BIT - char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes + char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes #else - char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes + char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes #endif - uint16_t flags; - }; + uint16_t flags; + }; - struct String { - SizeType length; - SizeType hashcode; //!< reserved - const Ch* str; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + struct String { + SizeType length; + SizeType hashcode; //!< reserved + const Ch* str; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars - // (excluding the terminating zero) and store a value to determine the length of the contained - // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string - // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as - // the string terminator as well. For getting the string length back from that value just use - // "MaxSize - str[LenPos]". - // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode, - // 13-chars strings for CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). - struct ShortString { - enum { MaxChars = sizeof(static_cast(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; - Ch str[MaxChars]; + // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars + // (excluding the terminating zero) and store a value to determine the length of the contained + // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string + // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as + // the string terminator as well. For getting the string length back from that value just use + // "MaxSize - str[LenPos]". + // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode, + // 13-chars strings for CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). + struct ShortString { + enum { MaxChars = sizeof(static_cast(0)->payload) / sizeof(Ch), + MaxSize = MaxChars - 1, + LenPos = MaxSize }; + Ch str[MaxChars]; - inline static bool Usable(SizeType len) { return (MaxSize >= len); } - inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); } - inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); } - }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + inline static bool Usable(SizeType len) { return (MaxSize >= len); } + inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); } + inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); } + }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - // By using proper binary layout, retrieval of different integer types do not need conversions. - union Number { + // By using proper binary layout, retrieval of different integer types do not need conversions. + union Number { #if CEREAL_RAPIDJSON_ENDIAN == CEREAL_RAPIDJSON_LITTLEENDIAN - struct I { - int i; - char padding[4]; - }i; - struct U { - unsigned u; - char padding2[4]; - }u; + struct I { + int i; + char padding[4]; + } i; + struct U { + unsigned u; + char padding2[4]; + } u; #else - struct I { - char padding[4]; - int i; - }i; - struct U { - char padding2[4]; - unsigned u; - }u; + struct I { + char padding[4]; + int i; + } i; + struct U { + char padding2[4]; + unsigned u; + } u; #endif - int64_t i64; - uint64_t u64; - double d; - }; // 8 bytes + int64_t i64; + uint64_t u64; + double d; + }; // 8 bytes - struct ObjectData { - SizeType size; - SizeType capacity; - Member* members; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + struct ObjectData { + SizeType size; + SizeType capacity; + Member* members; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - struct ArrayData { - SizeType size; - SizeType capacity; - GenericValue* elements; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + struct ArrayData { + SizeType size; + SizeType capacity; + GenericValue* elements; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - union Data { - String s; - ShortString ss; - Number n; - ObjectData o; - ArrayData a; - Flag f; - }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION + union Data { + String s; + ShortString ss; + Number n; + ObjectData o; + ArrayData a; + Flag f; + }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with CEREAL_RAPIDJSON_48BITPOINTER_OPTIMIZATION - CEREAL_RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return CEREAL_RAPIDJSON_GETPOINTER(Ch, data_.s.str); } - CEREAL_RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return CEREAL_RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } - CEREAL_RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return CEREAL_RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } - CEREAL_RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return CEREAL_RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } - CEREAL_RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return CEREAL_RAPIDJSON_GETPOINTER(Member, data_.o.members); } - CEREAL_RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return CEREAL_RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } + CEREAL_RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return CEREAL_RAPIDJSON_GETPOINTER(Ch, data_.s.str); } + CEREAL_RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return CEREAL_RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } + CEREAL_RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return CEREAL_RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } + CEREAL_RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return CEREAL_RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } + CEREAL_RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return CEREAL_RAPIDJSON_GETPOINTER(Member, data_.o.members); } + CEREAL_RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return CEREAL_RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } - // Initialize this value as array with initial data, without calling destructor. - void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { - data_.f.flags = kArrayFlag; - if (count) { - GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); - SetElementsPointer(e); - std::memcpy(static_cast(e), values, count * sizeof(GenericValue)); - } - else - SetElementsPointer(0); - data_.a.size = data_.a.capacity = count; - } + // Initialize this value as array with initial data, without calling destructor. + void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { + data_.f.flags = kArrayFlag; + if (count) { + GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); + SetElementsPointer(e); + std::memcpy(static_cast(e), values, count * sizeof(GenericValue)); + } else + SetElementsPointer(0); + data_.a.size = data_.a.capacity = count; + } - //! Initialize this value as object with initial data, without calling destructor. - void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { - data_.f.flags = kObjectFlag; - if (count) { - Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); - SetMembersPointer(m); - std::memcpy(static_cast(m), members, count * sizeof(Member)); - } - else - SetMembersPointer(0); - data_.o.size = data_.o.capacity = count; - } + //! Initialize this value as object with initial data, without calling destructor. + void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { + data_.f.flags = kObjectFlag; + if (count) { + Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); + SetMembersPointer(m); + std::memcpy(static_cast(m), members, count * sizeof(Member)); + } else + SetMembersPointer(0); + data_.o.size = data_.o.capacity = count; + } - //! Initialize this value as constant string, without calling destructor. - void SetStringRaw(StringRefType s) CEREAL_RAPIDJSON_NOEXCEPT { - data_.f.flags = kConstStringFlag; - SetStringPointer(s); - data_.s.length = s.length; - } + //! Initialize this value as constant string, without calling destructor. + void SetStringRaw(StringRefType s) CEREAL_RAPIDJSON_NOEXCEPT { + data_.f.flags = kConstStringFlag; + SetStringPointer(s); + data_.s.length = s.length; + } - //! Initialize this value as copy string with initial data, without calling destructor. - void SetStringRaw(StringRefType s, Allocator& allocator) { - Ch* str = 0; - if (ShortString::Usable(s.length)) { - data_.f.flags = kShortStringFlag; - data_.ss.SetLength(s.length); - str = data_.ss.str; - } else { - data_.f.flags = kCopyStringFlag; - data_.s.length = s.length; - str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); - SetStringPointer(str); - } - std::memcpy(str, s, s.length * sizeof(Ch)); - str[s.length] = '\0'; - } + //! Initialize this value as copy string with initial data, without calling destructor. + void SetStringRaw(StringRefType s, Allocator& allocator) { + Ch* str = 0; + if (ShortString::Usable(s.length)) { + data_.f.flags = kShortStringFlag; + data_.ss.SetLength(s.length); + str = data_.ss.str; + } else { + data_.f.flags = kCopyStringFlag; + data_.s.length = s.length; + str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); + SetStringPointer(str); + } + std::memcpy(str, s, s.length * sizeof(Ch)); + str[s.length] = '\0'; + } - //! Assignment without calling destructor - void RawAssign(GenericValue& rhs) CEREAL_RAPIDJSON_NOEXCEPT { - data_ = rhs.data_; - // data_.f.flags = rhs.data_.f.flags; - rhs.data_.f.flags = kNullFlag; - } + //! Assignment without calling destructor + void RawAssign(GenericValue& rhs) CEREAL_RAPIDJSON_NOEXCEPT { + data_ = rhs.data_; + // data_.f.flags = rhs.data_.f.flags; + rhs.data_.f.flags = kNullFlag; + } - template - bool StringEqual(const GenericValue& rhs) const { - CEREAL_RAPIDJSON_ASSERT(IsString()); - CEREAL_RAPIDJSON_ASSERT(rhs.IsString()); + template + bool StringEqual(const GenericValue& rhs) const { + CEREAL_RAPIDJSON_ASSERT(IsString()); + CEREAL_RAPIDJSON_ASSERT(rhs.IsString()); - const SizeType len1 = GetStringLength(); - const SizeType len2 = rhs.GetStringLength(); - if(len1 != len2) { return false; } + const SizeType len1 = GetStringLength(); + const SizeType len2 = rhs.GetStringLength(); + if (len1 != len2) { + return false; + } - const Ch* const str1 = GetString(); - const Ch* const str2 = rhs.GetString(); - if(str1 == str2) { return true; } // fast path for constant string + const Ch* const str1 = GetString(); + const Ch* const str2 = rhs.GetString(); + if (str1 == str2) { + return true; + } // fast path for constant string - return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); - } + return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); + } - Data data_; + Data data_; }; //! GenericValue with UTF8 encoding -typedef GenericValue > Value; +typedef GenericValue> Value; /////////////////////////////////////////////////////////////////////////////// // GenericDocument @@ -2129,388 +2301,411 @@ typedef GenericValue > Value; */ template , typename StackAllocator = CrtAllocator> class GenericDocument : public GenericValue { -public: - typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. - typedef GenericValue ValueType; //!< Value type of the document. - typedef Allocator AllocatorType; //!< Allocator type from template parameter. + public: + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericValue ValueType; //!< Value type of the document. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. - //! Constructor - /*! Creates an empty document of specified type. - \param type Mandatory type of object to create. - \param allocator Optional allocator for allocating memory. - \param stackCapacity Optional initial capacity of stack in bytes. - \param stackAllocator Optional allocator for allocating memory for stack. - */ - explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : - GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() - { - if (!allocator_) - ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)(); - } + //! Constructor + /*! Creates an empty document of specified type. + \param type Mandatory type of object to create. + \param allocator Optional allocator for allocating memory. + \param stackCapacity Optional initial capacity of stack in bytes. + \param stackAllocator Optional allocator for allocating memory for stack. + */ + explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { + if (!allocator_) + ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)(); + } - //! Constructor - /*! Creates an empty document which type is Null. - \param allocator Optional allocator for allocating memory. - \param stackCapacity Optional initial capacity of stack in bytes. - \param stackAllocator Optional allocator for allocating memory for stack. - */ - GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : - allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() - { - if (!allocator_) - ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)(); - } + //! Constructor + /*! Creates an empty document which type is Null. + \param allocator Optional allocator for allocating memory. + \param stackCapacity Optional initial capacity of stack in bytes. + \param stackAllocator Optional allocator for allocating memory for stack. + */ + GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { + if (!allocator_) + ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)(); + } #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move constructor in C++11 - GenericDocument(GenericDocument&& rhs) CEREAL_RAPIDJSON_NOEXCEPT - : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document - allocator_(rhs.allocator_), - ownAllocator_(rhs.ownAllocator_), - stack_(std::move(rhs.stack_)), - parseResult_(rhs.parseResult_) - { - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.parseResult_ = ParseResult(); - } + //! Move constructor in C++11 + GenericDocument(GenericDocument&& rhs) CEREAL_RAPIDJSON_NOEXCEPT + : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document + allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + stack_(std::move(rhs.stack_)), + parseResult_(rhs.parseResult_) { + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.parseResult_ = ParseResult(); + } #endif - ~GenericDocument() { - Destroy(); - } + ~GenericDocument() { + Destroy(); + } #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS - //! Move assignment in C++11 - GenericDocument& operator=(GenericDocument&& rhs) CEREAL_RAPIDJSON_NOEXCEPT - { - // The cast to ValueType is necessary here, because otherwise it would - // attempt to call GenericValue's templated assignment operator. - ValueType::operator=(std::forward(rhs)); + //! Move assignment in C++11 + GenericDocument& operator=(GenericDocument&& rhs) CEREAL_RAPIDJSON_NOEXCEPT { + // The cast to ValueType is necessary here, because otherwise it would + // attempt to call GenericValue's templated assignment operator. + ValueType::operator=(std::forward(rhs)); - // Calling the destructor here would prematurely call stack_'s destructor - Destroy(); + // Calling the destructor here would prematurely call stack_'s destructor + Destroy(); - allocator_ = rhs.allocator_; - ownAllocator_ = rhs.ownAllocator_; - stack_ = std::move(rhs.stack_); - parseResult_ = rhs.parseResult_; + allocator_ = rhs.allocator_; + ownAllocator_ = rhs.ownAllocator_; + stack_ = std::move(rhs.stack_); + parseResult_ = rhs.parseResult_; - rhs.allocator_ = 0; - rhs.ownAllocator_ = 0; - rhs.parseResult_ = ParseResult(); + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.parseResult_ = ParseResult(); - return *this; - } + return *this; + } #endif - //! Exchange the contents of this document with those of another. - /*! - \param rhs Another document. - \note Constant complexity. - \see GenericValue::Swap - */ - GenericDocument& Swap(GenericDocument& rhs) CEREAL_RAPIDJSON_NOEXCEPT { - ValueType::Swap(rhs); - stack_.Swap(rhs.stack_); - internal::Swap(allocator_, rhs.allocator_); - internal::Swap(ownAllocator_, rhs.ownAllocator_); - internal::Swap(parseResult_, rhs.parseResult_); - return *this; - } + //! Exchange the contents of this document with those of another. + /*! + \param rhs Another document. + \note Constant complexity. + \see GenericValue::Swap + */ + GenericDocument& Swap(GenericDocument& rhs) CEREAL_RAPIDJSON_NOEXCEPT { + ValueType::Swap(rhs); + stack_.Swap(rhs.stack_); + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(parseResult_, rhs.parseResult_); + return *this; + } - // Allow Swap with ValueType. - // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. - using ValueType::Swap; + // Allow Swap with ValueType. + // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. + using ValueType::Swap; - //! free-standing swap function helper - /*! - Helper function to enable support for common swap implementation pattern based on \c std::swap: - \code - void swap(MyClass& a, MyClass& b) { - using std::swap; - swap(a.doc, b.doc); - // ... - } - \endcode - \see Swap() - */ - friend inline void swap(GenericDocument& a, GenericDocument& b) CEREAL_RAPIDJSON_NOEXCEPT { a.Swap(b); } + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.doc, b.doc); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericDocument& a, GenericDocument& b) CEREAL_RAPIDJSON_NOEXCEPT { a.Swap(b); } - //! Populate this document by a generator which produces SAX events. - /*! \tparam Generator A functor with bool f(Handler) prototype. - \param g Generator functor which sends SAX events to the parameter. - \return The document itself for fluent API. - */ - template - GenericDocument& Populate(Generator& g) { - ClearStackOnExit scope(*this); - if (g(*this)) { - CEREAL_RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object - ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document - } - return *this; - } + //! Populate this document by a generator which produces SAX events. + /*! \tparam Generator A functor with bool f(Handler) prototype. + \param g Generator functor which sends SAX events to the parameter. + \return The document itself for fluent API. + */ + template + GenericDocument& Populate(Generator& g) { + ClearStackOnExit scope(*this); + if (g(*this)) { + CEREAL_RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + ValueType::operator=(*stack_.template Pop(1)); // Move value from stack to document + } + return *this; + } - //!@name Parse from stream - //!@{ + //!@name Parse from stream + //!@{ - //! Parse JSON text from an input stream (with Encoding conversion) - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam SourceEncoding Encoding of input stream - \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - GenericReader reader( - stack_.HasAllocator() ? &stack_.GetAllocator() : 0); - ClearStackOnExit scope(*this); - parseResult_ = reader.template Parse(is, *this); - if (parseResult_) { - CEREAL_RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object - ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document - } - return *this; - } + //! Parse JSON text from an input stream (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam SourceEncoding Encoding of input stream + \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + GenericReader reader( + stack_.HasAllocator() ? &stack_.GetAllocator() : 0); + ClearStackOnExit scope(*this); + parseResult_ = reader.template Parse(is, *this); + if (parseResult_) { + CEREAL_RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + ValueType::operator=(*stack_.template Pop(1)); // Move value from stack to document + } + return *this; + } - //! Parse JSON text from an input stream - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - return ParseStream(is); - } + //! Parse JSON text from an input stream + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream(is); + } - //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) - /*! \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - return ParseStream(is); - } - //!@} + //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) + /*! \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream(is); + } + //!@} - //!@name Parse in-place from mutable string - //!@{ + //!@name Parse in-place from mutable string + //!@{ - //! Parse JSON text from a mutable string - /*! \tparam parseFlags Combination of \ref ParseFlag. - \param str Mutable zero-terminated string to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseInsitu(Ch* str) { - GenericInsituStringStream s(str); - return ParseStream(s); - } + //! Parse JSON text from a mutable string + /*! \tparam parseFlags Combination of \ref ParseFlag. + \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseInsitu(Ch* str) { + GenericInsituStringStream s(str); + return ParseStream(s); + } - //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) - /*! \param str Mutable zero-terminated string to be parsed. - \return The document itself for fluent API. - */ - GenericDocument& ParseInsitu(Ch* str) { - return ParseInsitu(str); - } - //!@} + //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) + /*! \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + GenericDocument& ParseInsitu(Ch* str) { + return ParseInsitu(str); + } + //!@} - //!@name Parse from read-only string - //!@{ + //!@name Parse from read-only string + //!@{ - //! Parse JSON text from a read-only string (with Encoding conversion) - /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). - \tparam SourceEncoding Transcoding from input Encoding - \param str Read-only zero-terminated string to be parsed. - */ - template - GenericDocument& Parse(const typename SourceEncoding::Ch* str) { - CEREAL_RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - GenericStringStream s(str); - return ParseStream(s); - } + //! Parse JSON text from a read-only string (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). + \tparam SourceEncoding Transcoding from input Encoding + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const typename SourceEncoding::Ch* str) { + CEREAL_RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + GenericStringStream s(str); + return ParseStream(s); + } - //! Parse JSON text from a read-only string - /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). - \param str Read-only zero-terminated string to be parsed. - */ - template - GenericDocument& Parse(const Ch* str) { - return Parse(str); - } + //! Parse JSON text from a read-only string + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const Ch* str) { + return Parse(str); + } - //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) - /*! \param str Read-only zero-terminated string to be parsed. - */ - GenericDocument& Parse(const Ch* str) { - return Parse(str); - } + //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) + /*! \param str Read-only zero-terminated string to be parsed. + */ + GenericDocument& Parse(const Ch* str) { + return Parse(str); + } - template - GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { - CEREAL_RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch)); - EncodedInputStream is(ms); - ParseStream(is); - return *this; - } + template + GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { + CEREAL_RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch)); + EncodedInputStream is(ms); + ParseStream(is); + return *this; + } - template - GenericDocument& Parse(const Ch* str, size_t length) { - return Parse(str, length); - } + template + GenericDocument& Parse(const Ch* str, size_t length) { + return Parse(str, length); + } - GenericDocument& Parse(const Ch* str, size_t length) { - return Parse(str, length); - } + GenericDocument& Parse(const Ch* str, size_t length) { + return Parse(str, length); + } #if CEREAL_RAPIDJSON_HAS_STDSTRING - template - GenericDocument& Parse(const std::basic_string& str) { - // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t) - return Parse(str.c_str()); - } + template + GenericDocument& Parse(const std::basic_string& str) { + // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t) + return Parse(str.c_str()); + } - template - GenericDocument& Parse(const std::basic_string& str) { - return Parse(str.c_str()); - } + template + GenericDocument& Parse(const std::basic_string& str) { + return Parse(str.c_str()); + } - GenericDocument& Parse(const std::basic_string& str) { - return Parse(str); - } + GenericDocument& Parse(const std::basic_string& str) { + return Parse(str); + } #endif // CEREAL_RAPIDJSON_HAS_STDSTRING - //!@} + //!@} - //!@name Handling parse errors - //!@{ + //!@name Handling parse errors + //!@{ - //! Whether a parse error has occurred in the last parsing. - bool HasParseError() const { return parseResult_.IsError(); } + //! Whether a parse error has occurred in the last parsing. + bool HasParseError() const { return parseResult_.IsError(); } - //! Get the \ref ParseErrorCode of last parsing. - ParseErrorCode GetParseError() const { return parseResult_.Code(); } + //! Get the \ref ParseErrorCode of last parsing. + ParseErrorCode GetParseError() const { return parseResult_.Code(); } - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorOffset() const { return parseResult_.Offset(); } + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorOffset() const { return parseResult_.Offset(); } - //! Implicit conversion to get the last parse result + //! Implicit conversion to get the last parse result #ifndef __clang // -Wdocumentation - /*! \return \ref ParseResult of the last parse operation + /*! \return \ref ParseResult of the last parse operation - \code - Document doc; - ParseResult ok = doc.Parse(json); - if (!ok) - printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); - \endcode - */ + \code + Document doc; + ParseResult ok = doc.Parse(json); + if (!ok) + printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); + \endcode + */ #endif - operator ParseResult() const { return parseResult_; } - //!@} + operator ParseResult() const { return parseResult_; } + //!@} - //! Get the allocator of this document. - Allocator& GetAllocator() { - CEREAL_RAPIDJSON_ASSERT(allocator_); - return *allocator_; - } + //! Get the allocator of this document. + Allocator& GetAllocator() { + CEREAL_RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } - //! Get the capacity of stack in bytes. - size_t GetStackCapacity() const { return stack_.GetCapacity(); } + //! Get the capacity of stack in bytes. + size_t GetStackCapacity() const { return stack_.GetCapacity(); } -private: - // clear stack on any exit from ParseStream, e.g. due to exception - struct ClearStackOnExit { - explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} - ~ClearStackOnExit() { d_.ClearStack(); } - private: - ClearStackOnExit(const ClearStackOnExit&); - ClearStackOnExit& operator=(const ClearStackOnExit&); - GenericDocument& d_; - }; + private: + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} + ~ClearStackOnExit() { d_.ClearStack(); } - // callers of the following private Handler functions - // template friend class GenericReader; // for parsing - template friend class GenericValue; // for deep copying + private: + ClearStackOnExit(const ClearStackOnExit&); + ClearStackOnExit& operator=(const ClearStackOnExit&); + GenericDocument& d_; + }; -public: - // Implementation of Handler - bool Null() { new (stack_.template Push()) ValueType(); return true; } - bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } - bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } - bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } - bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } - bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } - bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } + // callers of the following private Handler functions + // template friend class GenericReader; // for parsing + template + friend class GenericValue; // for deep copying - bool RawNumber(const Ch* str, SizeType length, bool copy) { - if (copy) - new (stack_.template Push()) ValueType(str, length, GetAllocator()); - else - new (stack_.template Push()) ValueType(str, length); - return true; - } + public: + // Implementation of Handler + bool Null() { + new (stack_.template Push()) ValueType(); + return true; + } + bool Bool(bool b) { + new (stack_.template Push()) ValueType(b); + return true; + } + bool Int(int i) { + new (stack_.template Push()) ValueType(i); + return true; + } + bool Uint(unsigned i) { + new (stack_.template Push()) ValueType(i); + return true; + } + bool Int64(int64_t i) { + new (stack_.template Push()) ValueType(i); + return true; + } + bool Uint64(uint64_t i) { + new (stack_.template Push()) ValueType(i); + return true; + } + bool Double(double d) { + new (stack_.template Push()) ValueType(d); + return true; + } - bool String(const Ch* str, SizeType length, bool copy) { - if (copy) - new (stack_.template Push()) ValueType(str, length, GetAllocator()); - else - new (stack_.template Push()) ValueType(str, length); - return true; - } + bool RawNumber(const Ch* str, SizeType length, bool copy) { + if (copy) + new (stack_.template Push()) ValueType(str, length, GetAllocator()); + else + new (stack_.template Push()) ValueType(str, length); + return true; + } - bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } + bool String(const Ch* str, SizeType length, bool copy) { + if (copy) + new (stack_.template Push()) ValueType(str, length, GetAllocator()); + else + new (stack_.template Push()) ValueType(str, length); + return true; + } - bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } + bool StartObject() { + new (stack_.template Push()) ValueType(kObjectType); + return true; + } - bool EndObject(SizeType memberCount) { - typename ValueType::Member* members = stack_.template Pop(memberCount); - stack_.template Top()->SetObjectRaw(members, memberCount, GetAllocator()); - return true; - } + bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } - bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } + bool EndObject(SizeType memberCount) { + typename ValueType::Member* members = stack_.template Pop(memberCount); + stack_.template Top()->SetObjectRaw(members, memberCount, GetAllocator()); + return true; + } - bool EndArray(SizeType elementCount) { - ValueType* elements = stack_.template Pop(elementCount); - stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); - return true; - } + bool StartArray() { + new (stack_.template Push()) ValueType(kArrayType); + return true; + } -private: - //! Prohibit copying - GenericDocument(const GenericDocument&); - //! Prohibit assignment - GenericDocument& operator=(const GenericDocument&); + bool EndArray(SizeType elementCount) { + ValueType* elements = stack_.template Pop(elementCount); + stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); + return true; + } - void ClearStack() { - if (Allocator::kNeedFree) - while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) - (stack_.template Pop(1))->~ValueType(); - else - stack_.Clear(); - stack_.ShrinkToFit(); - } + private: + //! Prohibit copying + GenericDocument(const GenericDocument&); + //! Prohibit assignment + GenericDocument& operator=(const GenericDocument&); - void Destroy() { - CEREAL_RAPIDJSON_DELETE(ownAllocator_); - } + void ClearStack() { + if (Allocator::kNeedFree) + while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) + (stack_.template Pop(1))->~ValueType(); + else + stack_.Clear(); + stack_.ShrinkToFit(); + } - static const size_t kDefaultStackCapacity = 1024; - Allocator* allocator_; - Allocator* ownAllocator_; - internal::Stack stack_; - ParseResult parseResult_; + void Destroy() { + CEREAL_RAPIDJSON_DELETE(ownAllocator_); + } + + static const size_t kDefaultStackCapacity = 1024; + Allocator* allocator_; + Allocator* ownAllocator_; + internal::Stack stack_; + ParseResult parseResult_; }; //! GenericDocument with UTF8 encoding -typedef GenericDocument > Document; +typedef GenericDocument> Document; //! Helper class for accessing Value of array type. /*! @@ -2519,50 +2714,73 @@ typedef GenericDocument > Document; */ template class GenericArray { -public: - typedef GenericArray ConstArray; - typedef GenericArray Array; - typedef ValueT PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; - typedef ValueType* ValueIterator; // This may be const or non-const iterator - typedef const ValueT* ConstValueIterator; - typedef typename ValueType::AllocatorType AllocatorType; - typedef typename ValueType::StringRefType StringRefType; + public: + typedef GenericArray ConstArray; + typedef GenericArray Array; + typedef ValueT PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef ValueType* ValueIterator; // This may be const or non-const iterator + typedef const ValueT* ConstValueIterator; + typedef typename ValueType::AllocatorType AllocatorType; + typedef typename ValueType::StringRefType StringRefType; - template - friend class GenericValue; + template + friend class GenericValue; - GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} - GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } - ~GenericArray() {} + GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} + GenericArray& operator=(const GenericArray& rhs) { + value_ = rhs.value_; + return *this; + } + ~GenericArray() {} - SizeType Size() const { return value_.Size(); } - SizeType Capacity() const { return value_.Capacity(); } - bool Empty() const { return value_.Empty(); } - void Clear() const { value_.Clear(); } - ValueType& operator[](SizeType index) const { return value_[index]; } - ValueIterator Begin() const { return value_.Begin(); } - ValueIterator End() const { return value_.End(); } - GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } - GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } + SizeType Size() const { return value_.Size(); } + SizeType Capacity() const { return value_.Capacity(); } + bool Empty() const { return value_.Empty(); } + void Clear() const { value_.Clear(); } + ValueType& operator[](SizeType index) const { return value_[index]; } + ValueIterator Begin() const { return value_.Begin(); } + ValueIterator End() const { return value_.End(); } + GenericArray Reserve(SizeType newCapacity, AllocatorType& allocator) const { + value_.Reserve(newCapacity, allocator); + return *this; + } + GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { + value_.PushBack(value, allocator); + return *this; + } #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } + GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { + value_.PushBack(value, allocator); + return *this; + } #endif // CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } - template CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } - GenericArray PopBack() const { value_.PopBack(); return *this; } - ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } - ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } + GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { + value_.PushBack(value, allocator); + return *this; + } + template + CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue>), (const GenericArray&)) + PushBack(T value, AllocatorType& allocator) const { + value_.PushBack(value, allocator); + return *this; + } + GenericArray PopBack() const { + value_.PopBack(); + return *this; + } + ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } #if CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR - ValueIterator begin() const { return value_.Begin(); } - ValueIterator end() const { return value_.End(); } + ValueIterator begin() const { return value_.Begin(); } + ValueIterator end() const { return value_.End(); } #endif -private: - GenericArray(); - GenericArray(ValueType& value) : value_(value) {} - ValueType& value_; + private: + GenericArray(); + GenericArray(ValueType& value) : value_(value) {} + ValueType& value_; }; //! Helper class for accessing Value of object type. @@ -2572,85 +2790,134 @@ private: */ template class GenericObject { -public: - typedef GenericObject ConstObject; - typedef GenericObject Object; - typedef ValueT PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; - typedef GenericMemberIterator MemberIterator; // This may be const or non-const iterator - typedef GenericMemberIterator ConstMemberIterator; - typedef typename ValueType::AllocatorType AllocatorType; - typedef typename ValueType::StringRefType StringRefType; - typedef typename ValueType::EncodingType EncodingType; - typedef typename ValueType::Ch Ch; + public: + typedef GenericObject ConstObject; + typedef GenericObject Object; + typedef ValueT PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef GenericMemberIterator MemberIterator; // This may be const or non-const iterator + typedef GenericMemberIterator ConstMemberIterator; + typedef typename ValueType::AllocatorType AllocatorType; + typedef typename ValueType::StringRefType StringRefType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename ValueType::Ch Ch; - template - friend class GenericValue; + template + friend class GenericValue; - GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} - GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } - ~GenericObject() {} + GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} + GenericObject& operator=(const GenericObject& rhs) { + value_ = rhs.value_; + return *this; + } + ~GenericObject() {} - SizeType MemberCount() const { return value_.MemberCount(); } - SizeType MemberCapacity() const { return value_.MemberCapacity(); } - bool ObjectEmpty() const { return value_.ObjectEmpty(); } - template ValueType& operator[](T* name) const { return value_[name]; } - template ValueType& operator[](const GenericValue& name) const { return value_[name]; } + SizeType MemberCount() const { return value_.MemberCount(); } + SizeType MemberCapacity() const { return value_.MemberCapacity(); } + bool ObjectEmpty() const { return value_.ObjectEmpty(); } + template + ValueType& operator[](T* name) const { return value_[name]; } + template + ValueType& operator[](const GenericValue& name) const { return value_[name]; } #if CEREAL_RAPIDJSON_HAS_STDSTRING - ValueType& operator[](const std::basic_string& name) const { return value_[name]; } + ValueType& operator[](const std::basic_string& name) const { return value_[name]; } #endif - MemberIterator MemberBegin() const { return value_.MemberBegin(); } - MemberIterator MemberEnd() const { return value_.MemberEnd(); } - GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; } - bool HasMember(const Ch* name) const { return value_.HasMember(name); } + MemberIterator MemberBegin() const { return value_.MemberBegin(); } + MemberIterator MemberEnd() const { return value_.MemberEnd(); } + GenericObject MemberReserve(SizeType newCapacity, AllocatorType& allocator) const { + value_.MemberReserve(newCapacity, allocator); + return *this; + } + bool HasMember(const Ch* name) const { return value_.HasMember(name); } #if CEREAL_RAPIDJSON_HAS_STDSTRING - bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } + bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } #endif - template bool HasMember(const GenericValue& name) const { return value_.HasMember(name); } - MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); } - template MemberIterator FindMember(const GenericValue& name) const { return value_.FindMember(name); } + template + bool HasMember(const GenericValue& name) const { return value_.HasMember(name); } + MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); } + template + MemberIterator FindMember(const GenericValue& name) const { return value_.FindMember(name); } #if CEREAL_RAPIDJSON_HAS_STDSTRING - MemberIterator FindMember(const std::basic_string& name) const { return value_.FindMember(name); } + MemberIterator FindMember(const std::basic_string& name) const { return value_.FindMember(name); } #endif - GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { + value_.AddMember(name, value, allocator); + return *this; + } + GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { + value_.AddMember(name, value, allocator); + return *this; + } #if CEREAL_RAPIDJSON_HAS_STDSTRING - GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { + value_.AddMember(name, value, allocator); + return *this; + } #endif - template CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + template + CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue>), (ValueType&)) + AddMember(ValueType& name, T value, AllocatorType& allocator) const { + value_.AddMember(name, value, allocator); + return *this; + } #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { + value_.AddMember(name, value, allocator); + return *this; + } + GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { + value_.AddMember(name, value, allocator); + return *this; + } + GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { + value_.AddMember(name, value, allocator); + return *this; + } + GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { + value_.AddMember(name, value, allocator); + return *this; + } #endif // CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - template CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - void RemoveAllMembers() { value_.RemoveAllMembers(); } - bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } + GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { + value_.AddMember(name, value, allocator); + return *this; + } + GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { + value_.AddMember(name, value, allocator); + return *this; + } + template + CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue>), (GenericObject)) + AddMember(StringRefType name, T value, AllocatorType& allocator) const { + value_.AddMember(name, value, allocator); + return *this; + } + void RemoveAllMembers() { value_.RemoveAllMembers(); } + bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } #if CEREAL_RAPIDJSON_HAS_STDSTRING - bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } + bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } #endif - template bool RemoveMember(const GenericValue& name) const { return value_.RemoveMember(name); } - MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } - MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } - MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } - bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } + template + bool RemoveMember(const GenericValue& name) const { return value_.RemoveMember(name); } + MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } + MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } + bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } #if CEREAL_RAPIDJSON_HAS_STDSTRING - bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } + bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } #endif - template bool EraseMember(const GenericValue& name) const { return value_.EraseMember(name); } + template + bool EraseMember(const GenericValue& name) const { return value_.EraseMember(name); } #if CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR - MemberIterator begin() const { return value_.MemberBegin(); } - MemberIterator end() const { return value_.MemberEnd(); } + MemberIterator begin() const { return value_.MemberBegin(); } + MemberIterator end() const { return value_.MemberEnd(); } #endif -private: - GenericObject(); - GenericObject(ValueType& value) : value_(value) {} - ValueType& value_; + private: + GenericObject(); + GenericObject(ValueType& value) : value_(value) {} + ValueType& value_; }; CEREAL_RAPIDJSON_NAMESPACE_END diff --git a/Deer/vendor/enet/Build.lua b/Deer/vendor/enet/Build.lua new file mode 100755 index 0000000..92f00b9 --- /dev/null +++ b/Deer/vendor/enet/Build.lua @@ -0,0 +1,48 @@ +project "enet" + kind "StaticLib" + language "C" + staticruntime "on" + + targetdir ("../../../bin/" .. OutputDir .. "/%{prj.name}") + objdir ("../../../bin/int/" .. OutputDir .. "/%{prj.name}") + + includedirs { + "include" + } + + -- Core source files + files { + "callbacks.c", + "compress.c", + "host.c", + "list.c", + "packet.c", + "peer.c", + "protocol.c", + "unix.c", -- Only Unix/Linux file + "include/enet/**.h" + } + + -- Platform-specific defines for Linux/Debian + filter "system:linux" + defines { + "HAS_FCNTL=1", + "HAS_POLL=1", + "HAS_GETADDRINFO=1", + "HAS_GETNAMEINFO=1", + "HAS_GETHOSTBYNAME_R=1", + "HAS_GETHOSTBYADDR_R=1", + "HAS_INET_PTON=1", + "HAS_INET_NTOP=1", + "HAS_MSGHDR_FLAGS=1", + "HAS_SOCKLEN_T=1" + } + + -- Build configurations + filter "configurations:Debug" + symbols "On" + + filter "configurations:Release" + optimize "On" + + filter {} -- clear filter diff --git a/Deer/vendor/enet/CMakeLists.txt b/Deer/vendor/enet/CMakeLists.txt new file mode 100644 index 0000000..c6459b6 --- /dev/null +++ b/Deer/vendor/enet/CMakeLists.txt @@ -0,0 +1,102 @@ +cmake_minimum_required(VERSION 2.8.12...3.20) + +project(enet) + +# The "configure" step. +include(CheckFunctionExists) +include(CheckStructHasMember) +include(CheckTypeSize) +check_function_exists("fcntl" HAS_FCNTL) +check_function_exists("poll" HAS_POLL) +check_function_exists("getaddrinfo" HAS_GETADDRINFO) +check_function_exists("getnameinfo" HAS_GETNAMEINFO) +check_function_exists("gethostbyname_r" HAS_GETHOSTBYNAME_R) +check_function_exists("gethostbyaddr_r" HAS_GETHOSTBYADDR_R) +check_function_exists("inet_pton" HAS_INET_PTON) +check_function_exists("inet_ntop" HAS_INET_NTOP) +check_struct_has_member("struct msghdr" "msg_flags" "sys/types.h;sys/socket.h" HAS_MSGHDR_FLAGS) +set(CMAKE_EXTRA_INCLUDE_FILES "sys/types.h" "sys/socket.h") +check_type_size("socklen_t" HAS_SOCKLEN_T BUILTIN_TYPES_ONLY) +unset(CMAKE_EXTRA_INCLUDE_FILES) +if(MSVC) + add_definitions(-W3) +else() + add_definitions(-Wno-error) +endif() + +if(HAS_FCNTL) + add_definitions(-DHAS_FCNTL=1) +endif() +if(HAS_POLL) + add_definitions(-DHAS_POLL=1) +endif() +if(HAS_GETNAMEINFO) + add_definitions(-DHAS_GETNAMEINFO=1) +endif() +if(HAS_GETADDRINFO) + add_definitions(-DHAS_GETADDRINFO=1) +endif() +if(HAS_GETHOSTBYNAME_R) + add_definitions(-DHAS_GETHOSTBYNAME_R=1) +endif() +if(HAS_GETHOSTBYADDR_R) + add_definitions(-DHAS_GETHOSTBYADDR_R=1) +endif() +if(HAS_INET_PTON) + add_definitions(-DHAS_INET_PTON=1) +endif() +if(HAS_INET_NTOP) + add_definitions(-DHAS_INET_NTOP=1) +endif() +if(HAS_MSGHDR_FLAGS) + add_definitions(-DHAS_MSGHDR_FLAGS=1) +endif() +if(HAS_SOCKLEN_T) + add_definitions(-DHAS_SOCKLEN_T=1) +endif() + +include_directories(${PROJECT_SOURCE_DIR}/include) + +set(INCLUDE_FILES_PREFIX include/enet) +set(INCLUDE_FILES + ${INCLUDE_FILES_PREFIX}/callbacks.h + ${INCLUDE_FILES_PREFIX}/enet.h + ${INCLUDE_FILES_PREFIX}/list.h + ${INCLUDE_FILES_PREFIX}/protocol.h + ${INCLUDE_FILES_PREFIX}/time.h + ${INCLUDE_FILES_PREFIX}/types.h + ${INCLUDE_FILES_PREFIX}/unix.h + ${INCLUDE_FILES_PREFIX}/utility.h + ${INCLUDE_FILES_PREFIX}/win32.h +) + +set(SOURCE_FILES + callbacks.c + compress.c + host.c + list.c + packet.c + peer.c + protocol.c + unix.c + win32.c) + +source_group(include FILES ${INCLUDE_FILES}) +source_group(source FILES ${SOURCE_FILES}) + +add_library(enet STATIC + ${INCLUDE_FILES} + ${SOURCE_FILES} +) + +if (MINGW) + target_link_libraries(enet winmm ws2_32) +endif() + +install(TARGETS enet + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib/static + LIBRARY DESTINATION lib) + +install(DIRECTORY include/ + DESTINATION include) diff --git a/Deer/vendor/enet/ChangeLog b/Deer/vendor/enet/ChangeLog new file mode 100644 index 0000000..0fc45d3 --- /dev/null +++ b/Deer/vendor/enet/ChangeLog @@ -0,0 +1,209 @@ +ENet 1.3.18 (April 14, 2024): + +* Packet sending performance improvements +* MTU negotiation fixes +* Checksum alignment fix +* No more dynamic initialization of checksum table +* ENET_SOCKOPT_TTL +* Other miscellaneous small improvements + +ENet 1.3.17 (November 15, 2020): + +* fixes for sender getting too far ahead of receiver that can cause instability with reliable packets + +ENet 1.3.16 (September 8, 2020): + +* fix bug in unreliable fragment queuing +* use single output queue for reliable and unreliable packets for saner ordering +* revert experimental throttle changes that were less stable than prior algorithm + +ENet 1.3.15 (April 20, 2020): + +* quicker RTT initialization +* use fractional precision for RTT calculations +* fixes for packet throttle with low RTT variance +* miscellaneous socket bug fixes + +ENet 1.3.14 (January 27, 2019): + +* bug fix for enet_peer_disconnect_later() +* use getaddrinfo and getnameinfo where available +* miscellaneous cleanups + +ENet 1.3.13 (April 30, 2015): + +* miscellaneous bug fixes +* added premake and cmake support +* miscellaneous documentation cleanups + +ENet 1.3.12 (April 24, 2014): + +* added maximumPacketSize and maximumWaitingData fields to ENetHost to limit the amount of +data waiting to be delivered on a peer (beware that the default maximumPacketSize is +32MB and should be set higher if desired as should maximumWaitingData) + +ENet 1.3.11 (December 26, 2013): + +* allow an ENetHost to connect to itself +* fixed possible bug with disconnect notifications during connect attempts +* fixed some preprocessor definition bugs + +ENet 1.3.10 (October 23, 2013); + +* doubled maximum reliable window size +* fixed RCVTIMEO/SNDTIMEO socket options and also added NODELAY + +ENet 1.3.9 (August 19, 2013): + +* added duplicatePeers option to ENetHost which can limit the number of peers from duplicate IPs +* added enet_socket_get_option() and ENET_SOCKOPT_ERROR +* added enet_host_random_seed() platform stub + +ENet 1.3.8 (June 2, 2013): + +* added enet_linked_version() for checking the linked version +* added enet_socket_get_address() for querying the local address of a socket +* silenced some debugging prints unless ENET_DEBUG is defined during compilation +* handle EINTR in enet_socket_wait() so that enet_host_service() doesn't propagate errors from signals +* optimized enet_host_bandwidth_throttle() to be less expensive for large numbers of peers + +ENet 1.3.7 (March 6, 2013): + +* added ENET_PACKET_FLAG_SENT to indicate that a packet is being freed because it has been sent +* added userData field to ENetPacket +* changed how random seed is generated on Windows to avoid import warnings +* fixed case where disconnects could be generated with no preceding connect event + +ENet 1.3.6 (December 11, 2012): + +* added support for intercept callback in ENetHost that can be used to process raw packets before ENet +* added enet_socket_shutdown() for issuing shutdown on a socket +* fixed enet_socket_connect() to not error on non-blocking connects +* fixed bug in MTU negotiation during connections + +ENet 1.3.5 (July 31, 2012): + +* fixed bug in unreliable packet fragment queuing + +ENet 1.3.4 (May 29, 2012): + +* added enet_peer_ping_interval() for configuring per-peer ping intervals +* added enet_peer_timeout() for configuring per-peer timeouts +* added protocol packet size limits + +ENet 1.3.3 (June 28, 2011): + +* fixed bug with simultaneous disconnects not dispatching events + +ENet 1.3.2 (May 31, 2011): + +* added support for unreliable packet fragmenting via the packet flag +ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT +* fixed regression in unreliable packet queuing +* added check against received port to limit some forms of IP-spoofing + +ENet 1.3.1 (February 10, 2011): + +* fixed bug in tracking of reliable data in transit +* reliable data window size now scales with the throttle +* fixed bug in fragment length calculation when checksums are used + +ENet 1.3.0 (June 5, 2010): + +* enet_host_create() now requires the channel limit to be specified as +a parameter +* enet_host_connect() now accepts a data parameter which is supplied +to the receiving receiving host in the event data field for a connect event +* added an adaptive order-2 PPM range coder as a built-in compressor option +which can be set with enet_host_compress_with_range_coder() +* added support for packet compression configurable with a callback +* improved session number handling to not rely on the packet checksum +field, saving 4 bytes per packet unless the checksum option is used +* removed the dependence on the rand callback for session number handling + +Caveats: This version is not protocol compatible with the 1.2 series or +earlier. The enet_host_connect and enet_host_create API functions require +supplying additional parameters. + +ENet 1.2.5 (June 28, 2011): + +* fixed bug with simultaneous disconnects not dispatching events + +ENet 1.2.4 (May 31, 2011): + +* fixed regression in unreliable packet queuing +* added check against received port to limit some forms of IP-spoofing + +ENet 1.2.3 (February 10, 2011): + +* fixed bug in tracking reliable data in transit + +ENet 1.2.2 (June 5, 2010): + +* checksum functionality is now enabled by setting a checksum callback +inside ENetHost instead of being a configure script option +* added totalSentData, totalSentPackets, totalReceivedData, and +totalReceivedPackets counters inside ENetHost for getting usage +statistics +* added enet_host_channel_limit() for limiting the maximum number of +channels allowed by connected peers +* now uses dispatch queues for event dispatch rather than potentially +unscalable array walking +* added no_memory callback that is called when a malloc attempt fails, +such that if no_memory returns rather than aborts (the default behavior), +then the error is propagated to the return value of the API calls +* now uses packed attribute for protocol structures on platforms with +strange alignment rules +* improved autoconf build system contributed by Nathan Brink allowing +for easier building as a shared library + +Caveats: If you were using the compile-time option that enabled checksums, +make sure to set the checksum callback inside ENetHost to enet_crc32 to +regain the old behavior. The ENetCallbacks structure has added new fields, +so make sure to clear the structure to zero before use if +using enet_initialize_with_callbacks(). + +ENet 1.2.1 (November 12, 2009): + +* fixed bug that could cause disconnect events to be dropped +* added thin wrapper around select() for portable usage +* added ENET_SOCKOPT_REUSEADDR socket option +* factored enet_socket_bind()/enet_socket_listen() out of enet_socket_create() +* added contributed Code::Blocks build file + +ENet 1.2 (February 12, 2008): + +* fixed bug in VERIFY_CONNECT acknowledgement that could cause connect +attempts to occasionally timeout +* fixed acknowledgements to check both the outgoing and sent queues +when removing acknowledged packets +* fixed accidental bit rot in the MSVC project file +* revised sequence number overflow handling to address some possible +disconnect bugs +* added enet_host_check_events() for getting only local queued events +* factored out socket option setting into enet_socket_set_option() so +that socket options are now set separately from enet_socket_create() + +Caveats: While this release is superficially protocol compatible with 1.1, +differences in the sequence number overflow handling can potentially cause +random disconnects. + +ENet 1.1 (June 6, 2007): + +* optional CRC32 just in case someone needs a stronger checksum than UDP +provides (--enable-crc32 configure option) +* the size of packet headers are half the size they used to be (so less +overhead when sending small packets) +* enet_peer_disconnect_later() that waits till all queued outgoing +packets get sent before issuing an actual disconnect +* freeCallback field in individual packets for notification of when a +packet is about to be freed +* ENET_PACKET_FLAG_NO_ALLOCATE for supplying pre-allocated data to a +packet (can be used in concert with freeCallback to support some custom +allocation schemes that the normal memory allocation callbacks would +normally not allow) +* enet_address_get_host_ip() for printing address numbers +* promoted the enet_socket_*() functions to be part of the API now +* a few stability/crash fixes + + diff --git a/Deer/vendor/enet/LICENSE b/Deer/vendor/enet/LICENSE new file mode 100644 index 0000000..ec14b3f --- /dev/null +++ b/Deer/vendor/enet/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2002-2024 Lee Salzman + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Deer/vendor/enet/Makefile.am b/Deer/vendor/enet/Makefile.am new file mode 100644 index 0000000..ddd69cf --- /dev/null +++ b/Deer/vendor/enet/Makefile.am @@ -0,0 +1,22 @@ +pkgconfigdir = $(libdir)/pkgconfig +nodist_pkgconfig_DATA = libenet.pc + +enetincludedir=$(includedir)/enet +enetinclude_HEADERS = \ + include/enet/callbacks.h \ + include/enet/enet.h \ + include/enet/list.h \ + include/enet/protocol.h \ + include/enet/time.h \ + include/enet/types.h \ + include/enet/unix.h \ + include/enet/utility.h \ + include/enet/win32.h + +lib_LTLIBRARIES = libenet.la +libenet_la_SOURCES = callbacks.c compress.c host.c list.c packet.c peer.c protocol.c unix.c win32.c +# see info '(libtool) Updating version info' before making a release +libenet_la_LDFLAGS = $(AM_LDFLAGS) -version-info 7:6:0 +AM_CPPFLAGS = -I$(top_srcdir)/include + +ACLOCAL_AMFLAGS = -Im4 diff --git a/Deer/vendor/enet/README b/Deer/vendor/enet/README new file mode 100644 index 0000000..3b6318b --- /dev/null +++ b/Deer/vendor/enet/README @@ -0,0 +1,15 @@ +Please visit the ENet homepage at http://sauerbraten.org/enet/ for installation +and usage instructions. + +If you obtained this package from github, the quick description on how to build +is: + +# Generate the build system. + +autoreconf -vfi + +# Compile and install the library. + +./configure && make && make install + + diff --git a/Deer/vendor/enet/callbacks.c b/Deer/vendor/enet/callbacks.c new file mode 100644 index 0000000..b3990af --- /dev/null +++ b/Deer/vendor/enet/callbacks.c @@ -0,0 +1,53 @@ +/** + @file callbacks.c + @brief ENet callback functions +*/ +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +static ENetCallbacks callbacks = { malloc, free, abort }; + +int +enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits) +{ + if (version < ENET_VERSION_CREATE (1, 3, 0)) + return -1; + + if (inits -> malloc != NULL || inits -> free != NULL) + { + if (inits -> malloc == NULL || inits -> free == NULL) + return -1; + + callbacks.malloc = inits -> malloc; + callbacks.free = inits -> free; + } + + if (inits -> no_memory != NULL) + callbacks.no_memory = inits -> no_memory; + + return enet_initialize (); +} + +ENetVersion +enet_linked_version (void) +{ + return ENET_VERSION; +} + +void * +enet_malloc (size_t size) +{ + void * memory = callbacks.malloc (size); + + if (memory == NULL) + callbacks.no_memory (); + + return memory; +} + +void +enet_free (void * memory) +{ + callbacks.free (memory); +} + diff --git a/Deer/vendor/enet/compress.c b/Deer/vendor/enet/compress.c new file mode 100644 index 0000000..784489a --- /dev/null +++ b/Deer/vendor/enet/compress.c @@ -0,0 +1,654 @@ +/** + @file compress.c + @brief An adaptive order-2 PPM range coder +*/ +#define ENET_BUILDING_LIB 1 +#include +#include "enet/enet.h" + +typedef struct _ENetSymbol +{ + /* binary indexed tree of symbols */ + enet_uint8 value; + enet_uint8 count; + enet_uint16 under; + enet_uint16 left, right; + + /* context defined by this symbol */ + enet_uint16 symbols; + enet_uint16 escapes; + enet_uint16 total; + enet_uint16 parent; +} ENetSymbol; + +/* adaptation constants tuned aggressively for small packet sizes rather than large file compression */ +enum +{ + ENET_RANGE_CODER_TOP = 1<<24, + ENET_RANGE_CODER_BOTTOM = 1<<16, + + ENET_CONTEXT_SYMBOL_DELTA = 3, + ENET_CONTEXT_SYMBOL_MINIMUM = 1, + ENET_CONTEXT_ESCAPE_MINIMUM = 1, + + ENET_SUBCONTEXT_ORDER = 2, + ENET_SUBCONTEXT_SYMBOL_DELTA = 2, + ENET_SUBCONTEXT_ESCAPE_DELTA = 5 +}; + +/* context exclusion roughly halves compression speed, so disable for now */ +#undef ENET_CONTEXT_EXCLUSION + +typedef struct _ENetRangeCoder +{ + /* only allocate enough symbols for reasonable MTUs, would need to be larger for large file compression */ + ENetSymbol symbols[4096]; +} ENetRangeCoder; + +void * +enet_range_coder_create (void) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) enet_malloc (sizeof (ENetRangeCoder)); + if (rangeCoder == NULL) + return NULL; + + return rangeCoder; +} + +void +enet_range_coder_destroy (void * context) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; + if (rangeCoder == NULL) + return; + + enet_free (rangeCoder); +} + +#define ENET_SYMBOL_CREATE(symbol, value_, count_) \ +{ \ + symbol = & rangeCoder -> symbols [nextSymbol ++]; \ + symbol -> value = value_; \ + symbol -> count = count_; \ + symbol -> under = count_; \ + symbol -> left = 0; \ + symbol -> right = 0; \ + symbol -> symbols = 0; \ + symbol -> escapes = 0; \ + symbol -> total = 0; \ + symbol -> parent = 0; \ +} + +#define ENET_CONTEXT_CREATE(context, escapes_, minimum) \ +{ \ + ENET_SYMBOL_CREATE (context, 0, 0); \ + (context) -> escapes = escapes_; \ + (context) -> total = escapes_ + 256*minimum; \ + (context) -> symbols = 0; \ +} + +static enet_uint16 +enet_symbol_rescale (ENetSymbol * symbol) +{ + enet_uint16 total = 0; + for (;;) + { + symbol -> count -= symbol->count >> 1; + symbol -> under = symbol -> count; + if (symbol -> left) + symbol -> under += enet_symbol_rescale (symbol + symbol -> left); + total += symbol -> under; + if (! symbol -> right) break; + symbol += symbol -> right; + } + return total; +} + +#define ENET_CONTEXT_RESCALE(context, minimum) \ +{ \ + (context) -> total = (context) -> symbols ? enet_symbol_rescale ((context) + (context) -> symbols) : 0; \ + (context) -> escapes -= (context) -> escapes >> 1; \ + (context) -> total += (context) -> escapes + 256*minimum; \ +} + +#define ENET_RANGE_CODER_OUTPUT(value) \ +{ \ + if (outData >= outEnd) \ + return 0; \ + * outData ++ = value; \ +} + +#define ENET_RANGE_CODER_ENCODE(under, count, total) \ +{ \ + encodeRange /= (total); \ + encodeLow += (under) * encodeRange; \ + encodeRange *= (count); \ + for (;;) \ + { \ + if((encodeLow ^ (encodeLow + encodeRange)) >= ENET_RANGE_CODER_TOP) \ + { \ + if(encodeRange >= ENET_RANGE_CODER_BOTTOM) break; \ + encodeRange = -encodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \ + } \ + ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \ + encodeRange <<= 8; \ + encodeLow <<= 8; \ + } \ +} + +#define ENET_RANGE_CODER_FLUSH \ +{ \ + while (encodeLow) \ + { \ + ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \ + encodeLow <<= 8; \ + } \ +} + +#define ENET_RANGE_CODER_FREE_SYMBOLS \ +{ \ + if (nextSymbol >= sizeof (rangeCoder -> symbols) / sizeof (ENetSymbol) - ENET_SUBCONTEXT_ORDER ) \ + { \ + nextSymbol = 0; \ + ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); \ + predicted = 0; \ + order = 0; \ + } \ +} + +#define ENET_CONTEXT_ENCODE(context, symbol_, value_, under_, count_, update, minimum) \ +{ \ + under_ = value*minimum; \ + count_ = minimum; \ + if (! (context) -> symbols) \ + { \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + (context) -> symbols = symbol_ - (context); \ + } \ + else \ + { \ + ENetSymbol * node = (context) + (context) -> symbols; \ + for (;;) \ + { \ + if (value_ < node -> value) \ + { \ + node -> under += update; \ + if (node -> left) { node += node -> left; continue; } \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> left = symbol_ - node; \ + } \ + else \ + if (value_ > node -> value) \ + { \ + under_ += node -> under; \ + if (node -> right) { node += node -> right; continue; } \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> right = symbol_ - node; \ + } \ + else \ + { \ + count_ += node -> count; \ + under_ += node -> under - node -> count; \ + node -> under += update; \ + node -> count += update; \ + symbol_ = node; \ + } \ + break; \ + } \ + } \ +} + +#ifdef ENET_CONTEXT_EXCLUSION +static const ENetSymbol emptyContext = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +#define ENET_CONTEXT_WALK(context, body) \ +{ \ + const ENetSymbol * node = (context) + (context) -> symbols; \ + const ENetSymbol * stack [256]; \ + size_t stackSize = 0; \ + while (node -> left) \ + { \ + stack [stackSize ++] = node; \ + node += node -> left; \ + } \ + for (;;) \ + { \ + body; \ + if (node -> right) \ + { \ + node += node -> right; \ + while (node -> left) \ + { \ + stack [stackSize ++] = node; \ + node += node -> left; \ + } \ + } \ + else \ + if (stackSize <= 0) \ + break; \ + else \ + node = stack [-- stackSize]; \ + } \ +} + +#define ENET_CONTEXT_ENCODE_EXCLUDE(context, value_, under, total, minimum) \ +ENET_CONTEXT_WALK(context, { \ + if (node -> value != value_) \ + { \ + enet_uint16 parentCount = rangeCoder -> symbols [node -> parent].count + minimum; \ + if (node -> value < value_) \ + under -= parentCount; \ + total -= parentCount; \ + } \ +}) +#endif + +size_t +enet_range_coder_compress (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; + enet_uint8 * outStart = outData, * outEnd = & outData [outLimit]; + const enet_uint8 * inData, * inEnd; + enet_uint32 encodeLow = 0, encodeRange = ~0; + ENetSymbol * root; + enet_uint16 predicted = 0; + size_t order = 0, nextSymbol = 0; + + if (rangeCoder == NULL || inBufferCount <= 0 || inLimit <= 0) + return 0; + + inData = (const enet_uint8 *) inBuffers -> data; + inEnd = & inData [inBuffers -> dataLength]; + inBuffers ++; + inBufferCount --; + + ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); + + for (;;) + { + ENetSymbol * subcontext, * symbol; +#ifdef ENET_CONTEXT_EXCLUSION + const ENetSymbol * childContext = & emptyContext; +#endif + enet_uint8 value; + enet_uint16 count, under, * parent = & predicted, total; + if (inData >= inEnd) + { + if (inBufferCount <= 0) + break; + inData = (const enet_uint8 *) inBuffers -> data; + inEnd = & inData [inBuffers -> dataLength]; + inBuffers ++; + inBufferCount --; + } + value = * inData ++; + + for (subcontext = & rangeCoder -> symbols [predicted]; + subcontext != root; +#ifdef ENET_CONTEXT_EXCLUSION + childContext = subcontext, +#endif + subcontext = & rangeCoder -> symbols [subcontext -> parent]) + { + ENET_CONTEXT_ENCODE (subcontext, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0); + * parent = symbol - rangeCoder -> symbols; + parent = & symbol -> parent; + total = subcontext -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA) + ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, 0); +#endif + if (count > 0) + { + ENET_RANGE_CODER_ENCODE (subcontext -> escapes + under, count, total); + } + else + { + if (subcontext -> escapes > 0 && subcontext -> escapes < total) + ENET_RANGE_CODER_ENCODE (0, subcontext -> escapes, total); + subcontext -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA; + subcontext -> total += ENET_SUBCONTEXT_ESCAPE_DELTA; + } + subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (subcontext, 0); + if (count > 0) goto nextInput; + } + + ENET_CONTEXT_ENCODE (root, symbol, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM); + * parent = symbol - rangeCoder -> symbols; + parent = & symbol -> parent; + total = root -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA) + ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, ENET_CONTEXT_SYMBOL_MINIMUM); +#endif + ENET_RANGE_CODER_ENCODE (root -> escapes + under, count, total); + root -> total += ENET_CONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM); + + nextInput: + if (order >= ENET_SUBCONTEXT_ORDER) + predicted = rangeCoder -> symbols [predicted].parent; + else + order ++; + ENET_RANGE_CODER_FREE_SYMBOLS; + } + + ENET_RANGE_CODER_FLUSH; + + return (size_t) (outData - outStart); +} + +#define ENET_RANGE_CODER_SEED \ +{ \ + if (inData < inEnd) decodeCode |= * inData ++ << 24; \ + if (inData < inEnd) decodeCode |= * inData ++ << 16; \ + if (inData < inEnd) decodeCode |= * inData ++ << 8; \ + if (inData < inEnd) decodeCode |= * inData ++; \ +} + +#define ENET_RANGE_CODER_READ(total) ((decodeCode - decodeLow) / (decodeRange /= (total))) + +#define ENET_RANGE_CODER_DECODE(under, count, total) \ +{ \ + decodeLow += (under) * decodeRange; \ + decodeRange *= (count); \ + for (;;) \ + { \ + if((decodeLow ^ (decodeLow + decodeRange)) >= ENET_RANGE_CODER_TOP) \ + { \ + if(decodeRange >= ENET_RANGE_CODER_BOTTOM) break; \ + decodeRange = -decodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \ + } \ + decodeCode <<= 8; \ + if (inData < inEnd) \ + decodeCode |= * inData ++; \ + decodeRange <<= 8; \ + decodeLow <<= 8; \ + } \ +} + +#define ENET_CONTEXT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, createRoot, visitNode, createRight, createLeft) \ +{ \ + under_ = 0; \ + count_ = minimum; \ + if (! (context) -> symbols) \ + { \ + createRoot; \ + } \ + else \ + { \ + ENetSymbol * node = (context) + (context) -> symbols; \ + for (;;) \ + { \ + enet_uint16 after = under_ + node -> under + (node -> value + 1)*minimum, before = node -> count + minimum; \ + visitNode; \ + if (code >= after) \ + { \ + under_ += node -> under; \ + if (node -> right) { node += node -> right; continue; } \ + createRight; \ + } \ + else \ + if (code < after - before) \ + { \ + node -> under += update; \ + if (node -> left) { node += node -> left; continue; } \ + createLeft; \ + } \ + else \ + { \ + value_ = node -> value; \ + count_ += node -> count; \ + under_ = after - before; \ + node -> under += update; \ + node -> count += update; \ + symbol_ = node; \ + } \ + break; \ + } \ + } \ +} + +#define ENET_CONTEXT_TRY_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \ +ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, return 0, exclude (node -> value, after, before), return 0, return 0) + +#define ENET_CONTEXT_ROOT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \ +ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, \ + { \ + value_ = code / minimum; \ + under_ = code - code%minimum; \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + (context) -> symbols = symbol_ - (context); \ + }, \ + exclude (node -> value, after, before), \ + { \ + value_ = node->value + 1 + (code - after)/minimum; \ + under_ = code - (code - after)%minimum; \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> right = symbol_ - node; \ + }, \ + { \ + value_ = node->value - 1 - (after - before - code - 1)/minimum; \ + under_ = code - (after - before - code - 1)%minimum; \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> left = symbol_ - node; \ + }) \ + +#ifdef ENET_CONTEXT_EXCLUSION +typedef struct _ENetExclude +{ + enet_uint8 value; + enet_uint16 under; +} ENetExclude; + +#define ENET_CONTEXT_DECODE_EXCLUDE(context, total, minimum) \ +{ \ + enet_uint16 under = 0; \ + nextExclude = excludes; \ + ENET_CONTEXT_WALK (context, { \ + under += rangeCoder -> symbols [node -> parent].count + minimum; \ + nextExclude -> value = node -> value; \ + nextExclude -> under = under; \ + nextExclude ++; \ + }); \ + total -= under; \ +} + +#define ENET_CONTEXT_EXCLUDED(value_, after, before) \ +{ \ + size_t low = 0, high = nextExclude - excludes; \ + for(;;) \ + { \ + size_t mid = (low + high) >> 1; \ + const ENetExclude * exclude = & excludes [mid]; \ + if (value_ < exclude -> value) \ + { \ + if (low + 1 < high) \ + { \ + high = mid; \ + continue; \ + } \ + if (exclude > excludes) \ + after -= exclude [-1].under; \ + } \ + else \ + { \ + if (value_ > exclude -> value) \ + { \ + if (low + 1 < high) \ + { \ + low = mid; \ + continue; \ + } \ + } \ + else \ + before = 0; \ + after -= exclude -> under; \ + } \ + break; \ + } \ +} +#endif + +#define ENET_CONTEXT_NOT_EXCLUDED(value_, after, before) + +size_t +enet_range_coder_decompress (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; + enet_uint8 * outStart = outData, * outEnd = & outData [outLimit]; + const enet_uint8 * inEnd = & inData [inLimit]; + enet_uint32 decodeLow = 0, decodeCode = 0, decodeRange = ~0; + ENetSymbol * root; + enet_uint16 predicted = 0; + size_t order = 0, nextSymbol = 0; +#ifdef ENET_CONTEXT_EXCLUSION + ENetExclude excludes [256]; + ENetExclude * nextExclude = excludes; +#endif + + if (rangeCoder == NULL || inLimit <= 0) + return 0; + + ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); + + ENET_RANGE_CODER_SEED; + + for (;;) + { + ENetSymbol * subcontext, * symbol, * patch; +#ifdef ENET_CONTEXT_EXCLUSION + const ENetSymbol * childContext = & emptyContext; +#endif + enet_uint8 value = 0; + enet_uint16 code, under, count, bottom, * parent = & predicted, total; + + for (subcontext = & rangeCoder -> symbols [predicted]; + subcontext != root; +#ifdef ENET_CONTEXT_EXCLUSION + childContext = subcontext, +#endif + subcontext = & rangeCoder -> symbols [subcontext -> parent]) + { + if (subcontext -> escapes <= 0) + continue; + total = subcontext -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, 0); +#endif + if (subcontext -> escapes >= total) + continue; + code = ENET_RANGE_CODER_READ (total); + if (code < subcontext -> escapes) + { + ENET_RANGE_CODER_DECODE (0, subcontext -> escapes, total); + continue; + } + code -= subcontext -> escapes; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + { + ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_EXCLUDED); + } + else +#endif + { + ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_NOT_EXCLUDED); + } + bottom = symbol - rangeCoder -> symbols; + ENET_RANGE_CODER_DECODE (subcontext -> escapes + under, count, total); + subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (subcontext, 0); + goto patchContexts; + } + + total = root -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, ENET_CONTEXT_SYMBOL_MINIMUM); +#endif + code = ENET_RANGE_CODER_READ (total); + if (code < root -> escapes) + { + ENET_RANGE_CODER_DECODE (0, root -> escapes, total); + break; + } + code -= root -> escapes; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + { + ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_EXCLUDED); + } + else +#endif + { + ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_NOT_EXCLUDED); + } + bottom = symbol - rangeCoder -> symbols; + ENET_RANGE_CODER_DECODE (root -> escapes + under, count, total); + root -> total += ENET_CONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM); + + patchContexts: + for (patch = & rangeCoder -> symbols [predicted]; + patch != subcontext; + patch = & rangeCoder -> symbols [patch -> parent]) + { + ENET_CONTEXT_ENCODE (patch, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0); + * parent = symbol - rangeCoder -> symbols; + parent = & symbol -> parent; + if (count <= 0) + { + patch -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA; + patch -> total += ENET_SUBCONTEXT_ESCAPE_DELTA; + } + patch -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || patch -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (patch, 0); + } + * parent = bottom; + + ENET_RANGE_CODER_OUTPUT (value); + + if (order >= ENET_SUBCONTEXT_ORDER) + predicted = rangeCoder -> symbols [predicted].parent; + else + order ++; + ENET_RANGE_CODER_FREE_SYMBOLS; + } + + return (size_t) (outData - outStart); +} + +/** @defgroup host ENet host functions + @{ +*/ + +/** Sets the packet compressor the host should use to the default range coder. + @param host host to enable the range coder for + @returns 0 on success, < 0 on failure +*/ +int +enet_host_compress_with_range_coder (ENetHost * host) +{ + ENetCompressor compressor; + memset (& compressor, 0, sizeof (compressor)); + compressor.context = enet_range_coder_create(); + if (compressor.context == NULL) + return -1; + compressor.compress = enet_range_coder_compress; + compressor.decompress = enet_range_coder_decompress; + compressor.destroy = enet_range_coder_destroy; + enet_host_compress (host, & compressor); + return 0; +} + +/** @} */ + + diff --git a/Deer/vendor/enet/configure.ac b/Deer/vendor/enet/configure.ac new file mode 100644 index 0000000..552e7df --- /dev/null +++ b/Deer/vendor/enet/configure.ac @@ -0,0 +1,28 @@ +AC_INIT([libenet], [1.3.18]) +AC_CONFIG_SRCDIR([include/enet/enet.h]) +AM_INIT_AUTOMAKE([foreign]) + +AC_CONFIG_MACRO_DIR([m4]) + +AC_PROG_CC +AC_PROG_LIBTOOL + +AC_CHECK_FUNC(getaddrinfo, [AC_DEFINE(HAS_GETADDRINFO)]) +AC_CHECK_FUNC(getnameinfo, [AC_DEFINE(HAS_GETNAMEINFO)]) +AC_CHECK_FUNC(gethostbyaddr_r, [AC_DEFINE(HAS_GETHOSTBYADDR_R)]) +AC_CHECK_FUNC(gethostbyname_r, [AC_DEFINE(HAS_GETHOSTBYNAME_R)]) +AC_CHECK_FUNC(poll, [AC_DEFINE(HAS_POLL)]) +AC_CHECK_FUNC(fcntl, [AC_DEFINE(HAS_FCNTL)]) +AC_CHECK_FUNC(inet_pton, [AC_DEFINE(HAS_INET_PTON)]) +AC_CHECK_FUNC(inet_ntop, [AC_DEFINE(HAS_INET_NTOP)]) + +AC_CHECK_MEMBER(struct msghdr.msg_flags, [AC_DEFINE(HAS_MSGHDR_FLAGS)], , [#include ]) + +AC_CHECK_TYPE(socklen_t, [AC_DEFINE(HAS_SOCKLEN_T)], , + #include + #include +) + +AC_CONFIG_FILES([Makefile + libenet.pc]) +AC_OUTPUT diff --git a/Deer/vendor/enet/enet.dsp b/Deer/vendor/enet/enet.dsp new file mode 100644 index 0000000..285c020 --- /dev/null +++ b/Deer/vendor/enet/enet.dsp @@ -0,0 +1,168 @@ +# Microsoft Developer Studio Project File - Name="enet" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=enet - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "enet.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "enet.mak" CFG="enet - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "enet - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "enet - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "enet - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /O2 /I "include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "enet - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /G6 /MTd /W3 /ZI /Od /I "include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "enet - Win32 Release" +# Name "enet - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\host.c +# End Source File +# Begin Source File + +SOURCE=.\list.c +# End Source File +# Begin Source File + +SOURCE=.\callbacks.c +# End Source File +# Begin Source File + +SOURCE=.\compress.c +# End Source File +# Begin Source File + +SOURCE=.\packet.c +# End Source File +# Begin Source File + +SOURCE=.\peer.c +# End Source File +# Begin Source File + +SOURCE=.\protocol.c +# End Source File +# Begin Source File + +SOURCE=.\unix.c +# End Source File +# Begin Source File + +SOURCE=.\win32.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\include\enet\enet.h +# End Source File +# Begin Source File + +SOURCE=.\include\enet\list.h +# End Source File +# Begin Source File + +SOURCE=.\include\enet\callbacks.h +# End Source File +# Begin Source File + +SOURCE=.\include\enet\protocol.h +# End Source File +# Begin Source File + +SOURCE=.\include\enet\time.h +# End Source File +# Begin Source File + +SOURCE=.\include\enet\types.h +# End Source File +# Begin Source File + +SOURCE=.\include\enet\unix.h +# End Source File +# Begin Source File + +SOURCE=.\include\enet\utility.h +# End Source File +# Begin Source File + +SOURCE=.\include\enet\win32.h +# End Source File +# End Group +# End Target +# End Project diff --git a/Deer/vendor/enet/host.c b/Deer/vendor/enet/host.c new file mode 100644 index 0000000..fff946a --- /dev/null +++ b/Deer/vendor/enet/host.c @@ -0,0 +1,503 @@ +/** + @file host.c + @brief ENet host management functions +*/ +#define ENET_BUILDING_LIB 1 +#include +#include "enet/enet.h" + +/** @defgroup host ENet host functions + @{ +*/ + +/** Creates a host for communicating to peers. + + @param address the address at which other peers may connect to this host. If NULL, then no peers may connect to the host. + @param peerCount the maximum number of peers that should be allocated for the host. + @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT + @param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. + @param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. + + @returns the host on success and NULL on failure + + @remarks ENet will strategically drop packets on specific sides of a connection between hosts + to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine + the window size of a connection which limits the amount of reliable packets that may be in transit + at any given time. +*/ +ENetHost * +enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) +{ + ENetHost * host; + ENetPeer * currentPeer; + + if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID) + return NULL; + + host = (ENetHost *) enet_malloc (sizeof (ENetHost)); + if (host == NULL) + return NULL; + memset (host, 0, sizeof (ENetHost)); + + host -> peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer)); + if (host -> peers == NULL) + { + enet_free (host); + + return NULL; + } + memset (host -> peers, 0, peerCount * sizeof (ENetPeer)); + + host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM); + if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0)) + { + if (host -> socket != ENET_SOCKET_NULL) + enet_socket_destroy (host -> socket); + + enet_free (host -> peers); + enet_free (host); + + return NULL; + } + + enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1); + enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1); + enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE); + enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE); + + if (address != NULL && enet_socket_get_address (host -> socket, & host -> address) < 0) + host -> address = * address; + + if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) + channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; + else + if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) + channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; + + host -> randomSeed = (enet_uint32) (size_t) host; + host -> randomSeed += enet_host_random_seed (); + host -> randomSeed = (host -> randomSeed << 16) | (host -> randomSeed >> 16); + host -> channelLimit = channelLimit; + host -> incomingBandwidth = incomingBandwidth; + host -> outgoingBandwidth = outgoingBandwidth; + host -> bandwidthThrottleEpoch = 0; + host -> recalculateBandwidthLimits = 0; + host -> mtu = ENET_HOST_DEFAULT_MTU; + host -> peerCount = peerCount; + host -> commandCount = 0; + host -> bufferCount = 0; + host -> checksum = NULL; + host -> receivedAddress.host = ENET_HOST_ANY; + host -> receivedAddress.port = 0; + host -> receivedData = NULL; + host -> receivedDataLength = 0; + + host -> totalSentData = 0; + host -> totalSentPackets = 0; + host -> totalReceivedData = 0; + host -> totalReceivedPackets = 0; + host -> totalQueued = 0; + + host -> connectedPeers = 0; + host -> bandwidthLimitedPeers = 0; + host -> duplicatePeers = ENET_PROTOCOL_MAXIMUM_PEER_ID; + host -> maximumPacketSize = ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE; + host -> maximumWaitingData = ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA; + + host -> compressor.context = NULL; + host -> compressor.compress = NULL; + host -> compressor.decompress = NULL; + host -> compressor.destroy = NULL; + + host -> intercept = NULL; + + enet_list_clear (& host -> dispatchQueue); + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + currentPeer -> host = host; + currentPeer -> incomingPeerID = currentPeer - host -> peers; + currentPeer -> outgoingSessionID = currentPeer -> incomingSessionID = 0xFF; + currentPeer -> data = NULL; + + enet_list_clear (& currentPeer -> acknowledgements); + enet_list_clear (& currentPeer -> sentReliableCommands); + enet_list_clear (& currentPeer -> outgoingCommands); + enet_list_clear (& currentPeer -> outgoingSendReliableCommands); + enet_list_clear (& currentPeer -> dispatchedCommands); + + enet_peer_reset (currentPeer); + } + + return host; +} + +/** Destroys the host and all resources associated with it. + @param host pointer to the host to destroy +*/ +void +enet_host_destroy (ENetHost * host) +{ + ENetPeer * currentPeer; + + if (host == NULL) + return; + + enet_socket_destroy (host -> socket); + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + enet_peer_reset (currentPeer); + } + + if (host -> compressor.context != NULL && host -> compressor.destroy) + (* host -> compressor.destroy) (host -> compressor.context); + + enet_free (host -> peers); + enet_free (host); +} + +enet_uint32 +enet_host_random (ENetHost * host) +{ + /* Mulberry32 by Tommy Ettinger */ + enet_uint32 n = (host -> randomSeed += 0x6D2B79F5U); + n = (n ^ (n >> 15)) * (n | 1U); + n ^= n + (n ^ (n >> 7)) * (n | 61U); + return n ^ (n >> 14); +} + +/** Initiates a connection to a foreign host. + @param host host seeking the connection + @param address destination for the connection + @param channelCount number of channels to allocate + @param data user data supplied to the receiving host + @returns a peer representing the foreign host on success, NULL on failure + @remarks The peer returned will have not completed the connection until enet_host_service() + notifies of an ENET_EVENT_TYPE_CONNECT event for the peer. +*/ +ENetPeer * +enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount, enet_uint32 data) +{ + ENetPeer * currentPeer; + ENetChannel * channel; + ENetProtocol command; + + if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) + channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; + else + if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) + channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED) + break; + } + + if (currentPeer >= & host -> peers [host -> peerCount]) + return NULL; + + currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); + if (currentPeer -> channels == NULL) + return NULL; + currentPeer -> channelCount = channelCount; + currentPeer -> state = ENET_PEER_STATE_CONNECTING; + currentPeer -> address = * address; + currentPeer -> connectID = enet_host_random (host); + currentPeer -> mtu = host -> mtu; + + if (host -> outgoingBandwidth == 0) + currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + currentPeer -> windowSize = (host -> outgoingBandwidth / + ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + for (channel = currentPeer -> channels; + channel < & currentPeer -> channels [channelCount]; + ++ channel) + { + channel -> outgoingReliableSequenceNumber = 0; + channel -> outgoingUnreliableSequenceNumber = 0; + channel -> incomingReliableSequenceNumber = 0; + channel -> incomingUnreliableSequenceNumber = 0; + + enet_list_clear (& channel -> incomingReliableCommands); + enet_list_clear (& channel -> incomingUnreliableCommands); + + channel -> usedReliableWindows = 0; + memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); + } + + command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID); + command.connect.incomingSessionID = currentPeer -> incomingSessionID; + command.connect.outgoingSessionID = currentPeer -> outgoingSessionID; + command.connect.mtu = ENET_HOST_TO_NET_32 (currentPeer -> mtu); + command.connect.windowSize = ENET_HOST_TO_NET_32 (currentPeer -> windowSize); + command.connect.channelCount = ENET_HOST_TO_NET_32 (channelCount); + command.connect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth); + command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); + command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleInterval); + command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration); + command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration); + command.connect.connectID = currentPeer -> connectID; + command.connect.data = ENET_HOST_TO_NET_32 (data); + + enet_peer_queue_outgoing_command (currentPeer, & command, NULL, 0, 0); + + return currentPeer; +} + +/** Queues a packet to be sent to all peers associated with the host. + @param host host on which to broadcast the packet + @param channelID channel on which to broadcast + @param packet packet to broadcast +*/ +void +enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet) +{ + ENetPeer * currentPeer; + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state != ENET_PEER_STATE_CONNECTED) + continue; + + enet_peer_send (currentPeer, channelID, packet); + } + + if (packet -> referenceCount == 0) + enet_packet_destroy (packet); +} + +/** Sets the packet compressor the host should use to compress and decompress packets. + @param host host to enable or disable compression for + @param compressor callbacks for for the packet compressor; if NULL, then compression is disabled +*/ +void +enet_host_compress (ENetHost * host, const ENetCompressor * compressor) +{ + if (host -> compressor.context != NULL && host -> compressor.destroy) + (* host -> compressor.destroy) (host -> compressor.context); + + if (compressor) + host -> compressor = * compressor; + else + host -> compressor.context = NULL; +} + +/** Limits the maximum allowed channels of future incoming connections. + @param host host to limit + @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT +*/ +void +enet_host_channel_limit (ENetHost * host, size_t channelLimit) +{ + if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) + channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; + else + if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) + channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; + + host -> channelLimit = channelLimit; +} + + +/** Adjusts the bandwidth limits of a host. + @param host host to adjust + @param incomingBandwidth new incoming bandwidth + @param outgoingBandwidth new outgoing bandwidth + @remarks the incoming and outgoing bandwidth parameters are identical in function to those + specified in enet_host_create(). +*/ +void +enet_host_bandwidth_limit (ENetHost * host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) +{ + host -> incomingBandwidth = incomingBandwidth; + host -> outgoingBandwidth = outgoingBandwidth; + host -> recalculateBandwidthLimits = 1; +} + +void +enet_host_bandwidth_throttle (ENetHost * host) +{ + enet_uint32 timeCurrent = enet_time_get (), + elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch, + peersRemaining = (enet_uint32) host -> connectedPeers, + dataTotal = ~0, + bandwidth = ~0, + throttle = 0, + bandwidthLimit = 0; + int needsAdjustment = host -> bandwidthLimitedPeers > 0 ? 1 : 0; + ENetPeer * peer; + ENetProtocol command; + + if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) + return; + + host -> bandwidthThrottleEpoch = timeCurrent; + + if (peersRemaining == 0) + return; + + if (host -> outgoingBandwidth != 0) + { + dataTotal = 0; + bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + continue; + + dataTotal += peer -> outgoingDataTotal; + } + } + + while (peersRemaining > 0 && needsAdjustment != 0) + { + needsAdjustment = 0; + + if (dataTotal <= bandwidth) + throttle = ENET_PEER_PACKET_THROTTLE_SCALE; + else + throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + enet_uint32 peerBandwidth; + + if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || + peer -> incomingBandwidth == 0 || + peer -> outgoingBandwidthThrottleEpoch == timeCurrent) + continue; + + peerBandwidth = (peer -> incomingBandwidth * elapsedTime) / 1000; + if ((throttle * peer -> outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth) + continue; + + peer -> packetThrottleLimit = (peerBandwidth * + ENET_PEER_PACKET_THROTTLE_SCALE) / peer -> outgoingDataTotal; + + if (peer -> packetThrottleLimit == 0) + peer -> packetThrottleLimit = 1; + + if (peer -> packetThrottle > peer -> packetThrottleLimit) + peer -> packetThrottle = peer -> packetThrottleLimit; + + peer -> outgoingBandwidthThrottleEpoch = timeCurrent; + + peer -> incomingDataTotal = 0; + peer -> outgoingDataTotal = 0; + + needsAdjustment = 1; + -- peersRemaining; + bandwidth -= peerBandwidth; + dataTotal -= peerBandwidth; + } + } + + if (peersRemaining > 0) + { + if (dataTotal <= bandwidth) + throttle = ENET_PEER_PACKET_THROTTLE_SCALE; + else + throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || + peer -> outgoingBandwidthThrottleEpoch == timeCurrent) + continue; + + peer -> packetThrottleLimit = throttle; + + if (peer -> packetThrottle > peer -> packetThrottleLimit) + peer -> packetThrottle = peer -> packetThrottleLimit; + + peer -> incomingDataTotal = 0; + peer -> outgoingDataTotal = 0; + } + } + + if (host -> recalculateBandwidthLimits) + { + host -> recalculateBandwidthLimits = 0; + + peersRemaining = (enet_uint32) host -> connectedPeers; + bandwidth = host -> incomingBandwidth; + needsAdjustment = 1; + + if (bandwidth == 0) + bandwidthLimit = 0; + else + while (peersRemaining > 0 && needsAdjustment != 0) + { + needsAdjustment = 0; + bandwidthLimit = bandwidth / peersRemaining; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || + peer -> incomingBandwidthThrottleEpoch == timeCurrent) + continue; + + if (peer -> outgoingBandwidth > 0 && + peer -> outgoingBandwidth >= bandwidthLimit) + continue; + + peer -> incomingBandwidthThrottleEpoch = timeCurrent; + + needsAdjustment = 1; + -- peersRemaining; + bandwidth -= peer -> outgoingBandwidth; + } + } + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + continue; + + command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); + + if (peer -> incomingBandwidthThrottleEpoch == timeCurrent) + command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (peer -> outgoingBandwidth); + else + command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (bandwidthLimit); + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); + } + } +} + +/** @} */ diff --git a/Deer/vendor/enet/include/enet/callbacks.h b/Deer/vendor/enet/include/enet/callbacks.h new file mode 100644 index 0000000..340a4a9 --- /dev/null +++ b/Deer/vendor/enet/include/enet/callbacks.h @@ -0,0 +1,27 @@ +/** + @file callbacks.h + @brief ENet callbacks +*/ +#ifndef __ENET_CALLBACKS_H__ +#define __ENET_CALLBACKS_H__ + +#include + +typedef struct _ENetCallbacks +{ + void * (ENET_CALLBACK * malloc) (size_t size); + void (ENET_CALLBACK * free) (void * memory); + void (ENET_CALLBACK * no_memory) (void); +} ENetCallbacks; + +/** @defgroup callbacks ENet internal callbacks + @{ + @ingroup private +*/ +extern void * enet_malloc (size_t); +extern void enet_free (void *); + +/** @} */ + +#endif /* __ENET_CALLBACKS_H__ */ + diff --git a/Deer/vendor/enet/include/enet/enet.h b/Deer/vendor/enet/include/enet/enet.h new file mode 100644 index 0000000..3001018 --- /dev/null +++ b/Deer/vendor/enet/include/enet/enet.h @@ -0,0 +1,616 @@ +/** + @file enet.h + @brief ENet public header file +*/ +#ifndef __ENET_ENET_H__ +#define __ENET_ENET_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#ifdef _WIN32 +#include "enet/win32.h" +#else +#include "enet/unix.h" +#endif + +#include "enet/types.h" +#include "enet/protocol.h" +#include "enet/list.h" +#include "enet/callbacks.h" + +#define ENET_VERSION_MAJOR 1 +#define ENET_VERSION_MINOR 3 +#define ENET_VERSION_PATCH 18 +#define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch)) +#define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF) +#define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF) +#define ENET_VERSION_GET_PATCH(version) ((version)&0xFF) +#define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH) + +typedef enet_uint32 ENetVersion; + +struct _ENetHost; +struct _ENetEvent; +struct _ENetPacket; + +typedef enum _ENetSocketType +{ + ENET_SOCKET_TYPE_STREAM = 1, + ENET_SOCKET_TYPE_DATAGRAM = 2 +} ENetSocketType; + +typedef enum _ENetSocketWait +{ + ENET_SOCKET_WAIT_NONE = 0, + ENET_SOCKET_WAIT_SEND = (1 << 0), + ENET_SOCKET_WAIT_RECEIVE = (1 << 1), + ENET_SOCKET_WAIT_INTERRUPT = (1 << 2) +} ENetSocketWait; + +typedef enum _ENetSocketOption +{ + ENET_SOCKOPT_NONBLOCK = 1, + ENET_SOCKOPT_BROADCAST = 2, + ENET_SOCKOPT_RCVBUF = 3, + ENET_SOCKOPT_SNDBUF = 4, + ENET_SOCKOPT_REUSEADDR = 5, + ENET_SOCKOPT_RCVTIMEO = 6, + ENET_SOCKOPT_SNDTIMEO = 7, + ENET_SOCKOPT_ERROR = 8, + ENET_SOCKOPT_NODELAY = 9, + ENET_SOCKOPT_TTL = 10 +} ENetSocketOption; + +typedef enum _ENetSocketShutdown +{ + ENET_SOCKET_SHUTDOWN_READ = 0, + ENET_SOCKET_SHUTDOWN_WRITE = 1, + ENET_SOCKET_SHUTDOWN_READ_WRITE = 2 +} ENetSocketShutdown; + +#define ENET_HOST_ANY 0 +#define ENET_HOST_BROADCAST 0xFFFFFFFFU +#define ENET_PORT_ANY 0 + +/** + * Portable internet address structure. + * + * The host must be specified in network byte-order, and the port must be in host + * byte-order. The constant ENET_HOST_ANY may be used to specify the default + * server host. The constant ENET_HOST_BROADCAST may be used to specify the + * broadcast address (255.255.255.255). This makes sense for enet_host_connect, + * but not for enet_host_create. Once a server responds to a broadcast, the + * address is updated from ENET_HOST_BROADCAST to the server's actual IP address. + */ +typedef struct _ENetAddress +{ + enet_uint32 host; + enet_uint16 port; +} ENetAddress; + +/** + * Packet flag bit constants. + * + * The host must be specified in network byte-order, and the port must be in + * host byte-order. The constant ENET_HOST_ANY may be used to specify the + * default server host. + + @sa ENetPacket +*/ +typedef enum _ENetPacketFlag +{ + /** packet must be received by the target peer and resend attempts should be + * made until the packet is delivered */ + ENET_PACKET_FLAG_RELIABLE = (1 << 0), + /** packet will not be sequenced with other packets + * not supported for reliable packets + */ + ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1), + /** packet will not allocate data, and user must supply it instead */ + ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2), + /** packet will be fragmented using unreliable (instead of reliable) sends + * if it exceeds the MTU */ + ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3), + + /** whether the packet has been sent from all queues it has been entered into */ + ENET_PACKET_FLAG_SENT = (1<<8) +} ENetPacketFlag; + +typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *); + +/** + * ENet packet structure. + * + * An ENet data packet that may be sent to or received from a peer. The shown + * fields should only be read and never modified. The data field contains the + * allocated data for the packet. The dataLength fields specifies the length + * of the allocated data. The flags field is either 0 (specifying no flags), + * or a bitwise-or of any combination of the following flags: + * + * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer + * and resend attempts should be made until the packet is delivered + * + * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets + * (not supported for reliable packets) + * + * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead + * + * ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT - packet will be fragmented using unreliable + * (instead of reliable) sends if it exceeds the MTU + * + * ENET_PACKET_FLAG_SENT - whether the packet has been sent from all queues it has been entered into + @sa ENetPacketFlag + */ +typedef struct _ENetPacket +{ + size_t referenceCount; /**< internal use only */ + enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */ + enet_uint8 * data; /**< allocated data for packet */ + size_t dataLength; /**< length of data */ + ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */ + void * userData; /**< application private data, may be freely modified */ +} ENetPacket; + +typedef struct _ENetAcknowledgement +{ + ENetListNode acknowledgementList; + enet_uint32 sentTime; + ENetProtocol command; +} ENetAcknowledgement; + +typedef struct _ENetOutgoingCommand +{ + ENetListNode outgoingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + enet_uint32 sentTime; + enet_uint32 roundTripTimeout; + enet_uint32 queueTime; + enet_uint32 fragmentOffset; + enet_uint16 fragmentLength; + enet_uint16 sendAttempts; + ENetProtocol command; + ENetPacket * packet; +} ENetOutgoingCommand; + +typedef struct _ENetIncomingCommand +{ + ENetListNode incomingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + ENetProtocol command; + enet_uint32 fragmentCount; + enet_uint32 fragmentsRemaining; + enet_uint32 * fragments; + ENetPacket * packet; +} ENetIncomingCommand; + +typedef enum _ENetPeerState +{ + ENET_PEER_STATE_DISCONNECTED = 0, + ENET_PEER_STATE_CONNECTING = 1, + ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, + ENET_PEER_STATE_CONNECTION_PENDING = 3, + ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, + ENET_PEER_STATE_CONNECTED = 5, + ENET_PEER_STATE_DISCONNECT_LATER = 6, + ENET_PEER_STATE_DISCONNECTING = 7, + ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, + ENET_PEER_STATE_ZOMBIE = 9 +} ENetPeerState; + +#ifndef ENET_BUFFER_MAXIMUM +#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) +#endif + +enum +{ + ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024, + ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024, + ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000, + ENET_HOST_DEFAULT_MTU = 1392, + ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE = 32 * 1024 * 1024, + ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024, + + ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500, + ENET_PEER_DEFAULT_PACKET_THROTTLE = 32, + ENET_PEER_PACKET_THROTTLE_SCALE = 32, + ENET_PEER_PACKET_THROTTLE_COUNTER = 7, + ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2, + ENET_PEER_PACKET_THROTTLE_DECELERATION = 2, + ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000, + ENET_PEER_PACKET_LOSS_SCALE = (1 << 16), + ENET_PEER_PACKET_LOSS_INTERVAL = 10000, + ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024, + ENET_PEER_TIMEOUT_LIMIT = 32, + ENET_PEER_TIMEOUT_MINIMUM = 5000, + ENET_PEER_TIMEOUT_MAXIMUM = 30000, + ENET_PEER_PING_INTERVAL = 500, + ENET_PEER_UNSEQUENCED_WINDOWS = 64, + ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024, + ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32, + ENET_PEER_RELIABLE_WINDOWS = 16, + ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000, + ENET_PEER_FREE_RELIABLE_WINDOWS = 8 +}; + +typedef struct _ENetChannel +{ + enet_uint16 outgoingReliableSequenceNumber; + enet_uint16 outgoingUnreliableSequenceNumber; + enet_uint16 usedReliableWindows; + enet_uint16 reliableWindows [ENET_PEER_RELIABLE_WINDOWS]; + enet_uint16 incomingReliableSequenceNumber; + enet_uint16 incomingUnreliableSequenceNumber; + ENetList incomingReliableCommands; + ENetList incomingUnreliableCommands; +} ENetChannel; + +typedef enum _ENetPeerFlag +{ + ENET_PEER_FLAG_NEEDS_DISPATCH = (1 << 0), + ENET_PEER_FLAG_CONTINUE_SENDING = (1 << 1) +} ENetPeerFlag; + +/** + * An ENet peer which data packets may be sent or received from. + * + * No fields should be modified unless otherwise specified. + */ +typedef struct _ENetPeer +{ + ENetListNode dispatchList; + struct _ENetHost * host; + enet_uint16 outgoingPeerID; + enet_uint16 incomingPeerID; + enet_uint32 connectID; + enet_uint8 outgoingSessionID; + enet_uint8 incomingSessionID; + ENetAddress address; /**< Internet address of the peer */ + void * data; /**< Application private data, may be freely modified */ + ENetPeerState state; + ENetChannel * channels; + size_t channelCount; /**< Number of channels allocated for communication with peer */ + enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ + enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ + enet_uint32 incomingBandwidthThrottleEpoch; + enet_uint32 outgoingBandwidthThrottleEpoch; + enet_uint32 incomingDataTotal; + enet_uint32 outgoingDataTotal; + enet_uint32 lastSendTime; + enet_uint32 lastReceiveTime; + enet_uint32 nextTimeout; + enet_uint32 earliestTimeout; + enet_uint32 packetLossEpoch; + enet_uint32 packetsSent; + enet_uint32 packetsLost; + enet_uint32 packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ + enet_uint32 packetLossVariance; + enet_uint32 packetThrottle; + enet_uint32 packetThrottleLimit; + enet_uint32 packetThrottleCounter; + enet_uint32 packetThrottleEpoch; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 packetThrottleInterval; + enet_uint32 pingInterval; + enet_uint32 timeoutLimit; + enet_uint32 timeoutMinimum; + enet_uint32 timeoutMaximum; + enet_uint32 lastRoundTripTime; + enet_uint32 lowestRoundTripTime; + enet_uint32 lastRoundTripTimeVariance; + enet_uint32 highestRoundTripTimeVariance; + enet_uint32 roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */ + enet_uint32 roundTripTimeVariance; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 reliableDataInTransit; + enet_uint16 outgoingReliableSequenceNumber; + ENetList acknowledgements; + ENetList sentReliableCommands; + ENetList outgoingSendReliableCommands; + ENetList outgoingCommands; + ENetList dispatchedCommands; + enet_uint16 flags; + enet_uint16 reserved; + enet_uint16 incomingUnsequencedGroup; + enet_uint16 outgoingUnsequencedGroup; + enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; + enet_uint32 eventData; + size_t totalWaitingData; +} ENetPeer; + +/** An ENet packet compressor for compressing UDP packets before socket sends or receives. + */ +typedef struct _ENetCompressor +{ + /** Context data for the compressor. Must be non-NULL. */ + void * context; + /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ + size_t (ENET_CALLBACK * compress) (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit); + /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ + size_t (ENET_CALLBACK * decompress) (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit); + /** Destroys the context when compression is disabled or the host is destroyed. May be NULL. */ + void (ENET_CALLBACK * destroy) (void * context); +} ENetCompressor; + +/** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */ +typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * buffers, size_t bufferCount); + +/** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */ +typedef int (ENET_CALLBACK * ENetInterceptCallback) (struct _ENetHost * host, struct _ENetEvent * event); + +/** An ENet host for communicating with peers. + * + * No fields should be modified unless otherwise stated. + + @sa enet_host_create() + @sa enet_host_destroy() + @sa enet_host_connect() + @sa enet_host_service() + @sa enet_host_flush() + @sa enet_host_broadcast() + @sa enet_host_compress() + @sa enet_host_compress_with_range_coder() + @sa enet_host_channel_limit() + @sa enet_host_bandwidth_limit() + @sa enet_host_bandwidth_throttle() + */ +typedef struct _ENetHost +{ + ENetSocket socket; + ENetAddress address; /**< Internet address of the host */ + enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ + enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ + enet_uint32 bandwidthThrottleEpoch; + enet_uint32 mtu; + enet_uint32 randomSeed; + int recalculateBandwidthLimits; + ENetPeer * peers; /**< array of peers allocated for this host */ + size_t peerCount; /**< number of peers allocated for this host */ + size_t channelLimit; /**< maximum number of channels allowed for connected peers */ + enet_uint32 serviceTime; + ENetList dispatchQueue; + enet_uint32 totalQueued; + size_t packetSize; + enet_uint16 headerFlags; + ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; + size_t commandCount; + ENetBuffer buffers [ENET_BUFFER_MAXIMUM]; + size_t bufferCount; + ENetChecksumCallback checksum; /**< callback the user can set to enable packet checksums for this host */ + ENetCompressor compressor; + enet_uint8 packetData [2][ENET_PROTOCOL_MAXIMUM_MTU]; + ENetAddress receivedAddress; + enet_uint8 * receivedData; + size_t receivedDataLength; + enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */ + ENetInterceptCallback intercept; /**< callback the user can set to intercept received raw UDP packets */ + size_t connectedPeers; + size_t bandwidthLimitedPeers; + size_t duplicatePeers; /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */ + size_t maximumPacketSize; /**< the maximum allowable packet size that may be sent or received on a peer */ + size_t maximumWaitingData; /**< the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */ +} ENetHost; + +/** + * An ENet event type, as specified in @ref ENetEvent. + */ +typedef enum _ENetEventType +{ + /** no event occurred within the specified time limit */ + ENET_EVENT_TYPE_NONE = 0, + + /** a connection request initiated by enet_host_connect has completed. + * The peer field contains the peer which successfully connected. + */ + ENET_EVENT_TYPE_CONNECT = 1, + + /** a peer has disconnected. This event is generated on a successful + * completion of a disconnect initiated by enet_peer_disconnect, if + * a peer has timed out, or if a connection request intialized by + * enet_host_connect has timed out. The peer field contains the peer + * which disconnected. The data field contains user supplied data + * describing the disconnection, or 0, if none is available. + */ + ENET_EVENT_TYPE_DISCONNECT = 2, + + /** a packet has been received from a peer. The peer field specifies the + * peer which sent the packet. The channelID field specifies the channel + * number upon which the packet was received. The packet field contains + * the packet that was received; this packet must be destroyed with + * enet_packet_destroy after use. + */ + ENET_EVENT_TYPE_RECEIVE = 3 +} ENetEventType; + +/** + * An ENet event as returned by enet_host_service(). + + @sa enet_host_service + */ +typedef struct _ENetEvent +{ + ENetEventType type; /**< type of the event */ + ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */ + enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */ + enet_uint32 data; /**< data associated with the event, if appropriate */ + ENetPacket * packet; /**< packet associated with the event, if appropriate */ +} ENetEvent; + +/** @defgroup global ENet global functions + @{ +*/ + +/** + Initializes ENet globally. Must be called prior to using any functions in + ENet. + @returns 0 on success, < 0 on failure +*/ +ENET_API int enet_initialize (void); + +/** + Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. Make sure the ENetCallbacks structure is zeroed out so that any additional callbacks added in future versions will be properly ignored. + + @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use + @param inits user-overridden callbacks where any NULL callbacks will use ENet's defaults + @returns 0 on success, < 0 on failure +*/ +ENET_API int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits); + +/** + Shuts down ENet globally. Should be called when a program that has + initialized ENet exits. +*/ +ENET_API void enet_deinitialize (void); + +/** + Gives the linked version of the ENet library. + @returns the version number +*/ +ENET_API ENetVersion enet_linked_version (void); + +/** @} */ + +/** @defgroup private ENet private implementation functions */ + +/** + Returns the wall-time in milliseconds. Its initial value is unspecified + unless otherwise set. + */ +ENET_API enet_uint32 enet_time_get (void); +/** + Sets the current wall-time in milliseconds. + */ +ENET_API void enet_time_set (enet_uint32); + +/** @defgroup socket ENet socket functions + @{ +*/ +ENET_API ENetSocket enet_socket_create (ENetSocketType); +ENET_API int enet_socket_bind (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_get_address (ENetSocket, ENetAddress *); +ENET_API int enet_socket_listen (ENetSocket, int); +ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *); +ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); +ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t); +ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32); +ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int); +ENET_API int enet_socket_get_option (ENetSocket, ENetSocketOption, int *); +ENET_API int enet_socket_shutdown (ENetSocket, ENetSocketShutdown); +ENET_API void enet_socket_destroy (ENetSocket); +ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); + +/** @} */ + +/** @defgroup Address ENet address functions + @{ +*/ + +/** Attempts to parse the printable form of the IP address in the parameter hostName + and sets the host field in the address parameter if successful. + @param address destination to store the parsed IP address + @param hostName IP address to parse + @retval 0 on success + @retval < 0 on failure + @returns the address of the given hostName in address on success +*/ +ENET_API int enet_address_set_host_ip (ENetAddress * address, const char * hostName); + +/** Attempts to resolve the host named by the parameter hostName and sets + the host field in the address parameter if successful. + @param address destination to store resolved address + @param hostName host name to lookup + @retval 0 on success + @retval < 0 on failure + @returns the address of the given hostName in address on success +*/ +ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName); + +/** Gives the printable form of the IP address specified in the address parameter. + @param address address printed + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength); + +/** Attempts to do a reverse lookup of the host field in the address parameter. + @param address address used for reverse lookup + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength); + +/** @} */ + +ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32); +ENET_API void enet_packet_destroy (ENetPacket *); +ENET_API int enet_packet_resize (ENetPacket *, size_t); +ENET_API enet_uint32 enet_crc32 (const ENetBuffer *, size_t); + +ENET_API ENetHost * enet_host_create (const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32); +ENET_API void enet_host_destroy (ENetHost *); +ENET_API ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t, enet_uint32); +ENET_API int enet_host_check_events (ENetHost *, ENetEvent *); +ENET_API int enet_host_service (ENetHost *, ENetEvent *, enet_uint32); +ENET_API void enet_host_flush (ENetHost *); +ENET_API void enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *); +ENET_API void enet_host_compress (ENetHost *, const ENetCompressor *); +ENET_API int enet_host_compress_with_range_coder (ENetHost * host); +ENET_API void enet_host_channel_limit (ENetHost *, size_t); +ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32); +extern void enet_host_bandwidth_throttle (ENetHost *); +extern enet_uint32 enet_host_random_seed (void); +extern enet_uint32 enet_host_random (ENetHost *); + +ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *); +ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID); +ENET_API void enet_peer_ping (ENetPeer *); +ENET_API void enet_peer_ping_interval (ENetPeer *, enet_uint32); +ENET_API void enet_peer_timeout (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); +ENET_API void enet_peer_reset (ENetPeer *); +ENET_API void enet_peer_disconnect (ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_now (ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32); +ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); +extern int enet_peer_throttle (ENetPeer *, enet_uint32); +extern void enet_peer_reset_queues (ENetPeer *); +extern int enet_peer_has_outgoing_commands (ENetPeer *); +extern void enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *); +extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16); +extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32); +extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16); +extern void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *, ENetIncomingCommand *); +extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *, ENetIncomingCommand *); +extern void enet_peer_on_connect (ENetPeer *); +extern void enet_peer_on_disconnect (ENetPeer *); + +ENET_API void * enet_range_coder_create (void); +ENET_API void enet_range_coder_destroy (void *); +ENET_API size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t); +ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t); + +extern size_t enet_protocol_command_size (enet_uint8); + +#ifdef __cplusplus +} +#endif + +#endif /* __ENET_ENET_H__ */ + diff --git a/Deer/vendor/enet/include/enet/list.h b/Deer/vendor/enet/include/enet/list.h new file mode 100644 index 0000000..d7b2600 --- /dev/null +++ b/Deer/vendor/enet/include/enet/list.h @@ -0,0 +1,43 @@ +/** + @file list.h + @brief ENet list management +*/ +#ifndef __ENET_LIST_H__ +#define __ENET_LIST_H__ + +#include + +typedef struct _ENetListNode +{ + struct _ENetListNode * next; + struct _ENetListNode * previous; +} ENetListNode; + +typedef ENetListNode * ENetListIterator; + +typedef struct _ENetList +{ + ENetListNode sentinel; +} ENetList; + +extern void enet_list_clear (ENetList *); + +extern ENetListIterator enet_list_insert (ENetListIterator, void *); +extern void * enet_list_remove (ENetListIterator); +extern ENetListIterator enet_list_move (ENetListIterator, void *, void *); + +extern size_t enet_list_size (ENetList *); + +#define enet_list_begin(list) ((list) -> sentinel.next) +#define enet_list_end(list) (& (list) -> sentinel) + +#define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list)) + +#define enet_list_next(iterator) ((iterator) -> next) +#define enet_list_previous(iterator) ((iterator) -> previous) + +#define enet_list_front(list) ((void *) (list) -> sentinel.next) +#define enet_list_back(list) ((void *) (list) -> sentinel.previous) + +#endif /* __ENET_LIST_H__ */ + diff --git a/Deer/vendor/enet/include/enet/protocol.h b/Deer/vendor/enet/include/enet/protocol.h new file mode 100644 index 0000000..f8c73d8 --- /dev/null +++ b/Deer/vendor/enet/include/enet/protocol.h @@ -0,0 +1,198 @@ +/** + @file protocol.h + @brief ENet protocol +*/ +#ifndef __ENET_PROTOCOL_H__ +#define __ENET_PROTOCOL_H__ + +#include "enet/types.h" + +enum +{ + ENET_PROTOCOL_MINIMUM_MTU = 576, + ENET_PROTOCOL_MAXIMUM_MTU = 4096, + ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32, + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096, + ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536, + ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1, + ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255, + ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF, + ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024 +}; + +typedef enum _ENetProtocolCommand +{ + ENET_PROTOCOL_COMMAND_NONE = 0, + ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, + ENET_PROTOCOL_COMMAND_CONNECT = 2, + ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, + ENET_PROTOCOL_COMMAND_DISCONNECT = 4, + ENET_PROTOCOL_COMMAND_PING = 5, + ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, + ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, + ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, + ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, + ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, + ENET_PROTOCOL_COMMAND_COUNT = 13, + + ENET_PROTOCOL_COMMAND_MASK = 0x0F +} ENetProtocolCommand; + +typedef enum _ENetProtocolFlag +{ + ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), + ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), + + ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14), + ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), + ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, + + ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), + ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 +} ENetProtocolFlag; + +#ifdef _MSC_VER +#pragma pack(push, 1) +#define ENET_PACKED +#elif defined(__GNUC__) || defined(__clang__) +#define ENET_PACKED __attribute__ ((packed)) +#else +#define ENET_PACKED +#endif + +typedef struct _ENetProtocolHeader +{ + enet_uint16 peerID; + enet_uint16 sentTime; +} ENET_PACKED ENetProtocolHeader; + +typedef struct _ENetProtocolCommandHeader +{ + enet_uint8 command; + enet_uint8 channelID; + enet_uint16 reliableSequenceNumber; +} ENET_PACKED ENetProtocolCommandHeader; + +typedef struct _ENetProtocolAcknowledge +{ + ENetProtocolCommandHeader header; + enet_uint16 receivedReliableSequenceNumber; + enet_uint16 receivedSentTime; +} ENET_PACKED ENetProtocolAcknowledge; + +typedef struct _ENetProtocolConnect +{ + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 connectID; + enet_uint32 data; +} ENET_PACKED ENetProtocolConnect; + +typedef struct _ENetProtocolVerifyConnect +{ + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 connectID; +} ENET_PACKED ENetProtocolVerifyConnect; + +typedef struct _ENetProtocolBandwidthLimit +{ + ENetProtocolCommandHeader header; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; +} ENET_PACKED ENetProtocolBandwidthLimit; + +typedef struct _ENetProtocolThrottleConfigure +{ + ENetProtocolCommandHeader header; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; +} ENET_PACKED ENetProtocolThrottleConfigure; + +typedef struct _ENetProtocolDisconnect +{ + ENetProtocolCommandHeader header; + enet_uint32 data; +} ENET_PACKED ENetProtocolDisconnect; + +typedef struct _ENetProtocolPing +{ + ENetProtocolCommandHeader header; +} ENET_PACKED ENetProtocolPing; + +typedef struct _ENetProtocolSendReliable +{ + ENetProtocolCommandHeader header; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendReliable; + +typedef struct _ENetProtocolSendUnreliable +{ + ENetProtocolCommandHeader header; + enet_uint16 unreliableSequenceNumber; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnreliable; + +typedef struct _ENetProtocolSendUnsequenced +{ + ENetProtocolCommandHeader header; + enet_uint16 unsequencedGroup; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnsequenced; + +typedef struct _ENetProtocolSendFragment +{ + ENetProtocolCommandHeader header; + enet_uint16 startSequenceNumber; + enet_uint16 dataLength; + enet_uint32 fragmentCount; + enet_uint32 fragmentNumber; + enet_uint32 totalLength; + enet_uint32 fragmentOffset; +} ENET_PACKED ENetProtocolSendFragment; + +typedef union _ENetProtocol +{ + ENetProtocolCommandHeader header; + ENetProtocolAcknowledge acknowledge; + ENetProtocolConnect connect; + ENetProtocolVerifyConnect verifyConnect; + ENetProtocolDisconnect disconnect; + ENetProtocolPing ping; + ENetProtocolSendReliable sendReliable; + ENetProtocolSendUnreliable sendUnreliable; + ENetProtocolSendUnsequenced sendUnsequenced; + ENetProtocolSendFragment sendFragment; + ENetProtocolBandwidthLimit bandwidthLimit; + ENetProtocolThrottleConfigure throttleConfigure; +} ENET_PACKED ENetProtocol; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +#endif /* __ENET_PROTOCOL_H__ */ + diff --git a/Deer/vendor/enet/include/enet/time.h b/Deer/vendor/enet/include/enet/time.h new file mode 100644 index 0000000..c82a546 --- /dev/null +++ b/Deer/vendor/enet/include/enet/time.h @@ -0,0 +1,18 @@ +/** + @file time.h + @brief ENet time constants and macros +*/ +#ifndef __ENET_TIME_H__ +#define __ENET_TIME_H__ + +#define ENET_TIME_OVERFLOW 86400000 + +#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) +#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) + +#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) + +#endif /* __ENET_TIME_H__ */ + diff --git a/Deer/vendor/enet/include/enet/types.h b/Deer/vendor/enet/include/enet/types.h new file mode 100644 index 0000000..ab010a4 --- /dev/null +++ b/Deer/vendor/enet/include/enet/types.h @@ -0,0 +1,13 @@ +/** + @file types.h + @brief type definitions for ENet +*/ +#ifndef __ENET_TYPES_H__ +#define __ENET_TYPES_H__ + +typedef unsigned char enet_uint8; /**< unsigned 8-bit type */ +typedef unsigned short enet_uint16; /**< unsigned 16-bit type */ +typedef unsigned int enet_uint32; /**< unsigned 32-bit type */ + +#endif /* __ENET_TYPES_H__ */ + diff --git a/Deer/vendor/enet/include/enet/unix.h b/Deer/vendor/enet/include/enet/unix.h new file mode 100644 index 0000000..b55be33 --- /dev/null +++ b/Deer/vendor/enet/include/enet/unix.h @@ -0,0 +1,48 @@ +/** + @file unix.h + @brief ENet Unix header +*/ +#ifndef __ENET_UNIX_H__ +#define __ENET_UNIX_H__ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef MSG_MAXIOVLEN +#define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN +#endif + +typedef int ENetSocket; + +#define ENET_SOCKET_NULL -1 + +#define ENET_HOST_TO_NET_16(value) (htons (value)) /**< macro that converts host to net byte-order of a 16-bit value */ +#define ENET_HOST_TO_NET_32(value) (htonl (value)) /**< macro that converts host to net byte-order of a 32-bit value */ + +#define ENET_NET_TO_HOST_16(value) (ntohs (value)) /**< macro that converts net to host byte-order of a 16-bit value */ +#define ENET_NET_TO_HOST_32(value) (ntohl (value)) /**< macro that converts net to host byte-order of a 32-bit value */ + +typedef struct +{ + void * data; + size_t dataLength; +} ENetBuffer; + +#define ENET_CALLBACK + +#define ENET_API extern + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_UNIX_H__ */ + diff --git a/Deer/vendor/enet/include/enet/utility.h b/Deer/vendor/enet/include/enet/utility.h new file mode 100644 index 0000000..b04bb7a --- /dev/null +++ b/Deer/vendor/enet/include/enet/utility.h @@ -0,0 +1,13 @@ +/** + @file utility.h + @brief ENet utility header +*/ +#ifndef __ENET_UTILITY_H__ +#define __ENET_UTILITY_H__ + +#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) +#define ENET_DIFFERENCE(x, y) ((x) < (y) ? (y) - (x) : (x) - (y)) + +#endif /* __ENET_UTILITY_H__ */ + diff --git a/Deer/vendor/enet/include/enet/win32.h b/Deer/vendor/enet/include/enet/win32.h new file mode 100644 index 0000000..6fbd7c0 --- /dev/null +++ b/Deer/vendor/enet/include/enet/win32.h @@ -0,0 +1,59 @@ +/** + @file win32.h + @brief ENet Win32 header +*/ +#ifndef __ENET_WIN32_H__ +#define __ENET_WIN32_H__ + +#ifdef _MSC_VER +#ifdef ENET_BUILDING_LIB +#pragma warning (disable: 4267) // size_t to int conversion +#pragma warning (disable: 4244) // 64bit to 32bit int +#pragma warning (disable: 4018) // signed/unsigned mismatch +#pragma warning (disable: 4146) // unary minus operator applied to unsigned type +#define _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_WARNINGS +#endif +#endif + +#include +#include + +typedef SOCKET ENetSocket; + +#define ENET_SOCKET_NULL INVALID_SOCKET + +#define ENET_HOST_TO_NET_16(value) (htons (value)) +#define ENET_HOST_TO_NET_32(value) (htonl (value)) + +#define ENET_NET_TO_HOST_16(value) (ntohs (value)) +#define ENET_NET_TO_HOST_32(value) (ntohl (value)) + +typedef struct +{ + size_t dataLength; + void * data; +} ENetBuffer; + +#define ENET_CALLBACK __cdecl + +#ifdef ENET_DLL +#ifdef ENET_BUILDING_LIB +#define ENET_API __declspec( dllexport ) +#else +#define ENET_API __declspec( dllimport ) +#endif /* ENET_BUILDING_LIB */ +#else /* !ENET_DLL */ +#define ENET_API extern +#endif /* ENET_DLL */ + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_WIN32_H__ */ + + diff --git a/Deer/vendor/enet/libenet.pc.in b/Deer/vendor/enet/libenet.pc.in new file mode 100644 index 0000000..7af85ad --- /dev/null +++ b/Deer/vendor/enet/libenet.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: @PACKAGE_NAME@ +Description: Low-latency UDP networking library supporting optional reliability +Version: @PACKAGE_VERSION@ +Cflags: -I${includedir} +Libs: -L${libdir} -lenet diff --git a/Deer/vendor/enet/list.c b/Deer/vendor/enet/list.c new file mode 100644 index 0000000..1c1a8df --- /dev/null +++ b/Deer/vendor/enet/list.c @@ -0,0 +1,75 @@ +/** + @file list.c + @brief ENet linked list functions +*/ +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +/** + @defgroup list ENet linked list utility functions + @ingroup private + @{ +*/ +void +enet_list_clear (ENetList * list) +{ + list -> sentinel.next = & list -> sentinel; + list -> sentinel.previous = & list -> sentinel; +} + +ENetListIterator +enet_list_insert (ENetListIterator position, void * data) +{ + ENetListIterator result = (ENetListIterator) data; + + result -> previous = position -> previous; + result -> next = position; + + result -> previous -> next = result; + position -> previous = result; + + return result; +} + +void * +enet_list_remove (ENetListIterator position) +{ + position -> previous -> next = position -> next; + position -> next -> previous = position -> previous; + + return position; +} + +ENetListIterator +enet_list_move (ENetListIterator position, void * dataFirst, void * dataLast) +{ + ENetListIterator first = (ENetListIterator) dataFirst, + last = (ENetListIterator) dataLast; + + first -> previous -> next = last -> next; + last -> next -> previous = first -> previous; + + first -> previous = position -> previous; + last -> next = position; + + first -> previous -> next = first; + position -> previous = last; + + return first; +} + +size_t +enet_list_size (ENetList * list) +{ + size_t size = 0; + ENetListIterator position; + + for (position = enet_list_begin (list); + position != enet_list_end (list); + position = enet_list_next (position)) + ++ size; + + return size; +} + +/** @} */ diff --git a/Deer/vendor/enet/packet.c b/Deer/vendor/enet/packet.c new file mode 100644 index 0000000..d51c640 --- /dev/null +++ b/Deer/vendor/enet/packet.c @@ -0,0 +1,158 @@ +/** + @file packet.c + @brief ENet packet management functions +*/ +#include +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +/** @defgroup Packet ENet packet functions + @{ +*/ + +/** Creates a packet that may be sent to a peer. + @param data initial contents of the packet's data; the packet's data will remain uninitialized if data is NULL. + @param dataLength size of the data allocated for this packet + @param flags flags for this packet as described for the ENetPacket structure. + @returns the packet on success, NULL on failure +*/ +ENetPacket * +enet_packet_create (const void * data, size_t dataLength, enet_uint32 flags) +{ + ENetPacket * packet = (ENetPacket *) enet_malloc (sizeof (ENetPacket)); + if (packet == NULL) + return NULL; + + if (flags & ENET_PACKET_FLAG_NO_ALLOCATE) + packet -> data = (enet_uint8 *) data; + else + if (dataLength <= 0) + packet -> data = NULL; + else + { + packet -> data = (enet_uint8 *) enet_malloc (dataLength); + if (packet -> data == NULL) + { + enet_free (packet); + return NULL; + } + + if (data != NULL) + memcpy (packet -> data, data, dataLength); + } + + packet -> referenceCount = 0; + packet -> flags = flags; + packet -> dataLength = dataLength; + packet -> freeCallback = NULL; + packet -> userData = NULL; + + return packet; +} + +/** Destroys the packet and deallocates its data. + @param packet packet to be destroyed +*/ +void +enet_packet_destroy (ENetPacket * packet) +{ + if (packet == NULL) + return; + + if (packet -> freeCallback != NULL) + (* packet -> freeCallback) (packet); + if (! (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE) && + packet -> data != NULL) + enet_free (packet -> data); + enet_free (packet); +} + +/** Attempts to resize the data in the packet to length specified in the + dataLength parameter + @param packet packet to resize + @param dataLength new size for the packet data + @returns 0 on success, < 0 on failure +*/ +int +enet_packet_resize (ENetPacket * packet, size_t dataLength) +{ + enet_uint8 * newData; + + if (dataLength <= packet -> dataLength || (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE)) + { + packet -> dataLength = dataLength; + + return 0; + } + + newData = (enet_uint8 *) enet_malloc (dataLength); + if (newData == NULL) + return -1; + + memcpy (newData, packet -> data, packet -> dataLength); + enet_free (packet -> data); + + packet -> data = newData; + packet -> dataLength = dataLength; + + return 0; +} + +static const enet_uint32 crcTable [256] = +{ + 0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x5005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0xBDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +enet_uint32 +enet_crc32 (const ENetBuffer * buffers, size_t bufferCount) +{ + enet_uint32 crc = 0xFFFFFFFF; + + while (bufferCount -- > 0) + { + const enet_uint8 * data = (const enet_uint8 *) buffers -> data, + * dataEnd = & data [buffers -> dataLength]; + + while (data < dataEnd) + { + crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++]; + } + + ++ buffers; + } + + return ENET_HOST_TO_NET_32 (~ crc); +} + +/** @} */ diff --git a/Deer/vendor/enet/peer.c b/Deer/vendor/enet/peer.c new file mode 100644 index 0000000..a7ac012 --- /dev/null +++ b/Deer/vendor/enet/peer.c @@ -0,0 +1,1027 @@ +/** + @file peer.c + @brief ENet peer management functions +*/ +#include +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +/** @defgroup peer ENet peer functions + @{ +*/ + +/** Configures throttle parameter for a peer. + + Unreliable packets are dropped by ENet in response to the varying conditions + of the Internet connection to the peer. The throttle represents a probability + that an unreliable packet should not be dropped and thus sent by ENet to the peer. + The lowest mean round trip time from the sending of a reliable packet to the + receipt of its acknowledgement is measured over an amount of time specified by + the interval parameter in milliseconds. If a measured round trip time happens to + be significantly less than the mean round trip time measured over the interval, + then the throttle probability is increased to allow more traffic by an amount + specified in the acceleration parameter, which is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE + constant. If a measured round trip time happens to be significantly greater than + the mean round trip time measured over the interval, then the throttle probability + is decreased to limit traffic by an amount specified in the deceleration parameter, which + is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE constant. When the throttle has + a value of ENET_PEER_PACKET_THROTTLE_SCALE, no unreliable packets are dropped by + ENet, and so 100% of all unreliable packets will be sent. When the throttle has a + value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable + packets will be sent. Intermediate values for the throttle represent intermediate + probabilities between 0% and 100% of unreliable packets being sent. The bandwidth + limits of the local and foreign hosts are taken into account to determine a + sensible limit for the throttle probability above which it should not raise even in + the best of conditions. + + @param peer peer to configure + @param interval interval, in milliseconds, over which to measure lowest mean RTT; the default value is ENET_PEER_PACKET_THROTTLE_INTERVAL. + @param acceleration rate at which to increase the throttle probability as mean RTT declines + @param deceleration rate at which to decrease the throttle probability as mean RTT increases +*/ +void +enet_peer_throttle_configure (ENetPeer * peer, enet_uint32 interval, enet_uint32 acceleration, enet_uint32 deceleration) +{ + ENetProtocol command; + + peer -> packetThrottleInterval = interval; + peer -> packetThrottleAcceleration = acceleration; + peer -> packetThrottleDeceleration = deceleration; + + command.header.command = ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + + command.throttleConfigure.packetThrottleInterval = ENET_HOST_TO_NET_32 (interval); + command.throttleConfigure.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (acceleration); + command.throttleConfigure.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (deceleration); + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); +} + +int +enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt) +{ + if (peer -> lastRoundTripTime <= peer -> lastRoundTripTimeVariance) + { + peer -> packetThrottle = peer -> packetThrottleLimit; + } + else + if (rtt <= peer -> lastRoundTripTime) + { + peer -> packetThrottle += peer -> packetThrottleAcceleration; + + if (peer -> packetThrottle > peer -> packetThrottleLimit) + peer -> packetThrottle = peer -> packetThrottleLimit; + + return 1; + } + else + if (rtt > peer -> lastRoundTripTime + 2 * peer -> lastRoundTripTimeVariance) + { + if (peer -> packetThrottle > peer -> packetThrottleDeceleration) + peer -> packetThrottle -= peer -> packetThrottleDeceleration; + else + peer -> packetThrottle = 0; + + return -1; + } + + return 0; +} + +/** Queues a packet to be sent. + + On success, ENet will assume ownership of the packet, and so enet_packet_destroy + should not be called on it thereafter. On failure, the caller still must destroy + the packet on its own as ENet has not queued the packet. The caller can also + check the packet's referenceCount field after sending to check if ENet queued + the packet and thus incremented the referenceCount. + + @param peer destination for the packet + @param channelID channel on which to send + @param packet packet to send + @retval 0 on success + @retval < 0 on failure +*/ +int +enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet) +{ + ENetChannel * channel; + ENetProtocol command; + size_t fragmentLength; + + if (peer -> state != ENET_PEER_STATE_CONNECTED || + channelID >= peer -> channelCount || + packet -> dataLength > peer -> host -> maximumPacketSize) + return -1; + + channel = & peer -> channels [channelID]; + fragmentLength = peer -> mtu - sizeof (ENetProtocolHeader) - sizeof (ENetProtocolSendFragment); + if (peer -> host -> checksum != NULL) + fragmentLength -= sizeof(enet_uint32); + + if (packet -> dataLength > fragmentLength) + { + enet_uint32 fragmentCount = (packet -> dataLength + fragmentLength - 1) / fragmentLength, + fragmentNumber, + fragmentOffset; + enet_uint8 commandNumber; + enet_uint16 startSequenceNumber; + ENetList fragments; + ENetOutgoingCommand * fragment; + + if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT) + return -1; + + if ((packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT)) == ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT && + channel -> outgoingUnreliableSequenceNumber < 0xFFFF) + { + commandNumber = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT; + startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingUnreliableSequenceNumber + 1); + } + else + { + commandNumber = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingReliableSequenceNumber + 1); + } + + enet_list_clear (& fragments); + + for (fragmentNumber = 0, + fragmentOffset = 0; + fragmentOffset < packet -> dataLength; + ++ fragmentNumber, + fragmentOffset += fragmentLength) + { + if (packet -> dataLength - fragmentOffset < fragmentLength) + fragmentLength = packet -> dataLength - fragmentOffset; + + fragment = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand)); + if (fragment == NULL) + { + while (! enet_list_empty (& fragments)) + { + fragment = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& fragments)); + + enet_free (fragment); + } + + return -1; + } + + fragment -> fragmentOffset = fragmentOffset; + fragment -> fragmentLength = fragmentLength; + fragment -> packet = packet; + fragment -> command.header.command = commandNumber; + fragment -> command.header.channelID = channelID; + fragment -> command.sendFragment.startSequenceNumber = startSequenceNumber; + fragment -> command.sendFragment.dataLength = ENET_HOST_TO_NET_16 (fragmentLength); + fragment -> command.sendFragment.fragmentCount = ENET_HOST_TO_NET_32 (fragmentCount); + fragment -> command.sendFragment.fragmentNumber = ENET_HOST_TO_NET_32 (fragmentNumber); + fragment -> command.sendFragment.totalLength = ENET_HOST_TO_NET_32 (packet -> dataLength); + fragment -> command.sendFragment.fragmentOffset = ENET_NET_TO_HOST_32 (fragmentOffset); + + enet_list_insert (enet_list_end (& fragments), fragment); + } + + packet -> referenceCount += fragmentNumber; + + while (! enet_list_empty (& fragments)) + { + fragment = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& fragments)); + + enet_peer_setup_outgoing_command (peer, fragment); + } + + return 0; + } + + command.header.channelID = channelID; + + if ((packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNSEQUENCED)) == ENET_PACKET_FLAG_UNSEQUENCED) + { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; + command.sendUnsequenced.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); + } + else + if (packet -> flags & ENET_PACKET_FLAG_RELIABLE || channel -> outgoingUnreliableSequenceNumber >= 0xFFFF) + { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); + } + else + { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE; + command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); + } + + if (enet_peer_queue_outgoing_command (peer, & command, packet, 0, packet -> dataLength) == NULL) + return -1; + + return 0; +} + +/** Attempts to dequeue any incoming queued packet. + @param peer peer to dequeue packets from + @param channelID holds the channel ID of the channel the packet was received on success + @returns a pointer to the packet, or NULL if there are no available incoming queued packets +*/ +ENetPacket * +enet_peer_receive (ENetPeer * peer, enet_uint8 * channelID) +{ + ENetIncomingCommand * incomingCommand; + ENetPacket * packet; + + if (enet_list_empty (& peer -> dispatchedCommands)) + return NULL; + + incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (& peer -> dispatchedCommands)); + + if (channelID != NULL) + * channelID = incomingCommand -> command.header.channelID; + + packet = incomingCommand -> packet; + + -- packet -> referenceCount; + + if (incomingCommand -> fragments != NULL) + enet_free (incomingCommand -> fragments); + + enet_free (incomingCommand); + + peer -> totalWaitingData -= packet -> dataLength; + + return packet; +} + +static void +enet_peer_reset_outgoing_commands (ENetList * queue) +{ + ENetOutgoingCommand * outgoingCommand; + + while (! enet_list_empty (queue)) + { + outgoingCommand = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (queue)); + + if (outgoingCommand -> packet != NULL) + { + -- outgoingCommand -> packet -> referenceCount; + + if (outgoingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (outgoingCommand -> packet); + } + + enet_free (outgoingCommand); + } +} + +static void +enet_peer_remove_incoming_commands (ENetList * queue, ENetListIterator startCommand, ENetListIterator endCommand, ENetIncomingCommand * excludeCommand) +{ + ENetListIterator currentCommand; + + for (currentCommand = startCommand; currentCommand != endCommand; ) + { + ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; + + currentCommand = enet_list_next (currentCommand); + + if (incomingCommand == excludeCommand) + continue; + + enet_list_remove (& incomingCommand -> incomingCommandList); + + if (incomingCommand -> packet != NULL) + { + -- incomingCommand -> packet -> referenceCount; + + if (incomingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (incomingCommand -> packet); + } + + if (incomingCommand -> fragments != NULL) + enet_free (incomingCommand -> fragments); + + enet_free (incomingCommand); + } +} + +static void +enet_peer_reset_incoming_commands (ENetList * queue) +{ + enet_peer_remove_incoming_commands(queue, enet_list_begin (queue), enet_list_end (queue), NULL); +} + +void +enet_peer_reset_queues (ENetPeer * peer) +{ + ENetChannel * channel; + + if (peer -> flags & ENET_PEER_FLAG_NEEDS_DISPATCH) + { + enet_list_remove (& peer -> dispatchList); + + peer -> flags &= ~ ENET_PEER_FLAG_NEEDS_DISPATCH; + } + + while (! enet_list_empty (& peer -> acknowledgements)) + enet_free (enet_list_remove (enet_list_begin (& peer -> acknowledgements))); + + enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands); + enet_peer_reset_outgoing_commands (& peer -> outgoingCommands); + enet_peer_reset_outgoing_commands (& peer -> outgoingSendReliableCommands); + enet_peer_reset_incoming_commands (& peer -> dispatchedCommands); + + if (peer -> channels != NULL && peer -> channelCount > 0) + { + for (channel = peer -> channels; + channel < & peer -> channels [peer -> channelCount]; + ++ channel) + { + enet_peer_reset_incoming_commands (& channel -> incomingReliableCommands); + enet_peer_reset_incoming_commands (& channel -> incomingUnreliableCommands); + } + + enet_free (peer -> channels); + } + + peer -> channels = NULL; + peer -> channelCount = 0; +} + +void +enet_peer_on_connect (ENetPeer * peer) +{ + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + { + if (peer -> incomingBandwidth != 0) + ++ peer -> host -> bandwidthLimitedPeers; + + ++ peer -> host -> connectedPeers; + } +} + +void +enet_peer_on_disconnect (ENetPeer * peer) +{ + if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) + { + if (peer -> incomingBandwidth != 0) + -- peer -> host -> bandwidthLimitedPeers; + + -- peer -> host -> connectedPeers; + } +} + +/** Forcefully disconnects a peer. + @param peer peer to forcefully disconnect + @remarks The foreign host represented by the peer is not notified of the disconnection and will timeout + on its connection to the local host. +*/ +void +enet_peer_reset (ENetPeer * peer) +{ + enet_peer_on_disconnect (peer); + + peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID; + peer -> connectID = 0; + + peer -> state = ENET_PEER_STATE_DISCONNECTED; + + peer -> incomingBandwidth = 0; + peer -> outgoingBandwidth = 0; + peer -> incomingBandwidthThrottleEpoch = 0; + peer -> outgoingBandwidthThrottleEpoch = 0; + peer -> incomingDataTotal = 0; + peer -> outgoingDataTotal = 0; + peer -> lastSendTime = 0; + peer -> lastReceiveTime = 0; + peer -> nextTimeout = 0; + peer -> earliestTimeout = 0; + peer -> packetLossEpoch = 0; + peer -> packetsSent = 0; + peer -> packetsLost = 0; + peer -> packetLoss = 0; + peer -> packetLossVariance = 0; + peer -> packetThrottle = ENET_PEER_DEFAULT_PACKET_THROTTLE; + peer -> packetThrottleLimit = ENET_PEER_PACKET_THROTTLE_SCALE; + peer -> packetThrottleCounter = 0; + peer -> packetThrottleEpoch = 0; + peer -> packetThrottleAcceleration = ENET_PEER_PACKET_THROTTLE_ACCELERATION; + peer -> packetThrottleDeceleration = ENET_PEER_PACKET_THROTTLE_DECELERATION; + peer -> packetThrottleInterval = ENET_PEER_PACKET_THROTTLE_INTERVAL; + peer -> pingInterval = ENET_PEER_PING_INTERVAL; + peer -> timeoutLimit = ENET_PEER_TIMEOUT_LIMIT; + peer -> timeoutMinimum = ENET_PEER_TIMEOUT_MINIMUM; + peer -> timeoutMaximum = ENET_PEER_TIMEOUT_MAXIMUM; + peer -> lastRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; + peer -> lowestRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; + peer -> lastRoundTripTimeVariance = 0; + peer -> highestRoundTripTimeVariance = 0; + peer -> roundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; + peer -> roundTripTimeVariance = 0; + peer -> mtu = peer -> host -> mtu; + peer -> reliableDataInTransit = 0; + peer -> outgoingReliableSequenceNumber = 0; + peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + peer -> incomingUnsequencedGroup = 0; + peer -> outgoingUnsequencedGroup = 0; + peer -> eventData = 0; + peer -> totalWaitingData = 0; + peer -> flags = 0; + + memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow)); + + enet_peer_reset_queues (peer); +} + +/** Sends a ping request to a peer. + @param peer destination for the ping request + @remarks ping requests factor into the mean round trip time as designated by the + roundTripTime field in the ENetPeer structure. ENet automatically pings all connected + peers at regular intervals, however, this function may be called to ensure more + frequent ping requests. +*/ +void +enet_peer_ping (ENetPeer * peer) +{ + ENetProtocol command; + + if (peer -> state != ENET_PEER_STATE_CONNECTED) + return; + + command.header.command = ENET_PROTOCOL_COMMAND_PING | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); +} + +/** Sets the interval at which pings will be sent to a peer. + + Pings are used both to monitor the liveness of the connection and also to dynamically + adjust the throttle during periods of low traffic so that the throttle has reasonable + responsiveness during traffic spikes. + + @param peer the peer to adjust + @param pingInterval the interval at which to send pings; defaults to ENET_PEER_PING_INTERVAL if 0 +*/ +void +enet_peer_ping_interval (ENetPeer * peer, enet_uint32 pingInterval) +{ + peer -> pingInterval = pingInterval ? pingInterval : ENET_PEER_PING_INTERVAL; +} + +/** Sets the timeout parameters for a peer. + + The timeout parameter control how and when a peer will timeout from a failure to acknowledge + reliable traffic. Timeout values use an exponential backoff mechanism, where if a reliable + packet is not acknowledge within some multiple of the average RTT plus a variance tolerance, + the timeout will be doubled until it reaches a set limit. If the timeout is thus at this + limit and reliable packets have been sent but not acknowledged within a certain minimum time + period, the peer will be disconnected. Alternatively, if reliable packets have been sent + but not acknowledged for a certain maximum time period, the peer will be disconnected regardless + of the current timeout limit value. + + @param peer the peer to adjust + @param timeoutLimit the timeout limit; defaults to ENET_PEER_TIMEOUT_LIMIT if 0 + @param timeoutMinimum the timeout minimum; defaults to ENET_PEER_TIMEOUT_MINIMUM if 0 + @param timeoutMaximum the timeout maximum; defaults to ENET_PEER_TIMEOUT_MAXIMUM if 0 +*/ + +void +enet_peer_timeout (ENetPeer * peer, enet_uint32 timeoutLimit, enet_uint32 timeoutMinimum, enet_uint32 timeoutMaximum) +{ + peer -> timeoutLimit = timeoutLimit ? timeoutLimit : ENET_PEER_TIMEOUT_LIMIT; + peer -> timeoutMinimum = timeoutMinimum ? timeoutMinimum : ENET_PEER_TIMEOUT_MINIMUM; + peer -> timeoutMaximum = timeoutMaximum ? timeoutMaximum : ENET_PEER_TIMEOUT_MAXIMUM; +} + +/** Force an immediate disconnection from a peer. + @param peer peer to disconnect + @param data data describing the disconnection + @remarks No ENET_EVENT_DISCONNECT event will be generated. The foreign peer is not + guaranteed to receive the disconnect notification, and is reset immediately upon + return from this function. +*/ +void +enet_peer_disconnect_now (ENetPeer * peer, enet_uint32 data) +{ + ENetProtocol command; + + if (peer -> state == ENET_PEER_STATE_DISCONNECTED) + return; + + if (peer -> state != ENET_PEER_STATE_ZOMBIE && + peer -> state != ENET_PEER_STATE_DISCONNECTING) + { + enet_peer_reset_queues (peer); + + command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; + command.header.channelID = 0xFF; + command.disconnect.data = ENET_HOST_TO_NET_32 (data); + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); + + enet_host_flush (peer -> host); + } + + enet_peer_reset (peer); +} + +/** Request a disconnection from a peer. + @param peer peer to request a disconnection + @param data data describing the disconnection + @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() + once the disconnection is complete. +*/ +void +enet_peer_disconnect (ENetPeer * peer, enet_uint32 data) +{ + ENetProtocol command; + + if (peer -> state == ENET_PEER_STATE_DISCONNECTING || + peer -> state == ENET_PEER_STATE_DISCONNECTED || + peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT || + peer -> state == ENET_PEER_STATE_ZOMBIE) + return; + + enet_peer_reset_queues (peer); + + command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT; + command.header.channelID = 0xFF; + command.disconnect.data = ENET_HOST_TO_NET_32 (data); + + if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) + command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + else + command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); + + if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) + { + enet_peer_on_disconnect (peer); + + peer -> state = ENET_PEER_STATE_DISCONNECTING; + } + else + { + enet_host_flush (peer -> host); + enet_peer_reset (peer); + } +} + +int +enet_peer_has_outgoing_commands (ENetPeer * peer) +{ + if (enet_list_empty (& peer -> outgoingCommands) && + enet_list_empty (& peer -> outgoingSendReliableCommands) && + enet_list_empty (& peer -> sentReliableCommands)) + return 0; + + return 1; +} + +/** Request a disconnection from a peer, but only after all queued outgoing packets are sent. + @param peer peer to request a disconnection + @param data data describing the disconnection + @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() + once the disconnection is complete. +*/ +void +enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data) +{ + if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) && + enet_peer_has_outgoing_commands (peer)) + { + peer -> state = ENET_PEER_STATE_DISCONNECT_LATER; + peer -> eventData = data; + } + else + enet_peer_disconnect (peer, data); +} + +ENetAcknowledgement * +enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command, enet_uint16 sentTime) +{ + ENetAcknowledgement * acknowledgement; + + if (command -> header.channelID < peer -> channelCount) + { + ENetChannel * channel = & peer -> channels [command -> header.channelID]; + enet_uint16 reliableWindow = command -> header.reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE, + currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (command -> header.reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + reliableWindow += ENET_PEER_RELIABLE_WINDOWS; + + if (reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1 && reliableWindow <= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS) + return NULL; + } + + acknowledgement = (ENetAcknowledgement *) enet_malloc (sizeof (ENetAcknowledgement)); + if (acknowledgement == NULL) + return NULL; + + peer -> outgoingDataTotal += sizeof (ENetProtocolAcknowledge); + + acknowledgement -> sentTime = sentTime; + acknowledgement -> command = * command; + + enet_list_insert (enet_list_end (& peer -> acknowledgements), acknowledgement); + + return acknowledgement; +} + +void +enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoingCommand) +{ + peer -> outgoingDataTotal += enet_protocol_command_size (outgoingCommand -> command.header.command) + outgoingCommand -> fragmentLength; + + if (outgoingCommand -> command.header.channelID == 0xFF) + { + ++ peer -> outgoingReliableSequenceNumber; + + outgoingCommand -> reliableSequenceNumber = peer -> outgoingReliableSequenceNumber; + outgoingCommand -> unreliableSequenceNumber = 0; + } + else + { + ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID]; + + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) + { + ++ channel -> outgoingReliableSequenceNumber; + channel -> outgoingUnreliableSequenceNumber = 0; + + outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; + outgoingCommand -> unreliableSequenceNumber = 0; + } + else + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED) + { + ++ peer -> outgoingUnsequencedGroup; + + outgoingCommand -> reliableSequenceNumber = 0; + outgoingCommand -> unreliableSequenceNumber = 0; + } + else + { + if (outgoingCommand -> fragmentOffset == 0) + ++ channel -> outgoingUnreliableSequenceNumber; + + outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; + outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber; + } + } + + outgoingCommand -> sendAttempts = 0; + outgoingCommand -> sentTime = 0; + outgoingCommand -> roundTripTimeout = 0; + outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber); + outgoingCommand -> queueTime = ++ peer -> host -> totalQueued; + + switch (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) + { + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: + outgoingCommand -> command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> unreliableSequenceNumber); + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: + outgoingCommand -> command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup); + break; + + default: + break; + } + + if ((outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) != 0 && + outgoingCommand -> packet != NULL) + enet_list_insert (enet_list_end (& peer -> outgoingSendReliableCommands), outgoingCommand); + else + enet_list_insert (enet_list_end (& peer -> outgoingCommands), outgoingCommand); +} + +ENetOutgoingCommand * +enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, enet_uint32 offset, enet_uint16 length) +{ + ENetOutgoingCommand * outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand)); + if (outgoingCommand == NULL) + return NULL; + + outgoingCommand -> command = * command; + outgoingCommand -> fragmentOffset = offset; + outgoingCommand -> fragmentLength = length; + outgoingCommand -> packet = packet; + if (packet != NULL) + ++ packet -> referenceCount; + + enet_peer_setup_outgoing_command (peer, outgoingCommand); + + return outgoingCommand; +} + +void +enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * channel, ENetIncomingCommand * queuedCommand) +{ + ENetListIterator droppedCommand, startCommand, currentCommand; + + for (droppedCommand = startCommand = currentCommand = enet_list_begin (& channel -> incomingUnreliableCommands); + currentCommand != enet_list_end (& channel -> incomingUnreliableCommands); + currentCommand = enet_list_next (currentCommand)) + { + ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; + + if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) + continue; + + if (incomingCommand -> reliableSequenceNumber == channel -> incomingReliableSequenceNumber) + { + if (incomingCommand -> fragmentsRemaining <= 0) + { + channel -> incomingUnreliableSequenceNumber = incomingCommand -> unreliableSequenceNumber; + continue; + } + + if (startCommand != currentCommand) + { + enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand)); + + if (! (peer -> flags & ENET_PEER_FLAG_NEEDS_DISPATCH)) + { + enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); + + peer -> flags |= ENET_PEER_FLAG_NEEDS_DISPATCH; + } + + droppedCommand = currentCommand; + } + else + if (droppedCommand != currentCommand) + droppedCommand = enet_list_previous (currentCommand); + } + else + { + enet_uint16 reliableWindow = incomingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE, + currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + reliableWindow += ENET_PEER_RELIABLE_WINDOWS; + if (reliableWindow >= currentWindow && reliableWindow < currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) + break; + + droppedCommand = enet_list_next (currentCommand); + + if (startCommand != currentCommand) + { + enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand)); + + if (! (peer -> flags & ENET_PEER_FLAG_NEEDS_DISPATCH)) + { + enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); + + peer -> flags |= ENET_PEER_FLAG_NEEDS_DISPATCH; + } + } + } + + startCommand = enet_list_next (currentCommand); + } + + if (startCommand != currentCommand) + { + enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand)); + + if (! (peer -> flags & ENET_PEER_FLAG_NEEDS_DISPATCH)) + { + enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); + + peer -> flags |= ENET_PEER_FLAG_NEEDS_DISPATCH; + } + + droppedCommand = currentCommand; + } + + enet_peer_remove_incoming_commands (& channel -> incomingUnreliableCommands, enet_list_begin (& channel -> incomingUnreliableCommands), droppedCommand, queuedCommand); +} + +void +enet_peer_dispatch_incoming_reliable_commands (ENetPeer * peer, ENetChannel * channel, ENetIncomingCommand * queuedCommand) +{ + ENetListIterator currentCommand; + + for (currentCommand = enet_list_begin (& channel -> incomingReliableCommands); + currentCommand != enet_list_end (& channel -> incomingReliableCommands); + currentCommand = enet_list_next (currentCommand)) + { + ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (incomingCommand -> fragmentsRemaining > 0 || + incomingCommand -> reliableSequenceNumber != (enet_uint16) (channel -> incomingReliableSequenceNumber + 1)) + break; + + channel -> incomingReliableSequenceNumber = incomingCommand -> reliableSequenceNumber; + + if (incomingCommand -> fragmentCount > 0) + channel -> incomingReliableSequenceNumber += incomingCommand -> fragmentCount - 1; + } + + if (currentCommand == enet_list_begin (& channel -> incomingReliableCommands)) + return; + + channel -> incomingUnreliableSequenceNumber = 0; + + enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingReliableCommands), enet_list_previous (currentCommand)); + + if (! (peer -> flags & ENET_PEER_FLAG_NEEDS_DISPATCH)) + { + enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); + + peer -> flags |= ENET_PEER_FLAG_NEEDS_DISPATCH; + } + + if (! enet_list_empty (& channel -> incomingUnreliableCommands)) + enet_peer_dispatch_incoming_unreliable_commands (peer, channel, queuedCommand); +} + +ENetIncomingCommand * +enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, const void * data, size_t dataLength, enet_uint32 flags, enet_uint32 fragmentCount) +{ + static ENetIncomingCommand dummyCommand; + + ENetChannel * channel = & peer -> channels [command -> header.channelID]; + enet_uint32 unreliableSequenceNumber = 0, reliableSequenceNumber = 0; + enet_uint16 reliableWindow, currentWindow; + ENetIncomingCommand * incomingCommand; + ENetListIterator currentCommand; + ENetPacket * packet = NULL; + + if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) + goto discardCommand; + + if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) + { + reliableSequenceNumber = command -> header.reliableSequenceNumber; + reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + reliableWindow += ENET_PEER_RELIABLE_WINDOWS; + + if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) + goto discardCommand; + } + + switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK) + { + case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: + case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: + if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber) + goto discardCommand; + + for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands)); + currentCommand != enet_list_end (& channel -> incomingReliableCommands); + currentCommand = enet_list_previous (currentCommand)) + { + incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber <= reliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) + break; + + goto discardCommand; + } + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT: + unreliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendUnreliable.unreliableSequenceNumber); + + if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber && + unreliableSequenceNumber <= channel -> incomingUnreliableSequenceNumber) + goto discardCommand; + + for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands)); + currentCommand != enet_list_end (& channel -> incomingUnreliableCommands); + currentCommand = enet_list_previous (currentCommand)) + { + incomingCommand = (ENetIncomingCommand *) currentCommand; + + if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) + continue; + + if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber > reliableSequenceNumber) + continue; + + if (incomingCommand -> unreliableSequenceNumber <= unreliableSequenceNumber) + { + if (incomingCommand -> unreliableSequenceNumber < unreliableSequenceNumber) + break; + + goto discardCommand; + } + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: + currentCommand = enet_list_end (& channel -> incomingUnreliableCommands); + break; + + default: + goto discardCommand; + } + + if (peer -> totalWaitingData >= peer -> host -> maximumWaitingData) + goto notifyError; + + packet = enet_packet_create (data, dataLength, flags); + if (packet == NULL) + goto notifyError; + + incomingCommand = (ENetIncomingCommand *) enet_malloc (sizeof (ENetIncomingCommand)); + if (incomingCommand == NULL) + goto notifyError; + + incomingCommand -> reliableSequenceNumber = command -> header.reliableSequenceNumber; + incomingCommand -> unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; + incomingCommand -> command = * command; + incomingCommand -> fragmentCount = fragmentCount; + incomingCommand -> fragmentsRemaining = fragmentCount; + incomingCommand -> packet = packet; + incomingCommand -> fragments = NULL; + + if (fragmentCount > 0) + { + if (fragmentCount <= ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT) + incomingCommand -> fragments = (enet_uint32 *) enet_malloc ((fragmentCount + 31) / 32 * sizeof (enet_uint32)); + if (incomingCommand -> fragments == NULL) + { + enet_free (incomingCommand); + + goto notifyError; + } + memset (incomingCommand -> fragments, 0, (fragmentCount + 31) / 32 * sizeof (enet_uint32)); + } + + if (packet != NULL) + { + ++ packet -> referenceCount; + + peer -> totalWaitingData += packet -> dataLength; + } + + enet_list_insert (enet_list_next (currentCommand), incomingCommand); + + switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK) + { + case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: + case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: + enet_peer_dispatch_incoming_reliable_commands (peer, channel, incomingCommand); + break; + + default: + enet_peer_dispatch_incoming_unreliable_commands (peer, channel, incomingCommand); + break; + } + + return incomingCommand; + +discardCommand: + if (fragmentCount > 0) + goto notifyError; + + if (packet != NULL && packet -> referenceCount == 0) + enet_packet_destroy (packet); + + return & dummyCommand; + +notifyError: + if (packet != NULL && packet -> referenceCount == 0) + enet_packet_destroy (packet); + + return NULL; +} + +/** @} */ diff --git a/Deer/vendor/enet/premake4.lua b/Deer/vendor/enet/premake4.lua new file mode 100644 index 0000000..0e6e7ad --- /dev/null +++ b/Deer/vendor/enet/premake4.lua @@ -0,0 +1,59 @@ +solution "enet" + configurations { "Debug", "Release" } + platforms { "x32", "x64" } + + project "enet_static" + kind "StaticLib" + language "C" + + files { "*.c" } + + includedirs { "include/" } + + configuration "Debug" + targetsuffix "d" + + defines({ "DEBUG" }) + + flags { "Symbols" } + + configuration "Release" + defines({ "NDEBUG" }) + + flags { "Optimize" } + + configuration { "Debug", "x64" } + targetsuffix "64d" + + configuration { "Release", "x64" } + targetsuffix "64" + + project "enet" + kind "SharedLib" + language "C" + + files { "*.c" } + + includedirs { "include/" } + + defines({"ENET_DLL=1" }) + + configuration "Debug" + targetsuffix "d" + + defines({ "DEBUG" }) + + flags { "Symbols" } + + configuration "Release" + defines({ "NDEBUG" }) + + flags { "Optimize" } + + configuration { "Debug", "x64" } + targetsuffix "64d" + + configuration { "Release", "x64" } + targetsuffix "64" + + \ No newline at end of file diff --git a/Deer/vendor/enet/protocol.c b/Deer/vendor/enet/protocol.c new file mode 100644 index 0000000..843a719 --- /dev/null +++ b/Deer/vendor/enet/protocol.c @@ -0,0 +1,1919 @@ +/** + @file protocol.c + @brief ENet protocol functions +*/ +#include +#include +#define ENET_BUILDING_LIB 1 +#include "enet/utility.h" +#include "enet/time.h" +#include "enet/enet.h" + +static const size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] = +{ + 0, + sizeof (ENetProtocolAcknowledge), + sizeof (ENetProtocolConnect), + sizeof (ENetProtocolVerifyConnect), + sizeof (ENetProtocolDisconnect), + sizeof (ENetProtocolPing), + sizeof (ENetProtocolSendReliable), + sizeof (ENetProtocolSendUnreliable), + sizeof (ENetProtocolSendFragment), + sizeof (ENetProtocolSendUnsequenced), + sizeof (ENetProtocolBandwidthLimit), + sizeof (ENetProtocolThrottleConfigure), + sizeof (ENetProtocolSendFragment) +}; + +size_t +enet_protocol_command_size (enet_uint8 commandNumber) +{ + return commandSizes [commandNumber & ENET_PROTOCOL_COMMAND_MASK]; +} + +static void +enet_protocol_change_state (ENetHost * host, ENetPeer * peer, ENetPeerState state) +{ + if (state == ENET_PEER_STATE_CONNECTED || state == ENET_PEER_STATE_DISCONNECT_LATER) + enet_peer_on_connect (peer); + else + enet_peer_on_disconnect (peer); + + peer -> state = state; +} + +static void +enet_protocol_dispatch_state (ENetHost * host, ENetPeer * peer, ENetPeerState state) +{ + enet_protocol_change_state (host, peer, state); + + if (! (peer -> flags & ENET_PEER_FLAG_NEEDS_DISPATCH)) + { + enet_list_insert (enet_list_end (& host -> dispatchQueue), & peer -> dispatchList); + + peer -> flags |= ENET_PEER_FLAG_NEEDS_DISPATCH; + } +} + +static int +enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event) +{ + while (! enet_list_empty (& host -> dispatchQueue)) + { + ENetPeer * peer = (ENetPeer *) enet_list_remove (enet_list_begin (& host -> dispatchQueue)); + + peer -> flags &= ~ ENET_PEER_FLAG_NEEDS_DISPATCH; + + switch (peer -> state) + { + case ENET_PEER_STATE_CONNECTION_PENDING: + case ENET_PEER_STATE_CONNECTION_SUCCEEDED: + enet_protocol_change_state (host, peer, ENET_PEER_STATE_CONNECTED); + + event -> type = ENET_EVENT_TYPE_CONNECT; + event -> peer = peer; + event -> data = peer -> eventData; + + return 1; + + case ENET_PEER_STATE_ZOMBIE: + host -> recalculateBandwidthLimits = 1; + + event -> type = ENET_EVENT_TYPE_DISCONNECT; + event -> peer = peer; + event -> data = peer -> eventData; + + enet_peer_reset (peer); + + return 1; + + case ENET_PEER_STATE_CONNECTED: + if (enet_list_empty (& peer -> dispatchedCommands)) + continue; + + event -> packet = enet_peer_receive (peer, & event -> channelID); + if (event -> packet == NULL) + continue; + + event -> type = ENET_EVENT_TYPE_RECEIVE; + event -> peer = peer; + + if (! enet_list_empty (& peer -> dispatchedCommands)) + { + peer -> flags |= ENET_PEER_FLAG_NEEDS_DISPATCH; + + enet_list_insert (enet_list_end (& host -> dispatchQueue), & peer -> dispatchList); + } + + return 1; + + default: + break; + } + } + + return 0; +} + +static void +enet_protocol_notify_connect (ENetHost * host, ENetPeer * peer, ENetEvent * event) +{ + host -> recalculateBandwidthLimits = 1; + + if (event != NULL) + { + enet_protocol_change_state (host, peer, ENET_PEER_STATE_CONNECTED); + + event -> type = ENET_EVENT_TYPE_CONNECT; + event -> peer = peer; + event -> data = peer -> eventData; + } + else + enet_protocol_dispatch_state (host, peer, peer -> state == ENET_PEER_STATE_CONNECTING ? ENET_PEER_STATE_CONNECTION_SUCCEEDED : ENET_PEER_STATE_CONNECTION_PENDING); +} + +static void +enet_protocol_notify_disconnect (ENetHost * host, ENetPeer * peer, ENetEvent * event) +{ + if (peer -> state >= ENET_PEER_STATE_CONNECTION_PENDING) + host -> recalculateBandwidthLimits = 1; + + if (peer -> state != ENET_PEER_STATE_CONNECTING && peer -> state < ENET_PEER_STATE_CONNECTION_SUCCEEDED) + enet_peer_reset (peer); + else + if (event != NULL) + { + event -> type = ENET_EVENT_TYPE_DISCONNECT; + event -> peer = peer; + event -> data = 0; + + enet_peer_reset (peer); + } + else + { + peer -> eventData = 0; + + enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); + } +} + +static void +enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer, ENetList * sentUnreliableCommands) +{ + ENetOutgoingCommand * outgoingCommand; + + if (enet_list_empty (sentUnreliableCommands)) + return; + + do + { + outgoingCommand = (ENetOutgoingCommand *) enet_list_front (sentUnreliableCommands); + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + + if (outgoingCommand -> packet != NULL) + { + -- outgoingCommand -> packet -> referenceCount; + + if (outgoingCommand -> packet -> referenceCount == 0) + { + outgoingCommand -> packet -> flags |= ENET_PACKET_FLAG_SENT; + + enet_packet_destroy (outgoingCommand -> packet); + } + } + + enet_free (outgoingCommand); + } while (! enet_list_empty (sentUnreliableCommands)); + + if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER && + ! enet_peer_has_outgoing_commands (peer)) + enet_peer_disconnect (peer, peer -> eventData); +} + +static ENetOutgoingCommand * +enet_protocol_find_sent_reliable_command (ENetList * list, enet_uint16 reliableSequenceNumber, enet_uint8 channelID) +{ + ENetListIterator currentCommand; + + for (currentCommand = enet_list_begin (list); + currentCommand != enet_list_end (list); + currentCommand = enet_list_next (currentCommand)) + { + ENetOutgoingCommand * outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + if (! (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)) + continue; + + if (outgoingCommand -> sendAttempts < 1) + break; + + if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber && + outgoingCommand -> command.header.channelID == channelID) + return outgoingCommand; + } + + return NULL; +} + +static ENetProtocolCommand +enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliableSequenceNumber, enet_uint8 channelID) +{ + ENetOutgoingCommand * outgoingCommand = NULL; + ENetListIterator currentCommand; + ENetProtocolCommand commandNumber; + int wasSent = 1; + + for (currentCommand = enet_list_begin (& peer -> sentReliableCommands); + currentCommand != enet_list_end (& peer -> sentReliableCommands); + currentCommand = enet_list_next (currentCommand)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber && + outgoingCommand -> command.header.channelID == channelID) + break; + } + + if (currentCommand == enet_list_end (& peer -> sentReliableCommands)) + { + outgoingCommand = enet_protocol_find_sent_reliable_command (& peer -> outgoingCommands, reliableSequenceNumber, channelID); + if (outgoingCommand == NULL) + outgoingCommand = enet_protocol_find_sent_reliable_command (& peer -> outgoingSendReliableCommands, reliableSequenceNumber, channelID); + + wasSent = 0; + } + + if (outgoingCommand == NULL) + return ENET_PROTOCOL_COMMAND_NONE; + + if (channelID < peer -> channelCount) + { + ENetChannel * channel = & peer -> channels [channelID]; + enet_uint16 reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + if (channel -> reliableWindows [reliableWindow] > 0) + { + -- channel -> reliableWindows [reliableWindow]; + if (! channel -> reliableWindows [reliableWindow]) + channel -> usedReliableWindows &= ~ (1 << reliableWindow); + } + } + + commandNumber = (ENetProtocolCommand) (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK); + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + + if (outgoingCommand -> packet != NULL) + { + if (wasSent) + peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength; + + -- outgoingCommand -> packet -> referenceCount; + + if (outgoingCommand -> packet -> referenceCount == 0) + { + outgoingCommand -> packet -> flags |= ENET_PACKET_FLAG_SENT; + + enet_packet_destroy (outgoingCommand -> packet); + } + } + + enet_free (outgoingCommand); + + if (enet_list_empty (& peer -> sentReliableCommands)) + return commandNumber; + + outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentReliableCommands); + + peer -> nextTimeout = outgoingCommand -> sentTime + outgoingCommand -> roundTripTimeout; + + return commandNumber; +} + +static ENetPeer * +enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENetProtocol * command) +{ + enet_uint8 incomingSessionID, outgoingSessionID; + enet_uint32 mtu, windowSize; + ENetChannel * channel; + size_t channelCount, duplicatePeers = 0; + ENetPeer * currentPeer, * peer = NULL; + ENetProtocol verifyCommand; + + channelCount = ENET_NET_TO_HOST_32 (command -> connect.channelCount); + + if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || + channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) + return NULL; + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED) + { + if (peer == NULL) + peer = currentPeer; + } + else + if (currentPeer -> state != ENET_PEER_STATE_CONNECTING && + currentPeer -> address.host == host -> receivedAddress.host) + { + if (currentPeer -> address.port == host -> receivedAddress.port && + currentPeer -> connectID == command -> connect.connectID) + return NULL; + + ++ duplicatePeers; + } + } + + if (peer == NULL || duplicatePeers >= host -> duplicatePeers) + return NULL; + + if (channelCount > host -> channelLimit) + channelCount = host -> channelLimit; + peer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); + if (peer -> channels == NULL) + return NULL; + peer -> channelCount = channelCount; + peer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT; + peer -> connectID = command -> connect.connectID; + peer -> address = host -> receivedAddress; + peer -> mtu = host -> mtu; + peer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> connect.outgoingPeerID); + peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.incomingBandwidth); + peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.outgoingBandwidth); + peer -> packetThrottleInterval = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleInterval); + peer -> packetThrottleAcceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleAcceleration); + peer -> packetThrottleDeceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleDeceleration); + peer -> eventData = ENET_NET_TO_HOST_32 (command -> connect.data); + + incomingSessionID = command -> connect.incomingSessionID == 0xFF ? peer -> outgoingSessionID : command -> connect.incomingSessionID; + incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + if (incomingSessionID == peer -> outgoingSessionID) + incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + peer -> outgoingSessionID = incomingSessionID; + + outgoingSessionID = command -> connect.outgoingSessionID == 0xFF ? peer -> incomingSessionID : command -> connect.outgoingSessionID; + outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + if (outgoingSessionID == peer -> incomingSessionID) + outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + peer -> incomingSessionID = outgoingSessionID; + + for (channel = peer -> channels; + channel < & peer -> channels [channelCount]; + ++ channel) + { + channel -> outgoingReliableSequenceNumber = 0; + channel -> outgoingUnreliableSequenceNumber = 0; + channel -> incomingReliableSequenceNumber = 0; + channel -> incomingUnreliableSequenceNumber = 0; + + enet_list_clear (& channel -> incomingReliableCommands); + enet_list_clear (& channel -> incomingUnreliableCommands); + + channel -> usedReliableWindows = 0; + memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); + } + + mtu = ENET_NET_TO_HOST_32 (command -> connect.mtu); + + if (mtu < ENET_PROTOCOL_MINIMUM_MTU) + mtu = ENET_PROTOCOL_MINIMUM_MTU; + else + if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) + mtu = ENET_PROTOCOL_MAXIMUM_MTU; + + if (mtu < peer -> mtu) + peer -> mtu = mtu; + + if (host -> outgoingBandwidth == 0 && + peer -> incomingBandwidth == 0) + peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + if (host -> outgoingBandwidth == 0 || + peer -> incomingBandwidth == 0) + peer -> windowSize = (ENET_MAX (host -> outgoingBandwidth, peer -> incomingBandwidth) / + ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + peer -> windowSize = (ENET_MIN (host -> outgoingBandwidth, peer -> incomingBandwidth) / + ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (peer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + peer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + if (peer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + if (host -> incomingBandwidth == 0) + windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + windowSize = (host -> incomingBandwidth / ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (windowSize > ENET_NET_TO_HOST_32 (command -> connect.windowSize)) + windowSize = ENET_NET_TO_HOST_32 (command -> connect.windowSize); + + if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + verifyCommand.header.command = ENET_PROTOCOL_COMMAND_VERIFY_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + verifyCommand.header.channelID = 0xFF; + verifyCommand.verifyConnect.outgoingPeerID = ENET_HOST_TO_NET_16 (peer -> incomingPeerID); + verifyCommand.verifyConnect.incomingSessionID = incomingSessionID; + verifyCommand.verifyConnect.outgoingSessionID = outgoingSessionID; + verifyCommand.verifyConnect.mtu = ENET_HOST_TO_NET_32 (peer -> mtu); + verifyCommand.verifyConnect.windowSize = ENET_HOST_TO_NET_32 (windowSize); + verifyCommand.verifyConnect.channelCount = ENET_HOST_TO_NET_32 (channelCount); + verifyCommand.verifyConnect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth); + verifyCommand.verifyConnect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); + verifyCommand.verifyConnect.packetThrottleInterval = ENET_HOST_TO_NET_32 (peer -> packetThrottleInterval); + verifyCommand.verifyConnect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (peer -> packetThrottleAcceleration); + verifyCommand.verifyConnect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (peer -> packetThrottleDeceleration); + verifyCommand.verifyConnect.connectID = peer -> connectID; + + enet_peer_queue_outgoing_command (peer, & verifyCommand, NULL, 0, 0); + + return peer; +} + +static int +enet_protocol_handle_send_reliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + size_t dataLength; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + dataLength = ENET_NET_TO_HOST_16 (command -> sendReliable.dataLength); + * currentData += dataLength; + if (dataLength > host -> maximumPacketSize || + * currentData < host -> receivedData || + * currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + if (enet_peer_queue_incoming_command (peer, command, (const enet_uint8 *) command + sizeof (ENetProtocolSendReliable), dataLength, ENET_PACKET_FLAG_RELIABLE, 0) == NULL) + return -1; + + return 0; +} + +static int +enet_protocol_handle_send_unsequenced (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + enet_uint32 unsequencedGroup, index; + size_t dataLength; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + dataLength = ENET_NET_TO_HOST_16 (command -> sendUnsequenced.dataLength); + * currentData += dataLength; + if (dataLength > host -> maximumPacketSize || + * currentData < host -> receivedData || + * currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + unsequencedGroup = ENET_NET_TO_HOST_16 (command -> sendUnsequenced.unsequencedGroup); + index = unsequencedGroup % ENET_PEER_UNSEQUENCED_WINDOW_SIZE; + + if (unsequencedGroup < peer -> incomingUnsequencedGroup) + unsequencedGroup += 0x10000; + + if (unsequencedGroup >= (enet_uint32) peer -> incomingUnsequencedGroup + ENET_PEER_FREE_UNSEQUENCED_WINDOWS * ENET_PEER_UNSEQUENCED_WINDOW_SIZE) + return 0; + + unsequencedGroup &= 0xFFFF; + + if (unsequencedGroup - index != peer -> incomingUnsequencedGroup) + { + peer -> incomingUnsequencedGroup = unsequencedGroup - index; + + memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow)); + } + else + if (peer -> unsequencedWindow [index / 32] & (1 << (index % 32))) + return 0; + + if (enet_peer_queue_incoming_command (peer, command, (const enet_uint8 *) command + sizeof (ENetProtocolSendUnsequenced), dataLength, ENET_PACKET_FLAG_UNSEQUENCED, 0) == NULL) + return -1; + + peer -> unsequencedWindow [index / 32] |= 1 << (index % 32); + + return 0; +} + +static int +enet_protocol_handle_send_unreliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + size_t dataLength; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + dataLength = ENET_NET_TO_HOST_16 (command -> sendUnreliable.dataLength); + * currentData += dataLength; + if (dataLength > host -> maximumPacketSize || + * currentData < host -> receivedData || + * currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + if (enet_peer_queue_incoming_command (peer, command, (const enet_uint8 *) command + sizeof (ENetProtocolSendUnreliable), dataLength, 0, 0) == NULL) + return -1; + + return 0; +} + +static int +enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + enet_uint32 fragmentNumber, + fragmentCount, + fragmentOffset, + fragmentLength, + startSequenceNumber, + totalLength; + ENetChannel * channel; + enet_uint16 startWindow, currentWindow; + ENetListIterator currentCommand; + ENetIncomingCommand * startCommand = NULL; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength); + * currentData += fragmentLength; + if (fragmentLength <= 0 || + fragmentLength > host -> maximumPacketSize || + * currentData < host -> receivedData || + * currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + channel = & peer -> channels [command -> header.channelID]; + startSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendFragment.startSequenceNumber); + startWindow = startSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (startSequenceNumber < channel -> incomingReliableSequenceNumber) + startWindow += ENET_PEER_RELIABLE_WINDOWS; + + if (startWindow < currentWindow || startWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) + return 0; + + fragmentNumber = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentNumber); + fragmentCount = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentCount); + fragmentOffset = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentOffset); + totalLength = ENET_NET_TO_HOST_32 (command -> sendFragment.totalLength); + + if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT || + fragmentNumber >= fragmentCount || + totalLength > host -> maximumPacketSize || + totalLength < fragmentCount || + fragmentOffset >= totalLength || + fragmentLength > totalLength - fragmentOffset) + return -1; + + for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands)); + currentCommand != enet_list_end (& channel -> incomingReliableCommands); + currentCommand = enet_list_previous (currentCommand)) + { + ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (startSequenceNumber >= channel -> incomingReliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber <= startSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < startSequenceNumber) + break; + + if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_FRAGMENT || + totalLength != incomingCommand -> packet -> dataLength || + fragmentCount != incomingCommand -> fragmentCount) + return -1; + + startCommand = incomingCommand; + break; + } + } + + if (startCommand == NULL) + { + ENetProtocol hostCommand = * command; + + hostCommand.header.reliableSequenceNumber = startSequenceNumber; + + startCommand = enet_peer_queue_incoming_command (peer, & hostCommand, NULL, totalLength, ENET_PACKET_FLAG_RELIABLE, fragmentCount); + if (startCommand == NULL) + return -1; + } + + if ((startCommand -> fragments [fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) + { + -- startCommand -> fragmentsRemaining; + + startCommand -> fragments [fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); + + if (fragmentOffset + fragmentLength > startCommand -> packet -> dataLength) + fragmentLength = startCommand -> packet -> dataLength - fragmentOffset; + + memcpy (startCommand -> packet -> data + fragmentOffset, + (enet_uint8 *) command + sizeof (ENetProtocolSendFragment), + fragmentLength); + + if (startCommand -> fragmentsRemaining <= 0) + enet_peer_dispatch_incoming_reliable_commands (peer, channel, NULL); + } + + return 0; +} + +static int +enet_protocol_handle_send_unreliable_fragment (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + enet_uint32 fragmentNumber, + fragmentCount, + fragmentOffset, + fragmentLength, + reliableSequenceNumber, + startSequenceNumber, + totalLength; + enet_uint16 reliableWindow, currentWindow; + ENetChannel * channel; + ENetListIterator currentCommand; + ENetIncomingCommand * startCommand = NULL; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength); + * currentData += fragmentLength; + if (fragmentLength > host -> maximumPacketSize || + * currentData < host -> receivedData || + * currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + channel = & peer -> channels [command -> header.channelID]; + reliableSequenceNumber = command -> header.reliableSequenceNumber; + startSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendFragment.startSequenceNumber); + + reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + reliableWindow += ENET_PEER_RELIABLE_WINDOWS; + + if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) + return 0; + + if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber && + startSequenceNumber <= channel -> incomingUnreliableSequenceNumber) + return 0; + + fragmentNumber = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentNumber); + fragmentCount = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentCount); + fragmentOffset = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentOffset); + totalLength = ENET_NET_TO_HOST_32 (command -> sendFragment.totalLength); + + if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT || + fragmentNumber >= fragmentCount || + totalLength > host -> maximumPacketSize || + fragmentOffset >= totalLength || + fragmentLength > totalLength - fragmentOffset) + return -1; + + for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands)); + currentCommand != enet_list_end (& channel -> incomingUnreliableCommands); + currentCommand = enet_list_previous (currentCommand)) + { + ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber > reliableSequenceNumber) + continue; + + if (incomingCommand -> unreliableSequenceNumber <= startSequenceNumber) + { + if (incomingCommand -> unreliableSequenceNumber < startSequenceNumber) + break; + + if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT || + totalLength != incomingCommand -> packet -> dataLength || + fragmentCount != incomingCommand -> fragmentCount) + return -1; + + startCommand = incomingCommand; + break; + } + } + + if (startCommand == NULL) + { + startCommand = enet_peer_queue_incoming_command (peer, command, NULL, totalLength, ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT, fragmentCount); + if (startCommand == NULL) + return -1; + } + + if ((startCommand -> fragments [fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) + { + -- startCommand -> fragmentsRemaining; + + startCommand -> fragments [fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); + + if (fragmentOffset + fragmentLength > startCommand -> packet -> dataLength) + fragmentLength = startCommand -> packet -> dataLength - fragmentOffset; + + memcpy (startCommand -> packet -> data + fragmentOffset, + (enet_uint8 *) command + sizeof (ENetProtocolSendFragment), + fragmentLength); + + if (startCommand -> fragmentsRemaining <= 0) + enet_peer_dispatch_incoming_unreliable_commands (peer, channel, NULL); + } + + return 0; +} + +static int +enet_protocol_handle_ping (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +{ + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + return -1; + + return 0; +} + +static int +enet_protocol_handle_bandwidth_limit (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +{ + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + return -1; + + if (peer -> incomingBandwidth != 0) + -- host -> bandwidthLimitedPeers; + + peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> bandwidthLimit.incomingBandwidth); + peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> bandwidthLimit.outgoingBandwidth); + + if (peer -> incomingBandwidth != 0) + ++ host -> bandwidthLimitedPeers; + + if (peer -> incomingBandwidth == 0 && host -> outgoingBandwidth == 0) + peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + if (peer -> incomingBandwidth == 0 || host -> outgoingBandwidth == 0) + peer -> windowSize = (ENET_MAX (peer -> incomingBandwidth, host -> outgoingBandwidth) / + ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + peer -> windowSize = (ENET_MIN (peer -> incomingBandwidth, host -> outgoingBandwidth) / + ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (peer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + peer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + if (peer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + return 0; +} + +static int +enet_protocol_handle_throttle_configure (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +{ + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + return -1; + + peer -> packetThrottleInterval = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleInterval); + peer -> packetThrottleAcceleration = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleAcceleration); + peer -> packetThrottleDeceleration = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleDeceleration); + + return 0; +} + +static int +enet_protocol_handle_disconnect (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +{ + if (peer -> state == ENET_PEER_STATE_DISCONNECTED || peer -> state == ENET_PEER_STATE_ZOMBIE || peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT) + return 0; + + enet_peer_reset_queues (peer); + + if (peer -> state == ENET_PEER_STATE_CONNECTION_SUCCEEDED || peer -> state == ENET_PEER_STATE_DISCONNECTING || peer -> state == ENET_PEER_STATE_CONNECTING) + enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); + else + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + { + if (peer -> state == ENET_PEER_STATE_CONNECTION_PENDING) host -> recalculateBandwidthLimits = 1; + + enet_peer_reset (peer); + } + else + if (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) + enet_protocol_change_state (host, peer, ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT); + else + enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); + + if (peer -> state != ENET_PEER_STATE_DISCONNECTED) + peer -> eventData = ENET_NET_TO_HOST_32 (command -> disconnect.data); + + return 0; +} + +static int +enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command) +{ + enet_uint32 roundTripTime, + receivedSentTime, + receivedReliableSequenceNumber; + ENetProtocolCommand commandNumber; + + if (peer -> state == ENET_PEER_STATE_DISCONNECTED || peer -> state == ENET_PEER_STATE_ZOMBIE) + return 0; + + receivedSentTime = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedSentTime); + receivedSentTime |= host -> serviceTime & 0xFFFF0000; + if ((receivedSentTime & 0x8000) > (host -> serviceTime & 0x8000)) + receivedSentTime -= 0x10000; + + if (ENET_TIME_LESS (host -> serviceTime, receivedSentTime)) + return 0; + + roundTripTime = ENET_TIME_DIFFERENCE (host -> serviceTime, receivedSentTime); + roundTripTime = ENET_MAX (roundTripTime, 1); + + if (peer -> lastReceiveTime > 0) + { + enet_peer_throttle (peer, roundTripTime); + + peer -> roundTripTimeVariance -= peer -> roundTripTimeVariance / 4; + + if (roundTripTime >= peer -> roundTripTime) + { + enet_uint32 diff = roundTripTime - peer -> roundTripTime; + peer -> roundTripTimeVariance += diff / 4; + peer -> roundTripTime += diff / 8; + } + else + { + enet_uint32 diff = peer -> roundTripTime - roundTripTime; + peer -> roundTripTimeVariance += diff / 4; + peer -> roundTripTime -= diff / 8; + } + } + else + { + peer -> roundTripTime = roundTripTime; + peer -> roundTripTimeVariance = (roundTripTime + 1) / 2; + } + + if (peer -> roundTripTime < peer -> lowestRoundTripTime) + peer -> lowestRoundTripTime = peer -> roundTripTime; + + if (peer -> roundTripTimeVariance > peer -> highestRoundTripTimeVariance) + peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance; + + if (peer -> packetThrottleEpoch == 0 || + ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> packetThrottleEpoch) >= peer -> packetThrottleInterval) + { + peer -> lastRoundTripTime = peer -> lowestRoundTripTime; + peer -> lastRoundTripTimeVariance = ENET_MAX (peer -> highestRoundTripTimeVariance, 1); + peer -> lowestRoundTripTime = peer -> roundTripTime; + peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance; + peer -> packetThrottleEpoch = host -> serviceTime; + } + + peer -> lastReceiveTime = ENET_MAX (host -> serviceTime, 1); + peer -> earliestTimeout = 0; + + receivedReliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedReliableSequenceNumber); + + commandNumber = enet_protocol_remove_sent_reliable_command (peer, receivedReliableSequenceNumber, command -> header.channelID); + + switch (peer -> state) + { + case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: + if (commandNumber != ENET_PROTOCOL_COMMAND_VERIFY_CONNECT) + return -1; + + enet_protocol_notify_connect (host, peer, event); + break; + + case ENET_PEER_STATE_DISCONNECTING: + if (commandNumber != ENET_PROTOCOL_COMMAND_DISCONNECT) + return -1; + + enet_protocol_notify_disconnect (host, peer, event); + break; + + case ENET_PEER_STATE_DISCONNECT_LATER: + if (! enet_peer_has_outgoing_commands (peer)) + enet_peer_disconnect (peer, peer -> eventData); + break; + + default: + break; + } + + return 0; +} + +static int +enet_protocol_handle_verify_connect (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command) +{ + enet_uint32 mtu, windowSize; + size_t channelCount; + + if (peer -> state != ENET_PEER_STATE_CONNECTING) + return 0; + + channelCount = ENET_NET_TO_HOST_32 (command -> verifyConnect.channelCount); + + if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT || + ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleInterval) != peer -> packetThrottleInterval || + ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleAcceleration) != peer -> packetThrottleAcceleration || + ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleDeceleration) != peer -> packetThrottleDeceleration || + command -> verifyConnect.connectID != peer -> connectID) + { + peer -> eventData = 0; + + enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); + + return -1; + } + + enet_protocol_remove_sent_reliable_command (peer, 1, 0xFF); + + if (channelCount < peer -> channelCount) + peer -> channelCount = channelCount; + + peer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> verifyConnect.outgoingPeerID); + peer -> incomingSessionID = command -> verifyConnect.incomingSessionID; + peer -> outgoingSessionID = command -> verifyConnect.outgoingSessionID; + + mtu = ENET_NET_TO_HOST_32 (command -> verifyConnect.mtu); + + if (mtu < ENET_PROTOCOL_MINIMUM_MTU) + mtu = ENET_PROTOCOL_MINIMUM_MTU; + else + if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) + mtu = ENET_PROTOCOL_MAXIMUM_MTU; + + if (mtu < peer -> mtu) + peer -> mtu = mtu; + + windowSize = ENET_NET_TO_HOST_32 (command -> verifyConnect.windowSize); + + if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + if (windowSize < peer -> windowSize) + peer -> windowSize = windowSize; + + peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> verifyConnect.incomingBandwidth); + peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> verifyConnect.outgoingBandwidth); + + enet_protocol_notify_connect (host, peer, event); + return 0; +} + +static int +enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event) +{ + ENetProtocolHeader * header; + ENetProtocol * command; + ENetPeer * peer; + enet_uint8 * currentData; + size_t headerSize; + enet_uint16 peerID, flags; + enet_uint8 sessionID; + + if (host -> receivedDataLength < (size_t) & ((ENetProtocolHeader *) 0) -> sentTime) + return 0; + + header = (ENetProtocolHeader *) host -> receivedData; + + peerID = ENET_NET_TO_HOST_16 (header -> peerID); + sessionID = (peerID & ENET_PROTOCOL_HEADER_SESSION_MASK) >> ENET_PROTOCOL_HEADER_SESSION_SHIFT; + flags = peerID & ENET_PROTOCOL_HEADER_FLAG_MASK; + peerID &= ~ (ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK); + + headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof (ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *) 0) -> sentTime); + if (host -> checksum != NULL) + headerSize += sizeof (enet_uint32); + + if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID) + peer = NULL; + else + if (peerID >= host -> peerCount) + return 0; + else + { + peer = & host -> peers [peerID]; + + if (peer -> state == ENET_PEER_STATE_DISCONNECTED || + peer -> state == ENET_PEER_STATE_ZOMBIE || + ((host -> receivedAddress.host != peer -> address.host || + host -> receivedAddress.port != peer -> address.port) && + peer -> address.host != ENET_HOST_BROADCAST) || + (peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID && + sessionID != peer -> incomingSessionID)) + return 0; + } + + if (flags & ENET_PROTOCOL_HEADER_FLAG_COMPRESSED) + { + size_t originalSize; + if (host -> compressor.context == NULL || host -> compressor.decompress == NULL) + return 0; + + originalSize = host -> compressor.decompress (host -> compressor.context, + host -> receivedData + headerSize, + host -> receivedDataLength - headerSize, + host -> packetData [1] + headerSize, + sizeof (host -> packetData [1]) - headerSize); + if (originalSize <= 0 || originalSize > sizeof (host -> packetData [1]) - headerSize) + return 0; + + memcpy (host -> packetData [1], header, headerSize); + host -> receivedData = host -> packetData [1]; + host -> receivedDataLength = headerSize + originalSize; + } + + if (host -> checksum != NULL) + { + enet_uint32 * checksum = (enet_uint32 *) & host -> receivedData [headerSize - sizeof (enet_uint32)]; + enet_uint32 desiredChecksum, newChecksum; + ENetBuffer buffer; + /* Checksum may be an unaligned pointer, use memcpy to avoid undefined behaviour. */ + memcpy (& desiredChecksum, checksum, sizeof (enet_uint32)); + + newChecksum = peer != NULL ? peer -> connectID : 0; + memcpy (checksum, & newChecksum, sizeof (enet_uint32)); + + buffer.data = host -> receivedData; + buffer.dataLength = host -> receivedDataLength; + + if (host -> checksum (& buffer, 1) != desiredChecksum) + return 0; + } + + if (peer != NULL) + { + peer -> address.host = host -> receivedAddress.host; + peer -> address.port = host -> receivedAddress.port; + peer -> incomingDataTotal += host -> receivedDataLength; + } + + currentData = host -> receivedData + headerSize; + + while (currentData < & host -> receivedData [host -> receivedDataLength]) + { + enet_uint8 commandNumber; + size_t commandSize; + + command = (ENetProtocol *) currentData; + + if (currentData + sizeof (ENetProtocolCommandHeader) > & host -> receivedData [host -> receivedDataLength]) + break; + + commandNumber = command -> header.command & ENET_PROTOCOL_COMMAND_MASK; + if (commandNumber >= ENET_PROTOCOL_COMMAND_COUNT) + break; + + commandSize = commandSizes [commandNumber]; + if (commandSize == 0 || currentData + commandSize > & host -> receivedData [host -> receivedDataLength]) + break; + + currentData += commandSize; + + if (peer == NULL && commandNumber != ENET_PROTOCOL_COMMAND_CONNECT) + break; + + command -> header.reliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> header.reliableSequenceNumber); + + switch (commandNumber) + { + case ENET_PROTOCOL_COMMAND_ACKNOWLEDGE: + if (enet_protocol_handle_acknowledge (host, event, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_CONNECT: + if (peer != NULL) + goto commandError; + peer = enet_protocol_handle_connect (host, header, command); + if (peer == NULL) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_VERIFY_CONNECT: + if (enet_protocol_handle_verify_connect (host, event, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_DISCONNECT: + if (enet_protocol_handle_disconnect (host, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_PING: + if (enet_protocol_handle_ping (host, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: + if (enet_protocol_handle_send_reliable (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: + if (enet_protocol_handle_send_unreliable (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: + if (enet_protocol_handle_send_unsequenced (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: + if (enet_protocol_handle_send_fragment (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT: + if (enet_protocol_handle_bandwidth_limit (host, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE: + if (enet_protocol_handle_throttle_configure (host, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT: + if (enet_protocol_handle_send_unreliable_fragment (host, peer, command, & currentData)) + goto commandError; + break; + + default: + goto commandError; + } + + if (peer != NULL && + (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) != 0) + { + enet_uint16 sentTime; + + if (! (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME)) + break; + + sentTime = ENET_NET_TO_HOST_16 (header -> sentTime); + + switch (peer -> state) + { + case ENET_PEER_STATE_DISCONNECTING: + case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: + case ENET_PEER_STATE_DISCONNECTED: + case ENET_PEER_STATE_ZOMBIE: + break; + + case ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT: + if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) + enet_peer_queue_acknowledgement (peer, command, sentTime); + break; + + default: + enet_peer_queue_acknowledgement (peer, command, sentTime); + break; + } + } + } + +commandError: + if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE) + return 1; + + return 0; +} + +static int +enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event) +{ + int packets; + + for (packets = 0; packets < 256; ++ packets) + { + int receivedLength; + ENetBuffer buffer; + + buffer.data = host -> packetData [0]; + buffer.dataLength = sizeof (host -> packetData [0]); + + receivedLength = enet_socket_receive (host -> socket, + & host -> receivedAddress, + & buffer, + 1); + + if (receivedLength == -2) + continue; + + if (receivedLength < 0) + return -1; + + if (receivedLength == 0) + return 0; + + host -> receivedData = host -> packetData [0]; + host -> receivedDataLength = receivedLength; + + host -> totalReceivedData += receivedLength; + host -> totalReceivedPackets ++; + + if (host -> intercept != NULL) + { + switch (host -> intercept (host, event)) + { + case 1: + if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE) + return 1; + + continue; + + case -1: + return -1; + + default: + break; + } + } + + switch (enet_protocol_handle_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: + return -1; + + default: + break; + } + } + + return 0; +} + +static void +enet_protocol_send_acknowledgements (ENetHost * host, ENetPeer * peer) +{ + ENetProtocol * command = & host -> commands [host -> commandCount]; + ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; + ENetAcknowledgement * acknowledgement; + ENetListIterator currentAcknowledgement; + enet_uint16 reliableSequenceNumber; + + currentAcknowledgement = enet_list_begin (& peer -> acknowledgements); + + while (currentAcknowledgement != enet_list_end (& peer -> acknowledgements)) + { + if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || + buffer >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || + peer -> mtu - host -> packetSize < sizeof (ENetProtocolAcknowledge)) + { + peer -> flags |= ENET_PEER_FLAG_CONTINUE_SENDING; + + break; + } + + acknowledgement = (ENetAcknowledgement *) currentAcknowledgement; + + currentAcknowledgement = enet_list_next (currentAcknowledgement); + + buffer -> data = command; + buffer -> dataLength = sizeof (ENetProtocolAcknowledge); + + host -> packetSize += buffer -> dataLength; + + reliableSequenceNumber = ENET_HOST_TO_NET_16 (acknowledgement -> command.header.reliableSequenceNumber); + + command -> header.command = ENET_PROTOCOL_COMMAND_ACKNOWLEDGE; + command -> header.channelID = acknowledgement -> command.header.channelID; + command -> header.reliableSequenceNumber = reliableSequenceNumber; + command -> acknowledge.receivedReliableSequenceNumber = reliableSequenceNumber; + command -> acknowledge.receivedSentTime = ENET_HOST_TO_NET_16 (acknowledgement -> sentTime); + + if ((acknowledgement -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) + enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); + + enet_list_remove (& acknowledgement -> acknowledgementList); + enet_free (acknowledgement); + + ++ command; + ++ buffer; + } + + host -> commandCount = command - host -> commands; + host -> bufferCount = buffer - host -> buffers; +} + +static int +enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * event) +{ + ENetOutgoingCommand * outgoingCommand; + ENetListIterator currentCommand, insertPosition, insertSendReliablePosition; + + currentCommand = enet_list_begin (& peer -> sentReliableCommands); + insertPosition = enet_list_begin (& peer -> outgoingCommands); + insertSendReliablePosition = enet_list_begin (& peer -> outgoingSendReliableCommands); + + while (currentCommand != enet_list_end (& peer -> sentReliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + currentCommand = enet_list_next (currentCommand); + + if (ENET_TIME_DIFFERENCE (host -> serviceTime, outgoingCommand -> sentTime) < outgoingCommand -> roundTripTimeout) + continue; + + if (peer -> earliestTimeout == 0 || + ENET_TIME_LESS (outgoingCommand -> sentTime, peer -> earliestTimeout)) + peer -> earliestTimeout = outgoingCommand -> sentTime; + + if (peer -> earliestTimeout != 0 && + (ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= peer -> timeoutMaximum || + ((1 << (outgoingCommand -> sendAttempts - 1)) >= peer -> timeoutLimit && + ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= peer -> timeoutMinimum))) + { + enet_protocol_notify_disconnect (host, peer, event); + + return 1; + } + + ++ peer -> packetsLost; + + outgoingCommand -> roundTripTimeout *= 2; + + if (outgoingCommand -> packet != NULL) + { + peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength; + + enet_list_insert (insertSendReliablePosition, enet_list_remove (& outgoingCommand -> outgoingCommandList)); + } + else + enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList)); + + if (currentCommand == enet_list_begin (& peer -> sentReliableCommands) && + ! enet_list_empty (& peer -> sentReliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + peer -> nextTimeout = outgoingCommand -> sentTime + outgoingCommand -> roundTripTimeout; + } + } + + return 0; +} + +static int +enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer, ENetList * sentUnreliableCommands) +{ + ENetProtocol * command = & host -> commands [host -> commandCount]; + ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; + ENetOutgoingCommand * outgoingCommand; + ENetListIterator currentCommand, currentSendReliableCommand; + ENetChannel *channel = NULL; + enet_uint16 reliableWindow = 0; + size_t commandSize; + int windowWrap = 0, canPing = 1; + + currentCommand = enet_list_begin (& peer -> outgoingCommands); + currentSendReliableCommand = enet_list_begin (& peer -> outgoingSendReliableCommands); + + for (;;) + { + if (currentCommand != enet_list_end (& peer -> outgoingCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + if (currentSendReliableCommand != enet_list_end (& peer -> outgoingSendReliableCommands) && + ENET_TIME_LESS (((ENetOutgoingCommand *) currentSendReliableCommand) -> queueTime, outgoingCommand -> queueTime)) + goto useSendReliableCommand; + + currentCommand = enet_list_next (currentCommand); + } + else + if (currentSendReliableCommand != enet_list_end (& peer -> outgoingSendReliableCommands)) + { + useSendReliableCommand: + outgoingCommand = (ENetOutgoingCommand *) currentSendReliableCommand; + currentSendReliableCommand = enet_list_next (currentSendReliableCommand); + } + else + break; + + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) + { + channel = outgoingCommand -> command.header.channelID < peer -> channelCount ? & peer -> channels [outgoingCommand -> command.header.channelID] : NULL; + reliableWindow = outgoingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + if (channel != NULL) + { + if (windowWrap) + continue; + else + if (outgoingCommand -> sendAttempts < 1 && + ! (outgoingCommand -> reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) && + (channel -> reliableWindows [(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE || + channel -> usedReliableWindows & ((((1 << (ENET_PEER_FREE_RELIABLE_WINDOWS + 2)) - 1) << reliableWindow) | + (((1 << (ENET_PEER_FREE_RELIABLE_WINDOWS + 2)) - 1) >> (ENET_PEER_RELIABLE_WINDOWS - reliableWindow))))) + { + windowWrap = 1; + currentSendReliableCommand = enet_list_end (& peer -> outgoingSendReliableCommands); + + continue; + } + } + + if (outgoingCommand -> packet != NULL) + { + enet_uint32 windowSize = (peer -> packetThrottle * peer -> windowSize) / ENET_PEER_PACKET_THROTTLE_SCALE; + + if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > ENET_MAX (windowSize, peer -> mtu)) + { + currentSendReliableCommand = enet_list_end (& peer -> outgoingSendReliableCommands); + + continue; + } + } + + canPing = 0; + } + + commandSize = commandSizes [outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK]; + if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || + buffer + 1 >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || + peer -> mtu - host -> packetSize < commandSize || + (outgoingCommand -> packet != NULL && + (enet_uint16) (peer -> mtu - host -> packetSize) < (enet_uint16) (commandSize + outgoingCommand -> fragmentLength))) + { + peer -> flags |= ENET_PEER_FLAG_CONTINUE_SENDING; + + break; + } + + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) + { + if (channel != NULL && outgoingCommand -> sendAttempts < 1) + { + channel -> usedReliableWindows |= 1 << reliableWindow; + ++ channel -> reliableWindows [reliableWindow]; + } + + ++ outgoingCommand -> sendAttempts; + + if (outgoingCommand -> roundTripTimeout == 0) + outgoingCommand -> roundTripTimeout = peer -> roundTripTime + 4 * peer -> roundTripTimeVariance; + + if (enet_list_empty (& peer -> sentReliableCommands)) + peer -> nextTimeout = host -> serviceTime + outgoingCommand -> roundTripTimeout; + + enet_list_insert (enet_list_end (& peer -> sentReliableCommands), + enet_list_remove (& outgoingCommand -> outgoingCommandList)); + + outgoingCommand -> sentTime = host -> serviceTime; + + host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_SENT_TIME; + + peer -> reliableDataInTransit += outgoingCommand -> fragmentLength; + } + else + { + if (outgoingCommand -> packet != NULL && outgoingCommand -> fragmentOffset == 0) + { + peer -> packetThrottleCounter += ENET_PEER_PACKET_THROTTLE_COUNTER; + peer -> packetThrottleCounter %= ENET_PEER_PACKET_THROTTLE_SCALE; + + if (peer -> packetThrottleCounter > peer -> packetThrottle) + { + enet_uint16 reliableSequenceNumber = outgoingCommand -> reliableSequenceNumber, + unreliableSequenceNumber = outgoingCommand -> unreliableSequenceNumber; + for (;;) + { + -- outgoingCommand -> packet -> referenceCount; + + if (outgoingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (outgoingCommand -> packet); + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + enet_free (outgoingCommand); + + if (currentCommand == enet_list_end (& peer -> outgoingCommands)) + break; + + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + if (outgoingCommand -> reliableSequenceNumber != reliableSequenceNumber || + outgoingCommand -> unreliableSequenceNumber != unreliableSequenceNumber) + break; + + currentCommand = enet_list_next (currentCommand); + } + + continue; + } + } + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + + if (outgoingCommand -> packet != NULL) + enet_list_insert (enet_list_end (sentUnreliableCommands), outgoingCommand); + } + + buffer -> data = command; + buffer -> dataLength = commandSize; + + host -> packetSize += buffer -> dataLength; + + * command = outgoingCommand -> command; + + if (outgoingCommand -> packet != NULL) + { + ++ buffer; + + buffer -> data = outgoingCommand -> packet -> data + outgoingCommand -> fragmentOffset; + buffer -> dataLength = outgoingCommand -> fragmentLength; + + host -> packetSize += outgoingCommand -> fragmentLength; + } + else + if (! (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)) + enet_free (outgoingCommand); + + ++ peer -> packetsSent; + + ++ command; + ++ buffer; + } + + host -> commandCount = command - host -> commands; + host -> bufferCount = buffer - host -> buffers; + + if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER && + ! enet_peer_has_outgoing_commands (peer) && + enet_list_empty (sentUnreliableCommands)) + enet_peer_disconnect (peer, peer -> eventData); + + return canPing; +} + +static int +enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int checkForTimeouts) +{ + enet_uint8 headerData [sizeof (ENetProtocolHeader) + sizeof (enet_uint32)]; + ENetProtocolHeader * header = (ENetProtocolHeader *) headerData; + int sentLength = 0; + size_t shouldCompress = 0; + ENetList sentUnreliableCommands; + + enet_list_clear (& sentUnreliableCommands); + + for (int sendPass = 0, continueSending = 0; sendPass <= continueSending; ++ sendPass) + for (ENetPeer * currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED || + currentPeer -> state == ENET_PEER_STATE_ZOMBIE || + (sendPass > 0 && ! (currentPeer -> flags & ENET_PEER_FLAG_CONTINUE_SENDING))) + continue; + + currentPeer -> flags &= ~ ENET_PEER_FLAG_CONTINUE_SENDING; + + host -> headerFlags = 0; + host -> commandCount = 0; + host -> bufferCount = 1; + host -> packetSize = sizeof (ENetProtocolHeader); + + if (! enet_list_empty (& currentPeer -> acknowledgements)) + enet_protocol_send_acknowledgements (host, currentPeer); + + if (checkForTimeouts != 0 && + ! enet_list_empty (& currentPeer -> sentReliableCommands) && + ENET_TIME_GREATER_EQUAL (host -> serviceTime, currentPeer -> nextTimeout) && + enet_protocol_check_timeouts (host, currentPeer, event) == 1) + { + if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE) + return 1; + else + goto nextPeer; + } + + if (((enet_list_empty (& currentPeer -> outgoingCommands) && + enet_list_empty (& currentPeer -> outgoingSendReliableCommands)) || + enet_protocol_check_outgoing_commands (host, currentPeer, & sentUnreliableCommands)) && + enet_list_empty (& currentPeer -> sentReliableCommands) && + ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime) >= currentPeer -> pingInterval && + currentPeer -> mtu - host -> packetSize >= sizeof (ENetProtocolPing)) + { + enet_peer_ping (currentPeer); + enet_protocol_check_outgoing_commands (host, currentPeer, & sentUnreliableCommands); + } + + if (host -> commandCount == 0) + goto nextPeer; + + if (currentPeer -> packetLossEpoch == 0) + currentPeer -> packetLossEpoch = host -> serviceTime; + else + if (ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> packetLossEpoch) >= ENET_PEER_PACKET_LOSS_INTERVAL && + currentPeer -> packetsSent > 0) + { + enet_uint32 packetLoss = currentPeer -> packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer -> packetsSent; + +#ifdef ENET_DEBUG + printf ("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> roundTripTime, currentPeer -> roundTripTimeVariance, currentPeer -> packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size (& currentPeer -> outgoingCommands) + enet_list_size (& currentPeer -> outgoingSendReliableCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0); +#endif + + currentPeer -> packetLossVariance = (currentPeer -> packetLossVariance * 3 + ENET_DIFFERENCE (packetLoss, currentPeer -> packetLoss)) / 4; + currentPeer -> packetLoss = (currentPeer -> packetLoss * 7 + packetLoss) / 8; + + currentPeer -> packetLossEpoch = host -> serviceTime; + currentPeer -> packetsSent = 0; + currentPeer -> packetsLost = 0; + } + + host -> buffers -> data = headerData; + if (host -> headerFlags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME) + { + header -> sentTime = ENET_HOST_TO_NET_16 (host -> serviceTime & 0xFFFF); + + host -> buffers -> dataLength = sizeof (ENetProtocolHeader); + } + else + host -> buffers -> dataLength = (size_t) & ((ENetProtocolHeader *) 0) -> sentTime; + + shouldCompress = 0; + if (host -> compressor.context != NULL && host -> compressor.compress != NULL) + { + size_t originalSize = host -> packetSize - sizeof(ENetProtocolHeader), + compressedSize = host -> compressor.compress (host -> compressor.context, + & host -> buffers [1], host -> bufferCount - 1, + originalSize, + host -> packetData [1], + originalSize); + if (compressedSize > 0 && compressedSize < originalSize) + { + host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED; + shouldCompress = compressedSize; +#ifdef ENET_DEBUG_COMPRESS + printf ("peer %u: compressed %u -> %u (%u%%)\n", currentPeer -> incomingPeerID, originalSize, compressedSize, (compressedSize * 100) / originalSize); +#endif + } + } + + if (currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID) + host -> headerFlags |= currentPeer -> outgoingSessionID << ENET_PROTOCOL_HEADER_SESSION_SHIFT; + header -> peerID = ENET_HOST_TO_NET_16 (currentPeer -> outgoingPeerID | host -> headerFlags); + if (host -> checksum != NULL) + { + enet_uint32 * checksum = (enet_uint32 *) & headerData [host -> buffers -> dataLength]; + enet_uint32 newChecksum = currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer -> connectID : 0; + /* Checksum may be unaligned, use memcpy to avoid undefined behaviour. */ + memcpy(checksum, & newChecksum, sizeof (enet_uint32)); + host -> buffers -> dataLength += sizeof (enet_uint32); + newChecksum = host -> checksum (host -> buffers, host -> bufferCount); + memcpy(checksum, & newChecksum, sizeof (enet_uint32)); + } + + if (shouldCompress > 0) + { + host -> buffers [1].data = host -> packetData [1]; + host -> buffers [1].dataLength = shouldCompress; + host -> bufferCount = 2; + } + + currentPeer -> lastSendTime = host -> serviceTime; + + sentLength = enet_socket_send (host -> socket, & currentPeer -> address, host -> buffers, host -> bufferCount); + + enet_protocol_remove_sent_unreliable_commands (currentPeer, & sentUnreliableCommands); + + if (sentLength < 0) + return -1; + + host -> totalSentData += sentLength; + host -> totalSentPackets ++; + + nextPeer: + if (currentPeer -> flags & ENET_PEER_FLAG_CONTINUE_SENDING) + continueSending = sendPass + 1; + } + + return 0; +} + +/** Sends any queued packets on the host specified to its designated peers. + + @param host host to flush + @remarks this function need only be used in circumstances where one wishes to send queued packets earlier than in a call to enet_host_service(). + @ingroup host +*/ +void +enet_host_flush (ENetHost * host) +{ + host -> serviceTime = enet_time_get (); + + enet_protocol_send_outgoing_commands (host, NULL, 0); +} + +/** Checks for any queued events on the host and dispatches one if available. + + @param host host to check for events + @param event an event structure where event details will be placed if available + @retval > 0 if an event was dispatched + @retval 0 if no events are available + @retval < 0 on failure + @ingroup host +*/ +int +enet_host_check_events (ENetHost * host, ENetEvent * event) +{ + if (event == NULL) return -1; + + event -> type = ENET_EVENT_TYPE_NONE; + event -> peer = NULL; + event -> packet = NULL; + + return enet_protocol_dispatch_incoming_commands (host, event); +} + +/** Waits for events on the host specified and shuttles packets between + the host and its peers. + + @param host host to service + @param event an event structure where event details will be placed if one occurs + if event == NULL then no events will be delivered + @param timeout number of milliseconds that ENet should wait for events + @retval > 0 if an event occurred within the specified time limit + @retval 0 if no event occurred + @retval < 0 on failure + @remarks enet_host_service should be called fairly regularly for adequate performance + @ingroup host +*/ +int +enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout) +{ + enet_uint32 waitCondition; + + if (event != NULL) + { + event -> type = ENET_EVENT_TYPE_NONE; + event -> peer = NULL; + event -> packet = NULL; + + switch (enet_protocol_dispatch_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: +#ifdef ENET_DEBUG + perror ("Error dispatching incoming packets"); +#endif + + return -1; + + default: + break; + } + } + + host -> serviceTime = enet_time_get (); + + timeout += host -> serviceTime; + + do + { + if (ENET_TIME_DIFFERENCE (host -> serviceTime, host -> bandwidthThrottleEpoch) >= ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) + enet_host_bandwidth_throttle (host); + + switch (enet_protocol_send_outgoing_commands (host, event, 1)) + { + case 1: + return 1; + + case -1: +#ifdef ENET_DEBUG + perror ("Error sending outgoing packets"); +#endif + + return -1; + + default: + break; + } + + switch (enet_protocol_receive_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: +#ifdef ENET_DEBUG + perror ("Error receiving incoming packets"); +#endif + + return -1; + + default: + break; + } + + switch (enet_protocol_send_outgoing_commands (host, event, 1)) + { + case 1: + return 1; + + case -1: +#ifdef ENET_DEBUG + perror ("Error sending outgoing packets"); +#endif + + return -1; + + default: + break; + } + + if (event != NULL) + { + switch (enet_protocol_dispatch_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: +#ifdef ENET_DEBUG + perror ("Error dispatching incoming packets"); +#endif + + return -1; + + default: + break; + } + } + + if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout)) + return 0; + + do + { + host -> serviceTime = enet_time_get (); + + if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout)) + return 0; + + waitCondition = ENET_SOCKET_WAIT_RECEIVE | ENET_SOCKET_WAIT_INTERRUPT; + + if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0) + return -1; + } + while (waitCondition & ENET_SOCKET_WAIT_INTERRUPT); + + host -> serviceTime = enet_time_get (); + } while (waitCondition & ENET_SOCKET_WAIT_RECEIVE); + + return 0; +} + diff --git a/Deer/vendor/enet/unix.c b/Deer/vendor/enet/unix.c new file mode 100644 index 0000000..6669216 --- /dev/null +++ b/Deer/vendor/enet/unix.c @@ -0,0 +1,624 @@ +/** + @file unix.c + @brief ENet Unix system specific functions +*/ +#ifndef _WIN32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +#ifdef __APPLE__ +#ifdef HAS_POLL +#undef HAS_POLL +#endif +#ifndef HAS_FCNTL +#define HAS_FCNTL 1 +#endif +#ifndef HAS_INET_PTON +#define HAS_INET_PTON 1 +#endif +#ifndef HAS_INET_NTOP +#define HAS_INET_NTOP 1 +#endif +#ifndef HAS_MSGHDR_FLAGS +#define HAS_MSGHDR_FLAGS 1 +#endif +#ifndef HAS_SOCKLEN_T +#define HAS_SOCKLEN_T 1 +#endif +#ifndef HAS_GETADDRINFO +#define HAS_GETADDRINFO 1 +#endif +#ifndef HAS_GETNAMEINFO +#define HAS_GETNAMEINFO 1 +#endif +#endif + +#ifdef HAS_FCNTL +#include +#endif + +#ifdef HAS_POLL +#include +#endif + +#if !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined) +typedef int socklen_t; +#endif + +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +static enet_uint32 timeBase = 0; + +int +enet_initialize (void) +{ + return 0; +} + +void +enet_deinitialize (void) +{ +} + +enet_uint32 +enet_host_random_seed (void) +{ + return (enet_uint32) time (NULL); +} + +enet_uint32 +enet_time_get (void) +{ + struct timeval timeVal; + + gettimeofday (& timeVal, NULL); + + return timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - timeBase; +} + +void +enet_time_set (enet_uint32 newTimeBase) +{ + struct timeval timeVal; + + gettimeofday (& timeVal, NULL); + + timeBase = timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - newTimeBase; +} + +int +enet_address_set_host_ip (ENetAddress * address, const char * name) +{ +#ifdef HAS_INET_PTON + if (! inet_pton (AF_INET, name, & address -> host)) +#else + if (! inet_aton (name, (struct in_addr *) & address -> host)) +#endif + return -1; + + return 0; +} + +int +enet_address_set_host (ENetAddress * address, const char * name) +{ +#ifdef HAS_GETADDRINFO + struct addrinfo hints, * resultList = NULL, * result = NULL; + + memset (& hints, 0, sizeof (hints)); + hints.ai_family = AF_INET; + + if (getaddrinfo (name, NULL, NULL, & resultList) != 0) + return -1; + + for (result = resultList; result != NULL; result = result -> ai_next) + { + if (result -> ai_family == AF_INET && result -> ai_addr != NULL && result -> ai_addrlen >= sizeof (struct sockaddr_in)) + { + struct sockaddr_in * sin = (struct sockaddr_in *) result -> ai_addr; + + address -> host = sin -> sin_addr.s_addr; + + freeaddrinfo (resultList); + + return 0; + } + } + + if (resultList != NULL) + freeaddrinfo (resultList); +#else + struct hostent * hostEntry = NULL; +#ifdef HAS_GETHOSTBYNAME_R + struct hostent hostData; + char buffer [2048]; + int errnum; + +#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__GNU__) + gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); +#else + hostEntry = gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & errnum); +#endif +#else + hostEntry = gethostbyname (name); +#endif + + if (hostEntry != NULL && hostEntry -> h_addrtype == AF_INET) + { + address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0]; + + return 0; + } +#endif + + return enet_address_set_host_ip (address, name); +} + +int +enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) +{ +#ifdef HAS_INET_NTOP + if (inet_ntop (AF_INET, & address -> host, name, nameLength) == NULL) +#else + char * addr = inet_ntoa (* (struct in_addr *) & address -> host); + if (addr != NULL) + { + size_t addrLen = strlen(addr); + if (addrLen >= nameLength) + return -1; + memcpy (name, addr, addrLen + 1); + } + else +#endif + return -1; + return 0; +} + +int +enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) +{ +#ifdef HAS_GETNAMEINFO + struct sockaddr_in sin; + int err; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + err = getnameinfo ((struct sockaddr *) & sin, sizeof (sin), name, nameLength, NULL, 0, NI_NAMEREQD); + if (! err) + { + if (name != NULL && nameLength > 0 && ! memchr (name, '\0', nameLength)) + return -1; + return 0; + } + if (err != EAI_NONAME) + return -1; +#else + struct in_addr in; + struct hostent * hostEntry = NULL; +#ifdef HAS_GETHOSTBYADDR_R + struct hostent hostData; + char buffer [2048]; + int errnum; + + in.s_addr = address -> host; + +#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__GNU__) + gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); +#else + hostEntry = gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & errnum); +#endif +#else + in.s_addr = address -> host; + + hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); +#endif + + if (hostEntry != NULL) + { + size_t hostLen = strlen (hostEntry -> h_name); + if (hostLen >= nameLength) + return -1; + memcpy (name, hostEntry -> h_name, hostLen + 1); + return 0; + } +#endif + + return enet_address_get_host_ip (address, name, nameLength); +} + +int +enet_socket_bind (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + + if (address != NULL) + { + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + else + { + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + } + + return bind (socket, + (struct sockaddr *) & sin, + sizeof (struct sockaddr_in)); +} + +int +enet_socket_get_address (ENetSocket socket, ENetAddress * address) +{ + struct sockaddr_in sin; + socklen_t sinLength = sizeof (struct sockaddr_in); + + if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1) + return -1; + + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + + return 0; +} + +int +enet_socket_listen (ENetSocket socket, int backlog) +{ + return listen (socket, backlog < 0 ? SOMAXCONN : backlog); +} + +ENetSocket +enet_socket_create (ENetSocketType type) +{ + return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); +} + +int +enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) +{ + int result = -1; + switch (option) + { + case ENET_SOCKOPT_NONBLOCK: +#ifdef HAS_FCNTL + result = fcntl (socket, F_SETFL, (value ? O_NONBLOCK : 0) | (fcntl (socket, F_GETFL) & ~O_NONBLOCK)); +#else + result = ioctl (socket, FIONBIO, & value); +#endif + break; + + case ENET_SOCKOPT_BROADCAST: + result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_REUSEADDR: + result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_RCVBUF: + result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_SNDBUF: + result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_RCVTIMEO: + { + struct timeval timeVal; + timeVal.tv_sec = value / 1000; + timeVal.tv_usec = (value % 1000) * 1000; + result = setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) & timeVal, sizeof (struct timeval)); + break; + } + + case ENET_SOCKOPT_SNDTIMEO: + { + struct timeval timeVal; + timeVal.tv_sec = value / 1000; + timeVal.tv_usec = (value % 1000) * 1000; + result = setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO, (char *) & timeVal, sizeof (struct timeval)); + break; + } + + case ENET_SOCKOPT_NODELAY: + result = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_TTL: + result = setsockopt (socket, IPPROTO_IP, IP_TTL, (char *) & value, sizeof (int)); + break; + + default: + break; + } + return result == -1 ? -1 : 0; +} + +int +enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value) +{ + int result = -1; + socklen_t len; + switch (option) + { + case ENET_SOCKOPT_ERROR: + len = sizeof (int); + result = getsockopt (socket, SOL_SOCKET, SO_ERROR, value, & len); + break; + + case ENET_SOCKOPT_TTL: + len = sizeof (int); + result = getsockopt (socket, IPPROTO_IP, IP_TTL, (char *) value, & len); + break; + + default: + break; + } + return result == -1 ? -1 : 0; +} + +int +enet_socket_connect (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + int result; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)); + if (result == -1 && errno == EINPROGRESS) + return 0; + + return result; +} + +ENetSocket +enet_socket_accept (ENetSocket socket, ENetAddress * address) +{ + int result; + struct sockaddr_in sin; + socklen_t sinLength = sizeof (struct sockaddr_in); + + result = accept (socket, + address != NULL ? (struct sockaddr *) & sin : NULL, + address != NULL ? & sinLength : NULL); + + if (result == -1) + return ENET_SOCKET_NULL; + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return result; +} + +int +enet_socket_shutdown (ENetSocket socket, ENetSocketShutdown how) +{ + return shutdown (socket, (int) how); +} + +void +enet_socket_destroy (ENetSocket socket) +{ + if (socket != -1) + close (socket); +} + +int +enet_socket_send (ENetSocket socket, + const ENetAddress * address, + const ENetBuffer * buffers, + size_t bufferCount) +{ + struct msghdr msgHdr; + struct sockaddr_in sin; + int sentLength; + + memset (& msgHdr, 0, sizeof (struct msghdr)); + + if (address != NULL) + { + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + msgHdr.msg_name = & sin; + msgHdr.msg_namelen = sizeof (struct sockaddr_in); + } + + msgHdr.msg_iov = (struct iovec *) buffers; + msgHdr.msg_iovlen = bufferCount; + + sentLength = sendmsg (socket, & msgHdr, MSG_NOSIGNAL); + + if (sentLength == -1) + { + if (errno == EWOULDBLOCK) + return 0; + + return -1; + } + + return sentLength; +} + +int +enet_socket_receive (ENetSocket socket, + ENetAddress * address, + ENetBuffer * buffers, + size_t bufferCount) +{ + struct msghdr msgHdr; + struct sockaddr_in sin; + int recvLength; + + memset (& msgHdr, 0, sizeof (struct msghdr)); + + if (address != NULL) + { + msgHdr.msg_name = & sin; + msgHdr.msg_namelen = sizeof (struct sockaddr_in); + } + + msgHdr.msg_iov = (struct iovec *) buffers; + msgHdr.msg_iovlen = bufferCount; + + recvLength = recvmsg (socket, & msgHdr, MSG_NOSIGNAL); + + if (recvLength == -1) + { + if (errno == EWOULDBLOCK) + return 0; + + return -1; + } + +#ifdef HAS_MSGHDR_FLAGS + if (msgHdr.msg_flags & MSG_TRUNC) + return -2; +#endif + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return recvLength; +} + +int +enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout) +{ + struct timeval timeVal; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal); +} + +int +enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout) +{ +#ifdef HAS_POLL + struct pollfd pollSocket; + int pollCount; + + pollSocket.fd = socket; + pollSocket.events = 0; + + if (* condition & ENET_SOCKET_WAIT_SEND) + pollSocket.events |= POLLOUT; + + if (* condition & ENET_SOCKET_WAIT_RECEIVE) + pollSocket.events |= POLLIN; + + pollCount = poll (& pollSocket, 1, timeout); + + if (pollCount < 0) + { + if (errno == EINTR && * condition & ENET_SOCKET_WAIT_INTERRUPT) + { + * condition = ENET_SOCKET_WAIT_INTERRUPT; + + return 0; + } + + return -1; + } + + * condition = ENET_SOCKET_WAIT_NONE; + + if (pollCount == 0) + return 0; + + if (pollSocket.revents & POLLOUT) + * condition |= ENET_SOCKET_WAIT_SEND; + + if (pollSocket.revents & POLLIN) + * condition |= ENET_SOCKET_WAIT_RECEIVE; + + return 0; +#else + fd_set readSet, writeSet; + struct timeval timeVal; + int selectCount; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + FD_ZERO (& readSet); + FD_ZERO (& writeSet); + + if (* condition & ENET_SOCKET_WAIT_SEND) + FD_SET (socket, & writeSet); + + if (* condition & ENET_SOCKET_WAIT_RECEIVE) + FD_SET (socket, & readSet); + + selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal); + + if (selectCount < 0) + { + if (errno == EINTR && * condition & ENET_SOCKET_WAIT_INTERRUPT) + { + * condition = ENET_SOCKET_WAIT_INTERRUPT; + + return 0; + } + + return -1; + } + + * condition = ENET_SOCKET_WAIT_NONE; + + if (selectCount == 0) + return 0; + + if (FD_ISSET (socket, & writeSet)) + * condition |= ENET_SOCKET_WAIT_SEND; + + if (FD_ISSET (socket, & readSet)) + * condition |= ENET_SOCKET_WAIT_RECEIVE; + + return 0; +#endif +} + +#endif + diff --git a/Deer/vendor/enet/win32.c b/Deer/vendor/enet/win32.c new file mode 100644 index 0000000..f395c09 --- /dev/null +++ b/Deer/vendor/enet/win32.c @@ -0,0 +1,454 @@ +/** + @file win32.c + @brief ENet Win32 system specific functions +*/ +#ifdef _WIN32 + +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" +#include +#include +#include + +static enet_uint32 timeBase = 0; + +int +enet_initialize (void) +{ + WORD versionRequested = MAKEWORD (1, 1); + WSADATA wsaData; + + if (WSAStartup (versionRequested, & wsaData)) + return -1; + + if (LOBYTE (wsaData.wVersion) != 1|| + HIBYTE (wsaData.wVersion) != 1) + { + WSACleanup (); + + return -1; + } + + timeBeginPeriod (1); + + return 0; +} + +void +enet_deinitialize (void) +{ + timeEndPeriod (1); + + WSACleanup (); +} + +enet_uint32 +enet_host_random_seed (void) +{ + return (enet_uint32) timeGetTime (); +} + +enet_uint32 +enet_time_get (void) +{ + return (enet_uint32) timeGetTime () - timeBase; +} + +void +enet_time_set (enet_uint32 newTimeBase) +{ + timeBase = (enet_uint32) timeGetTime () - newTimeBase; +} + +int +enet_address_set_host_ip (ENetAddress * address, const char * name) +{ + enet_uint8 vals [4] = { 0, 0, 0, 0 }; + int i; + + for (i = 0; i < 4; ++ i) + { + const char * next = name + 1; + if (* name != '0') + { + long val = strtol (name, (char **) & next, 10); + if (val < 0 || val > 255 || next == name || next - name > 3) + return -1; + vals [i] = (enet_uint8) val; + } + + if (* next != (i < 3 ? '.' : '\0')) + return -1; + name = next + 1; + } + + memcpy (& address -> host, vals, sizeof (enet_uint32)); + return 0; +} + +int +enet_address_set_host (ENetAddress * address, const char * name) +{ + struct hostent * hostEntry; + + hostEntry = gethostbyname (name); + if (hostEntry == NULL || + hostEntry -> h_addrtype != AF_INET) + return enet_address_set_host_ip (address, name); + + address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0]; + + return 0; +} + +int +enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) +{ + char * addr = inet_ntoa (* (struct in_addr *) & address -> host); + if (addr == NULL) + return -1; + else + { + size_t addrLen = strlen(addr); + if (addrLen >= nameLength) + return -1; + memcpy (name, addr, addrLen + 1); + } + return 0; +} + +int +enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) +{ + struct in_addr in; + struct hostent * hostEntry; + + in.s_addr = address -> host; + + hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); + if (hostEntry == NULL) + return enet_address_get_host_ip (address, name, nameLength); + else + { + size_t hostLen = strlen (hostEntry -> h_name); + if (hostLen >= nameLength) + return -1; + memcpy (name, hostEntry -> h_name, hostLen + 1); + } + + return 0; +} + +int +enet_socket_bind (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + + if (address != NULL) + { + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + else + { + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + } + + return bind (socket, + (struct sockaddr *) & sin, + sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0; +} + +int +enet_socket_get_address (ENetSocket socket, ENetAddress * address) +{ + struct sockaddr_in sin; + int sinLength = sizeof (struct sockaddr_in); + + if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1) + return -1; + + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + + return 0; +} + +int +enet_socket_listen (ENetSocket socket, int backlog) +{ + return listen (socket, backlog < 0 ? SOMAXCONN : backlog) == SOCKET_ERROR ? -1 : 0; +} + +ENetSocket +enet_socket_create (ENetSocketType type) +{ + return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); +} + +int +enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) +{ + int result = SOCKET_ERROR; + switch (option) + { + case ENET_SOCKOPT_NONBLOCK: + { + u_long nonBlocking = (u_long) value; + result = ioctlsocket (socket, FIONBIO, & nonBlocking); + break; + } + + case ENET_SOCKOPT_BROADCAST: + result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_REUSEADDR: + result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_RCVBUF: + result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_SNDBUF: + result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_RCVTIMEO: + result = setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_SNDTIMEO: + result = setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_NODELAY: + result = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_TTL: + result = setsockopt (socket, IPPROTO_IP, IP_TTL, (char *) & value, sizeof (int)); + break; + + default: + break; + } + return result == SOCKET_ERROR ? -1 : 0; +} + +int +enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value) +{ + int result = SOCKET_ERROR, len; + switch (option) + { + case ENET_SOCKOPT_ERROR: + len = sizeof(int); + result = getsockopt (socket, SOL_SOCKET, SO_ERROR, (char *) value, & len); + break; + + case ENET_SOCKOPT_TTL: + len = sizeof(int); + result = getsockopt (socket, IPPROTO_IP, IP_TTL, (char *) value, & len); + break; + + default: + break; + } + return result == SOCKET_ERROR ? -1 : 0; +} + +int +enet_socket_connect (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + int result; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)); + if (result == SOCKET_ERROR && WSAGetLastError () != WSAEWOULDBLOCK) + return -1; + + return 0; +} + +ENetSocket +enet_socket_accept (ENetSocket socket, ENetAddress * address) +{ + SOCKET result; + struct sockaddr_in sin; + int sinLength = sizeof (struct sockaddr_in); + + result = accept (socket, + address != NULL ? (struct sockaddr *) & sin : NULL, + address != NULL ? & sinLength : NULL); + + if (result == INVALID_SOCKET) + return ENET_SOCKET_NULL; + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return result; +} + +int +enet_socket_shutdown (ENetSocket socket, ENetSocketShutdown how) +{ + return shutdown (socket, (int) how) == SOCKET_ERROR ? -1 : 0; +} + +void +enet_socket_destroy (ENetSocket socket) +{ + if (socket != INVALID_SOCKET) + closesocket (socket); +} + +int +enet_socket_send (ENetSocket socket, + const ENetAddress * address, + const ENetBuffer * buffers, + size_t bufferCount) +{ + struct sockaddr_in sin; + DWORD sentLength = 0; + + if (address != NULL) + { + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + + if (WSASendTo (socket, + (LPWSABUF) buffers, + (DWORD) bufferCount, + & sentLength, + 0, + address != NULL ? (struct sockaddr *) & sin : NULL, + address != NULL ? sizeof (struct sockaddr_in) : 0, + NULL, + NULL) == SOCKET_ERROR) + { + if (WSAGetLastError () == WSAEWOULDBLOCK) + return 0; + + return -1; + } + + return (int) sentLength; +} + +int +enet_socket_receive (ENetSocket socket, + ENetAddress * address, + ENetBuffer * buffers, + size_t bufferCount) +{ + INT sinLength = sizeof (struct sockaddr_in); + DWORD flags = 0, + recvLength = 0; + struct sockaddr_in sin; + + if (WSARecvFrom (socket, + (LPWSABUF) buffers, + (DWORD) bufferCount, + & recvLength, + & flags, + address != NULL ? (struct sockaddr *) & sin : NULL, + address != NULL ? & sinLength : NULL, + NULL, + NULL) == SOCKET_ERROR) + { + switch (WSAGetLastError ()) + { + case WSAEWOULDBLOCK: + case WSAECONNRESET: + return 0; + case WSAEMSGSIZE: + return -2; + } + + return -1; + } + + if (flags & MSG_PARTIAL) + return -2; + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return (int) recvLength; +} + +int +enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout) +{ + struct timeval timeVal; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal); +} + +int +enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout) +{ + fd_set readSet, writeSet; + struct timeval timeVal; + int selectCount; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + FD_ZERO (& readSet); + FD_ZERO (& writeSet); + + if (* condition & ENET_SOCKET_WAIT_SEND) + FD_SET (socket, & writeSet); + + if (* condition & ENET_SOCKET_WAIT_RECEIVE) + FD_SET (socket, & readSet); + + selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal); + + if (selectCount < 0) + return -1; + + * condition = ENET_SOCKET_WAIT_NONE; + + if (selectCount == 0) + return 0; + + if (FD_ISSET (socket, & writeSet)) + * condition |= ENET_SOCKET_WAIT_SEND; + + if (FD_ISSET (socket, & readSet)) + * condition |= ENET_SOCKET_WAIT_RECEIVE; + + return 0; +} + +#endif + diff --git a/DeerStudio/Build.lua b/DeerStudio/Build.lua index 0e100e9..8e92aaa 100755 --- a/DeerStudio/Build.lua +++ b/DeerStudio/Build.lua @@ -6,6 +6,7 @@ project "DeerStudio" staticruntime "off" debugdir ".." + exceptionhandling "On" files { "src/**.h", "src/**.cpp", "vendor/stb/stb_image.cpp" } diff --git a/DeerStudio/headers/DeerStudio/AngelScriptEngine.h b/DeerStudio/headers/DeerStudio/AngelScriptEngine.h index 901d91e..3c6c85f 100644 --- a/DeerStudio/headers/DeerStudio/AngelScriptEngine.h +++ b/DeerStudio/headers/DeerStudio/AngelScriptEngine.h @@ -115,6 +115,7 @@ namespace Deer { void shutdown(); void extract(asIScriptModule*); + void generatePredefined(); void updateTypes(); inline void invalidate() { state = ModuleState::ExecutionError; } diff --git a/DeerStudio/src/DeerStudio/AngelScriptEngine/ErrorHandle.cpp b/DeerStudio/src/DeerStudio/AngelScriptEngine/ErrorHandle.cpp index 54941e3..dea0dad 100644 --- a/DeerStudio/src/DeerStudio/AngelScriptEngine/ErrorHandle.cpp +++ b/DeerStudio/src/DeerStudio/AngelScriptEngine/ErrorHandle.cpp @@ -53,7 +53,7 @@ namespace Deer { } } - bool AngelScriptEngine::ImplementsInterface(asITypeInfo* type, asITypeInfo* iface) { + bool ImplementsInterface(asITypeInfo* type, asITypeInfo* iface) { for (uint32_t i = 0; i < type->GetInterfaceCount(); i++) { if (type->GetInterface(i) == iface) return true; diff --git a/DeerStudio/src/DeerStudio/AngelScriptEngine/ModuleLoading.cpp b/DeerStudio/src/DeerStudio/AngelScriptEngine/ModuleLoading.cpp index c24ccb4..17e2182 100644 --- a/DeerStudio/src/DeerStudio/AngelScriptEngine/ModuleLoading.cpp +++ b/DeerStudio/src/DeerStudio/AngelScriptEngine/ModuleLoading.cpp @@ -47,7 +47,7 @@ namespace Deer { if (module.state != ModuleState::NotBuilt) return false; - int err; + int err = 0; module.state = ModuleState::Building; for (const std::string& dependency : module.moduleInfo.module_requires) { @@ -83,7 +83,7 @@ namespace Deer { } DEER_CORE_TRACE("Loading module {}", module.moduleInfo.moduleName); - scriptBuilder.StartNewModule(scriptEngine, module.moduleInfo.moduleName.c_str()); + err = scriptBuilder.StartNewModule(scriptEngine, module.moduleInfo.moduleName.c_str()); if (err < 0) { DEER_EDITOR_ENGINE_ERROR("Failed to init module for {0}", module.moduleInfo.moduleName.c_str()); module.state = ModuleState::CompilationFailed; @@ -149,8 +149,8 @@ namespace Deer { DEER_CORE_ERROR("Module description missing 'name' field: {}", path.string().c_str()); return; } - } catch (const std::exception& e) { - DEER_CORE_ERROR("Module description missing 'name' field: {}", path.string().c_str()); + } catch (const cereal::RapidJSONException& e) { + DEER_CORE_ERROR("Module description format error : {}, {}", path.string().c_str(), e.what()); return; } @@ -184,9 +184,8 @@ namespace Deer { for (Module& module : modules) { if (module.state == ModuleState::NotBuilt) { loadModule(module); - generateAngelscriptPredefined(); } - saveAngelscriptPredefined(module.moduleInfo.modulePath); + module.generatePredefined(); } for (Module& module : modules) { diff --git a/DeerStudio/src/DeerStudio/AngelScriptEngine/PredefinedAngelScript.cpp b/DeerStudio/src/DeerStudio/AngelScriptEngine/ModulePredefinedGenerator.cpp similarity index 83% rename from DeerStudio/src/DeerStudio/AngelScriptEngine/PredefinedAngelScript.cpp rename to DeerStudio/src/DeerStudio/AngelScriptEngine/ModulePredefinedGenerator.cpp index 32f5674..9a773c2 100644 --- a/DeerStudio/src/DeerStudio/AngelScriptEngine/PredefinedAngelScript.cpp +++ b/DeerStudio/src/DeerStudio/AngelScriptEngine/ModulePredefinedGenerator.cpp @@ -1,9 +1,3 @@ - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// THIS FILE IS A MODIFIED VERSION -// https://github.com/sashi0034/angel-lsp/blob/main/examples/OpenSiv3D/make_predefined.cpp -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - #include "DeerRender/Log.h" #include "DeerStudio/AngelScriptEngine.h" #include "angelscript.h" @@ -207,15 +201,29 @@ void printClassTypeList(const asIScriptEngine& engine) { void printGlobalFunctionList(const asIScriptEngine& engine) { for (int i = 0; i < engine.GetGlobalFunctionCount(); ++i) { const auto f = engine.GetGlobalFunctionByIndex(i); - if (!f) - continue; std::string_view ns = f->GetNamespace(); if (!ns.empty()) stream << "namespace " << ns << " { "; - stream << f->GetDeclaration(false, false, true) << ";"; + int methodReturnId = f->GetReturnTypeId(); + if (methodReturnId == -1) { + stream << "? "; + } else { + stream << f->GetEngine()->GetTypeDeclaration(methodReturnId) << " "; + } + + stream << f->GetName() << "("; + + writeParameters(f); + stream << ")"; + + // stream << "\t" << m->GetDeclaration(false, false, true); + + if (f->IsProperty()) + stream << " property"; + stream << ";"; if (!ns.empty()) - stream << " }"; + stream << "\t}"; stream << "\n"; } } @@ -259,36 +267,26 @@ void printGlobalTypedef(const asIScriptEngine& engine) { } } -void printAngelInfo(const asIScriptEngine& engine) { - printFuncList(engine); - - printEnumList(engine); - - printClassTypeList(engine); - - printGlobalFunctionList(engine); - - printGlobalPropertyList(engine); - - printGlobalTypedef(engine); -} - namespace Deer { - void AngelScriptEngine::generateAngelscriptPredefined() { - stream.clear(); - stream << "//This file was generated automatically\n"; + namespace AngelScriptEngine { + void Module::generatePredefined() { + stream.clear(); + stream.str(""); + str.clear(); + stream << "// This file is autogenerated"; - printAngelInfo(*Deer::AngelScriptEngine::scriptEngine); + printFuncList(*scriptEngine); + printEnumList(*scriptEngine); + printClassTypeList(*scriptEngine); + printGlobalFunctionList(*scriptEngine); + printGlobalPropertyList(*scriptEngine); + printGlobalTypedef(*scriptEngine); - str = stream.str(); - } - - void AngelScriptEngine::saveAngelscriptPredefined(const Path& path) { - Deer::Path filePath = path / "as.predefined"; - - std::ofstream file(filePath, std::ios::out | std::ios::binary); - file.write(reinterpret_cast(str.c_str()), str.size()); - - file.close(); - } + Path path = Path(moduleInfo.modulePath) / "as.predefined"; + std::ofstream predefinedFile(path); + std::string info = stream.str(); + predefinedFile.write(info.c_str(), info.size()); + predefinedFile.close(); + } + } // namespace AngelScriptEngine } // namespace Deer \ No newline at end of file diff --git a/DeerStudio/src/DeerStudio/DeerStudio.cpp b/DeerStudio/src/DeerStudio/DeerStudio.cpp index a1cb159..ef5559c 100644 --- a/DeerStudio/src/DeerStudio/DeerStudio.cpp +++ b/DeerStudio/src/DeerStudio/DeerStudio.cpp @@ -4,11 +4,8 @@ #include "DeerRender/DataStore.h" #include "DeerRender/Scene.h" #include "DeerRender/Tools/Path.h" -#include "DeerRender/Voxel.h" -#include "DeerRender/VoxelWorld.h" #include "DeerRender/Application.h" -#include "DeerRender/GizmoRenderer.h" // TMP #include "DeerRender/Mesh.h" @@ -19,8 +16,6 @@ #include "DeerStudio/StudioAPI/UI.h" -int main(int argc, char** args) { Deer::DeerStudio::main(); } - namespace Deer { namespace DeerStudio { void main() { @@ -36,6 +31,7 @@ namespace Deer { SetupImGuiStyle(); AngelScriptEngine::initialize(); + RenderUtils::initializeRenderUtils(); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20, 20)); @@ -46,15 +42,16 @@ namespace Deer { Application::run(); AngelScriptEngine::deinitialize(); + RenderUtils::deinitializeRenderUtils(); + + Scene::clear(); + Application::shutdownWindow(); Log::shutdown(); } void onUpdate() { AngelScriptEngine::update(); - - if (VoxelWorld::isInitialized()) - VoxelWorld::bakeNextChunk(); } void onRender() { @@ -106,14 +103,10 @@ namespace Deer { // viewport_onImGui(); AngelScriptEngine::render(); - - Scene::gizmoRenderer.refresh(); ImGui::End(); } void onEvent(Event& e) { - // viewport_onEvent(e); - EventDispatcher ed(e); ed.dispatch(onWindowCloseEvent); @@ -124,4 +117,6 @@ namespace Deer { return true; } } // namespace DeerStudio -} // namespace Deer \ No newline at end of file +} // namespace Deer + +int main(int argc, char** args) { Deer::DeerStudio::main(); } diff --git a/DeerStudioServer/Build.lua b/DeerStudioServer/Build.lua new file mode 100755 index 0000000..d761a04 --- /dev/null +++ b/DeerStudioServer/Build.lua @@ -0,0 +1,67 @@ +project "DeerStudioServer" + kind "ConsoleApp" + language "C++" + cppdialect "C++20" + + staticruntime "off" + + debugdir ".." + + files { "src/**.h", "src/**.cpp" } + + includedirs + { + "src", + "../Deer/Include", + "../Deer/vendor/spdlog/include", + "../Deer/vendor/glm", + "../Deer/vendor/entt/include", + "../Deer/vendor/angelScript/include", + "../Deer/vendor/cereal/include" + } + + links + { + "Deer", + "spdlog", + "angelScript" + } + defines { "DEER_SERVICE", + "AS_ENABLE_METADATA" } + + targetdir ("../bin/" .. OutputDir .. "/%{prj.name}") + objdir ("../bin/int/" .. OutputDir .. "/%{prj.name}") + + filter "system:linux" + toolset "clang" + defines { "LINUX" } + buildoptions { "-std=c++20" } + -- Link libraries for GTK3 and its dependencies + links { + "pthread" -- POSIX threads library + + } + + filter "system:linux" + defines { "PLATFORM_LINUX" } + + filter "system:windows" + systemversion "latest" + defines { "WINDOWS" } + + filter "configurations:Debug" + defines { "DEBUG" } + runtime "Debug" + symbols "On" + + filter "configurations:Release" + defines { "RELEASE" } + runtime "Release" + optimize "On" + symbols "On" + + filter "configurations:Dist" + defines { "DIST" } + runtime "Release" + optimize "On" + symbols "Off" diff --git a/DeerStudioServer/src/main.cpp b/DeerStudioServer/src/main.cpp new file mode 100644 index 0000000..58c82f9 --- /dev/null +++ b/DeerStudioServer/src/main.cpp @@ -0,0 +1,14 @@ +#include "DeerCore/Log.h" + +namespace Deer { + void main() { + Deer::Log::init(); + DEER_CORE_INFO("Working!!!"); + Deer::Log::shutdown(); + } +} // namespace Deer + +int main() { + Deer::main(); + return 0; +} \ No newline at end of file diff --git a/Resources/shader.glsl b/Resources/shader.glsl index 11990ed..37806b0 100644 --- a/Resources/shader.glsl +++ b/Resources/shader.glsl @@ -36,7 +36,7 @@ void main() vec3 lightDir = normalize(vec3(1.0, 7.0, 3.0)) * 0.2f + 0.8f; float light = clamp(dot(normalize(normal), lightDir), 0.1, 1.0); - fragColor = vec4(uv.r, uv.g, light, 1); + fragColor = vec4(light, light, light, 1); // fragColor = vec4(uv.r, uv.g, 0, 1); objectID = u_objectID; } diff --git a/imgui.ini b/imgui.ini index 183b723..b20d25c 100644 --- a/imgui.ini +++ b/imgui.ini @@ -4,8 +4,8 @@ Size=2560,1371 Collapsed=0 [Window][ViewportPanel] -Pos=559,34 -Size=1441,704 +Pos=488,34 +Size=1512,804 Collapsed=0 DockId=0x00000004,0 @@ -16,13 +16,13 @@ Collapsed=0 [Window][TreePanel] Pos=0,34 -Size=557,704 +Size=486,1336 Collapsed=0 DockId=0x00000001,0 [Window][ResourceExplorer] -Pos=0,740 -Size=2560,630 +Pos=0,840 +Size=2560,530 Collapsed=0 DockId=0x00000006,0 @@ -34,7 +34,7 @@ DockId=0xA1672E74,1 [Window][PropertiesPanel] Pos=2002,34 -Size=558,704 +Size=558,1336 Collapsed=0 DockId=0x00000003,0 @@ -67,11 +67,11 @@ DockId=0x00000004,0 [Docking][Data] DockSpace ID=0x0AC2E849 Window=0xD0388BC8 Pos=0,34 Size=2560,1336 Split=Y - DockNode ID=0x00000005 Parent=0x0AC2E849 SizeRef=1920,704 Split=X + DockNode ID=0x00000005 Parent=0x0AC2E849 SizeRef=1920,804 Split=X DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1360,645 Split=X Selected=0xD9E076F4 - DockNode ID=0x00000001 Parent=0x00000002 SizeRef=557,976 Selected=0x16E3C1E7 - DockNode ID=0x00000004 Parent=0x00000002 SizeRef=1441,976 CentralNode=1 Selected=0x0F5FFC8C + DockNode ID=0x00000001 Parent=0x00000002 SizeRef=486,976 Selected=0x16E3C1E7 + DockNode ID=0x00000004 Parent=0x00000002 SizeRef=1512,976 CentralNode=1 Selected=0x0F5FFC8C DockNode ID=0x00000003 Parent=0x00000005 SizeRef=558,645 Selected=0x9876A79B - DockNode ID=0x00000006 Parent=0x0AC2E849 SizeRef=1920,630 Selected=0x018A0F9B + DockNode ID=0x00000006 Parent=0x0AC2E849 SizeRef=1920,530 Selected=0x018A0F9B DockSpace ID=0xA1672E74 Pos=0,34 Size=1920,976 CentralNode=1 Selected=0x9ED090AF diff --git a/premake5.lua b/premake5.lua index e0387d5..f51d3a8 100755 --- a/premake5.lua +++ b/premake5.lua @@ -19,6 +19,7 @@ include "Deer/vendor/GLFW/Build.lua" include "Deer/vendor/glad/Build.lua" include "Deer/vendor/imgui/Build.lua" include "Deer/vendor/angelScript/Build.lua" +include "Deer/vendor/enet/Build.lua" include "DeerStudio/vendor/assimp/Build.lua" group "" @@ -28,4 +29,5 @@ group "" group "Studio" include "DeerStudio/Build.lua" +include "DeerStudioServer/Build.lua" group ""