diff options
-rw-r--r-- | compat/base-of.hpp | 8 | ||||
-rw-r--r-- | src/scenery-proto.hpp | 3 | ||||
-rw-r--r-- | src/scenery-type.hpp | 2 | ||||
-rw-r--r-- | src/scenery.hpp | 3 | ||||
-rw-r--r-- | src/world.cpp | 27 | ||||
-rw-r--r-- | src/world.hpp | 4 | ||||
-rw-r--r-- | test/save.cpp | 23 |
7 files changed, 60 insertions, 10 deletions
diff --git a/compat/base-of.hpp b/compat/base-of.hpp new file mode 100644 index 00000000..d5f539d5 --- /dev/null +++ b/compat/base-of.hpp @@ -0,0 +1,8 @@ +#pragma once + +namespace floormat { + +template<typename Base, typename Derived> +constexpr inline bool is_strict_base_of = std::is_base_of_v<Base, Derived> && !std::is_same_v<Base, Derived>; + +} // namespace floormat diff --git a/src/scenery-proto.hpp b/src/scenery-proto.hpp index c5889b04..44c8fe6f 100644 --- a/src/scenery-proto.hpp +++ b/src/scenery-proto.hpp @@ -41,4 +41,7 @@ struct scenery_proto : object_proto scenery_proto& operator=(scenery_proto&&) noexcept; }; +template<> struct scenery_type_<generic_scenery_proto> : std::integral_constant<scenery_type, scenery_type::generic> {}; +template<> struct scenery_type_<door_scenery_proto> : std::integral_constant<scenery_type, scenery_type::door> {}; + } // namespace floormat diff --git a/src/scenery-type.hpp b/src/scenery-type.hpp index 3879e225..98cb9b10 100644 --- a/src/scenery-type.hpp +++ b/src/scenery-type.hpp @@ -6,4 +6,6 @@ enum class scenery_type : unsigned char { none, generic, door, COUNT, }; +template<typename T> struct scenery_type_; + } // namespace floormat diff --git a/src/scenery.hpp b/src/scenery.hpp index 6699fe2f..beb06db5 100644 --- a/src/scenery.hpp +++ b/src/scenery.hpp @@ -66,4 +66,7 @@ template<> struct object_type_<generic_scenery> : std::integral_constant<object_ template<> struct object_type_<door_scenery> : std::integral_constant<object_type, object_type::scenery> {}; template<> struct object_type_<scenery_proto> : std::integral_constant<object_type, object_type::scenery> {}; +template<> struct scenery_type_<generic_scenery> : std::integral_constant<scenery_type, scenery_type::generic> {}; +template<> struct scenery_type_<door_scenery> : std::integral_constant<scenery_type, scenery_type::door> {}; + } // namespace floormat diff --git a/src/world.cpp b/src/world.cpp index 9f7c0cc3..dd6f2ca7 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -196,7 +196,12 @@ void world::set_object_counter(object_id value) void world::throw_on_wrong_object_type(object_id id, object_type actual, object_type expected) { - fm_throw("object '{}' has wrong object type '{}', should be '{}'"_cf, id, (size_t)actual, (size_t)expected); + fm_throw("object {} has wrong object type {}, should be {}"_cf, id, (size_t)actual, (size_t)expected); +} + +void world::throw_on_wrong_scenery_type(object_id id, scenery_type actual, scenery_type expected) +{ + fm_throw("object {} has wrong scenery type {}, should be {}"_cf, id, (size_t)actual, (size_t)expected); } void world::throw_on_empty_scenery_proto(object_id id, global_coords pos, Vector2b offset) @@ -285,18 +290,30 @@ std::shared_ptr<T> world::find_object(object_id id) return {}; else if constexpr(std::is_same_v<T, object>) return ptr; + else if (ptr->type() != object_type_<T>::value) [[unlikely]] + throw_on_wrong_object_type(id, ptr->type(), object_type_<T>::value); + else + return static_pointer_cast<T>(move(ptr)); +} + +template<typename T> +requires is_strict_base_of<scenery, T> +std::shared_ptr<T> world::find_object(object_id id) +{ + if (auto ptr = find_object<scenery>(id); !ptr) + return {}; + else if (ptr->scenery_type() != scenery_type_<T>::value) [[unlikely]] + throw_on_wrong_scenery_type(id, ptr->scenery_type(), scenery_type_<T>::value); else - { - if (!(ptr->type() == object_type_<T>::value)) [[unlikely]] - throw_on_wrong_object_type(id, ptr->type(), object_type_<T>::value); return static_pointer_cast<T>(move(ptr)); - } } template std::shared_ptr<object> world::find_object<object>(object_id id); template std::shared_ptr<critter> world::find_object<critter>(object_id id); template std::shared_ptr<scenery> world::find_object<scenery>(object_id id); template std::shared_ptr<light> world::find_object<light>(object_id id); +template std::shared_ptr<generic_scenery> world::find_object<generic_scenery>(object_id id); +template std::shared_ptr<door_scenery> world::find_object<door_scenery>(object_id id); template<bool sorted> std::shared_ptr<scenery> world::make_scenery(object_id id, global_coords pos, scenery_proto&& proto) diff --git a/src/world.hpp b/src/world.hpp index e92979db..52cb1f64 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -1,8 +1,10 @@ #pragma once #include "compat/safe-ptr.hpp" +#include "compat/base-of.hpp" #include "chunk.hpp" #include "global-coords.hpp" #include "object-type.hpp" +#include "scenery-type.hpp" #include "loader/policy.hpp" #include <memory> #include <unordered_map> @@ -50,6 +52,7 @@ private: std::shared_ptr<object> find_object_(object_id id); [[noreturn]] static void throw_on_wrong_object_type(object_id id, object_type actual, object_type expected); + [[noreturn]] static void throw_on_wrong_scenery_type(object_id id, scenery_type actual, scenery_type expected); [[noreturn]] static void throw_on_empty_scenery_proto(object_id id, global_coords pos, Vector2b offset); friend struct object; @@ -91,6 +94,7 @@ public: } template<bool sorted = true> std::shared_ptr<scenery> make_scenery(object_id id, global_coords pos, scenery_proto&& proto); template<typename T = object> std::shared_ptr<T> find_object(object_id id); + template<typename T> requires is_strict_base_of<scenery, T> std::shared_ptr<T> find_object(object_id id); shared_ptr_wrapper<critter> ensure_player_character(object_id& id, critter_proto p); shared_ptr_wrapper<critter> ensure_player_character(object_id& id); diff --git a/test/save.cpp b/test/save.cpp index 8edb5b4d..675041c7 100644 --- a/test/save.cpp +++ b/test/save.cpp @@ -1,6 +1,7 @@ #include "app.hpp" #include "src/world.hpp" #include "loader/loader.hpp" +#include "loader/scenery-cell.hpp" #include "src/scenery.hpp" #include "src/scenery-proto.hpp" #include "src/critter.hpp" @@ -264,18 +265,30 @@ void test_save_objs() fm_assert(p.falloff == obj2.falloff); fm_assert(p.enabled == obj2.enabled); assert_chunks_equal(w.at(ch), w2.at(ch)); + //const auto obj3 = w.find_object<generic_scenery>(id); // must fail + } + + { + // --- scenery --- + auto w = world(); + scenery_proto p; + p.atlas = loader.invalid_scenery_atlas().proto->atlas; + p.subtype = generic_scenery_proto{}; + constexpr auto ch = chunk_coords_{-3, 4, 0}; + constexpr auto coord = global_coords{ch, { 3, 4}}; + const auto id = w.make_id(); + const auto objʹ = w.make_scenery(id, coord, move(p)); + const auto obj = std::static_pointer_cast<generic_scenery>(objʹ); + const auto obj2 = w.find_object<generic_scenery>(id); + //const auto obj3 = w.find_object<door_scenery>(id); // must fail + fm_assert(obj == obj2); } #if 0 - constexpr auto coord = global_coords{{-3, 4, 0}, { 3, 4}}; constexpr auto coord = global_coords{{ 5, -6, 0}, { 4, 7}}; constexpr auto coord = global_coords{{-7, 8, 0}, { 9, 1}}; constexpr auto coord = global_coords{{ 9, 0, 0}, {15, 0}}; #endif - - { - - } } } // namespace |