From 31fd5bbc08234686cf798a93a18e0bb73615d1bf Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 1 Sep 2023 22:27:30 +0200 Subject: rename entity -> object --- draw/anim.cpp | 2 +- draw/anim.hpp | 6 +- editor/app.cpp | 8 +- editor/app.hpp | 2 +- editor/camera.cpp | 2 +- editor/draw.cpp | 2 +- editor/editor.cpp | 2 +- editor/imgui.cpp | 16 +-- editor/inspect-draw.cpp | 4 +- editor/inspect-types.cpp | 74 +++++------ editor/inspect.hpp | 4 +- editor/scenery-editor.cpp | 6 +- editor/update.cpp | 4 +- editor/vobj-editor.cpp | 10 +- editor/vobj-editor.hpp | 8 +- main/clickable.hpp | 4 +- serialize/scenery.cpp | 4 +- serialize/world-impl.hpp | 14 +-- serialize/world-reader.cpp | 62 +++++----- serialize/world-writer.cpp | 58 ++++----- shaders/lightmap.cpp | 8 +- shaders/lightmap.hpp | 2 +- src/character.cpp | 16 +-- src/character.hpp | 14 +-- src/chunk-collision.cpp | 12 +- src/chunk-scenery.cpp | 30 ++--- src/chunk-scenery.hpp | 10 +- src/chunk.cpp | 44 +++---- src/chunk.hpp | 32 ++--- src/entity-type.hpp | 10 -- src/entity.cpp | 300 --------------------------------------------- src/entity.hpp | 89 -------------- src/light.cpp | 8 +- src/light.hpp | 12 +- src/object-type.hpp | 10 ++ src/object.cpp | 300 +++++++++++++++++++++++++++++++++++++++++++++ src/object.hpp | 89 ++++++++++++++ src/scenery.cpp | 12 +- src/scenery.hpp | 14 +-- src/world.cpp | 54 ++++---- src/world.hpp | 54 ++++---- test/entity.cpp | 259 -------------------------------------- test/object.cpp | 259 ++++++++++++++++++++++++++++++++++++++ test/serializer.cpp | 22 ++-- 44 files changed, 976 insertions(+), 976 deletions(-) delete mode 100644 src/entity-type.hpp delete mode 100644 src/entity.cpp delete mode 100644 src/entity.hpp create mode 100644 src/object-type.hpp create mode 100644 src/object.cpp create mode 100644 src/object.hpp delete mode 100644 test/entity.cpp create mode 100644 test/object.cpp diff --git a/draw/anim.cpp b/draw/anim.cpp index 5f52f680..e83bf5e5 100644 --- a/draw/anim.cpp +++ b/draw/anim.cpp @@ -28,7 +28,7 @@ std::array anim_mesh::make_index_array() } void anim_mesh::add_clickable(tile_shader& shader, const Vector2i& win_size, - entity* s_, const chunk::topo_sort_data& data, + object* s_, const chunk::topo_sort_data& data, std::vector& list) { const auto& s = *s_; diff --git a/draw/anim.hpp b/draw/anim.hpp index ebee14be..5951e11b 100644 --- a/draw/anim.hpp +++ b/draw/anim.hpp @@ -20,7 +20,7 @@ struct tile_shader; struct anim_atlas; struct chunk; struct clickable; -struct entity; +struct object; struct anim_mesh final { @@ -30,7 +30,7 @@ struct anim_mesh final void draw(tile_shader& shader, anim_atlas& atlas, rotation r, size_t frame, const Vector3& pos, float depth); void draw(tile_shader& shader, anim_atlas& atlas, rotation r, size_t frame, local_coords xy, Vector2b offset, float dpeth); static void add_clickable(tile_shader& shader, const Vector2i& win_size, - entity* s_, const chunk::topo_sort_data& data, + object* s_, const chunk::topo_sort_data& data, std::vector& list); private: @@ -43,7 +43,7 @@ private: }; using quad_data = std::array; - Array _draw_array; + Array _draw_array; Array> _draw_indexes; Array> _draw_vertexes; diff --git a/editor/app.cpp b/editor/app.cpp index e1e4af39..43e3116c 100644 --- a/editor/app.cpp +++ b/editor/app.cpp @@ -39,7 +39,7 @@ void app::reset_world() void app::ensure_player_character(world& w) { if (_character_id) - if (auto C = w.find_entity(_character_id); C && C->type() == entity_type::character) + if (auto C = w.find_object(_character_id); C && C->type() == object_type::character) return; _character_id = 0; @@ -47,10 +47,10 @@ void app::ensure_player_character(world& w) for (const auto& [coord, c] : w.chunks()) { - for (const auto& e_ : c.entities()) + for (const auto& e_ : c.objects()) { const auto& e = *e_; - if (e.type() == entity_type::character) + if (e.type() == object_type::character) { const auto& C = static_cast(e); if (C.playable) @@ -66,7 +66,7 @@ void app::ensure_player_character(world& w) character_proto cproto; cproto.name = "Player"_s; cproto.playable = true; - _character_id = w.make_entity(w.make_id(), global_coords{}, cproto)->id; + _character_id = w.make_object(w.make_id(), global_coords{}, cproto)->id; } } diff --git a/editor/app.hpp b/editor/app.hpp index 6002c702..d3a02017 100644 --- a/editor/app.hpp +++ b/editor/app.hpp @@ -45,7 +45,7 @@ enum class popup_target_type : unsigned char { }; struct popup_target final { - object_id id; // todo switch to weak_ptr + object_id id; // todo switch to weak_ptr popup_target_type target = popup_target_type::none; bool operator==(const popup_target&) const; }; diff --git a/editor/camera.cpp b/editor/camera.cpp index 77e3a149..48a783cc 100644 --- a/editor/camera.cpp +++ b/editor/camera.cpp @@ -113,7 +113,7 @@ object_id app::object_at_cursor() Vector2 min(rect.m_min[0], rect.m_min[1]), max(rect.m_max[0], rect.m_max[1]); if (t0 >= min && t0 <= max) { - if (auto e_ = world.find_entity(x.data); + if (auto e_ = world.find_object(x.data); e_ && Vector2ui(e_->bbox_size).product() != 0) { ret = x.data; diff --git a/editor/draw.cpp b/editor/draw.cpp index 0b469380..bd0d863d 100644 --- a/editor/draw.cpp +++ b/editor/draw.cpp @@ -60,7 +60,7 @@ void app::draw_cursor() const auto offset = Vector3i(Vector2i(sel.offset), 0); const auto pos = cursor.tile->to_signed3()*iTILE_SIZE + offset; auto [ch, t] = w[*cursor.tile]; - if (!ch.can_place_entity(sel, cursor.tile->local())) + if (!ch.can_place_object(sel, cursor.tile->local())) shader.set_tint({1, 0, 1, 0.5f}); anim_mesh.draw(shader, *sel.atlas, sel.r, sel.frame, Vector3(pos), 1); } diff --git a/editor/editor.cpp b/editor/editor.cpp index a1de4b4f..9d283da0 100644 --- a/editor/editor.cpp +++ b/editor/editor.cpp @@ -110,7 +110,7 @@ void editor::on_click_(world& world, global_coords pos, button b) default: break; case button::place: if (const auto& sel = mode->get_selected()) - if (auto [ch, t] = world[pos]; ch.can_place_entity(sel.proto, pos.local())) + if (auto [ch, t] = world[pos]; ch.can_place_object(sel.proto, pos.local())) mode->place_tile(world, pos, sel, *_app); break; case button::remove: diff --git a/editor/imgui.cpp b/editor/imgui.cpp index 50ce0628..b0ac33fa 100644 --- a/editor/imgui.cpp +++ b/editor/imgui.cpp @@ -164,7 +164,7 @@ void app::draw_light_info() for (const auto& x : M->clickable_scenery()) { - if (x.e->type() == entity_type::light) + if (x.e->type() == object_type::light) { const auto dest = Math::Range2D(x.dest); const auto& e = static_cast(*x.e); @@ -210,12 +210,12 @@ void app::do_lightmap_test() return; auto& w = M->world(); - auto e_ = w.find_entity(_tested_light); + auto e_ = w.find_object(_tested_light); if (e_) { auto& e = *e_; - fm_assert(e_->type() == entity_type::light); + fm_assert(e_->type() == object_type::light); auto& shader = M->lightmap_shader(); auto ch = e.coord.chunk(); auto z = e.coord.z(); @@ -244,9 +244,9 @@ void app::do_lightmap_test() if (auto* chunk = w.at(c)) { auto offset = Vector2(Vector2i(c.x) - Vector2i(ch)); - for (const auto& e_ : chunk->entities()) + for (const auto& e_ : chunk->objects()) { - if (e_->type() == entity_type::light) + if (e_->type() == object_type::light) { const auto& li = static_cast(*e_); light_s L { @@ -311,7 +311,7 @@ void app::do_popup_menu() { const auto [id, target] = _popup_target; auto& w = M->world(); - auto e_ = w.find_entity(id); + auto e_ = w.find_object(id); if (target == popup_target_type::none || !e_) { @@ -343,7 +343,7 @@ void app::do_popup_menu() ImGui::MenuItem("Inspect", nullptr, !b_ins, b_ins)) inspectors.push_back(std::exchange(_popup_target, {})); if (bool b_testing = e.id == _tested_light; - e.type() == entity_type::light) + e.type() == object_type::light) if (ImGui::MenuItem("Test", nullptr, b_testing)) _tested_light = e.id; ImGui::SeparatorText("Modify"); @@ -351,7 +351,7 @@ void app::do_popup_menu() ImGui::MenuItem("Rotate", nullptr, false, next_rot != e.r && e.can_rotate(next_rot))) e.rotate(i, next_rot); if (ImGui::MenuItem("Delete", nullptr, false)) - e.chunk().remove_entity(e.index()); + e.chunk().remove_object(e.index()); } else _popup_target = {}; diff --git a/editor/inspect-draw.cpp b/editor/inspect-draw.cpp index be32edf7..fc5cbaab 100644 --- a/editor/inspect-draw.cpp +++ b/editor/inspect-draw.cpp @@ -30,7 +30,7 @@ void app::draw_inspector() for (auto i = inspectors.size()-1; i != -1uz; i--) { auto [id, target] = inspectors[i]; - auto e_ = w.find_entity(id); + auto e_ = w.find_object(id); if (!e_) { inspectors.erase(inspectors.begin() + ptrdiff_t(i)); @@ -56,7 +56,7 @@ auto z = e.coord.z(); bool is_open = true; if (auto b2 = begin_window(buf, &is_open)) { - bool ret = entities::inspect_entity_subtype(e); + bool ret = entities::inspect_object_subtype(e); (void)ret; } if (!is_open) diff --git a/editor/inspect-types.cpp b/editor/inspect-types.cpp index e29d5df9..84fbbd5d 100644 --- a/editor/inspect-types.cpp +++ b/editor/inspect-types.cpp @@ -16,51 +16,51 @@ namespace floormat::entities { using st = field_status; template<> -struct entity_accessors { +struct entity_accessors { static constexpr auto accessors() { - using E = Entity; + using E = Entity; return std::tuple{ E::type::field{"id"_s, - [](const entity& x) { return x.id; }, - [](entity&, object_id) {}, + [](const object& x) { return x.id; }, + [](object&, object_id) {}, constantly(st::readonly), }, E::type::field{"atlas"_s, - [](const entity& x) { return loader.strip_prefix(x.atlas->name()); }, - [](entity&, StringView) {}, + [](const object& x) { return loader.strip_prefix(x.atlas->name()); }, + [](object&, StringView) {}, constantly(st::readonly), }, E::type::field{"rotation"_s, - [](const entity& x) { return x.r; }, - [](entity& x, rotation r) { x.rotate(x.index(), r); }, + [](const object& x) { return x.r; }, + [](object& x, rotation r) { x.rotate(x.index(), r); }, }, E::type::field{"frame"_s, - [](const entity& x) { return x.frame; }, - [](entity& x, uint16_t value) { x.frame = value; }, - [](const entity& x) { + [](const object& x) { return x.frame; }, + [](object& x, uint16_t value) { x.frame = value; }, + [](const object& x) { return constraints::range{0, !x.atlas ? uint16_t(0) : uint16_t(x.atlas->info().nframes-1)}; }, }, E::type::field{"offset"_s, - [](const entity& x) { return Vector2i(x.offset); }, - //[](entity& x, Vector2i value) { x.set_bbox(value, x.bbox_offset, x.bbox_size, x.pass); }, - [](entity& x, Vector2i value) { x.move_to(value - Vector2i(x.offset)); }, + [](const object& x) { return Vector2i(x.offset); }, + //[](object& x, Vector2i value) { x.set_bbox(value, x.bbox_offset, x.bbox_size, x.pass); }, + [](object& x, Vector2i value) { x.move_to(value - Vector2i(x.offset)); }, //constantly(constraints::range{Vector2b(iTILE_SIZE2/-2), Vector2b(iTILE_SIZE2/2)}), }, E::type::field{"pass-mode"_s, - [](const entity& x) { return x.pass; }, - [](entity& x, pass_mode value) { x.set_bbox(x.offset, x.bbox_offset, x.bbox_size, value); }, + [](const object& x) { return x.pass; }, + [](object& x, pass_mode value) { x.set_bbox(x.offset, x.bbox_offset, x.bbox_size, value); }, }, E::type::field{"bbox-offset"_s, - [](const entity& x) { return x.bbox_offset; }, - [](entity& x, Vector2b value) { x.set_bbox(x.offset, value, x.bbox_size, x.pass); }, - [](const entity& x) { return x.pass == pass_mode::pass ? st::readonly : st::enabled; }, + [](const object& x) { return x.bbox_offset; }, + [](object& x, Vector2b value) { x.set_bbox(x.offset, value, x.bbox_size, x.pass); }, + [](const object& x) { return x.pass == pass_mode::pass ? st::readonly : st::enabled; }, }, E::type::field{"bbox-size"_s, - [](const entity& x) { return x.bbox_size; }, - [](entity& x, Vector2ub value) { x.set_bbox(x.offset, x.bbox_offset, value, x.pass); }, - [](const entity& x) { return x.pass == pass_mode::pass ? st::readonly : st::enabled; }, + [](const object& x) { return x.bbox_size; }, + [](object& x, Vector2ub value) { x.set_bbox(x.offset, x.bbox_offset, value, x.pass); }, + [](const object& x) { return x.pass == pass_mode::pass ? st::readonly : st::enabled; }, }, }; } @@ -71,7 +71,7 @@ struct entity_accessors { static constexpr auto accessors() { using E = Entity; - auto tuple0 = entity_accessors::accessors(); + auto tuple0 = entity_accessors::accessors(); auto tuple = std::tuple{ E::type::field{"interactive"_s, [](const scenery& x) { return x.interactive; }, @@ -87,15 +87,15 @@ template struct has_anim_atlas : std::false_type {} template requires requires (const T& x) { { x.atlas } -> std::convertible_to&>; } struct has_anim_atlas : std::true_type { - static const anim_atlas& get_atlas(const entity& x) { return *x.atlas; } + static const anim_atlas& get_atlas(const object& x) { return *x.atlas; } }; #if 0 -template<> struct has_anim_atlas : std::true_type { - static const anim_atlas& get_atlas(const entity& x) { return *x.atlas; } +template<> struct has_anim_atlas : std::true_type { + static const anim_atlas& get_atlas(const object& x) { return *x.atlas; } }; -template<> struct has_anim_atlas : has_anim_atlas {}; -template<> struct has_anim_atlas : has_anim_atlas {}; +template<> struct has_anim_atlas : has_anim_atlas {}; +template<> struct has_anim_atlas : has_anim_atlas {}; #endif using enum_pair = std::pair; @@ -178,7 +178,7 @@ struct entity_accessors { static constexpr auto accessors() { using E = Entity; - auto tuple0 = entity_accessors::accessors(); + auto tuple0 = entity_accessors::accessors(); auto tuple = std::tuple{ E::type::field{"name"_s, [](const character& x) { return x.name; }, @@ -209,7 +209,7 @@ struct entity_accessors static constexpr auto accessors() { using E = Entity; - auto tuple0 = entity_accessors::accessors(); + auto tuple0 = entity_accessors::accessors(); auto tuple = std::tuple{ E::type::field{"color"_s, [](const light& x) { return x.color; }, @@ -233,20 +233,20 @@ struct entity_accessors } }; -//template bool inspect_type(entity&); +//template bool inspect_type(object&); template bool inspect_type(scenery&, inspect_intent_t); template bool inspect_type(character&, inspect_intent_t); template bool inspect_type(light&, inspect_intent_t); -bool inspect_entity_subtype(entity& x) +bool inspect_object_subtype(object& x) { switch (auto type = x.type()) { - default: fm_warn_once("unknown entity subtype '%d'", (int)type); return false; - //case entity_type::none: return inspect_type(x); - case entity_type::scenery: return inspect_type(static_cast(x), inspect_intent_t{}); - case entity_type::character: return inspect_type(static_cast(x), inspect_intent_t{}); - case entity_type::light: return inspect_type(static_cast(x), inspect_intent_t{}); + default: fm_warn_once("unknown object subtype '%d'", (int)type); return false; + //case object_type::none: return inspect_type(x); + case object_type::scenery: return inspect_type(static_cast(x), inspect_intent_t{}); + case object_type::character: return inspect_type(static_cast(x), inspect_intent_t{}); + case object_type::light: return inspect_type(static_cast(x), inspect_intent_t{}); } } diff --git a/editor/inspect.hpp b/editor/inspect.hpp index 5bfb7c1f..df543f96 100644 --- a/editor/inspect.hpp +++ b/editor/inspect.hpp @@ -1,6 +1,6 @@ #pragma once #include -namespace floormat { struct entity; } +namespace floormat { struct object; } namespace floormat::entities { struct erased_accessor; @@ -27,7 +27,7 @@ template using field_repr_slider = field_repr_ using field_repr_drag = field_repr_; template using field_repr_cbx = field_repr_; -bool inspect_entity_subtype(entity& x); +bool inspect_object_subtype(object& x); template bool inspect_field(void* datum, const entities::erased_accessor& accessor, const ArrayView>& list, diff --git a/editor/scenery-editor.cpp b/editor/scenery-editor.cpp index 66ff94bb..19a24e99 100644 --- a/editor/scenery-editor.cpp +++ b/editor/scenery-editor.cpp @@ -85,14 +85,14 @@ void scenery_editor::place_tile(world& w, global_coords pos, const scenery_& s, if (!s) { auto [c, t] = w[pos]; - const auto& es = c.entities(); + const auto& es = c.objects(); start: while (auto id = a.object_at_cursor()) { for (auto i = es.size()-1; i != (size_t)-1; i--) { if (es[i]->id == id) { - c.remove_entity(i); + c.remove_object(i); goto start; } } @@ -101,7 +101,7 @@ start: while (auto id = a.object_at_cursor()) } else // todo check collision at pos - w.make_entity(w.make_id(), pos, s.proto); + w.make_object(w.make_id(), pos, s.proto); } } // namespace floormat diff --git a/editor/update.cpp b/editor/update.cpp index ae64a2f3..4dacaf8a 100644 --- a/editor/update.cpp +++ b/editor/update.cpp @@ -222,7 +222,7 @@ void app::update_world(float dt) if (!c_) continue; auto& c = *c_; - const auto& es = c.entities(); + const auto& es = c.objects(); const auto size = es.size(); for (auto i = size-1; i != (size_t)-1; i--) es[i]->update(i, dt); @@ -234,7 +234,7 @@ void app::update_character([[maybe_unused]] float dt) if (_character_id) { auto& w = M->world(); - auto c = w.find_entity(_character_id); + auto c = w.find_object(_character_id); if (c && c->playable) c->set_keys(keys[key_left], keys[key_right], keys[key_up], keys[key_down]); } diff --git a/editor/vobj-editor.cpp b/editor/vobj-editor.cpp index d242f68f..4d3f3f03 100644 --- a/editor/vobj-editor.cpp +++ b/editor/vobj-editor.cpp @@ -45,14 +45,14 @@ void vobj_editor::place_tile(world& w, global_coords pos, const vobj_* x, struct if (!x) { auto [c, t] = w[pos]; - const auto& es = c.entities(); + const auto& es = c.objects(); start: while (auto id = a.object_at_cursor()) { for (auto i = es.size()-1; i != (size_t)-1; i--) { if (es[i]->id == id) { - c.remove_entity(i); + c.remove_object(i); goto start; } } @@ -69,7 +69,7 @@ start: while (auto id = a.object_at_cursor()) struct light_factory final : vobj_factory { - entity_type type() const override { return entity_type::light; } + object_type type() const override { return object_type::light; } const vobj_info& info() const override { @@ -80,9 +80,9 @@ struct light_factory final : vobj_factory return ret; } - std::shared_ptr make(world& w, object_id id, global_coords pos) const override + std::shared_ptr make(world& w, object_id id, global_coords pos) const override { - auto ret = w.make_entity(id, pos, light_proto{}); + auto ret = w.make_object(id, pos, light_proto{}); return ret; } }; diff --git a/editor/vobj-editor.hpp b/editor/vobj-editor.hpp index 46b5dce1..d8477011 100644 --- a/editor/vobj-editor.hpp +++ b/editor/vobj-editor.hpp @@ -1,5 +1,5 @@ #pragma once -#include "src/entity-type.hpp" +#include "src/object-type.hpp" #include "src/object-id.hpp" #include #include @@ -14,7 +14,7 @@ namespace floormat { struct world; struct global_coords; -struct entity; +struct object; struct anim_atlas; struct vobj_info; struct app; @@ -29,8 +29,8 @@ struct vobj_factory vobj_factory(); virtual ~vobj_factory() noexcept; virtual const vobj_info& info() const = 0; - virtual entity_type type() const = 0; - virtual std::shared_ptr make(world& w, object_id id, global_coords pos) const = 0; + virtual object_type type() const = 0; + virtual std::shared_ptr make(world& w, object_id id, global_coords pos) const = 0; StringView name() const; StringView descr() const; diff --git a/main/clickable.hpp b/main/clickable.hpp index da50a1d1..88c309ef 100644 --- a/main/clickable.hpp +++ b/main/clickable.hpp @@ -6,13 +6,13 @@ namespace floormat { -struct entity; +struct object; struct clickable final { Math::Range2D src; Math::Range2D dest; BitArrayView bitmask; - entity* e; + object* e; float depth, slope; Vector2s bb_min, bb_max; // debug only uint32_t stride; diff --git a/serialize/scenery.cpp b/serialize/scenery.cpp index 6bcd5fa9..33f81285 100644 --- a/serialize/scenery.cpp +++ b/serialize/scenery.cpp @@ -137,7 +137,7 @@ void adl_serializer::from_json(const json& j, scenery_proto& f) default: fm_throw("unhandled scenery type '{}'"_cf, (unsigned)type); case scenery_type::generic: - f.type = entity_type::scenery; + f.type = object_type::scenery; f.sc_type = scenery_type::generic; f.r = r; f.frame = frame; @@ -150,7 +150,7 @@ void adl_serializer::from_json(const json& j, scenery_proto& f) break; case scenery_type::door: fm_assert(f.atlas->info().fps > 0 && f.atlas->info().nframes > 0); - f.type = entity_type::scenery; + f.type = object_type::scenery; f.sc_type = scenery_type::door; f.r = r; f.frame = uint16_t(f.atlas->group(r).frames.size()-1); diff --git a/serialize/world-impl.hpp b/serialize/world-impl.hpp index d56c432c..b01e81ba 100644 --- a/serialize/world-impl.hpp +++ b/serialize/world-impl.hpp @@ -6,7 +6,7 @@ #include "src/tile.hpp" #include "src/pass-mode.hpp" #include "src/rotation.hpp" -#include "src/entity-type.hpp" +#include "src/object-type.hpp" #include #include #include @@ -24,16 +24,16 @@ * 9) Interned strings. * 10) Chunk Z level. * 11) RLE empty tiles. - * 12) Don't write entity name twice. + * 12) Don't write object name twice. * 13) Entity counter initialized to 1024. - * 14) Always store entity offset, rework how sc_exact works. + * 14) Always store object offset, rework how sc_exact works. * 15) Add light alpha. * 16) One more bit for light falloff enum. */ namespace floormat { -struct entity; -struct entity_proto; +struct object; +struct object_proto; } // namespace floormat namespace floormat::Serialize { @@ -63,7 +63,7 @@ constexpr inline auto scenery_magic = (uint16_t)~0xb00b; using pass_mode_i = std::underlying_type_t; constexpr inline pass_mode_i pass_mask = (1 << pass_mode_BITS)-1; -using entity_type_i = std::underlying_type_t; +using object_type_i = std::underlying_type_t; template constexpr inline auto highbits = (T(1) << N)-1 << sizeof(T)*8-N-off; @@ -78,7 +78,7 @@ constexpr inline atlasid scenery_id_max = int_max & ~scenery_id_flag_ma } // namespace -template concept entity_subtype = std::is_base_of_v || std::is_base_of_v; +template concept object_subtype = std::is_base_of_v || std::is_base_of_v; enum : tilemeta { meta_ground = 1 << 2, diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index b9dc0027..769dda20 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -40,7 +40,7 @@ private: world* _world; uint16_t PROTO = proto_version; - Array draw_array; + Array draw_array; Array> draw_vertexes; Array> draw_indexes; }; @@ -63,26 +63,26 @@ void reader_state::read_atlases(reader_t& s) } } -template -bool read_entity_flags(binary_reader& s, U& e) +template +bool read_object_flags(binary_reader& s, U& e) { - constexpr auto tag = entity_type_::value; + constexpr auto tag = object_type_::value; uint8_t flags; flags << s; e.pass = pass_mode(flags & pass_mask); if (e.type != tag) - fm_throw("invalid entity type '{}'"_cf, (int)e.type); - if constexpr(tag == entity_type::scenery) + fm_throw("invalid object type '{}'"_cf, (int)e.type); + if constexpr(tag == object_type::scenery) { e.active = !!(flags & 1 << 2); e.closing = !!(flags & 1 << 3); e.interactive = !!(flags & 1 << 4); } - else if constexpr(tag == entity_type::character) + else if constexpr(tag == object_type::character) { e.playable = !!(flags & 1 << 2); } else - static_assert(tag == entity_type::none); + static_assert(tag == object_type::none); return flags & 1 << 7; } @@ -109,7 +109,7 @@ void reader_state::read_sceneries(reader_t& s) atlasid id; id << s; fm_soft_assert(id < sz); fm_soft_assert(!sceneries[id]); - bool short_frame = read_entity_flags(s, sc); + bool short_frame = read_object_flags(s, sc); fm_debug_assert(sc.atlas != nullptr); if (short_frame) sc.frame = s.read(); @@ -164,7 +164,7 @@ StringView reader_state::lookup_string(uint32_t idx) void reader_state::read_chunks(reader_t& s) { - Array array; + Array array; const auto N = s.read(); #ifndef FM_NO_DEBUG [[maybe_unused]] size_t nbytes_read = 0; @@ -230,18 +230,18 @@ void reader_state::read_chunks(reader_t& s) read_old_scenery(s, ch, i); SET_CHUNK_SIZE(); } - uint32_t entity_count = 0; + uint32_t object_count = 0; if (PROTO >= 8) [[likely]] - entity_count << s; + object_count << s; SET_CHUNK_SIZE(); - for (auto i = 0uz; i < entity_count; i++) + for (auto i = 0uz; i < object_count; i++) { object_id _id; _id << s; const auto oid = _id & lowbits<60, object_id>; fm_soft_assert(oid != 0); - const auto type = entity_type(_id >> 61); + const auto type = object_type(_id >> 61); const auto local = local_coords{s.read()}; Vector2b offset; @@ -259,12 +259,12 @@ void reader_state::read_chunks(reader_t& s) SET_CHUNK_SIZE(); switch (type) { - case entity_type::character: { + case object_type::character: { character_proto proto; proto.offset = offset; uint8_t id; id << s; proto.r = rotation(id >> sizeof(id)*8-1-rotation_BITS & rotation_MASK); - if (read_entity_flags(s, proto)) + if (read_object_flags(s, proto)) proto.frame = s.read(); else proto.frame << s; @@ -297,12 +297,12 @@ void reader_state::read_chunks(reader_t& s) read_bbox(s, proto); } SET_CHUNK_SIZE(); - auto e = _world->make_entity(oid, {ch, local}, proto); + auto e = _world->make_object(oid, {ch, local}, proto); e->offset_frac = offset_frac; (void)e; break; } - case entity_type::scenery: { + case object_type::scenery: { atlasid id; id << s; const bool exact = id & meta_short_scenery_bit; const auto r = rotation(id >> sizeof(id)*8-1-rotation_BITS & rotation_MASK); @@ -313,7 +313,7 @@ void reader_state::read_chunks(reader_t& s) sc.r = r; if (!exact) { - if (read_entity_flags(s, sc)) + if (read_object_flags(s, sc)) sc.frame = s.read(); else sc.frame << s; @@ -327,11 +327,11 @@ void reader_state::read_chunks(reader_t& s) if (sc.active) sc.delta << s; } - auto e = _world->make_entity(oid, {ch, local}, sc); + auto e = _world->make_object(oid, {ch, local}, sc); (void)e; break; } - case entity_type::light: { + case object_type::light: { light_proto proto; proto.offset = offset; @@ -364,20 +364,20 @@ void reader_state::read_chunks(reader_t& s) read_bbox(s, proto); } SET_CHUNK_SIZE(); - auto L = _world->make_entity(oid, {ch, local}, proto); + auto L = _world->make_object(oid, {ch, local}, proto); L->enabled = enabled; (void)L; break; } default: - fm_throw("invalid_entity_type '{}'"_cf, (int)type); + fm_throw("invalid_object_type '{}'"_cf, (int)type); } } SET_CHUNK_SIZE(); fm_assert(c.is_scenery_modified()); fm_assert(c.is_passability_modified()); - c.sort_entities(); + c.sort_objects(); c.ensure_ground_mesh(); c.ensure_wall_mesh(); c.ensure_scenery_mesh({ draw_array, draw_vertexes, draw_indexes }); @@ -396,7 +396,7 @@ void reader_state::read_old_scenery(reader_t& s, chunk_coords_ ch, size_t i) sc.r = r; if (!exact) { - if (read_entity_flags(s, sc)) + if (read_object_flags(s, sc)) sc.frame = s.read(); else sc.frame << s; @@ -424,7 +424,7 @@ void reader_state::read_old_scenery(reader_t& s, chunk_coords_ ch, size_t i) } } global_coords coord{ch, local_coords{i}}; - auto e = _world->make_entity(_world->make_id(), coord, sc); + auto e = _world->make_object(_world->make_id(), coord, sc); (void)e; } @@ -441,22 +441,22 @@ void reader_state::deserialize_world(ArrayView buf) (size_t)proto, (size_t)min_proto_version, (size_t)proto_version); PROTO = proto; fm_assert(PROTO > 0); - object_id entity_counter = world::entity_counter_init; + object_id object_counter = world::object_counter_init; read_atlases(s); if (PROTO >= 3) [[likely]] read_sceneries(s); if (PROTO >= 9) [[likely]] read_strings(s); if (PROTO >= 8) [[likely]] - entity_counter << s; + object_counter << s; read_chunks(s); s.assert_end(); if (PROTO >= 8) [[likely]] - fm_assert(_world->entity_counter() == world::entity_counter_init); + fm_assert(_world->object_counter() == world::object_counter_init); if (PROTO >= 13) [[likely]] - _world->set_entity_counter(entity_counter); + _world->set_object_counter(object_counter); else if (PROTO >= 8) [[likely]] - _world->set_entity_counter(std::max(world::entity_counter_init, entity_counter)); + _world->set_object_counter(std::max(world::object_counter_init, object_counter)); _world = nullptr; } diff --git a/serialize/world-writer.cpp b/serialize/world-writer.cpp index b07de09a..6d32762f 100644 --- a/serialize/world-writer.cpp +++ b/serialize/world-writer.cpp @@ -77,7 +77,7 @@ private: constexpr auto tile_size = sizeof(tilemeta) + (sizeof(atlasid) + sizeof(variant_t)) * 3; constexpr auto chunkbuf_size = sizeof(chunk_magic) + sizeof(chunk_coords_) + tile_size * TILE_COUNT + sizeof(uint32_t); -constexpr auto entity_size = std::max({ sizeof(character), sizeof(scenery), sizeof(light), }); +constexpr auto object_size = std::max({ sizeof(character), sizeof(scenery), sizeof(light), }); writer_state::writer_state(const world& world) : _world{&world} { @@ -178,28 +178,28 @@ scenery_pair writer_state::intern_scenery(const scenery& sc, bool create) return {}; } -template -void write_entity_flags(binary_writer& s, const U& e) +template +void write_object_flags(binary_writer& s, const U& e) { uint8_t flags = 0; auto pass = (pass_mode_i)e.pass; fm_assert((pass & pass_mask) == pass); flags |= pass; - constexpr auto tag = entity_type_::value; + constexpr auto tag = object_type_::value; if (e.type_of() != tag) - fm_abort("invalid entity type '%d'", (int)e.type_of()); - if constexpr(tag == entity_type::scenery) + fm_abort("invalid object type '%d'", (int)e.type_of()); + if constexpr(tag == object_type::scenery) { flags |= (1 << 2) * e.active; flags |= (1 << 3) * e.closing; flags |= (1 << 4) * e.interactive; } - else if constexpr(tag == entity_type::character) + else if constexpr(tag == object_type::character) { flags |= (1 << 2) * e.playable; } else - static_assert(tag == entity_type::none); + static_assert(tag == object_type::none); flags |= (1 << 7) * (e.frame <= 0xff); s << flags; } @@ -287,7 +287,7 @@ void writer_state::serialize_scenery_names() s.write_asciiz_string(sc->name); } s << idx; - write_entity_flags(s, sc->proto); + write_object_flags(s, sc->proto); if (sc->proto.frame <= 0xff) s << (uint8_t)sc->proto.frame; else @@ -322,19 +322,19 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) { constexpr auto def_char_bbox_size = Vector2ub(iTILE_SIZE2); // copied from character_proto - const auto entity_count = (uint32_t)c.entities().size(); - s << entity_count; - fm_assert(entity_count == c.entities().size()); - for (const auto& e_ : c.entities()) + const auto object_count = (uint32_t)c.objects().size(); + s << object_count; + fm_assert(object_count == c.objects().size()); + for (const auto& e_ : c.objects()) { const auto& e = *e_; - fm_assert(s.bytes_written() + entity_size <= chunk_buf.size()); + fm_assert(s.bytes_written() + object_size <= chunk_buf.size()); object_id oid = e.id; fm_assert((oid & lowbits<60, object_id>) == e.id); const auto type = e.type(); - const auto type_ = (entity_type_i)type; - fm_assert(type_ == (type_ & lowbits)); - oid |= (object_id)type << 64 - entity_type_BITS; + const auto type_ = (object_type_i)type; + fm_assert(type_ == (type_ & lowbits)); + oid |= (object_id)type << 64 - object_type_BITS; s << oid; const auto local = e.coord.local(); s << local.to_index(); @@ -350,8 +350,8 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) switch (type) { default: - fm_abort("invalid entity type '%d'", (int)type); - case entity_type::character: { + fm_abort("invalid object type '%d'", (int)type); + case object_type::character: { const auto& C = static_cast(e); uint8_t id = 0; const auto sc_exact = @@ -360,7 +360,7 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) id |= meta_short_scenery_bit * sc_exact; id |= static_cast(C.r) << sizeof(id)*8-1-rotation_BITS; s << id; - write_entity_flags(s, C); + write_object_flags(s, C); if (C.frame <= 0xff) s << (uint8_t)C.frame; else @@ -373,7 +373,7 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) write_bbox(s, C); break; } - case entity_type::scenery: { + case object_type::scenery: { const auto& sc = static_cast(e); auto [ss, img_s, sc_exact] = intern_scenery(sc, true); sc_exact = sc_exact && @@ -391,7 +391,7 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) s << id; if (!sc_exact) { - write_entity_flags(s, sc); + write_object_flags(s, sc); fm_assert(sc.active || sc.delta == 0); if (sc.frame <= 0xff) s << (uint8_t)sc.frame; @@ -403,7 +403,7 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) } break; } - case entity_type::light: { + case object_type::light: { const auto& L = static_cast(e); const auto exact = L.frame == 0 && L.pass == pass_mode::pass && L.bbox_offset.isZero() && L.bbox_size.isZero(); @@ -441,7 +441,7 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) void writer_state::serialize_chunk(const chunk& c, chunk_coords_ coord) { fm_assert(chunk_buf.empty()); - const auto es_size = sizeof(uint32_t) + entity_size*c.entities().size(); + const auto es_size = sizeof(uint32_t) + object_size*c.objects().size(); chunk_buf.resize(std::max(chunk_buf.size(), chunkbuf_size + es_size)); auto s = binary_writer{chunk_buf.begin()}; @@ -534,16 +534,16 @@ ArrayView writer_state::serialize_world() for (const auto& [_, c] : _world->chunks()) { - for (const auto& e_ : c.entities()) + for (const auto& e_ : c.objects()) { const auto& e = *e_; switch (e.type()) { - case entity_type::scenery: + case object_type::scenery: intern_scenery(static_cast(e), false); break; - case entity_type::character: - case entity_type::light: + case object_type::character: + case object_type::light: break; default: fm_abort("invalid scenery type '%d'", (int)e.type()); @@ -597,7 +597,7 @@ ArrayView writer_state::serialize_world() copy(atlas_buf); copy(scenery_buf); copy(string_buf); - copy_int((object_id)_world->entity_counter()); + copy_int((object_id)_world->object_counter()); copy_int((chunksiz)_world->size()); for (const auto& buf : chunk_bufs) copy(buf); diff --git a/shaders/lightmap.cpp b/shaders/lightmap.cpp index 0585223b..47a7a5e0 100644 --- a/shaders/lightmap.cpp +++ b/shaders/lightmap.cpp @@ -5,7 +5,7 @@ #include "src/chunk.hpp" #include "src/tile-bbox.hpp" #include "src/tile-atlas.hpp" -#include "src/entity.hpp" +#include "src/object.hpp" #include #include #include @@ -371,7 +371,7 @@ void lightmap_shader::add_chunk(Vector2 neighbor_offset, chunk& c) neighbor_offset += Vector2(half_neighbors); add_geometry(neighbor_offset, c); - add_entities(neighbor_offset, c); + add_objects(neighbor_offset, c); } void lightmap_shader::add_geometry(Vector2 neighbor_offset, chunk& c) @@ -407,9 +407,9 @@ void lightmap_shader::add_geometry(Vector2 neighbor_offset, chunk& c) } } -void lightmap_shader::add_entities(Vector2 neighbor_offset, chunk& c) +void lightmap_shader::add_objects(Vector2 neighbor_offset, chunk& c) { - for (const auto& e_ : c.entities()) + for (const auto& e_ : c.objects()) { const auto& e = *e_; if (e.is_virtual()) diff --git a/shaders/lightmap.hpp b/shaders/lightmap.hpp index 2dea87e9..2a0869bc 100644 --- a/shaders/lightmap.hpp +++ b/shaders/lightmap.hpp @@ -74,7 +74,7 @@ private: GL::Mesh make_occlusion_mesh(); static std::array quad_indexes(size_t N); - void add_entities(Vector2 neighbor_offset, chunk& c); + void add_objects(Vector2 neighbor_offset, chunk& c); void add_geometry(Vector2 neighbor_offset, chunk& c); void add_rect(Vector2 neighbor_offset, Vector2 min, Vector2 max); void add_rect(Vector2 neighbor_offset, Pair minmax); diff --git a/src/character.cpp b/src/character.cpp index b05d8093..3e252e7a 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -2,7 +2,7 @@ #include "src/anim-atlas.hpp" #include "loader/loader.hpp" #include "src/world.hpp" -#include "src/entity.hpp" +#include "src/object.hpp" #include "shaders/shader.hpp" #include "src/RTree-search.hpp" #include "compat/exception.hpp" @@ -91,16 +91,16 @@ character_proto& character_proto::operator=(const character_proto&) = default; character_proto::character_proto() { - type = entity_type::character; + type = object_type::character; atlas = loader.anim_atlas("npc-walk", loader.ANIM_PATH); } -bool character_proto::operator==(const entity_proto& e0) const +bool character_proto::operator==(const object_proto& e0) const { if (type != e0.type) return false; - if (!entity_proto::operator==(e0)) + if (!object_proto::operator==(e0)) return false; const auto& s0 = static_cast(e0); @@ -195,26 +195,26 @@ done: } } -entity_type character::type() const noexcept { return entity_type::character; } +object_type character::type() const noexcept { return object_type::character; } character::operator character_proto() const { character_proto ret; - static_cast(ret) = entity::operator entity_proto(); + static_cast(ret) = object::operator object_proto(); ret.name = name; ret.playable = playable; return ret; } character::character(object_id id, struct chunk& c, const character_proto& proto) : - entity{id, c, proto}, + object{id, c, proto}, name{proto.name}, playable{proto.playable} { if (!name) name = "(Unnamed)"_s; fm_soft_assert(atlas->check_rotation(r)); - entity::set_bbox_(offset, bbox_offset, Vector2ub(iTILE_SIZE2/2), pass); + object::set_bbox_(offset, bbox_offset, Vector2ub(iTILE_SIZE2/2), pass); } } // namespace floormat diff --git a/src/character.hpp b/src/character.hpp index 06833f75..2c7543a5 100644 --- a/src/character.hpp +++ b/src/character.hpp @@ -1,7 +1,7 @@ #pragma once #include "src/global-coords.hpp" #include "src/rotation.hpp" -#include "src/entity.hpp" +#include "src/object.hpp" #include namespace floormat { @@ -9,7 +9,7 @@ namespace floormat { struct anim_atlas; struct world; -struct character_proto : entity_proto +struct character_proto : object_proto { String name; bool playable : 1 = false; @@ -18,12 +18,12 @@ struct character_proto : entity_proto character_proto(const character_proto&); ~character_proto() noexcept override; character_proto& operator=(const character_proto&); - bool operator==(const entity_proto& proto) const override; + bool operator==(const object_proto& proto) const override; }; -struct character final : entity +struct character final : object { - entity_type type() const noexcept override; + object_type type() const noexcept override; explicit operator character_proto() const; void update(size_t i, float dt) override; @@ -44,7 +44,7 @@ private: character(object_id id, struct chunk& c, const character_proto& proto); }; -template<> struct entity_type_ : std::integral_constant {}; -template<> struct entity_type_ : std::integral_constant {}; +template<> struct object_type_ : std::integral_constant {}; +template<> struct object_type_ : std::integral_constant {}; } // namespace floormat diff --git a/src/chunk-collision.cpp b/src/chunk-collision.cpp index 9810cee3..db7f3ede 100644 --- a/src/chunk-collision.cpp +++ b/src/chunk-collision.cpp @@ -1,6 +1,6 @@ #include "chunk.hpp" #include "tile-atlas.hpp" -#include "entity.hpp" +#include "object.hpp" #include "src/RTree-search.hpp" #include "src/chunk-scenery.hpp" #include "src/tile-bbox.hpp" @@ -22,7 +22,7 @@ constexpr object_id make_id(collision_type type, pass_mode p, object_id id) void chunk::ensure_passability() noexcept { - fm_assert(_entities_sorted); // not strictly necessary + fm_assert(_objects_sorted); // not strictly necessary if (!_pass_modified) return; @@ -30,7 +30,7 @@ void chunk::ensure_passability() noexcept _rtree.RemoveAll(); - for (const std::shared_ptr& s : entities()) + for (const std::shared_ptr& s : objects()) { bbox box; if (_bbox_for_scenery(*s, box)) @@ -64,7 +64,7 @@ void chunk::ensure_passability() noexcept } } -bool chunk::_bbox_for_scenery(const entity& s, local_coords local, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, bbox& value) noexcept +bool chunk::_bbox_for_scenery(const object& s, local_coords local, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, bbox& value) noexcept { auto [start, end] = scenery_tile(local, offset, bbox_offset, bbox_size); auto id = make_id(collision_type::scenery, s.pass, s.id); @@ -72,7 +72,7 @@ bool chunk::_bbox_for_scenery(const entity& s, local_coords local, Vector2b offs return s.atlas && !Vector2ui(s.bbox_size).isZero(); } -bool chunk::_bbox_for_scenery(const entity& s, bbox& value) noexcept +bool chunk::_bbox_for_scenery(const object& s, bbox& value) noexcept { return _bbox_for_scenery(s, s.coord.local(), s.offset, s.bbox_offset, s.bbox_size, value); } @@ -116,7 +116,7 @@ void chunk::_replace_bbox(const bbox& x0, const bbox& x1, bool b0, bool b1) CORRADE_ASSUME(false); } -bool chunk::can_place_entity(const entity_proto& proto, local_coords pos) +bool chunk::can_place_object(const object_proto& proto, local_coords pos) { (void)ensure_scenery_mesh(); diff --git a/src/chunk-scenery.cpp b/src/chunk-scenery.cpp index 6a3987aa..d211b6a4 100644 --- a/src/chunk-scenery.cpp +++ b/src/chunk-scenery.cpp @@ -1,6 +1,6 @@ #include "chunk-scenery.hpp" #include "shaders/shader.hpp" -#include "entity.hpp" +#include "object.hpp" #include "anim-atlas.hpp" #include "tile-atlas.hpp" #include @@ -11,7 +11,7 @@ namespace floormat { auto chunk::ensure_scenery_mesh() noexcept -> scenery_mesh_tuple { - Array array; + Array array; Array> scenery_vertexes; Array> scenery_indexes; return ensure_scenery_mesh({array, scenery_vertexes, scenery_indexes}); @@ -23,7 +23,7 @@ bool chunk::topo_sort_data::intersects(const topo_sort_data& o) const min[1] <= o.max[1] && max[1] >= o.min[1]; } -static void topo_dfs(Array& array, size_t& output, size_t i, size_t size) // NOLINT(misc-no-recursion) +static void topo_dfs(Array& array, size_t& output, size_t i, size_t size) // NOLINT(misc-no-recursion) { using m = typename chunk::topo_sort_data::m; @@ -69,7 +69,7 @@ static void topo_dfs(Array& array, size_t& output, siz output++; } -static void topological_sort(Array& array, size_t size) +static void topological_sort(Array& array, size_t size) { size_t output = 0; @@ -79,7 +79,7 @@ static void topological_sort(Array& array, size_t size fm_assert(output == size); } -auto chunk::make_topo_sort_data(entity& e, uint32_t mesh_idx) -> topo_sort_data +auto chunk::make_topo_sort_data(object& e, uint32_t mesh_idx) -> topo_sort_data { const auto& a = *e.atlas; const auto& f = a.frame(e.r, e.frame); @@ -94,7 +94,7 @@ auto chunk::make_topo_sort_data(entity& e, uint32_t mesh_idx) -> topo_sort_data .in_mesh_idx = mesh_idx, .ord = e.ordinal(), }; - if (e.type() == entity_type::scenery && !e.is_dynamic()) + if (e.type() == object_type::scenery && !e.is_dynamic()) { const auto bb_min_ = world_pos - Vector3(Vector2(e.bbox_size/2), 0); const auto bb_max_ = bb_min_ + Vector3(Vector2(e.bbox_size), 0); @@ -122,7 +122,7 @@ auto chunk::make_topo_sort_data(entity& e, uint32_t mesh_idx) -> topo_sort_data break; } } - else if (e.type() == entity_type::character) + else if (e.type() == object_type::character) data.mode = topo_sort_data::mode_character; return data; } @@ -131,7 +131,7 @@ auto chunk::ensure_scenery_mesh(scenery_scratch_buffers buffers) noexcept -> sce { ensure_scenery_buffers(buffers); - fm_assert(_entities_sorted); + fm_assert(_objects_sorted); if (_scenery_modified) { @@ -139,7 +139,7 @@ auto chunk::ensure_scenery_mesh(scenery_scratch_buffers buffers) noexcept -> sce const auto count = fm_begin( size_t ret = 0; - for (const auto& e : _entities) + for (const auto& e : _objects) ret += !e->is_dynamic(); return ret; ); @@ -147,7 +147,7 @@ auto chunk::ensure_scenery_mesh(scenery_scratch_buffers buffers) noexcept -> sce auto& scenery_vertexes = buffers.scenery_vertexes; auto& scenery_indexes = buffers.scenery_indexes; - for (auto i = 0uz; const auto& e : _entities) + for (auto i = 0uz; const auto& e : _objects) { if (e->is_dynamic()) continue; @@ -177,22 +177,22 @@ auto chunk::ensure_scenery_mesh(scenery_scratch_buffers buffers) noexcept -> sce scenery_mesh = Utility::move(mesh); } - const auto size = _entities.size(); + const auto size = _objects.size(); auto& array = buffers.array; uint32_t j = 0, i = 0; - for (const auto& e : _entities) + for (const auto& e : _objects) { auto index = e->is_dynamic() ? (uint32_t)-1 : j++; array[i++] = { e.get(), (uint32_t)-1, e->ordinal(), make_topo_sort_data(*e, index) }; } topological_sort(array, i); - return { scenery_mesh, ArrayView{array, size}, j }; + return { scenery_mesh, ArrayView{array, size}, j }; } void chunk::ensure_scenery_buffers(scenery_scratch_buffers bufs) { - const size_t len_ = _entities.size(); + const size_t len_ = _objects.size(); if (len_ <= bufs.array.size()) return; @@ -204,7 +204,7 @@ void chunk::ensure_scenery_buffers(scenery_scratch_buffers bufs) else len = std::bit_ceil(len_); - bufs.array = Array{NoInit, len}; + bufs.array = Array{NoInit, len}; bufs.scenery_vertexes = Array>{NoInit, len}; bufs.scenery_indexes = Array>{NoInit, len}; } diff --git a/src/chunk-scenery.hpp b/src/chunk-scenery.hpp index 5648da5c..89e40078 100644 --- a/src/chunk-scenery.hpp +++ b/src/chunk-scenery.hpp @@ -9,7 +9,7 @@ struct chunk::topo_sort_data { enum m : uint8_t { mode_none, mode_static, mode_character, }; - entity* in = nullptr; + object* in = nullptr; Vector2i min, max, center; uint32_t in_mesh_idx; float slope = 0, ord; @@ -20,9 +20,9 @@ struct chunk::topo_sort_data bool intersects(const topo_sort_data& other) const; }; -struct chunk::entity_draw_order +struct chunk::object_draw_order { - entity *e; + object *e; uint32_t mesh_idx; float ord; topo_sort_data data; @@ -30,13 +30,13 @@ struct chunk::entity_draw_order struct chunk::scenery_mesh_tuple { GL::Mesh& mesh; - ArrayView array; + ArrayView array; size_t size; }; struct chunk::scenery_scratch_buffers { - Array& array; + Array& array; Array>& scenery_vertexes; Array>& scenery_indexes; }; diff --git a/src/chunk.cpp b/src/chunk.cpp index ff35f292..f8b823a8 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -9,7 +9,7 @@ namespace floormat { namespace { -constexpr auto entity_id_lessp = [](const auto& a, const auto& b) { return a->id < b->id; }; +constexpr auto object_id_lessp = [](const auto& a, const auto& b) { return a->id < b->id; }; size_t _reload_no_ = 0; // NOLINT @@ -27,9 +27,9 @@ bool chunk::empty(bool force) const noexcept if (!force && !_maybe_empty) return false; for (auto i = 0uz; i < TILE_COUNT; i++) - if (!_entities.empty() || _ground && _ground->_ground_atlases[i] || _walls && (_walls->_wall_atlases[i*2+0] || _walls->_wall_atlases[i*2+1])) + if (!_objects.empty() || _ground && _ground->_ground_atlases[i] || _walls && (_walls->_wall_atlases[i*2+0] || _walls->_wall_atlases[i*2+1])) return _maybe_empty = false; - if (!_entities.empty()) + if (!_objects.empty()) return false; return true; } @@ -98,7 +98,7 @@ chunk::chunk(struct world& w) noexcept : _world{&w} chunk::~chunk() noexcept { _teardown = true; - _entities.clear(); + _objects.clear(); _rtree.RemoveAll(); } @@ -107,46 +107,46 @@ chunk& chunk::operator=(chunk&&) noexcept = default; bool chunk::bbox::operator==(const bbox& other) const noexcept = default; -void chunk::add_entity_unsorted(const std::shared_ptr& e) +void chunk::add_object_unsorted(const std::shared_ptr& e) { - _entities_sorted = false; + _objects_sorted = false; if (!e->is_dynamic()) mark_scenery_modified(); if (bbox bb; _bbox_for_scenery(*e, bb)) _add_bbox(bb); - _entities.push_back(e); + _objects.push_back(e); } -void chunk::sort_entities() +void chunk::sort_objects() { - if (_entities_sorted) + if (_objects_sorted) return; - _entities_sorted = true; + _objects_sorted = true; mark_scenery_modified(); - std::sort(_entities.begin(), _entities.end(), [](const auto& a, const auto& b) { + std::sort(_objects.begin(), _objects.end(), [](const auto& a, const auto& b) { return a->id < b->id; }); } -void chunk::add_entity(const std::shared_ptr& e) +void chunk::add_object(const std::shared_ptr& e) { - fm_assert(_entities_sorted); + fm_assert(_objects_sorted); if (!e->is_dynamic()) mark_scenery_modified(); if (bbox bb; _bbox_for_scenery(*e, bb)) _add_bbox(bb); - auto& es = _entities; + auto& es = _objects; es.reserve(es.size() + 1); - auto it = std::lower_bound(es.cbegin(), es.cend(), e, entity_id_lessp); - _entities.insert(it, e); + auto it = std::lower_bound(es.cbegin(), es.cend(), e, object_id_lessp); + _objects.insert(it, e); } -void chunk::remove_entity(size_t i) +void chunk::remove_object(size_t i) { - fm_assert(_entities_sorted); - auto& es = _entities; + fm_assert(_objects_sorted); + auto& es = _objects; fm_debug_assert(i < es.size()); const auto& e = es[i]; if (!e->is_dynamic()) @@ -156,10 +156,10 @@ void chunk::remove_entity(size_t i) es.erase(es.cbegin() + ptrdiff_t(i)); } -const std::vector>& chunk::entities() const +const std::vector>& chunk::objects() const { - fm_assert(_entities_sorted); - return _entities; + fm_assert(_objects_sorted); + return _objects; } } // namespace floormat diff --git a/src/chunk.hpp b/src/chunk.hpp index a41ed9a0..6a7e3fc9 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -13,8 +13,8 @@ namespace Corrade::Containers { template class Array; } namespace floormat { struct anim_atlas; -struct entity; -struct entity_proto; +struct object; +struct object_proto; class tile_iterator; class tile_const_iterator; @@ -23,7 +23,7 @@ enum class collision : unsigned char { }; enum class collision_type : unsigned char { - none, entity, scenery, geometry, + none, object, scenery, geometry, }; struct collision_data final { @@ -35,7 +35,7 @@ struct collision_data final { struct chunk final { friend struct tile_ref; - friend struct entity; + friend struct object; friend struct world; tile_ref operator[](size_t idx) noexcept; @@ -82,7 +82,7 @@ struct chunk final const size_t size; }; struct topo_sort_data; - struct entity_draw_order; + struct object_draw_order; struct scenery_mesh_tuple; struct scenery_scratch_buffers; @@ -108,13 +108,13 @@ struct chunk final RTree* rtree() noexcept; struct world& world() noexcept { return *_world; } - [[nodiscard]] bool can_place_entity(const entity_proto& proto, local_coords pos); + [[nodiscard]] bool can_place_object(const object_proto& proto, local_coords pos); - void add_entity(const std::shared_ptr& e); - void add_entity_unsorted(const std::shared_ptr& e); - void sort_entities(); - void remove_entity(size_t i); - const std::vector>& entities() const; + void add_object(const std::shared_ptr& e); + void add_object_unsorted(const std::shared_ptr& e); + void sort_objects(); + void remove_object(size_t i); + const std::vector>& objects() const; private: struct ground_stuff { @@ -131,7 +131,7 @@ private: Pointer _ground; Pointer _walls; - std::vector> _entities; + std::vector> _objects; struct world* _world; GL::Mesh ground_mesh{NoCreate}, wall_mesh{NoCreate}, scenery_mesh{NoCreate}; @@ -144,10 +144,10 @@ private: _scenery_modified : 1 = true, _pass_modified : 1 = true, _teardown : 1 = false, - _entities_sorted : 1 = true; + _objects_sorted : 1 = true; void ensure_scenery_buffers(scenery_scratch_buffers bufs); - static topo_sort_data make_topo_sort_data(entity& e, uint32_t mesh_idx); + static topo_sort_data make_topo_sort_data(object& e, uint32_t mesh_idx); struct bbox final // NOLINT(cppcoreguidelines-pro-type-member-init) { @@ -156,8 +156,8 @@ private: bool operator==(const bbox& other) const noexcept; }; - static bool _bbox_for_scenery(const entity& s, bbox& value) noexcept; - static bool _bbox_for_scenery(const entity& s, local_coords local, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, bbox& value) noexcept; + static bool _bbox_for_scenery(const object& s, bbox& value) noexcept; + static bool _bbox_for_scenery(const object& s, local_coords local, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, bbox& value) noexcept; void _remove_bbox(const bbox& x); void _add_bbox(const bbox& x); void _replace_bbox(const bbox& x0, const bbox& x, bool b0, bool b); diff --git a/src/entity-type.hpp b/src/entity-type.hpp deleted file mode 100644 index 308bc8a6..00000000 --- a/src/entity-type.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -namespace floormat { - -enum class entity_type : unsigned char { - none, character, scenery, light, -}; -constexpr inline size_t entity_type_BITS = 3; - -} // namespace floormat diff --git a/src/entity.cpp b/src/entity.cpp deleted file mode 100644 index 2a8c5aa1..00000000 --- a/src/entity.cpp +++ /dev/null @@ -1,300 +0,0 @@ -#include "entity.hpp" -#include "world.hpp" -#include "rotation.inl" -#include "anim-atlas.hpp" -#include "src/RTree-search.hpp" -#include "compat/exception.hpp" -#include "shaders/shader.hpp" -#include -#include - -namespace floormat { - -namespace { - -constexpr auto entity_id_lessp = [](const auto& a, const auto& b) { return a->id < b->id; }; - -} // namespace - -bool entity_proto::operator==(const entity_proto&) const = default; -entity_proto& entity_proto::operator=(const entity_proto&) = default; -entity_proto::~entity_proto() noexcept = default; -entity_proto::entity_proto() = default; -entity_proto::entity_proto(const entity_proto&) = default; -entity_type entity_proto::type_of() const noexcept { return type; } - -entity::entity(object_id id, struct chunk& c, const entity_proto& proto) : - id{id}, c{&c}, atlas{proto.atlas}, - offset{proto.offset}, bbox_offset{proto.bbox_offset}, - bbox_size{proto.bbox_size}, delta{proto.delta}, - frame{proto.frame}, r{proto.r}, pass{proto.pass} -{ - fm_soft_assert(atlas); - fm_soft_assert(atlas->check_rotation(r)); - fm_soft_assert(frame < atlas->info().nframes); -} - -entity::~entity() noexcept -{ - fm_debug_assert(id); - if (c->_teardown || c->_world->_teardown) [[unlikely]] - return; - if (chunk::bbox bb; c->_bbox_for_scenery(*this, bb)) - c->_remove_bbox(bb); - c->_world->do_kill_entity(id); - const_cast(id) = 0; -} - -float entity::ordinal() const -{ - return ordinal(coord.local(), offset, atlas->group(r).z_offset); -} - -float entity::ordinal(local_coords xy, Vector2b offset, Vector2s z_offset) const -{ - constexpr auto inv_tile_size = 1.f/TILE_SIZE2; - auto offset_ = ordinal_offset(offset); - auto vec = Vector2(xy) + offset_*inv_tile_size; - return vec[0] + vec[1] + Vector2(z_offset).sum(); -} - -struct chunk& entity::chunk() const -{ - return *c; -} - -size_t entity::index() const -{ - auto& c = chunk(); - const auto fn = [id = id](const auto& a, const auto&) { return a->id < id; }; - auto& es = c._entities; - auto it = std::lower_bound(es.cbegin(), es.cend(), nullptr, fn); - fm_assert(it != es.cend()); - fm_assert((*it)->id == id); - return (size_t)std::distance(es.cbegin(), it); -} - -bool entity::is_virtual() const -{ - return false; -} - -bool entity::can_rotate(global_coords coord, rotation new_r, rotation old_r, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size) -{ - if (bbox_offset.isZero() && bbox_size[0] == bbox_size[1]) - return true; - const auto offset_ = rotate_point(offset, old_r, new_r); - const auto bbox_offset_ = rotate_point(bbox_offset, old_r, new_r); - const auto bbox_size_ = rotate_size(bbox_size, old_r, new_r); - return can_move_to({}, coord, offset_, bbox_offset_, bbox_size_); -} - -bool entity::can_rotate(rotation new_r) -{ - if (new_r == r) - return true; - - return can_rotate(coord, new_r, r, offset, bbox_offset, bbox_size); -} - -void entity::rotate(size_t, rotation new_r) -{ - fm_assert(atlas->check_rotation(new_r)); - auto offset_ = !is_dynamic() ? rotate_point(offset, r, new_r) : offset; - auto bbox_offset_ = rotate_point(bbox_offset, r, new_r); - auto bbox_size_ = rotate_size(bbox_size, r, new_r); - set_bbox(offset_, bbox_offset_, bbox_size_, pass); - if (r != new_r && !is_dynamic()) - c->mark_scenery_modified(); - - const_cast(r) = new_r; -} - -template constexpr T sgn(T val) { return T(T(0) < val) - T(val < T(0)); } - -Pair entity::normalize_coords(global_coords coord, Vector2b cur_offset, Vector2i new_offset) -{ - auto off_tmp = Vector2i(cur_offset) + new_offset; - auto off_new = off_tmp % iTILE_SIZE2; - constexpr auto half_tile = iTILE_SIZE2/2; - for (auto i = 0uz; i < 2; i++) - { - auto sign = sgn(off_new[i]); - auto absval = std::abs(off_new[i]); - if (absval > half_tile[i]) - { - Vector2i v(0); - v[i] = sign; - coord += v; - off_new[i] = (iTILE_SIZE[i] - absval)*-sign; - } - } - return { coord, Vector2b(off_new) }; -} - -template -static bool do_search(struct chunk* c, chunk_coords_ coord, object_id id, Vector2 min, Vector2 max, Vector2b off = {}) -{ - if constexpr(neighbor) - { - const auto ch = chunk_coords{(int16_t)(coord.x + off[0]), (int16_t)(coord.y + off[1])}; - constexpr auto size = TILE_SIZE2 * TILE_MAX_DIM, grace = TILE_SIZE2 * 4; - const auto off_ = Vector2(off) * size; - min -= off_; - max -= off_; - if (!(min + grace >= Vector2{} && max - grace <= size)) [[likely]] - return true; - auto& w = c->world(); - c = w.at({ch, coord.z}); - if (!c) [[unlikely]] - return true; - } - bool ret = true; - c->rtree()->Search(min.data(), max.data(), [&](object_id data, const auto&) { - auto x = std::bit_cast(data); - if (x.data != id && x.pass != (uint64_t)pass_mode::pass) - return ret = false; - else - return true; - }); - return ret; -} - -bool entity::can_move_to(Vector2i delta, global_coords coord2, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size) -{ - auto [coord_, offset_] = normalize_coords(coord2, offset, delta); - - if (coord_.z() != coord.z()) [[unlikely]] - return false; - - auto& w = *c->_world; - auto& c_ = coord_.chunk() == coord.chunk() ? *c : w[{coord_.chunk(), coord_.z()}]; - - const auto center = Vector2(coord_.local())*TILE_SIZE2 + Vector2(offset_) + Vector2(bbox_offset), - half_bbox = Vector2(bbox_size)*.5f, - min = center - half_bbox, max = min + Vector2(bbox_size); - auto ch = chunk_coords_{coord_.chunk(), coord_.z()}; - if (!do_search(&c_, ch, id, min, max)) - return false; - for (const auto& off : world::neighbor_offsets) - if (!do_search(&c_, ch, id, min, max, off)) - return false; - return true; -} - -bool entity::can_move_to(Vector2i delta) -{ - return can_move_to(delta, coord, offset, bbox_offset, bbox_size); -} - -size_t entity::move_to(size_t& i, Vector2i delta, rotation new_r) -{ - if (!can_rotate(new_r)) - return i; - - auto& es = c->_entities; - fm_debug_assert(i < es.size()); - auto e_ = es[i]; - - fm_assert(&*e_ == this); - auto& w = *c->_world; - const auto [coord_, offset_] = normalize_coords(coord, offset, delta); - - if (coord_ == coord && offset_ == offset) - return i; - - if (!is_dynamic()) - c->mark_scenery_modified(); - - chunk::bbox bb0, bb1; - const auto bb_offset = rotate_point(bbox_offset, r, new_r); - const auto bb_size = rotate_size(bbox_size, r, new_r); - bool b0 = c->_bbox_for_scenery(*this, bb0), - b1 = c->_bbox_for_scenery(*this, coord_.local(), offset_, bb_offset, bb_size, bb1); - - if (coord_.chunk() == coord.chunk()) - { - c->_replace_bbox(bb0, bb1, b0, b1); - const_cast(coord) = coord_; - set_bbox_(offset_, bb_offset, bb_size, pass); - const_cast(r) = new_r; - //for (auto i = 0uz; const auto& x : es) fm_debug("%zu %s %f", i++, x->atlas->name().data(), x->ordinal()); - //fm_debug("insert (%hd;%hd|%hhd;%hhd) %td -> %zu | %f", coord_.chunk().x, coord_.chunk().y, coord_.local().x, coord_.local().y, pos1, es.size(), e.ordinal()); - } - else - { - //fm_debug("change-chunk (%hd;%hd|%hhd;%hhd)", coord_.chunk().x, coord_.chunk().y, coord_.local().x, coord_.local().y); - auto& c2 = w[{coord_.chunk(), coord_.z()}]; - if (!is_dynamic()) - c2.mark_scenery_modified(); - c2._add_bbox(bb1); - c->remove_entity(i); - auto& es = c2._entities; - auto it = std::lower_bound(es.cbegin(), es.cend(), e_, entity_id_lessp); - const_cast(coord) = coord_; - set_bbox_(offset_, bb_offset, bb_size, pass); - const_cast(r) = new_r; - const_cast(c) = &c2; - i = (size_t)std::distance(es.cbegin(), it); - es.insert(it, std::move(e_)); - } - - return i; -} - -void entity::move_to(Magnum::Vector2i delta) -{ - auto i = index(); - (void)move_to(i, delta, r); -} - -void entity::set_bbox_(Vector2b offset_, Vector2b bbox_offset_, Vector2ub bbox_size_, pass_mode pass_) -{ - const_cast(offset) = offset_; - const_cast(bbox_offset) = bbox_offset_; - const_cast(bbox_size) = bbox_size_; - const_cast(pass) = pass_; -} - -entity::operator entity_proto() const -{ - entity_proto ret; - ret.atlas = atlas; - ret.offset = offset; - ret.bbox_offset = bbox_offset; - ret.bbox_size = bbox_size; - ret.delta = delta; - ret.frame = frame; - ret.type = type(); - ret.r = r; - ret.pass = pass; - return ret; -} - -void entity::set_bbox(Vector2b offset_, Vector2b bbox_offset_, Vector2ub bbox_size_, pass_mode pass) -{ - if (offset != offset_) - if (!is_dynamic()) - c->mark_scenery_modified(); - - chunk::bbox bb0, bb; - const bool b0 = c->_bbox_for_scenery(*this, bb0); - set_bbox_(offset_, bbox_offset_, bbox_size_, pass); - const bool b = c->_bbox_for_scenery(*this, bb); - c->_replace_bbox(bb0, bb, b0, b); -} - -bool entity::can_activate(size_t) const { return false; } -bool entity::activate(size_t) { return false; } - -bool entity::is_dynamic() const -{ - return atlas->info().fps > 0; -} - -entity_type entity::type_of() const noexcept -{ - return type(); -} - -} // namespace floormat diff --git a/src/entity.hpp b/src/entity.hpp deleted file mode 100644 index e332c93a..00000000 --- a/src/entity.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once -#include "compat/defs.hpp" -#include "src/global-coords.hpp" -#include "src/rotation.hpp" -#include "src/pass-mode.hpp" -#include "src/entity-type.hpp" -#include "src/object-id.hpp" -#include -#include - -namespace floormat { - -template struct entity_type_; -struct anim_atlas; -struct world; -struct chunk; - -struct entity_proto -{ - std::shared_ptr atlas; - Vector2b offset, bbox_offset; - Vector2ub bbox_size = Vector2ub(iTILE_SIZE2); - uint16_t delta = 0, frame = 0; - entity_type type : 3 = entity_type::none; - rotation r : rotation_BITS = rotation::N; - pass_mode pass : pass_mode_BITS = pass_mode::see_through; - - entity_proto& operator=(const entity_proto&); - entity_proto(); - entity_proto(const entity_proto&); - - virtual bool operator==(const entity_proto&) const; - bool operator!=(const entity_proto& o) const { return !operator==(o); } - virtual ~entity_proto() noexcept; - - entity_type type_of() const noexcept; -}; - -// todo rename to 'object' -struct entity -{ - fm_DECLARE_DELETED_COPY_ASSIGNMENT(entity); - - const object_id id = 0; - struct chunk* const c; - const std::shared_ptr atlas; - const global_coords coord; - const Vector2b offset, bbox_offset; - const Vector2ub bbox_size; - uint16_t delta = 0, frame = 0; - const rotation r = rotation::N; - const pass_mode pass = pass_mode::see_through; - - virtual ~entity() noexcept; - - virtual Vector2 ordinal_offset(Vector2b offset) const = 0; - virtual float depth_offset() const = 0; - float ordinal() const; - float ordinal(local_coords xy, Vector2b offset, Vector2s z_offset) const; - struct chunk& chunk() const; - size_t index() const; - virtual bool is_virtual() const; - - explicit operator entity_proto() const; - - virtual entity_type type() const noexcept = 0; - virtual bool can_activate(size_t i) const; - virtual bool activate(size_t i); - virtual void update(size_t i, float dt) = 0; - virtual void rotate(size_t i, rotation r); - virtual bool can_rotate(global_coords coord, rotation new_r, rotation old_r, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size); - virtual bool can_move_to(Vector2i delta, global_coords coord, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_aize); - virtual void set_bbox(Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, pass_mode pass); - - entity_type type_of() const noexcept; - static Pair normalize_coords(global_coords coord, Vector2b cur_offset, Vector2i delta); - - virtual bool is_dynamic() const; - bool can_rotate(rotation new_r); - bool can_move_to(Vector2i delta); - size_t move_to(size_t& i, Vector2i delta, rotation new_r); - void move_to(Vector2i delta); - -protected: - entity(object_id id, struct chunk& c, const entity_proto& proto); - void set_bbox_(Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, pass_mode pass); -}; - -} // namespace floormat diff --git a/src/light.cpp b/src/light.cpp index 58246d94..13f39b22 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -14,7 +14,7 @@ light_proto::light_proto() { atlas = loader.vobj("light"_s).atlas; pass = pass_mode::pass; - type = entity_type::light; + type = object_type::light; } light_proto::light_proto(const light_proto&) = default; @@ -23,7 +23,7 @@ light_proto::~light_proto() noexcept = default; bool light_proto::operator==(const light_proto&) const = default; light::light(object_id id, struct chunk& c, const light_proto& proto) : - entity{id, c, proto}, + object{id, c, proto}, max_distance{proto.max_distance}, color{proto.color}, falloff{proto.falloff}, @@ -46,7 +46,7 @@ Vector2 light::ordinal_offset(Vector2b) const light::operator light_proto() const { light_proto ret; - static_cast(ret) = entity_proto(*this); + static_cast(ret) = object_proto(*this); ret.max_distance = max_distance; ret.color = color; ret.falloff = falloff; @@ -54,7 +54,7 @@ light::operator light_proto() const return ret; } -entity_type light::type() const noexcept { return entity_type::light; } +object_type light::type() const noexcept { return object_type::light; } void light::update(size_t, float) {} bool light::is_dynamic() const { return true; } bool light::is_virtual() const { return true; } diff --git a/src/light.hpp b/src/light.hpp index a58e0221..b5c4469a 100644 --- a/src/light.hpp +++ b/src/light.hpp @@ -1,13 +1,13 @@ #pragma once #include "src/light-falloff.hpp" -#include "src/entity.hpp" +#include "src/object.hpp" #include #include #include namespace floormat { -struct light_proto : entity_proto +struct light_proto : object_proto { light_proto(); light_proto(const light_proto&); @@ -21,7 +21,7 @@ struct light_proto : entity_proto uint8_t enabled : 1 = true; }; -struct light final : entity +struct light final : object { float max_distance; Color4ub color; @@ -32,7 +32,7 @@ struct light final : entity Vector2 ordinal_offset(Vector2b offset) const override; float depth_offset() const override; - entity_type type() const noexcept override; + object_type type() const noexcept override; void update(size_t i, float dt) override; bool is_dynamic() const override; bool is_virtual() const override; @@ -42,7 +42,7 @@ struct light final : entity friend struct world; }; -template<> struct entity_type_ : std::integral_constant {}; -template<> struct entity_type_ : std::integral_constant {}; +template<> struct object_type_ : std::integral_constant {}; +template<> struct object_type_ : std::integral_constant {}; } // namespace floormat diff --git a/src/object-type.hpp b/src/object-type.hpp new file mode 100644 index 00000000..1a1d1aff --- /dev/null +++ b/src/object-type.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace floormat { + +enum class object_type : unsigned char { + none, character, scenery, light, +}; +constexpr inline size_t object_type_BITS = 3; + +} // namespace floormat diff --git a/src/object.cpp b/src/object.cpp new file mode 100644 index 00000000..1dc05f4b --- /dev/null +++ b/src/object.cpp @@ -0,0 +1,300 @@ +#include "object.hpp" +#include "world.hpp" +#include "rotation.inl" +#include "anim-atlas.hpp" +#include "src/RTree-search.hpp" +#include "compat/exception.hpp" +#include "shaders/shader.hpp" +#include +#include + +namespace floormat { + +namespace { + +constexpr auto object_id_lessp = [](const auto& a, const auto& b) { return a->id < b->id; }; + +} // namespace + +bool object_proto::operator==(const object_proto&) const = default; +object_proto& object_proto::operator=(const object_proto&) = default; +object_proto::~object_proto() noexcept = default; +object_proto::object_proto() = default; +object_proto::object_proto(const object_proto&) = default; +object_type object_proto::type_of() const noexcept { return type; } + +object::object(object_id id, struct chunk& c, const object_proto& proto) : + id{id}, c{&c}, atlas{proto.atlas}, + offset{proto.offset}, bbox_offset{proto.bbox_offset}, + bbox_size{proto.bbox_size}, delta{proto.delta}, + frame{proto.frame}, r{proto.r}, pass{proto.pass} +{ + fm_soft_assert(atlas); + fm_soft_assert(atlas->check_rotation(r)); + fm_soft_assert(frame < atlas->info().nframes); +} + +object::~object() noexcept +{ + fm_debug_assert(id); + if (c->_teardown || c->_world->_teardown) [[unlikely]] + return; + if (chunk::bbox bb; c->_bbox_for_scenery(*this, bb)) + c->_remove_bbox(bb); + c->_world->do_kill_object(id); + const_cast(id) = 0; +} + +float object::ordinal() const +{ + return ordinal(coord.local(), offset, atlas->group(r).z_offset); +} + +float object::ordinal(local_coords xy, Vector2b offset, Vector2s z_offset) const +{ + constexpr auto inv_tile_size = 1.f/TILE_SIZE2; + auto offset_ = ordinal_offset(offset); + auto vec = Vector2(xy) + offset_*inv_tile_size; + return vec[0] + vec[1] + Vector2(z_offset).sum(); +} + +struct chunk& object::chunk() const +{ + return *c; +} + +size_t object::index() const +{ + auto& c = chunk(); + const auto fn = [id = id](const auto& a, const auto&) { return a->id < id; }; + auto& es = c._objects; + auto it = std::lower_bound(es.cbegin(), es.cend(), nullptr, fn); + fm_assert(it != es.cend()); + fm_assert((*it)->id == id); + return (size_t)std::distance(es.cbegin(), it); +} + +bool object::is_virtual() const +{ + return false; +} + +bool object::can_rotate(global_coords coord, rotation new_r, rotation old_r, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size) +{ + if (bbox_offset.isZero() && bbox_size[0] == bbox_size[1]) + return true; + const auto offset_ = rotate_point(offset, old_r, new_r); + const auto bbox_offset_ = rotate_point(bbox_offset, old_r, new_r); + const auto bbox_size_ = rotate_size(bbox_size, old_r, new_r); + return can_move_to({}, coord, offset_, bbox_offset_, bbox_size_); +} + +bool object::can_rotate(rotation new_r) +{ + if (new_r == r) + return true; + + return can_rotate(coord, new_r, r, offset, bbox_offset, bbox_size); +} + +void object::rotate(size_t, rotation new_r) +{ + fm_assert(atlas->check_rotation(new_r)); + auto offset_ = !is_dynamic() ? rotate_point(offset, r, new_r) : offset; + auto bbox_offset_ = rotate_point(bbox_offset, r, new_r); + auto bbox_size_ = rotate_size(bbox_size, r, new_r); + set_bbox(offset_, bbox_offset_, bbox_size_, pass); + if (r != new_r && !is_dynamic()) + c->mark_scenery_modified(); + + const_cast(r) = new_r; +} + +template constexpr T sgn(T val) { return T(T(0) < val) - T(val < T(0)); } + +Pair object::normalize_coords(global_coords coord, Vector2b cur_offset, Vector2i new_offset) +{ + auto off_tmp = Vector2i(cur_offset) + new_offset; + auto off_new = off_tmp % iTILE_SIZE2; + constexpr auto half_tile = iTILE_SIZE2/2; + for (auto i = 0uz; i < 2; i++) + { + auto sign = sgn(off_new[i]); + auto absval = std::abs(off_new[i]); + if (absval > half_tile[i]) + { + Vector2i v(0); + v[i] = sign; + coord += v; + off_new[i] = (iTILE_SIZE[i] - absval)*-sign; + } + } + return { coord, Vector2b(off_new) }; +} + +template +static bool do_search(struct chunk* c, chunk_coords_ coord, object_id id, Vector2 min, Vector2 max, Vector2b off = {}) +{ + if constexpr(neighbor) + { + const auto ch = chunk_coords{(int16_t)(coord.x + off[0]), (int16_t)(coord.y + off[1])}; + constexpr auto size = TILE_SIZE2 * TILE_MAX_DIM, grace = TILE_SIZE2 * 4; + const auto off_ = Vector2(off) * size; + min -= off_; + max -= off_; + if (!(min + grace >= Vector2{} && max - grace <= size)) [[likely]] + return true; + auto& w = c->world(); + c = w.at({ch, coord.z}); + if (!c) [[unlikely]] + return true; + } + bool ret = true; + c->rtree()->Search(min.data(), max.data(), [&](object_id data, const auto&) { + auto x = std::bit_cast(data); + if (x.data != id && x.pass != (uint64_t)pass_mode::pass) + return ret = false; + else + return true; + }); + return ret; +} + +bool object::can_move_to(Vector2i delta, global_coords coord2, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size) +{ + auto [coord_, offset_] = normalize_coords(coord2, offset, delta); + + if (coord_.z() != coord.z()) [[unlikely]] + return false; + + auto& w = *c->_world; + auto& c_ = coord_.chunk() == coord.chunk() ? *c : w[{coord_.chunk(), coord_.z()}]; + + const auto center = Vector2(coord_.local())*TILE_SIZE2 + Vector2(offset_) + Vector2(bbox_offset), + half_bbox = Vector2(bbox_size)*.5f, + min = center - half_bbox, max = min + Vector2(bbox_size); + auto ch = chunk_coords_{coord_.chunk(), coord_.z()}; + if (!do_search(&c_, ch, id, min, max)) + return false; + for (const auto& off : world::neighbor_offsets) + if (!do_search(&c_, ch, id, min, max, off)) + return false; + return true; +} + +bool object::can_move_to(Vector2i delta) +{ + return can_move_to(delta, coord, offset, bbox_offset, bbox_size); +} + +size_t object::move_to(size_t& i, Vector2i delta, rotation new_r) +{ + if (!can_rotate(new_r)) + return i; + + auto& es = c->_objects; + fm_debug_assert(i < es.size()); + auto e_ = es[i]; + + fm_assert(&*e_ == this); + auto& w = *c->_world; + const auto [coord_, offset_] = normalize_coords(coord, offset, delta); + + if (coord_ == coord && offset_ == offset) + return i; + + if (!is_dynamic()) + c->mark_scenery_modified(); + + chunk::bbox bb0, bb1; + const auto bb_offset = rotate_point(bbox_offset, r, new_r); + const auto bb_size = rotate_size(bbox_size, r, new_r); + bool b0 = c->_bbox_for_scenery(*this, bb0), + b1 = c->_bbox_for_scenery(*this, coord_.local(), offset_, bb_offset, bb_size, bb1); + + if (coord_.chunk() == coord.chunk()) + { + c->_replace_bbox(bb0, bb1, b0, b1); + const_cast(coord) = coord_; + set_bbox_(offset_, bb_offset, bb_size, pass); + const_cast(r) = new_r; + //for (auto i = 0uz; const auto& x : es) fm_debug("%zu %s %f", i++, x->atlas->name().data(), x->ordinal()); + //fm_debug("insert (%hd;%hd|%hhd;%hhd) %td -> %zu | %f", coord_.chunk().x, coord_.chunk().y, coord_.local().x, coord_.local().y, pos1, es.size(), e.ordinal()); + } + else + { + //fm_debug("change-chunk (%hd;%hd|%hhd;%hhd)", coord_.chunk().x, coord_.chunk().y, coord_.local().x, coord_.local().y); + auto& c2 = w[{coord_.chunk(), coord_.z()}]; + if (!is_dynamic()) + c2.mark_scenery_modified(); + c2._add_bbox(bb1); + c->remove_object(i); + auto& es = c2._objects; + auto it = std::lower_bound(es.cbegin(), es.cend(), e_, object_id_lessp); + const_cast(coord) = coord_; + set_bbox_(offset_, bb_offset, bb_size, pass); + const_cast(r) = new_r; + const_cast(c) = &c2; + i = (size_t)std::distance(es.cbegin(), it); + es.insert(it, std::move(e_)); + } + + return i; +} + +void object::move_to(Magnum::Vector2i delta) +{ + auto i = index(); + (void)move_to(i, delta, r); +} + +void object::set_bbox_(Vector2b offset_, Vector2b bbox_offset_, Vector2ub bbox_size_, pass_mode pass_) +{ + const_cast(offset) = offset_; + const_cast(bbox_offset) = bbox_offset_; + const_cast(bbox_size) = bbox_size_; + const_cast(pass) = pass_; +} + +object::operator object_proto() const +{ + object_proto ret; + ret.atlas = atlas; + ret.offset = offset; + ret.bbox_offset = bbox_offset; + ret.bbox_size = bbox_size; + ret.delta = delta; + ret.frame = frame; + ret.type = type(); + ret.r = r; + ret.pass = pass; + return ret; +} + +void object::set_bbox(Vector2b offset_, Vector2b bbox_offset_, Vector2ub bbox_size_, pass_mode pass) +{ + if (offset != offset_) + if (!is_dynamic()) + c->mark_scenery_modified(); + + chunk::bbox bb0, bb; + const bool b0 = c->_bbox_for_scenery(*this, bb0); + set_bbox_(offset_, bbox_offset_, bbox_size_, pass); + const bool b = c->_bbox_for_scenery(*this, bb); + c->_replace_bbox(bb0, bb, b0, b); +} + +bool object::can_activate(size_t) const { return false; } +bool object::activate(size_t) { return false; } + +bool object::is_dynamic() const +{ + return atlas->info().fps > 0; +} + +object_type object::type_of() const noexcept +{ + return type(); +} + +} // namespace floormat diff --git a/src/object.hpp b/src/object.hpp new file mode 100644 index 00000000..f411a7ec --- /dev/null +++ b/src/object.hpp @@ -0,0 +1,89 @@ +#pragma once +#include "compat/defs.hpp" +#include "src/global-coords.hpp" +#include "src/rotation.hpp" +#include "src/pass-mode.hpp" +#include "src/object-type.hpp" +#include "src/object-id.hpp" +#include +#include + +namespace floormat { + +template struct object_type_; +struct anim_atlas; +struct world; +struct chunk; + +struct object_proto +{ + std::shared_ptr atlas; + Vector2b offset, bbox_offset; + Vector2ub bbox_size = Vector2ub(iTILE_SIZE2); + uint16_t delta = 0, frame = 0; + object_type type : 3 = object_type::none; + rotation r : rotation_BITS = rotation::N; + pass_mode pass : pass_mode_BITS = pass_mode::see_through; + + object_proto& operator=(const object_proto&); + object_proto(); + object_proto(const object_proto&); + + virtual bool operator==(const object_proto&) const; + bool operator!=(const object_proto& o) const { return !operator==(o); } + virtual ~object_proto() noexcept; + + object_type type_of() const noexcept; +}; + +// todo rename to 'object' +struct object +{ + fm_DECLARE_DELETED_COPY_ASSIGNMENT(object); + + const object_id id = 0; + struct chunk* const c; + const std::shared_ptr atlas; + const global_coords coord; + const Vector2b offset, bbox_offset; + const Vector2ub bbox_size; + uint16_t delta = 0, frame = 0; + const rotation r = rotation::N; + const pass_mode pass = pass_mode::see_through; + + virtual ~object() noexcept; + + virtual Vector2 ordinal_offset(Vector2b offset) const = 0; + virtual float depth_offset() const = 0; + float ordinal() const; + float ordinal(local_coords xy, Vector2b offset, Vector2s z_offset) const; + struct chunk& chunk() const; + size_t index() const; + virtual bool is_virtual() const; + + explicit operator object_proto() const; + + virtual object_type type() const noexcept = 0; + virtual bool can_activate(size_t i) const; + virtual bool activate(size_t i); + virtual void update(size_t i, float dt) = 0; + virtual void rotate(size_t i, rotation r); + virtual bool can_rotate(global_coords coord, rotation new_r, rotation old_r, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size); + virtual bool can_move_to(Vector2i delta, global_coords coord, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_aize); + virtual void set_bbox(Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, pass_mode pass); + + object_type type_of() const noexcept; + static Pair normalize_coords(global_coords coord, Vector2b cur_offset, Vector2i delta); + + virtual bool is_dynamic() const; + bool can_rotate(rotation new_r); + bool can_move_to(Vector2i delta); + size_t move_to(size_t& i, Vector2i delta, rotation new_r); + void move_to(Vector2i delta); + +protected: + object(object_id id, struct chunk& c, const object_proto& proto); + void set_bbox_(Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, pass_mode pass); +}; + +} // namespace floormat diff --git a/src/scenery.cpp b/src/scenery.cpp index c5435137..22c7083a 100644 --- a/src/scenery.cpp +++ b/src/scenery.cpp @@ -11,7 +11,7 @@ namespace floormat { scenery_proto::scenery_proto() { - type = entity_type::scenery; + type = object_type::scenery; } scenery_proto& scenery_proto::operator=(const scenery_proto&) = default; @@ -129,12 +129,12 @@ bool scenery::activate(size_t) return false; } -bool scenery_proto::operator==(const entity_proto& e0) const +bool scenery_proto::operator==(const object_proto& e0) const { if (type != e0.type) return false; - if (!entity_proto::operator==(e0)) + if (!object_proto::operator==(e0)) return false; const auto& s0 = static_cast(e0); @@ -142,12 +142,12 @@ bool scenery_proto::operator==(const entity_proto& e0) const closing == s0.closing && interactive == s0.interactive; } -entity_type scenery::type() const noexcept { return entity_type::scenery; } +object_type scenery::type() const noexcept { return object_type::scenery; } scenery::operator scenery_proto() const { scenery_proto ret; - static_cast(ret) = entity::operator entity_proto(); + static_cast(ret) = object::operator object_proto(); ret.sc_type = sc_type; ret.active = active; ret.closing = closing; @@ -156,7 +156,7 @@ scenery::operator scenery_proto() const } scenery::scenery(object_id id, struct chunk& c, const scenery_proto& proto) : - entity{id, c, proto}, sc_type{proto.sc_type}, active{proto.active}, + object{id, c, proto}, sc_type{proto.sc_type}, active{proto.active}, closing{proto.closing}, interactive{proto.interactive} { fm_debug_assert(atlas); // todo add placeholder graphic diff --git a/src/scenery.hpp b/src/scenery.hpp index 17fdad66..1c3b03ad 100644 --- a/src/scenery.hpp +++ b/src/scenery.hpp @@ -2,7 +2,7 @@ #include "pass-mode.hpp" #include "tile-defs.hpp" #include "rotation.hpp" -#include "entity.hpp" +#include "object.hpp" #include #include #include @@ -18,7 +18,7 @@ enum class scenery_type : unsigned char { }; constexpr inline size_t scenery_type_BITS = 3; -struct scenery_proto : entity_proto +struct scenery_proto : object_proto { scenery_type sc_type : scenery_type_BITS = scenery_type::none; unsigned char active : 1 = false; @@ -29,11 +29,11 @@ struct scenery_proto : entity_proto scenery_proto(const scenery_proto&); ~scenery_proto() noexcept override; scenery_proto& operator=(const scenery_proto&); - bool operator==(const entity_proto& proto) const override; + bool operator==(const object_proto& proto) const override; operator bool() const; }; -struct scenery final : entity +struct scenery final : object { scenery_type sc_type : 3 = scenery_type::none; unsigned char active : 1 = false; @@ -46,7 +46,7 @@ struct scenery final : entity bool can_activate(size_t i) const override; bool activate(size_t i) override; - entity_type type() const noexcept override; + object_type type() const noexcept override; explicit operator scenery_proto() const; private: @@ -54,7 +54,7 @@ private: scenery(object_id id, struct chunk& c, const scenery_proto& proto); }; -template<> struct entity_type_ : std::integral_constant {}; -template<> struct entity_type_ : std::integral_constant {}; +template<> struct object_type_ : std::integral_constant {}; +template<> struct object_type_ : std::integral_constant {}; } // namespace floormat diff --git a/src/world.cpp b/src/world.cpp index e829ab5e..97cc4702 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -1,6 +1,6 @@ #include "world.hpp" #include "chunk.hpp" -#include "entity.hpp" +#include "object.hpp" #include "compat/int-hash.hpp" #include "compat/exception.hpp" @@ -47,10 +47,10 @@ world& world::operator=(world&& w) noexcept fm_debug_assert(w._unique_id == nullptr); _last_chunk = {}; _chunks = std::move(w._chunks); - _entities = std::move(w._entities); - _entity_counter = w._entity_counter; + _objects = std::move(w._objects); + _object_counter = w._object_counter; _current_frame = w._current_frame; - w._entity_counter = 0; + w._object_counter = 0; for (auto& [id, c] : _chunks) c._world = this; @@ -71,19 +71,19 @@ world::~world() noexcept v.mark_scenery_modified(); v.mark_passability_modified(); _last_chunk = {}; - v._entities.clear(); + v._objects.clear(); } _last_chunk = {}; _chunks.clear(); - _entities.clear(); + _objects.clear(); } world::world(size_t capacity) : _chunks{capacity} { _chunks.max_load_factor(max_load_factor); _chunks.reserve(initial_capacity); - _entities.max_load_factor(max_load_factor); - _entities.reserve(initial_capacity); + _objects.max_load_factor(max_load_factor); + _objects.reserve(initial_capacity); } chunk& world::operator[](chunk_coords_ coord) noexcept @@ -122,10 +122,10 @@ void world::clear() _last_collection = 0; _chunks.clear(); _chunks.rehash(initial_capacity); - _entities.clear(); - _entities.rehash(initial_capacity); + _objects.clear(); + _objects.rehash(initial_capacity); _collect_every = initial_collect_every; - _entity_counter = entity_counter_init; + _object_counter = object_counter_init; auto& [c, pos] = _last_chunk; c = nullptr; pos = chunk_tuple::invalid_coords; @@ -158,44 +158,44 @@ void world::collect(bool force) fm_debug("world: collected %zu/%zu chunks", len, len0); } -void world::do_make_entity(const std::shared_ptr& e, global_coords pos, bool sorted) +void world::do_make_object(const std::shared_ptr& e, global_coords pos, bool sorted) { fm_assert(e->id > 0); fm_debug_assert(_unique_id && e->c->world()._unique_id == _unique_id); - fm_assert(!_entities.contains(e->id)); - fm_assert(e->type() != entity_type::none); + fm_assert(!_objects.contains(e->id)); + fm_assert(e->type() != object_type::none); const_cast(e->coord) = pos; - _entities[e->id] = e; + _objects[e->id] = e; if (sorted) - e->c->add_entity(e); + e->c->add_object(e); else - e->c->add_entity_unsorted(e); + e->c->add_object_unsorted(e); } -void world::do_kill_entity(object_id id) +void world::do_kill_object(object_id id) { fm_debug_assert(id > 0); - auto cnt = _entities.erase(id); + auto cnt = _objects.erase(id); fm_debug_assert(cnt > 0); } -std::shared_ptr world::find_entity_(object_id id) +std::shared_ptr world::find_object_(object_id id) { - auto it = _entities.find(id); - auto ret = it == _entities.end() ? nullptr : it->second.lock(); + auto it = _objects.find(id); + auto ret = it == _objects.end() ? nullptr : it->second.lock(); fm_debug_assert(!ret || &ret->c->world() == this); return ret; } -void world::set_entity_counter(object_id value) +void world::set_object_counter(object_id value) { - fm_assert(value >= _entity_counter); - _entity_counter = value; + fm_assert(value >= _object_counter); + _object_counter = value; } -void world::throw_on_wrong_entity_type(object_id id, entity_type actual, entity_type expected) +void world::throw_on_wrong_object_type(object_id id, object_type actual, object_type expected) { - fm_throw("object '{}' has wrong entity 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); } auto world::neighbors(floormat::chunk_coords_ coord) -> std::array diff --git a/src/world.hpp b/src/world.hpp index c176dbbe..8f82efab 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -2,7 +2,7 @@ #include "compat/defs.hpp" #include "chunk.hpp" #include "global-coords.hpp" -#include "entity-type.hpp" +#include "object-type.hpp" #include "compat/int-hash.hpp" #include #include @@ -16,15 +16,15 @@ struct std::hash final { namespace floormat { -struct entity; -template struct entity_type_; +struct object; +template struct object_type_; struct object_id_hasher { size_t operator()(object_id id) const noexcept { return int_hash(id); } }; struct world final { - static constexpr object_id entity_counter_init = 1024; + static constexpr object_id object_counter_init = 1024; static constexpr size_t initial_capacity = 512; static constexpr float max_load_factor = .5; static constexpr size_t initial_collect_every = 64; @@ -37,22 +37,22 @@ private: } _last_chunk; std::unordered_map _chunks; - tsl::robin_map, object_id_hasher> _entities; + tsl::robin_map, object_id_hasher> _objects; size_t _last_collection = 0; size_t _collect_every = initial_collect_every; std::shared_ptr _unique_id = std::make_shared('A'); - object_id _entity_counter = entity_counter_init; - uint64_t _current_frame = 1; // zero is special for struct entity + object_id _object_counter = object_counter_init; + uint64_t _current_frame = 1; // zero is special for struct object bool _teardown : 1 = false; explicit world(size_t capacity); - void do_make_entity(const std::shared_ptr& e, global_coords pos, bool sorted); - void do_kill_entity(object_id id); - std::shared_ptr find_entity_(object_id id); - [[noreturn]] static void throw_on_wrong_entity_type(object_id id, entity_type actual, entity_type expected); + void do_make_object(const std::shared_ptr& e, global_coords pos, bool sorted); + void do_kill_object(object_id id); + std::shared_ptr find_object_(object_id id); + [[noreturn]] static void throw_on_wrong_object_type(object_id id, object_type actual, object_type expected); - friend struct entity; + friend struct object; public: explicit world(); @@ -82,21 +82,21 @@ public: template requires requires(chunk& c) { T{object_id(), c, std::declval()...}; - std::is_base_of_v; + std::is_base_of_v; } - std::shared_ptr make_entity(object_id id, global_coords pos, Xs&&... xs) + std::shared_ptr make_object(object_id id, global_coords pos, Xs&&... xs) { auto ret = std::shared_ptr(new T{id, operator[](chunk_coords_{pos.chunk(), pos.z()}), Utility::forward(xs)...}); - do_make_entity(static_pointer_cast(ret), pos, sorted); + do_make_object(static_pointer_cast(ret), pos, sorted); return ret; } - template std::shared_ptr find_entity(object_id id); + template std::shared_ptr find_object(object_id id); bool is_teardown() const { return _teardown; } - object_id entity_counter() const { return _entity_counter; } - [[nodiscard]] object_id make_id() { return ++_entity_counter; } - void set_entity_counter(object_id value); + object_id object_counter() const { return _object_counter; } + [[nodiscard]] object_id make_id() { return ++_object_counter; } + void set_object_counter(object_id value); struct neighbor_pair final { chunk* c; chunk_coords_ coord; }; @@ -113,19 +113,19 @@ public: }; template -std::shared_ptr world::find_entity(object_id id) +std::shared_ptr world::find_object(object_id id) { - static_assert(std::is_same_v || std::is_base_of_v); - // make it a dependent name so that including "src/entity.hpp" isn't needed - using U = std::conditional_t, T, entity>; - if (std::shared_ptr ptr = find_entity_(id); !ptr) + static_assert(std::is_same_v || std::is_base_of_v); + // make it a dependent name so that including "src/object.hpp" isn't needed + using U = std::conditional_t, T, object>; + if (std::shared_ptr ptr = find_object_(id); !ptr) return {}; - else if constexpr(std::is_same_v) + else if constexpr(std::is_same_v) return ptr; else { - if (!(ptr->type() == entity_type_::value)) [[unlikely]] - throw_on_wrong_entity_type(id, ptr->type(), entity_type_::value); + if (!(ptr->type() == object_type_::value)) [[unlikely]] + throw_on_wrong_object_type(id, ptr->type(), object_type_::value); return static_pointer_cast(Utility::move(ptr)); } } diff --git a/test/entity.cpp b/test/entity.cpp deleted file mode 100644 index 3c099a37..00000000 --- a/test/entity.cpp +++ /dev/null @@ -1,259 +0,0 @@ -#include "app.hpp" -#include "compat/assert.hpp" -#include "entity/metadata.hpp" -#include - -using namespace floormat; -using namespace floormat::entities; - -namespace { - -struct TestAccessors { - constexpr int bar() const { return _bar; } - constexpr void set_bar(int value) { _bar = value; } - int foo; - int _bar; - int _baz; -}; - -} // namespace - -namespace floormat::entities { - -template<> struct entity_accessors { - static constexpr auto accessors() - { - using entity = Entity; - constexpr auto r_baz = [](const TestAccessors& x) { return x._baz; }; - constexpr auto w_baz = [](TestAccessors& x, int v) { x._baz = v; }; - - constexpr auto tuple = std::make_tuple( - entity::type::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo}, - entity::type::field{"bar"_s, &TestAccessors::bar, &TestAccessors::set_bar}, - entity::type::field("baz"_s, r_baz, w_baz) - ); - return tuple; - } -}; - -} // namespace floormat::entities - -namespace { - -using entity = Entity; -constexpr auto m_foo = entity::type::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo}; -constexpr auto m_bar = entity::type::field{"bar"_s, &TestAccessors::bar, &TestAccessors::set_bar}; -constexpr auto r_baz = [](const TestAccessors& x) { return x._baz; }; -constexpr auto w_baz = [](TestAccessors& x, int v) { x._baz = v; }; -constexpr auto m_baz = entity::type::field("baz"_s, r_baz, w_baz); - -} // namespace - -namespace floormat { - -namespace { - -constexpr bool test_accessors() -{ - auto x = TestAccessors{111, 222, 333}; - - { - auto a = m_foo.read(x), b = m_bar.read(x), c = m_baz.read(x); - fm_assert(a == 111 && b == 222 && c == 333); - } - - { - m_foo.write(x, 1111); - m_bar.write(x, 2222); - m_baz.write(x, 3333); - auto a = m_foo.read(x), b = m_bar.read(x), c = m_baz.read(x); - fm_assert(a == 1111 && b == 2222 && c == 3333); - } - return true; -} - -constexpr bool test_visitor() -{ - { - auto tuple = std::make_tuple((unsigned char)1, (unsigned short)2, (int)3, (long)4); - long ret = 0; - visit_tuple([&](auto x) { ret += (long)x; }, tuple); - fm_assert(ret == 1 + 2 + 3 + 4); - } - { - int ret = 0; - visit_tuple([&] { ret++; }, std::tuple<>{}); - fm_assert(ret == 0); - } - { - constexpr auto tuple = std::make_tuple((char)1, (short)2, (long)3); - static_assert(find_in_tuple([](auto x) { return x == 3; }, tuple)); - static_assert(!find_in_tuple([](auto x) { return x == 5; }, tuple)); - } - - return true; -} - -void test_fun2() { - using entity = Entity; - static constexpr auto read_fn = [](const TestAccessors& x) constexpr { return x.bar(); }; - static constexpr auto write_fn = [](TestAccessors& x, int value) constexpr { x.set_bar(value); }; - constexpr auto read_bar = fu2::function_view{read_fn}; - constexpr auto write_bar = fu2::function_view{write_fn}; - constexpr auto m_bar2 = entity::type::field{"bar"_s, read_bar, write_bar}; - - auto x = TestAccessors{1, 2, 3}; - fm_assert(m_bar2.read(x) == 2); - m_bar2.write(x, 22); - fm_assert(m_bar2.read(x) == 22); -} - -void test_erasure() { - erased_accessor accessors[] = { - m_foo.erased(), - m_bar.erased(), - m_baz.erased(), - }; - auto obj = TestAccessors{1, 2, 3}; - int value = 0; - accessors[1].read_fun(&obj, accessors[1].reader, &value); - fm_assert(value == 2); - int value2 = 22222, value2_ = 0; - accessors[1].write_fun(&obj, accessors[1].writer, &value2); - accessors[1].read_fun(&obj, accessors[1].reader, &value2_); - fm_assert(value2 == value2_); -} - -void test_metadata() -{ - constexpr auto m = entity_metadata(); - static_assert(sizeof m == 1); - fm_assert(m.class_name == name_of); - fm_assert(m.class_name.contains("TestAccessors"_s)); - const auto [foo, bar, baz] = m.accessors; - const auto [foo2, bar2, baz2] = m.erased_accessors; - TestAccessors x{0, 0, 0}; - foo.write(x, 1); - fm_assert(x.foo == 1); - int bar_ = 2; - bar2.write_fun(&x, bar2.writer, &bar_); - fm_assert(x.bar() == 2); - baz2.write(x, 3); - fm_assert(baz2.read(x) == 3); -} - -void test_type_name() -{ - struct foobar; - constexpr StringView name = name_of; - fm_assert(name.contains("foobar"_s)); - static_assert(name.data() == name_of.data()); - static_assert(name_of != name_of); - static_assert(name_of != name_of); - using foobar2 = foobar; - static_assert(name_of.data() == name_of.data()); -} - -[[maybe_unused]] constexpr void test_null_writer() -{ - using entity = Entity; - constexpr auto foo = entity::type::field{"foo"_s, &TestAccessors::foo, nullptr}; - static_assert(foo.writer == nullptr); - static_assert(!foo.can_write); - static_assert(std::get<0>(entity_accessors::accessors()).can_write); -} - -void test_predicate() -{ - using entity = Entity; - constexpr TestAccessors x{0, 0, 0}; - constexpr auto foo = entity::type::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo, - [](const TestAccessors&) { return field_status::hidden; }}; - static_assert(foo.is_enabled(x) == field_status::hidden); - fm_assert(foo.erased().is_enabled(&x) == field_status::hidden); - - foo.erased().do_asserts(); - - constexpr auto foo2 = entity::type::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo, - [](const TestAccessors&) { return field_status::readonly; }}; - static_assert(foo2.is_enabled(x) == field_status::readonly); - fm_assert(foo2.erased().is_enabled(&x) == field_status::readonly); - constexpr auto foo3 = entity::type::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo}; - static_assert(foo3.is_enabled(x) == field_status::enabled); - fm_assert(foo3.erased().is_enabled(&x) == field_status::enabled); -} - -constexpr bool test_names() -{ - constexpr auto m = entity_metadata(); - auto [foo1, bar1, baz1] = m.accessors; - auto [foo2, bar2, baz2] = m.erased_accessors; - - fm_assert(foo1.name == "foo"_s); - fm_assert(bar1.name == "bar"_s); - fm_assert(baz1.name == "baz"_s); - - fm_assert(foo2.field_name == "foo"_s); - fm_assert(bar2.field_name == "bar"_s); - fm_assert(baz2.field_name == "baz"_s); - return true; -} - -constexpr void test_constraints() -{ - using entity = Entity; - constexpr auto x = TestAccessors{}; - constexpr auto foo = entity::type::field { - "foo"_s, &TestAccessors::foo, &TestAccessors::foo, - constantly(constraints::max_length{42}), - constantly(constraints::range{37, 42}), - }; - - static_assert(foo.get_range(x) == constraints::range{37, 42}); - static_assert(foo.get_max_length(x) == 42); - - static_assert(m_foo.get_range(x) == constraints::range{}); - static_assert(m_foo.get_max_length(x) == (size_t)-1); - - constexpr auto foo2 = entity::type::field { - "foo"_s, &TestAccessors::foo, &TestAccessors::foo, - constantly(constraints::max_length {123}), - }; - static_assert(foo2.get_range(x) == constraints::range{}); - static_assert(foo2.get_max_length(x) == 123); -} - -void test_erased_constraints() -{ - using entity = Entity; - static constexpr auto foo = entity::type::field{ - "foo"_s, &TestAccessors::foo, &TestAccessors::foo, - constantly(constraints::max_length{42}), - constantly(constraints::range{37, 42}), - }; - static constexpr auto erased = foo.erased(); - const auto x = TestAccessors{}; - - erased.do_asserts(); - fm_assert(erased.get_range(&x) == constraints::range{37, 42}); - fm_assert(erased.get_max_length(&x) == 42); -} - -} // namespace - -void test_app::test_entity() -{ - static_assert(test_accessors()); - static_assert(test_visitor()); - test_null_writer(); - static_assert(test_names()); - test_predicate(); - test_fun2(); - test_erasure(); - test_type_name(); - test_metadata(); - test_constraints(); - test_erased_constraints(); -} - -} // namespace floormat diff --git a/test/object.cpp b/test/object.cpp new file mode 100644 index 00000000..3c099a37 --- /dev/null +++ b/test/object.cpp @@ -0,0 +1,259 @@ +#include "app.hpp" +#include "compat/assert.hpp" +#include "entity/metadata.hpp" +#include + +using namespace floormat; +using namespace floormat::entities; + +namespace { + +struct TestAccessors { + constexpr int bar() const { return _bar; } + constexpr void set_bar(int value) { _bar = value; } + int foo; + int _bar; + int _baz; +}; + +} // namespace + +namespace floormat::entities { + +template<> struct entity_accessors { + static constexpr auto accessors() + { + using entity = Entity; + constexpr auto r_baz = [](const TestAccessors& x) { return x._baz; }; + constexpr auto w_baz = [](TestAccessors& x, int v) { x._baz = v; }; + + constexpr auto tuple = std::make_tuple( + entity::type::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo}, + entity::type::field{"bar"_s, &TestAccessors::bar, &TestAccessors::set_bar}, + entity::type::field("baz"_s, r_baz, w_baz) + ); + return tuple; + } +}; + +} // namespace floormat::entities + +namespace { + +using entity = Entity; +constexpr auto m_foo = entity::type::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo}; +constexpr auto m_bar = entity::type::field{"bar"_s, &TestAccessors::bar, &TestAccessors::set_bar}; +constexpr auto r_baz = [](const TestAccessors& x) { return x._baz; }; +constexpr auto w_baz = [](TestAccessors& x, int v) { x._baz = v; }; +constexpr auto m_baz = entity::type::field("baz"_s, r_baz, w_baz); + +} // namespace + +namespace floormat { + +namespace { + +constexpr bool test_accessors() +{ + auto x = TestAccessors{111, 222, 333}; + + { + auto a = m_foo.read(x), b = m_bar.read(x), c = m_baz.read(x); + fm_assert(a == 111 && b == 222 && c == 333); + } + + { + m_foo.write(x, 1111); + m_bar.write(x, 2222); + m_baz.write(x, 3333); + auto a = m_foo.read(x), b = m_bar.read(x), c = m_baz.read(x); + fm_assert(a == 1111 && b == 2222 && c == 3333); + } + return true; +} + +constexpr bool test_visitor() +{ + { + auto tuple = std::make_tuple((unsigned char)1, (unsigned short)2, (int)3, (long)4); + long ret = 0; + visit_tuple([&](auto x) { ret += (long)x; }, tuple); + fm_assert(ret == 1 + 2 + 3 + 4); + } + { + int ret = 0; + visit_tuple([&] { ret++; }, std::tuple<>{}); + fm_assert(ret == 0); + } + { + constexpr auto tuple = std::make_tuple((char)1, (short)2, (long)3); + static_assert(find_in_tuple([](auto x) { return x == 3; }, tuple)); + static_assert(!find_in_tuple([](auto x) { return x == 5; }, tuple)); + } + + return true; +} + +void test_fun2() { + using entity = Entity; + static constexpr auto read_fn = [](const TestAccessors& x) constexpr { return x.bar(); }; + static constexpr auto write_fn = [](TestAccessors& x, int value) constexpr { x.set_bar(value); }; + constexpr auto read_bar = fu2::function_view{read_fn}; + constexpr auto write_bar = fu2::function_view{write_fn}; + constexpr auto m_bar2 = entity::type::field{"bar"_s, read_bar, write_bar}; + + auto x = TestAccessors{1, 2, 3}; + fm_assert(m_bar2.read(x) == 2); + m_bar2.write(x, 22); + fm_assert(m_bar2.read(x) == 22); +} + +void test_erasure() { + erased_accessor accessors[] = { + m_foo.erased(), + m_bar.erased(), + m_baz.erased(), + }; + auto obj = TestAccessors{1, 2, 3}; + int value = 0; + accessors[1].read_fun(&obj, accessors[1].reader, &value); + fm_assert(value == 2); + int value2 = 22222, value2_ = 0; + accessors[1].write_fun(&obj, accessors[1].writer, &value2); + accessors[1].read_fun(&obj, accessors[1].reader, &value2_); + fm_assert(value2 == value2_); +} + +void test_metadata() +{ + constexpr auto m = entity_metadata(); + static_assert(sizeof m == 1); + fm_assert(m.class_name == name_of); + fm_assert(m.class_name.contains("TestAccessors"_s)); + const auto [foo, bar, baz] = m.accessors; + const auto [foo2, bar2, baz2] = m.erased_accessors; + TestAccessors x{0, 0, 0}; + foo.write(x, 1); + fm_assert(x.foo == 1); + int bar_ = 2; + bar2.write_fun(&x, bar2.writer, &bar_); + fm_assert(x.bar() == 2); + baz2.write(x, 3); + fm_assert(baz2.read(x) == 3); +} + +void test_type_name() +{ + struct foobar; + constexpr StringView name = name_of; + fm_assert(name.contains("foobar"_s)); + static_assert(name.data() == name_of.data()); + static_assert(name_of != name_of); + static_assert(name_of != name_of); + using foobar2 = foobar; + static_assert(name_of.data() == name_of.data()); +} + +[[maybe_unused]] constexpr void test_null_writer() +{ + using entity = Entity; + constexpr auto foo = entity::type::field{"foo"_s, &TestAccessors::foo, nullptr}; + static_assert(foo.writer == nullptr); + static_assert(!foo.can_write); + static_assert(std::get<0>(entity_accessors::accessors()).can_write); +} + +void test_predicate() +{ + using entity = Entity; + constexpr TestAccessors x{0, 0, 0}; + constexpr auto foo = entity::type::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo, + [](const TestAccessors&) { return field_status::hidden; }}; + static_assert(foo.is_enabled(x) == field_status::hidden); + fm_assert(foo.erased().is_enabled(&x) == field_status::hidden); + + foo.erased().do_asserts(); + + constexpr auto foo2 = entity::type::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo, + [](const TestAccessors&) { return field_status::readonly; }}; + static_assert(foo2.is_enabled(x) == field_status::readonly); + fm_assert(foo2.erased().is_enabled(&x) == field_status::readonly); + constexpr auto foo3 = entity::type::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo}; + static_assert(foo3.is_enabled(x) == field_status::enabled); + fm_assert(foo3.erased().is_enabled(&x) == field_status::enabled); +} + +constexpr bool test_names() +{ + constexpr auto m = entity_metadata(); + auto [foo1, bar1, baz1] = m.accessors; + auto [foo2, bar2, baz2] = m.erased_accessors; + + fm_assert(foo1.name == "foo"_s); + fm_assert(bar1.name == "bar"_s); + fm_assert(baz1.name == "baz"_s); + + fm_assert(foo2.field_name == "foo"_s); + fm_assert(bar2.field_name == "bar"_s); + fm_assert(baz2.field_name == "baz"_s); + return true; +} + +constexpr void test_constraints() +{ + using entity = Entity; + constexpr auto x = TestAccessors{}; + constexpr auto foo = entity::type::field { + "foo"_s, &TestAccessors::foo, &TestAccessors::foo, + constantly(constraints::max_length{42}), + constantly(constraints::range{37, 42}), + }; + + static_assert(foo.get_range(x) == constraints::range{37, 42}); + static_assert(foo.get_max_length(x) == 42); + + static_assert(m_foo.get_range(x) == constraints::range{}); + static_assert(m_foo.get_max_length(x) == (size_t)-1); + + constexpr auto foo2 = entity::type::field { + "foo"_s, &TestAccessors::foo, &TestAccessors::foo, + constantly(constraints::max_length {123}), + }; + static_assert(foo2.get_range(x) == constraints::range{}); + static_assert(foo2.get_max_length(x) == 123); +} + +void test_erased_constraints() +{ + using entity = Entity; + static constexpr auto foo = entity::type::field{ + "foo"_s, &TestAccessors::foo, &TestAccessors::foo, + constantly(constraints::max_length{42}), + constantly(constraints::range{37, 42}), + }; + static constexpr auto erased = foo.erased(); + const auto x = TestAccessors{}; + + erased.do_asserts(); + fm_assert(erased.get_range(&x) == constraints::range{37, 42}); + fm_assert(erased.get_max_length(&x) == 42); +} + +} // namespace + +void test_app::test_entity() +{ + static_assert(test_accessors()); + static_assert(test_visitor()); + test_null_writer(); + static_assert(test_names()); + test_predicate(); + test_fun2(); + test_erasure(); + test_type_name(); + test_metadata(); + test_constraints(); + test_erased_constraints(); +} + +} // namespace floormat diff --git a/test/serializer.cpp b/test/serializer.cpp index 5d883ac1..20413afe 100644 --- a/test/serializer.cpp +++ b/test/serializer.cpp @@ -34,10 +34,10 @@ chunk& make_test_chunk(world& w, chunk_coords_ ch) c[{K, K }].wall_west() = { metal2, 0 }; c[{K, K+1}].wall_north() = { metal1, 0 }; c[{K+1, K }].wall_west() = { metal2, 0 }; - w.make_entity(w.make_id(), {ch, {3, 4}}, table); - w.make_entity(w.make_id(), {ch, {K, K+1}}, control_panel); + w.make_object(w.make_id(), {ch, {3, 4}}, table); + w.make_object(w.make_id(), {ch, {K, K+1}}, control_panel); { - auto& e = *w.make_entity(w.make_id(), {ch, {K+3, K+1}}, door); + auto& e = *w.make_object(w.make_id(), {ch, {K+3, K+1}}, door); auto i = e.index(); e.activate(i); e.update(i, 1.f/60); @@ -49,7 +49,7 @@ chunk& make_test_chunk(world& w, chunk_coords_ ch) void assert_chunks_equal(const chunk& a, const chunk& b) { - fm_assert(a.entities().size() == b.entities().size()); + fm_assert(a.objects().size() == b.objects().size()); for (auto i = 0uz; i < TILE_COUNT; i++) { @@ -57,28 +57,28 @@ void assert_chunks_equal(const chunk& a, const chunk& b) fm_assert(a1 == b1); } - for (auto i = 0uz; i < a.entities().size(); i++) + for (auto i = 0uz; i < a.objects().size(); i++) { - const auto& ae = *a.entities()[i]; - const auto& be = *b.entities()[i]; + const auto& ae = *a.objects()[i]; + const auto& be = *b.objects()[i]; fm_assert(ae.type() == be.type()); switch (ae.type()) { - case entity_type::character: { + case object_type::character: { const auto& e1 = static_cast(ae); const auto& e2 = static_cast(be); const auto p1 = character_proto(e1), p2 = character_proto(e2); fm_assert(p1 == p2); break; } - case entity_type::scenery: { + case object_type::scenery: { const auto& e1 = static_cast(ae); const auto& e2 = static_cast(be); const auto p1 = scenery_proto(e1), p2 = scenery_proto(e2); fm_assert(p1 == p2); break; } - case entity_type::light: { + case object_type::light: { const auto& e1 = static_cast(ae); const auto& e2 = static_cast(be); const auto p1 = light_proto(e1), p2 = light_proto(e2); @@ -86,7 +86,7 @@ void assert_chunks_equal(const chunk& a, const chunk& b) break; } default: - fm_abort("invalid entity type '%d'", (int)ae.type()); + fm_abort("invalid object type '%d'", (int)ae.type()); } } } -- cgit v1.2.3