#include "GameObject.hpp" #include "Level.hpp" #include "Player.hpp" #include "SceneThings.hpp" #include "World.hpp" #include #include #include #include #include #include using namespace std::literals; namespace ProjectBrussel_UNITY_ID { GameObject* CreateGameObject(GameObject::Kind kind, GameWorld* world) { using enum Tags::GameObjectKind; switch (kind) { case KD_Generic: return new GameObject(world); case KD_SimpleGeometry: return new SimpleGeometryObject(world); case KD_Building: return new BuildingObject(world); case KD_LevelWrapper: return new LevelWrapperObject(world); default: break; } return nullptr; } bool ValidateGameObjectChild(GameObject* parent, GameObject* child) { return parent->GetWorld() == child->GetWorld(); } } // namespace ProjectBrussel_UNITY_ID void GameObject::FreeRecursive(GameObject* obj) { if (!obj->mStopFreePropagation) { for (auto child : obj->GetChildren()) { FreeRecursive(obj); } } delete obj; } GameObject::GameObject(GameWorld* world) : GameObject(KD_Generic, world) { } GameObject::GameObject(Kind kind, GameWorld* world) : mEditorAttachment{ nullptr } , mWorld{ world } , mParent{ nullptr } , mRot(1.0f, 0.0f, 0.0f, 0.0f) , mPos(0.0f, 0.0f, 0.0f) , mScale(1.0f, 1.0f, 1.0f) , mKind{ kind } { } GameObject::~GameObject() { RemoveAllChildren(); if (mParent) { mParent->RemoveChild(this); // NOTE: from this point on, mParent will be nullptr } } GameObject::Kind GameObject::GetKind() const { return mKind; } GameWorld* GameObject::GetWorld() const { return mWorld; } GameObject* GameObject::GetParent() const { return mParent; } const PodVector& GameObject::GetChildren() const { return mChildren; } void GameObject::AddChild(GameObject* child) { using namespace ProjectBrussel_UNITY_ID; if (child->mParent) { return; } if (!ValidateGameObjectChild(this, child)) { return; } mChildren.push_back(child); child->SetParent(this); } GameObject* GameObject::RemoveChild(int index) { if (index < 0 || index >= mChildren.size()) { return nullptr; } auto it = mChildren.begin() + index; auto child = *it; // cancelUpdate(ret); std::swap(*it, mChildren.back()); mChildren.pop_back(); child->SetParent(nullptr); return child; } GameObject* GameObject::RemoveChild(GameObject* child) { if (child) { for (auto it = mChildren.begin(); it != mChildren.end(); ++it) { if (*it == child) { // cancelUpdate(child); std::swap(*it, mChildren.back()); mChildren.pop_back(); child->SetParent(nullptr); return child; } } } return nullptr; } void GameObject::RemoveSelfFromParent() { if (mParent) { mParent->RemoveChild(this); } } PodVector GameObject::RemoveAllChildren() { for (auto& child : mChildren) { child->SetParent(nullptr); } auto result = std::move(mChildren); // Moving from STL object leaves it in a valid but _unspecified_ state, call std::vector::clear() to guarantee it's empty // NOTE: even though we have the source code of PodVector, we still do this to follow convention mChildren.clear(); return result; } const glm::vec3& GameObject::GetPos() const { return mPos; } void GameObject::SetPos(const glm::vec3& pos) { mPos = pos; } const glm::quat& GameObject::GetRotation() const { return mRot; } void GameObject::SetRotation(const glm::quat& rotation) { mRot = rotation; } const glm::vec3& GameObject::GetScale() const { return mScale; } void GameObject::SetScale(const glm::vec3& scale) { mScale = scale; } std::span GameObject::GetRenderObjects() const { return {}; } void GameObject::OnInitialized() { } void GameObject::Awaken() { } void GameObject::Resleep() { } void GameObject::Update() { } rapidjson::Value GameObject::Serialize(GameObject* obj, rapidjson::Document& root) { rapidjson::Value result(rapidjson::kObjectType); result.AddMember("Type", rapidjson::StringRef(Metadata::EnumToString(obj->GetKind())), root.GetAllocator()); rapidjson::Value rvValue(rapidjson::kObjectType); obj->WriteSaveFormat(rvValue, root); result.AddMember("Value", rvValue, root.GetAllocator()); return result; } std::unique_ptr GameObject::Deserialize(const rapidjson::Value& value, GameWorld* world) { using namespace ProjectBrussel_UNITY_ID; auto rvType = rapidjson::GetProperty(value, rapidjson::kStringType, "Type"sv); if (!rvType) return nullptr; auto rvValue = rapidjson::GetProperty(value, rapidjson::kObjectType, "Value"sv); if (!rvValue) return nullptr; auto kind = Metadata::EnumFromString(rapidjson::AsStringView(*rvType)); assert(kind.has_value()); auto obj = std::unique_ptr(CreateGameObject(kind.value(), world)); if (!obj) return nullptr; obj->ReadSaveFormat(*rvValue); return obj; } void GameObject::ReadSaveFormat(const rapidjson::Value& value) { } void GameObject::WriteSaveFormat(rapidjson::Value& value, rapidjson::Document& root) { } void GameObject::SetParent(GameObject* parent) { if (mParent != parent) { mParent = parent; // needUpdate(); } } #include