diff --git a/docs/tasks/core.todo b/docs/tasks/core.todo index 3a4742b..78618fb 100644 --- a/docs/tasks/core.todo +++ b/docs/tasks/core.todo @@ -8,10 +8,10 @@ Build System: Core: ☐ Figure out how to represent Unique Entities and entity instances - and how this will work with UUIDs @critical - ☐ Implement generic serializeation system - ☐ JSON serializeable base class - ☐ JSON implementions should be stubbed out in non-editor builds - ☐ Binary serializeable base class + ✔ Implement generic serialization system @done(22-06-29 18:44) + ✔ JSON serializable base class @done(22-06-29 17:41) + ✔ JSON implementions should be stubbed out in non-editor builds @done(22-06-29 17:41) + ✔ Binary serializable base class @done(22-06-29 18:44) ✔ Wrap NFD in an API in the platform module @low @done(22-05-31 15:44) Wrapper added to utils - not platform ✔ Add custom (64 bit?) UUID generator (based on Chreno's UUIDs) @done(22-06-27 13:34) @@ -76,6 +76,9 @@ Core: Enitity: ✔ Single UUID @done(22-06-01 14:01) ✔ Functionality for adding/working with components (through EnTT) @done(22-06-01 14:01) + ☐ Serialize + ☐ JSON + ☐ Binary Components: ✔ Tag @done(22-06-23 15:49) @@ -90,6 +93,9 @@ Core: World (Lunariums version of a "Scene"): ☐ Implement the world without Regions first + ☐ Serialize world + ☐ JSON + ☐ Binary Implement Regions: ☐ Track/manage active regions @@ -145,7 +151,7 @@ Utils: Assets: ✔ Internal Asset Manager @high @done (1/25/2022, 3:58:20 PM) ☐ Document Index.Dat and the AssetIndex class - ☐ Move the GenerateFont method from internal_font.h into data_manager.h + ✔ Move the GenerateFont method from internal_font.h into data_manager.h @done(22-06-29 17:42) Types: - Classes that represent each resource Types @@ -158,7 +164,7 @@ Assets: Loaders: - Need class (or classes?) to load resources from the packed format that the pipeline generates Come up with binary file formats for each type: - ☐ .xml (This will probably be multiple different formats depending on what the .xml file is describing) + ☐ .json (This will probably be multiple different formats depending on what the .json file is describing) ☐ Image ☐ Script ☐ Audio diff --git a/docs/tasks/editor.todo b/docs/tasks/editor.todo index 178d3f3..1c3e257 100644 --- a/docs/tasks/editor.todo +++ b/docs/tasks/editor.todo @@ -42,6 +42,7 @@ Editor: World View: World Hierarchy (Tree View): + ☐ Handle showing Enities with children @high Asset Viewer: ✔ Get references to the EditorAsset objects instead of the raw file locations @done(22-06-01 18:48) diff --git a/src/assets/serializing/binary_serializable.h b/src/assets/serializing/binary_serializable.h new file mode 100644 index 0000000..323c1ea --- /dev/null +++ b/src/assets/serializing/binary_serializable.h @@ -0,0 +1,26 @@ +/****************************************************************************** +* File - binary_serializable.h +* Author - Joey Pollack +* Date - 2022/06/29 (y/m/d) +* Mod Date - 2022/06/29 (y/m/d) +* Description - base class for any object that can be serialized to binary +******************************************************************************/ + +#ifndef LUNARIUM_BINARY_SERIALIZABLE_H_ +#define LUNARIUM_BINARY_SERIALIZABLE_H_ + +#include + +namespace lunarium +{ + class BinaryFileBuffer; + + class BinarySerializable + { + public: + [[nodiscard]] OpRes Serialize(BinaryFileBuffer* pBuffer); + [[nodiscard]] OpRes Deserialize(BinaryFileBuffer* pBuffer); + }; +} + +#endif // LUNARIUM_BINARY_SERIALIZABLE_H_ \ No newline at end of file diff --git a/src/assets/serializing/json_serializable.h b/src/assets/serializing/json_serializable.h new file mode 100644 index 0000000..ae18666 --- /dev/null +++ b/src/assets/serializing/json_serializable.h @@ -0,0 +1,28 @@ +/****************************************************************************** +* File - json_serializable.h +* Author - Joey Pollack +* Date - 2022/06/29 (y/m/d) +* Mod Date - 2022/06/29 (y/m/d) +* Description - Base class for any json serializable object +******************************************************************************/ + +#ifndef LUNARIUM_JSON_SERIALIZABLE_H_ +#define LUNARIUM_JSON_SERIALIZABLE_H_ + +#include +#include + +namespace lunarium +{ + class JSONSerializable + { + public: + [[nodiscard]] virtual OpRes Serialize(nlohmann::json& node) = 0; + [[nodiscard]] virtual OpRes Deserialize(nlohmann::json& node) = 0; + [[nodiscard]] virtual nlohmann::json AsJSON() = 0; + [[nodiscord]] virtual bool IsValidNode(nlohmann::json& node) = 0; + + }; +} + +#endif // LUNARIUM_JSON_SERIALIZABLE_H_ \ No newline at end of file diff --git a/src/run_modes/editor/contents/World.cpp b/src/run_modes/editor/contents/World.cpp index d1f40fe..ee13a25 100644 --- a/src/run_modes/editor/contents/World.cpp +++ b/src/run_modes/editor/contents/World.cpp @@ -7,6 +7,7 @@ ******************************************************************************/ #include "world.h" +#include #include @@ -33,18 +34,24 @@ namespace lunarium { namespace editor return OpRes::OK(); } - OpRes World::LoadFromJSON(nlohmann::json& node) + OpRes World::Deserialize(nlohmann::json& node) { // TODO: Implement World::LoadFromJSON // Create the lunarium::World Object here // Replace the one created in the constructor + #if !BUILD_NO_EDITOR // Only does this when this is an editor build + + #endif return OpRes::OK(); } - OpRes World::SaveToJSON(nlohmann::json& node) + OpRes World::Serialize(nlohmann::json& node) { // TODO: Implement World::SaveToJSON // Store the entities UUID - the Entity class will serialize itself + #if !BUILD_NO_EDITOR // Only does this when this is an editor build + + #endif return OpRes::OK(); } @@ -54,4 +61,15 @@ namespace lunarium { namespace editor return true; } + nlohmann::json World::AsJSON() + { + #if !BUILD_NO_EDITOR // Only does this when this is an editor build + nlohmann::json node; + + return node; + #endif + + return nlohmann::json(); + } + }} \ No newline at end of file diff --git a/src/run_modes/editor/contents/content_manager.cpp b/src/run_modes/editor/contents/content_manager.cpp index 093c6c3..511c6d3 100644 --- a/src/run_modes/editor/contents/content_manager.cpp +++ b/src/run_modes/editor/contents/content_manager.cpp @@ -133,7 +133,7 @@ namespace lunarium { namespace editor pAsset->mLocation = std::filesystem::path(asset["Location"].get()); // Load type specific data - if (Failed(pAsset->LoadFromJSON(asset).LogIfFailed(Editor::LogCat).LogIfFailed(Editor::LogCat))) + if (Failed(pAsset->Deserialize(asset).LogIfFailed(Editor::LogCat).LogIfFailed(Editor::LogCat))) { return OpRes::Fail("Could not load asset type specific data for asset with ID: %llu, File: %s", pAsset->GetID(), pAsset->GetFileLocation().filename().string().c_str()); @@ -184,7 +184,7 @@ namespace lunarium { namespace editor // TODO: This needs to be a relative path! (Relative to the project root) asset["Location"] = pAsset->GetFileLocation().string().c_str(); - if (Failed(pAsset->SaveToJSON(asset).LogIfFailed(Editor::LogCat).LogIfFailed(Editor::LogCat))) + if (Failed(pAsset->Serialize(asset).LogIfFailed(Editor::LogCat).LogIfFailed(Editor::LogCat))) { return OpRes::Fail("Could not save asset meta data for file: %s", pAsset->GetFileLocation().string().c_str()); } diff --git a/src/run_modes/editor/contents/editor_asset.h b/src/run_modes/editor/contents/editor_asset.h index fbf963c..506eb92 100644 --- a/src/run_modes/editor/contents/editor_asset.h +++ b/src/run_modes/editor/contents/editor_asset.h @@ -11,14 +11,15 @@ #include "definitions.h" #include "content_manager.h" +#include +#include #include #include -#include namespace lunarium { namespace editor { - class EditorAsset + class EditorAsset : public JSONSerializable { public: EditorAsset(AssetType type); @@ -29,8 +30,10 @@ namespace lunarium { namespace editor bool GetIsTrashed() const; [[nodiscard]] virtual OpRes LoadRawFile() = 0; - [[nodiscard]] virtual OpRes LoadFromJSON(nlohmann::json& node) = 0; - [[nodiscard]] virtual OpRes SaveToJSON(nlohmann::json& node) = 0; + + + // [[nodiscard]] virtual OpRes LoadFromJSON(nlohmann::json& node) = 0; + //[[nodiscard]] virtual OpRes SaveToJSON(nlohmann::json& node) = 0; private: friend class ContentManager; @@ -43,7 +46,7 @@ namespace lunarium { namespace editor protected: std::filesystem::path mAssetDir; - [[nodiscord]] virtual bool IsValidNode(nlohmann::json& node) = 0; + // [[nodiscord]] virtual bool IsValidNode(nlohmann::json& node) = 0; private: // DISABLE COPY EditorAsset(const EditorAsset&) = delete; diff --git a/src/run_modes/editor/contents/tile_set.cpp b/src/run_modes/editor/contents/tile_set.cpp index bf116d3..c54a5cb 100644 --- a/src/run_modes/editor/contents/tile_set.cpp +++ b/src/run_modes/editor/contents/tile_set.cpp @@ -37,8 +37,10 @@ namespace lunarium { namespace editor return OpRes::OK(); } - OpRes TileSet::LoadFromJSON(nlohmann::json& node) - { + OpRes TileSet::Deserialize(nlohmann::json& node) + { + #if !BUILD_NO_EDITOR // Only does this when this is an editor build + // Load Image mSetImage = FileLoaders::LoadImage(mAssetDir / GetFileLocation()); if (!mSetImage) @@ -57,20 +59,40 @@ namespace lunarium { namespace editor mNumTiles.Width = node["NumTilesCol"].get(); mNumTiles.Height = node["NumTilesRow"].get(); + #endif return OpRes::OK(); } - OpRes TileSet::SaveToJSON(nlohmann::json& node) + OpRes TileSet::Serialize(nlohmann::json& node) { + #if !BUILD_NO_EDITOR // Only does this when this is an editor build + node["TileSetID"] = mTileSetID; node["TileSizeWidth"] = mTileSize.Width; node["TileSizeHeight"] = mTileSize.Height; node["NumTilesCol"] = mNumTiles.Width; node["NumTilesRow"] = mNumTiles.Height; + #endif return OpRes::OK(); } + nlohmann::json TileSet::AsJSON() + { + nlohmann::json node; + + #if !BUILD_NO_EDITOR // Only does this when this is an editor build + + node["TileSetID"] = mTileSetID; + node["TileSizeWidth"] = mTileSize.Width; + node["TileSizeHeight"] = mTileSize.Height; + node["NumTilesCol"] = mNumTiles.Width; + node["NumTilesRow"] = mNumTiles.Height; + + #endif + return node; + } + bool TileSet::IsValidNode(nlohmann::json& node) { if (node["TileSetID"].is_null()) { return false; } diff --git a/src/run_modes/editor/contents/tile_set.h b/src/run_modes/editor/contents/tile_set.h index c893687..464cc3a 100644 --- a/src/run_modes/editor/contents/tile_set.h +++ b/src/run_modes/editor/contents/tile_set.h @@ -24,8 +24,10 @@ namespace lunarium { namespace editor // Load the raw asset file from the internal location OpRes LoadRawFile(); - OpRes LoadFromJSON(nlohmann::json& node); - OpRes SaveToJSON(nlohmann::json& node); + OpRes Serialize(nlohmann::json& node); + OpRes Deserialize(nlohmann::json& node); + bool IsValidNode(nlohmann::json& node); + nlohmann::json AsJSON(); void SetTileSetID(int id); int GetTileSetID() const; @@ -47,7 +49,6 @@ namespace lunarium { namespace editor private: - [[nodiscord]] virtual bool IsValidNode(nlohmann::json& node); }; }} diff --git a/src/run_modes/editor/contents/world.h b/src/run_modes/editor/contents/world.h index 3b92629..88d77c5 100644 --- a/src/run_modes/editor/contents/world.h +++ b/src/run_modes/editor/contents/world.h @@ -28,8 +28,10 @@ namespace lunarium { namespace editor ~World(); [[nodiscard]] virtual OpRes LoadRawFile(); - [[nodiscard]] virtual OpRes LoadFromJSON(nlohmann::json& node); - [[nodiscard]] virtual OpRes SaveToJSON(nlohmann::json& node); + [[nodiscard]] virtual OpRes Serialize(nlohmann::json& node); + [[nodiscard]] virtual OpRes Deserialize(nlohmann::json& node); + [[nodiscord]] virtual bool IsValidNode(nlohmann::json& node); + [[nodiscard]] virtual nlohmann::json AsJSON(); lunarium::World* GetWorld(); @@ -38,7 +40,6 @@ namespace lunarium { namespace editor private: - [[nodiscord]] virtual bool IsValidNode(nlohmann::json& node); private: // DISABLED diff --git a/src/utils/binary_file_buffer.cpp b/src/utils/binary_file_buffer.cpp index e74f930..47854b0 100644 --- a/src/utils/binary_file_buffer.cpp +++ b/src/utils/binary_file_buffer.cpp @@ -15,7 +15,7 @@ namespace lunarium { BinaryFileBuffer::BinaryFileBuffer() - : mbIsLoaded(false), mpData(nullptr), mFileSize(0), mReadPos(0), mFileName("") + : mbIsLoaded(false), mpBuffer(nullptr), mFileSize(0), mBufferPos(0), mFileName("") { } @@ -24,6 +24,43 @@ namespace lunarium Unload(); } + bool BinaryFileBuffer::NewFile(int reserve_size) + { + if (mbIsLoaded) + { + Unload(); + } + + mpBuffer = new unsigned char[reserve_size]; + mFileSize = reserve_size; + mbIsLoaded = true; + + return true; + } + + bool BinaryFileBuffer::WriteFile(const char* filename, bool include_extra_bytes) + { + std::ofstream ofs(filename, std::ios_base::binary | std::ios_base::trunc); + if (!ofs.is_open()) + { + return false; + } + + // Only writing up to the buffer pos because the rest will be garbage data + int write_size = mBufferPos; + if (include_extra_bytes) + { + // Unless the user says otherwise + write_size = mFileSize; + } + + ofs.write((const char*)mpBuffer, write_size); + ofs.close(); + ofs.clear(); + mFileName = filename; + return true; + } + bool BinaryFileBuffer::LoadFile(const char * filename) { if (mbIsLoaded) @@ -43,9 +80,9 @@ namespace lunarium ifs.seekg(0, std::ios_base::beg); mFileSize = end - start; - mpData = new unsigned char[mFileSize]; + mpBuffer = new unsigned char[mFileSize]; - ifs.read((char*)mpData, mFileSize); + ifs.read((char*)mpBuffer, mFileSize); ifs.close(); ifs.clear(); @@ -60,12 +97,12 @@ namespace lunarium if (!mbIsLoaded) return; - delete[] mpData; - mpData = nullptr; + delete[] mpBuffer; + mpBuffer = nullptr; mFileSize = 0; mFileName = ""; - mReadPos = 0; + mBufferPos = 0; mbIsLoaded = false; } @@ -86,29 +123,130 @@ namespace lunarium const unsigned char* BinaryFileBuffer::GetBuffer() const { - return mpData; + return mpBuffer; } + ///////////////////////////////////////////////////////////////////// + // READ METHODS + ///////////////////////////////////////////////////////////////////// bool BinaryFileBuffer::Read(char * buffer, int numBytes) { - if (!mbIsLoaded || mReadPos >= mFileSize) + if (!mbIsLoaded || mBufferPos >= mFileSize) + return false; + + memcpy(buffer, &mpBuffer[mBufferPos], numBytes); + mBufferPos += numBytes; + + return true; + } + + int BinaryFileBuffer::ReadInt() + { + int value = 0; + Read((char*)&value, sizeof(int)); + return value; + } + + short BinaryFileBuffer::ReadShort() + { + short value = 0; + Read((char*)&value, sizeof(short)); + return value; + } + + char BinaryFileBuffer::ReadByte() + { + char value = 0; + Read((char*)&value, sizeof(char)); + return value; + } + + unsigned int BinaryFileBuffer::ReadUInt() + { + unsigned int value = 0; + Read((char*)&value, sizeof(unsigned int)); + return value; + } + + unsigned short BinaryFileBuffer::ReadUShort() + { + unsigned short value = 0; + Read((char*)&value, sizeof(unsigned short)); + return value; + } + + unsigned char BinaryFileBuffer::ReadUByte() + { + unsigned char value = 0; + Read((char*)&value, sizeof(unsigned char)); + return value; + } + + ///////////////////////////////////////////////////////////////////// + // WRITE METHODS + ///////////////////////////////////////////////////////////////////// + bool BinaryFileBuffer::Write(char* buffer, int num_bytes) + { + if (!mbIsLoaded) + { return false; + } - memcpy(buffer, &mpData[mReadPos], numBytes); - mReadPos += numBytes; + if (mBufferPos + num_bytes >= mFileSize) + { + // Reserve more space + int new_size = mFileSize * 2 + num_bytes; // adding num_bytes to make sure the write will fit + unsigned char* new_buffer = new unsigned char[new_size]; + memcpy(new_buffer, mpBuffer, mFileSize); + delete[] mpBuffer; + mpBuffer = new_buffer; + mFileSize = new_size; + } + memcpy(&mpBuffer[mBufferPos], buffer, num_bytes); + mBufferPos += num_bytes; return true; } + void BinaryFileBuffer::WriteInt(int value) + { + Write((char*)&value, sizeof(int)); + } + + void BinaryFileBuffer::WriteShort(short value) + { + Write((char*)&value, sizeof(short)); + } + + void BinaryFileBuffer::WriteByte(char value) + { + Write((char*)&value, sizeof(char)); + } + + void BinaryFileBuffer::WriteUInt(unsigned int value) + { + Write((char*)&value, sizeof(unsigned int)); + } + + void BinaryFileBuffer::WriteUShort(unsigned short value) + { + Write((char*)&value, sizeof(unsigned short)); + } + + void BinaryFileBuffer::WriteUByte(unsigned char value) + { + Write((char*)&value, sizeof(unsigned char)); + } + void BinaryFileBuffer::SeekTo(int pos) { - mReadPos = pos; + mBufferPos = pos; - if (mReadPos < 0) - mReadPos = 0; + if (mBufferPos < 0) + mBufferPos = 0; - if (mReadPos >= mFileSize) - mReadPos = mFileSize - 1; + if (mBufferPos >= mFileSize) + mBufferPos = mFileSize - 1; } } \ No newline at end of file diff --git a/src/utils/binary_file_buffer.h b/src/utils/binary_file_buffer.h index 790dfc4..1bf8447 100644 --- a/src/utils/binary_file_buffer.h +++ b/src/utils/binary_file_buffer.h @@ -21,6 +21,10 @@ namespace lunarium BinaryFileBuffer(); ~BinaryFileBuffer(); + /// Create a new file buffer of the given starting size + /// This will clear out any existing buffer + bool NewFile(int reserve_size); + bool WriteFile(const char* filename, bool include_extra_bytes = false); bool LoadFile(const char* filename); void Unload(); bool IsLoaded() const; @@ -29,6 +33,21 @@ namespace lunarium const unsigned char* GetBuffer() const; bool Read(char* buffer, int numBytes); + int ReadInt(); + short ReadShort(); + char ReadByte(); + unsigned int ReadUInt(); + unsigned short ReadUShort(); + unsigned char ReadUByte(); + + bool Write(char* buffer, int num_bytes); + void WriteInt(int value); + void WriteShort(short value); + void WriteByte(char value); + void WriteUInt(unsigned int value); + void WriteUShort(unsigned short value); + void WriteUByte(unsigned char value); + void SeekTo(int pos); private: @@ -36,8 +55,8 @@ namespace lunarium bool mbIsLoaded; std::string mFileName; int mFileSize; - unsigned char* mpData; - int mReadPos; + unsigned char* mpBuffer; + int mBufferPos; }; } diff --git a/src/world/entity.h b/src/world/entity.h index 116a419..f8cc5c2 100644 --- a/src/world/entity.h +++ b/src/world/entity.h @@ -13,13 +13,10 @@ #include #include #include +#include -namespace nlohmann -{ - class json; -} -namespace lunarium +namespace lunarium // TODO: : public JSONSerializable { class Entity {