Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add function that retrieves the type info of component from the type of serializable one and vice versa. #1

Merged
merged 3 commits into from
Jan 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: build

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

jobs:
macos:
timeout-minutes: 15
runs-on: macos-latest

steps:
- uses: actions/checkout@v3
- name: Build tests
run: |
cmake -DNODEC_SCENE_SERIALIZATION_BUILD_TESTS=ON -B ./build
cmake --build ./build
- name: Run tests
working-directory: build
run: |
ctest -C Debug --output-on-failure
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.15)

project(nodec_scene_serialization LANGUAGES CXX)

Expand Down
50 changes: 46 additions & 4 deletions include/nodec_scene_serialization/archive_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,62 @@

#include <nodec/resource_management/resource_registry.hpp>

#include "scene_serialization.hpp"

namespace nodec_scene_serialization {

class ArchiveContext {
public:
ArchiveContext(nodec::resource_management::ResourceRegistry &resource_registry)
: resource_registry_(&resource_registry) {}
ArchiveContext(SceneSerialization &scene_serialization,
nodec::resource_management::ResourceRegistry &resource_registry)
: scene_serialization_(scene_serialization),
resource_registry_(resource_registry) {}

SceneSerialization &scene_serialization() {
return scene_serialization_;
}

nodec::resource_management::ResourceRegistry &resource_registry() {
return *resource_registry_;
return resource_registry_;
}

private:
nodec::resource_management::ResourceRegistry *resource_registry_;
SceneSerialization &scene_serialization_;
nodec::resource_management::ResourceRegistry &resource_registry_;
};
} // namespace nodec_scene_serialization

#include <cereal/archives/binary.hpp>
#include <cereal/archives/json.hpp>
#include <cereal/archives/portable_binary.hpp>
#include <cereal/archives/xml.hpp>

#define CEREAL_FUTURE_EXPERIMENTAL
#include <cereal/archives/adapters.hpp>

namespace nodec_scene_serialization {
namespace internal {
// We couldn't write like this...
// CEREAL_REGISTER_ARCHIVE(cereal::UserDataAdapter<nodec_scene_serialization::ArchiveContext, cereal::JSONInputArchive>)
using JSONInputArchiveWithContext = cereal::UserDataAdapter<nodec_scene_serialization::ArchiveContext, cereal::JSONInputArchive>;
using JSONOutputArchiveWithContext = cereal::UserDataAdapter<nodec_scene_serialization::ArchiveContext, cereal::JSONOutputArchive>;
using BinaryInputArchiveWithContext = cereal::UserDataAdapter<nodec_scene_serialization::ArchiveContext, cereal::BinaryInputArchive>;
using BinaryOutputArchiveWithContext = cereal::UserDataAdapter<nodec_scene_serialization::ArchiveContext, cereal::BinaryOutputArchive>;
using PortableBinaryInputArchiveWithContext = cereal::UserDataAdapter<nodec_scene_serialization::ArchiveContext, cereal::PortableBinaryInputArchive>;
using PortableBinaryOutputArchiveWithContext = cereal::UserDataAdapter<nodec_scene_serialization::ArchiveContext, cereal::PortableBinaryOutputArchive>;
using XMLOutputArchiveWithContext = cereal::UserDataAdapter<nodec_scene_serialization::ArchiveContext, cereal::XMLOutputArchive>;
using XMLInputArchiveWithContext = cereal::UserDataAdapter<nodec_scene_serialization::ArchiveContext, cereal::XMLInputArchive>;

} // namespace internal
} // namespace nodec_scene_serialization

CEREAL_REGISTER_ARCHIVE(nodec_scene_serialization::internal::JSONInputArchiveWithContext)
CEREAL_REGISTER_ARCHIVE(nodec_scene_serialization::internal::JSONOutputArchiveWithContext)
CEREAL_REGISTER_ARCHIVE(nodec_scene_serialization::internal::BinaryInputArchiveWithContext)
CEREAL_REGISTER_ARCHIVE(nodec_scene_serialization::internal::BinaryOutputArchiveWithContext)
CEREAL_REGISTER_ARCHIVE(nodec_scene_serialization::internal::PortableBinaryInputArchiveWithContext)
CEREAL_REGISTER_ARCHIVE(nodec_scene_serialization::internal::PortableBinaryOutputArchiveWithContext)
CEREAL_REGISTER_ARCHIVE(nodec_scene_serialization::internal::XMLOutputArchiveWithContext)
CEREAL_REGISTER_ARCHIVE(nodec_scene_serialization::internal::XMLInputArchiveWithContext)

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
namespace nodec_scene_serialization {
namespace components {

class NonSerialized : public BaseSerializableComponent {
public:
struct NonSerialized : BaseSerializableComponent {
NonSerialized()
: BaseSerializableComponent(this) {}

Expand All @@ -18,7 +17,6 @@ class NonSerialized : public BaseSerializableComponent {
} // namespace components
} // namespace nodec_scene_serialization

CEREAL_REGISTER_TYPE(nodec_scene_serialization::components::NonSerialized)
CEREAL_REGISTER_POLYMORPHIC_RELATION(nodec_scene_serialization::BaseSerializableComponent, nodec_scene_serialization::components::NonSerialized)
NODEC_SCENE_REGISTER_SERIALIZABLE_COMPONENT(nodec_scene_serialization::components::NonSerialized)

#endif
3 changes: 1 addition & 2 deletions include/nodec_scene_serialization/components/prefab.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ namespace components {
* However, I think being Serializable and being saved to a file are two separate things,
* so I thought it might be a Prefab.
*/
class Prefab : public BaseSerializableComponent {
public:
struct Prefab : BaseSerializableComponent {
Prefab()
: BaseSerializableComponent(this) {}

Expand Down
51 changes: 45 additions & 6 deletions include/nodec_scene_serialization/scene_serialization.hpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
#ifndef NODEC_SCENE_SERIALIZATION__SCENE_SERIALIZATION_HPP_
#define NODEC_SCENE_SERIALIZATION__SCENE_SERIALIZATION_HPP_

#include "serializable_component.hpp"
#include "serializable_entity.hpp"

#include <nodec_scene/scene_registry.hpp>

#include <cassert>
#include <unordered_map>
#include <vector>

#include <nodec_scene/scene_registry.hpp>

#include "serializable_component.hpp"
#include "serializable_entity.hpp"

namespace nodec_scene_serialization {

class SceneSerialization final {
Expand All @@ -20,9 +20,25 @@ class SceneSerialization final {
private:
class BaseComponentSerialization {
public:
BaseComponentSerialization(const nodec::type_info &component_type_info,
const nodec::type_info &serializable_component_type_info)
: component_type_info_(component_type_info),
serializable_component_type_info_(serializable_component_type_info) {}

nodec::type_info type_info() const noexcept {
return component_type_info_;
}
nodec::type_info serializable_type_info() const noexcept {
return serializable_component_type_info_;
}

virtual std::unique_ptr<BaseSerializableComponent> serialize(const void *component) const = 0;
virtual void emplace_component(const BaseSerializableComponent *, SceneEntity, SceneRegistry &) const = 0;
virtual std::unique_ptr<BaseSerializableComponent> make_serializable_component() const = 0;

private:
nodec::type_info component_type_info_;
nodec::type_info serializable_component_type_info_;
};

template<typename Component, typename SerializableComponent>
Expand All @@ -31,6 +47,9 @@ class SceneSerialization final {
using Deserializer = std::function<Component(const SerializableComponent &)>;

public:
ComponentSerialization()
: BaseComponentSerialization(nodec::type_id<Component>(), nodec::type_id<SerializableComponent>()) {}

std::unique_ptr<BaseSerializableComponent> serialize(const void *component) const override {
assert(component);

Expand All @@ -51,7 +70,7 @@ class SceneSerialization final {
result.first = std::move(comp);
}

std::unique_ptr<BaseSerializableComponent> make_serializable_component() const {
std::unique_ptr<BaseSerializableComponent> make_serializable_component() const override {
return std::make_unique<SerializableComponent>();
}

Expand Down Expand Up @@ -196,6 +215,26 @@ class SceneSerialization final {
return iter->second->make_serializable_component();
}

/**
* @brief Gets the type info of runtime component from the given serializable component type info.
*/
nodec::type_info get_component_type_info(const nodec::type_info &serializable_component_type_info) const {
auto iter = serializable_component_dict_.find(serializable_component_type_info.seq_index());
if (iter == serializable_component_dict_.end()) return nodec::type_id<nullptr_t>();

return iter->second->type_info();
}

/**
* @brief Gets the type info of serializable component from the given runtime component type info.
*/
nodec::type_info get_serializable_component_type_info(const nodec::type_info &component_type_info) const {
auto iter = component_dict_.find(component_type_info.seq_index());
if (iter == component_dict_.end()) return nodec::type_id<nullptr_t>();

return iter->second->serializable_type_info();
}

private:
std::unordered_map<nodec::type_seq_index_type, std::shared_ptr<BaseComponentSerialization>> component_dict_;
std::unordered_map<nodec::type_seq_index_type, std::shared_ptr<BaseComponentSerialization>> serializable_component_dict_;
Expand Down
25 changes: 1 addition & 24 deletions include/nodec_scene_serialization/serializable_component.hpp
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
#ifndef NODEC_SCENE_SERIALIZATION__SERIALIZABLE_COMPONENT_HPP_
#define NODEC_SCENE_SERIALIZATION__SERIALIZABLE_COMPONENT_HPP_

#include "archive_context.hpp"

#include <nodec/type_info.hpp>

#include <cereal/types/polymorphic.hpp>
#include <nodec/type_info.hpp>

namespace nodec_scene_serialization {

struct BaseSerializableComponent {
public:
template<class Derived>
BaseSerializableComponent(Derived *)
: type_info_{&nodec::type_id<Derived>()} {
}

// BaseSerializableComponent()
// : type_info_{&nodec::type_id<BaseSerializableComponent>()} {
// }

virtual ~BaseSerializableComponent() = 0;

public:
const nodec::type_info &type_info() const noexcept {
return *type_info_;
}
Expand All @@ -45,20 +36,6 @@ inline BaseSerializableComponent::~BaseSerializableComponent() {}
#include <cereal/archives/portable_binary.hpp>
#include <cereal/archives/xml.hpp>

#define CEREAL_FUTURE_EXPERIMENTAL
#include <cereal/archives/adapters.hpp>

namespace nodec_scene_serialization {
namespace internal {
// We couldn't write like this...
// CEREAL_REGISTER_ARCHIVE(cereal::UserDataAdapter<nodec_scene_serialization::ArchiveContext, cereal::JSONInputArchive>)
using JSONInputArchiveWithContext = cereal::UserDataAdapter<nodec_scene_serialization::ArchiveContext, cereal::JSONInputArchive>;

} // namespace internal
} // namespace nodec_scene_serialization

CEREAL_REGISTER_ARCHIVE(nodec_scene_serialization::internal::JSONInputArchiveWithContext)

#define NODEC_SCENE_REGISTER_SERIALIZABLE_COMPONENT(T) \
CEREAL_REGISTER_TYPE(T) \
CEREAL_REGISTER_POLYMORPHIC_RELATION(nodec_scene_serialization::BaseSerializableComponent, T)
Expand Down
38 changes: 25 additions & 13 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
set(NODEC_DIR ../../../nodec)
set(MODULE_DIR ../..)
include(FetchContent)

add_subdirectory(${NODEC_DIR} nodec)
add_subdirectory(${MODULE_DIR}/nodec_serialization nodec_serialization)
add_subdirectory(${MODULE_DIR}/nodec_scene nodec_scene)
function(add_target_if_missing TARGET GIT_REPOSITORY GIT_TAG)
if(TARGET ${TARGET})
return()
endif()

message("${TARGET} not found. Fetch the contents")
FetchContent_Declare(
${TARGET}
GIT_REPOSITORY ${GIT_REPOSITORY}
GIT_TAG ${GIT_TAG}
GIT_SHALLOW 1
)
FetchContent_MakeAvailable(${TARGET})
endfunction(add_target_if_missing)

add_target_if_missing(nodec https://github.com/nodec-project/nodec.git main)
add_target_if_missing(nodec_scene https://github.com/nodec-project/nodec_scene.git main)
add_target_if_missing(nodec_serialization https://github.com/nodec-project/nodec_serialization.git main)

function(add_basic_test TARGET TEST_SOURCES)
add_executable(${TARGET} ${TEST_SOURCES})
target_link_libraries(${TARGET} nodec_scene_serialization)
target_include_directories(${TARGET}
PRIVATE ${NODEC_DIR}/tests/common
)
target_include_directories(${TARGET} PRIVATE ${nodec_SOURCE_DIR}/tests/common)

add_test(NAME ${TARGET} COMMAND ${TARGET})
endfunction(add_basic_test)

add_basic_test("scene_serialization" scene_serialization.cpp)
add_basic_test("entity_serializer" entity_serializer.cpp)
add_basic_test("entity_builder" entity_builder.cpp)
add_basic_test("entity_loader" entity_loader.cpp)
add_basic_test("entity_load_system" prefab_load_system.cpp)
add_basic_test("nodec_scene_serialization__scene_serialization" scene_serialization.cpp)
add_basic_test("nodec_scene_serialization__entity_serializer" entity_serializer.cpp)
add_basic_test("nodec_scene_serialization__entity_builder" entity_builder.cpp)
add_basic_test("nodec_scene_serialization__entity_loader" entity_loader.cpp)
add_basic_test("nodec_scene_serialization__entity_load_system" prefab_load_system.cpp)