From 387bc849853a102fd712c03a4fce92251315aa94 Mon Sep 17 00:00:00 2001 From: Curle Date: Sat, 11 Mar 2023 07:14:36 +0000 Subject: [PATCH] UUID & start on IDs --- projs/shadow/shadow-engine/CMakeLists.txt | 3 + projs/shadow/shadow-engine/core/inc/id/UUID.h | 64 +++++++++++++++++++ .../shadow/shadow-engine/core/src/id/UUID.cpp | 56 ++++++++++++++++ .../shadow-engine/shadow-entity/inc/id/ID.h | 60 +++++++++++++++++ .../shadow-engine/shadow-entity/src/id/ID.cpp | 16 +++++ 5 files changed, 199 insertions(+) create mode 100644 projs/shadow/shadow-engine/core/inc/id/UUID.h create mode 100644 projs/shadow/shadow-engine/core/src/id/UUID.cpp create mode 100644 projs/shadow/shadow-engine/shadow-entity/inc/id/ID.h create mode 100644 projs/shadow/shadow-engine/shadow-entity/src/id/ID.cpp diff --git a/projs/shadow/shadow-engine/CMakeLists.txt b/projs/shadow/shadow-engine/CMakeLists.txt index e5e2434..d1048e0 100644 --- a/projs/shadow/shadow-engine/CMakeLists.txt +++ b/projs/shadow/shadow-engine/CMakeLists.txt @@ -7,12 +7,14 @@ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) FILE(GLOB_RECURSE SOURCES core/src/*.cpp + shadow-entity/src/*.cpp shadow-renderer/src/*.cpp shadow-reflection/src/*.cpp shadow-utility/src/*.cpp ) FILE(GLOB_RECURSE HEADERS core/inc/*.h + shadow-entity/inc/*.h shadow-renderer/inc/*.h shadow-reflection/inc/*.h shadow-utility/inc/*.h @@ -24,6 +26,7 @@ target_include_directories(shadow-engine PRIVATE ${SDL2_INCLUDE_DIRS} PUBLIC core/inc + shadow-entity/inc shadow-renderer/inc shadow-reflection/inc shadow-utility/inc diff --git a/projs/shadow/shadow-engine/core/inc/id/UUID.h b/projs/shadow/shadow-engine/core/inc/id/UUID.h new file mode 100644 index 0000000..7213b26 --- /dev/null +++ b/projs/shadow/shadow-engine/core/inc/id/UUID.h @@ -0,0 +1,64 @@ +#pragma once +#include +#include +#include + +// ShadowEntity temporary namespace +namespace SE { + + /** + * Universally Unique ID. + * 128 Bits. + * + * Unique per runtime only - the suitability for serialization is undetermined. + */ + + class UUID { + + /** + * Data storage; 128 bits. + * 2 x 64 bit + * 4 x 32 bit + * 16 x 8 bit + */ + + union Data { + uint64_t u64[2]; + uint32_t u32[4]; + uint8_t u8[16]; + }; + + public: + // Create a new, unused, UUID. + static UUID Generate(); + // Check whether the UUID is correctly formed. + static bool IsValidStr(char const* str); + + // Create an empty UUID. + inline UUID() { std::memset(&data.u8, 0, 16); } + // Create a UUID based on the given values. + inline UUID(uint64_t i0, uint64_t i1) { data.u64[0] = i0; data.u64[1] = i1; } + inline UUID(uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3) { data.u32[0] = i0; data.u32[1] = i1; data.u32[2] = i2; data.u32[3] = i3; } + inline explicit UUID(std::string const& str) : UUID(str.c_str()) {} + // Create a UUID from the given format. + explicit UUID(char const* str); + + // Check whether the UUID is nonzero. + inline bool IsValid() const { return data.u64[0] != 0 && data.u64[1] != 0; } + // Set the UUID to zero. + inline void Clear() { std::memset(&data.u8, 0, 16); } + + // Get a section of the UUID's data as the given bit width. + inline uint8_t GetU8(size_t idx) const { return data.u8[idx]; } + inline uint32_t GetU32(size_t idx) const { return data.u32[idx]; } + inline uint64_t GetU64(size_t idx) const { return data.u64[idx]; } + + // Check whether this and a given UUID are in/equal. + __inline bool operator==(UUID const& other) const { return data.u64[0] == other.data.u64[0] && data.u64[1] == other.data.u64[1]; } + __inline bool operator!=(UUID const& other) const { return !(*this == other); } + + private: + + Data data {}; + }; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/core/src/id/UUID.cpp b/projs/shadow/shadow-engine/core/src/id/UUID.cpp new file mode 100644 index 0000000..efccdaa --- /dev/null +++ b/projs/shadow/shadow-engine/core/src/id/UUID.cpp @@ -0,0 +1,56 @@ +#include + +namespace SE { + static_assert(sizeof(UUID) == 16, "UUID has incorrect size"); + + /** + * Verify that a string has the correct format; + * XXXXXXXX-XXXX-XXX-XXXXX-XXXXXXXXXXXX + * + * The length must be 36. + * There must be dashes at index 8, 13, 18 and 23. + * @param str the input string + * @return whether the UUID string is correctly formed + */ + bool UUID::IsValidStr(const char *str) { + size_t const len = strlen(str); + if (len != 36) return false; + + for (size_t i = 0; i < len; i++) { + char c = str[i]; + if (c == '-') { + if (i != 8 && i != 13 && i != 18 && i != 23) return false; + } else if (! std::isxdigit(c)) { + return false; + } + } + + return true; + } + + UUID::UUID(char const* str ) { + // A single byte is two hex characters. + // Store them here so that we can use them later. + char c0 = '\0', c1; + + size_t const len = strlen( str ); + uint32_t byteIdx = 0; + + for (size_t i = 0; i < len; i++ ) { + char const c = str[i]; + if ( c == '-' ) + continue; + + // Scan for pairs of characters. + // Only assign a byte if two have been parsed. + if (c0 == '\0') { + c0 = c; + } else { + c1 = c; + data.u8[byteIdx++] = std::stoi(std::string(c0, c1)); + // Reset the first char so that we can return to scanning a pair. + c0 = '\0'; + } + } + } +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-entity/inc/id/ID.h b/projs/shadow/shadow-engine/shadow-entity/inc/id/ID.h new file mode 100644 index 0000000..91dce79 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-entity/inc/id/ID.h @@ -0,0 +1,60 @@ +#pragma once + +#include // Shadow-Engine/core/inc/id + +namespace SE { + + // An ID for a section of the scene (which may be unloaded separately of the level; for ie. open world Cells.) + using EntitySectionID = UUID; + // An ID for a scene (which contains all sections and entities). + using EntitySceneID = UUID; + + /** + * Contains the common data and functions for the Entity System's identifiers. + */ + struct IDContainer { + public: + IDContainer() = default; + explicit IDContainer(uint64_t v) : id(v) {} + + // Check if the ID is valid (non-zero) + __inline bool Valid() const { return id != 0; } + // Set this ID to be invalid (zero). + __inline void Invalidate() { id = 0; } + // Check for in/equality against another ID. + __inline bool operator==(IDContainer const& other) const { return id == other.id; } + __inline bool operator!=(IDContainer const& other) const { return id != other.id; } + + uint64_t id; + }; + + + /** + * An ID used for an Entity. + * Is only guaranteed to be unique in the current scene (ie. a level change may also change the IDs of the entities within). + */ + struct EntityID : public IDContainer { + /** + * @return a new, unused Entity ID. + */ + static EntityID Generate(); + + EntityID() = default; + explicit EntityID(uint64_t v) : IDContainer(v) {} + }; + + /** + * An ID used for a Component (a segment of data attached to an Entity). + * Is only guaranteed to be unique in the current scene (ie. a level change may also change the IDs of the components within). + */ + struct ComponentID : public IDContainer { + /** + * @return a new, unused Component ID. + */ + static ComponentID Generate(); + + ComponentID() = default; + explicit ComponentID(uint64_t v) : IDContainer(v) {} + }; +} + diff --git a/projs/shadow/shadow-engine/shadow-entity/src/id/ID.cpp b/projs/shadow/shadow-engine/shadow-entity/src/id/ID.cpp new file mode 100644 index 0000000..b5c5435 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-entity/src/id/ID.cpp @@ -0,0 +1,16 @@ +#include +#include + +namespace SE { + static std::atomic entityID = 1; + EntityID EntityID::Generate() { + EntityID id(entityID++); + return id; + } + + static std::atomic componentID = 1; + ComponentID ComponentID::Generate() { + ComponentID id(componentID++); + return id; + } +} \ No newline at end of file