Skip to content

Commit

Permalink
add find_object specialization for scenery subtypes
Browse files Browse the repository at this point in the history
  • Loading branch information
sthalik committed Apr 14, 2024
1 parent c8ae1f8 commit 9d35200
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 10 deletions.
8 changes: 8 additions & 0 deletions compat/base-of.hpp
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions src/scenery-proto.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions src/scenery-type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ enum class scenery_type : unsigned char {
none, generic, door, COUNT,
};

template<typename T> struct scenery_type_;

} // namespace floormat
3 changes: 3 additions & 0 deletions src/scenery.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
27 changes: 22 additions & 5 deletions src/world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions src/world.hpp
Original file line number Diff line number Diff line change
@@ -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>
Expand Down Expand Up @@ -50,6 +52,7 @@ class world final
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;
Expand Down Expand Up @@ -91,6 +94,7 @@ class world final
}
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);
Expand Down
23 changes: 18 additions & 5 deletions test/save.cpp
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 9d35200

Please sign in to comment.