diff options
-rw-r--r-- | editor/update.cpp | 28 | ||||
-rw-r--r-- | src/critter-script.cpp | 2 | ||||
-rw-r--r-- | src/critter.cpp | 12 | ||||
-rw-r--r-- | src/critter.hpp | 2 | ||||
-rw-r--r-- | src/light.cpp | 2 | ||||
-rw-r--r-- | src/light.hpp | 2 | ||||
-rw-r--r-- | src/object.cpp | 35 | ||||
-rw-r--r-- | src/object.hpp | 7 | ||||
-rw-r--r-- | src/scenery.cpp | 4 | ||||
-rw-r--r-- | src/scenery.hpp | 4 | ||||
-rw-r--r-- | src/script-enums.hpp | 18 | ||||
-rw-r--r-- | src/script.hpp | 18 | ||||
-rw-r--r-- | src/script.inl | 31 | ||||
-rw-r--r-- | src/world.hpp | 2 | ||||
-rw-r--r-- | test/save.cpp | 4 |
15 files changed, 116 insertions, 55 deletions
diff --git a/editor/update.cpp b/editor/update.cpp index 0fe064c0..1e47d197 100644 --- a/editor/update.cpp +++ b/editor/update.cpp @@ -240,20 +240,24 @@ void app::update_world(Ns dt) continue; auto& c = *cʹ; const auto& es = c.objects(); - auto size = es.size(); - for (auto i = 0uz; i < size; i++) + auto size = (uint32_t)es.size(); + for (auto i = 0u; i < size; i++) { - auto& e = *es[i]; - if (e.last_frame_no == frame_no) [[unlikely]] - continue; - e.last_frame_no = frame_no; - const auto* const ch = &e.chunk(); - size_t index = i; - e.update(index, dt); - if (&e.chunk() != ch || (uint32_t)index > i) [[unlikely]] + auto eʹ = es[i]; + auto index = size_t{i}; + { + auto& e = *eʹ; + if (e.last_frame_no == frame_no) [[unlikely]] + continue; + e.last_frame_no = frame_no; + } { - i--; - size = es.size(); + eʹ->update(eʹ, index, dt); + if (&eʹ->chunk() != cʹ || index > i) [[unlikely]] + { + i--; + size = (uint32_t)es.size(); + } } } } diff --git a/src/critter-script.cpp b/src/critter-script.cpp index b222f628..a10694fd 100644 --- a/src/critter-script.cpp +++ b/src/critter-script.cpp @@ -34,7 +34,7 @@ void empty_critter_script::on_init(const std::shared_ptr<critter>& p) } void empty_critter_script::on_update(const std::shared_ptr<critter>& p, size_t&, const Ns&) { - DBG_nospace << " update critter:" << (void*)&*p << " id:" << p->id << (p->name ? " name:" : "") << p->name; + //DBG_nospace << " update critter:" << (void*)&*p << " id:" << p->id << (p->name ? " name:" : "") << p->name; touch_ptr(p); } void empty_critter_script::on_destroy(const std::shared_ptr<critter>& p, script_destroy_reason r) diff --git a/src/critter.cpp b/src/critter.cpp index f743f614..18f91797 100644 --- a/src/critter.cpp +++ b/src/critter.cpp @@ -1,4 +1,6 @@ #include "critter.hpp" + +#include "critter-script.hpp" #include "compat/limits.hpp" #include "tile-constants.hpp" #include "src/point.inl" @@ -361,8 +363,15 @@ Vector2 critter::ordinal_offset(Vector2b offset) const return Vector2(offset); } -void critter::update(size_t& i, const Ns& dt) +void critter::update(const std::shared_ptr<object>& ptrʹ, size_t& i, const Ns& dt) { + fm_debug_assert(&*ptrʹ == this); + + check_script_update_1(script.state()); + script->on_update(std::static_pointer_cast<critter>(ptrʹ), i, dt); + if (check_script_update_2(script.state())) [[unlikely]] + return; + if (playable) [[unlikely]] { movement.AUTO &= !(movement.L | movement.R | movement.U | movement.D); @@ -546,7 +555,6 @@ critter::critter(object_id id, class chunk& c, critter_proto proto) : critter::~critter() noexcept { - //fm_assert(!script); } void critter::init_script(const std::shared_ptr<object>& ptrʹ) diff --git a/src/critter.hpp b/src/critter.hpp index 954499c3..4b919122 100644 --- a/src/critter.hpp +++ b/src/critter.hpp @@ -32,7 +32,7 @@ struct critter final : object object_type type() const noexcept override; explicit operator critter_proto() const; - void update(size_t& i, const Ns& dt) override; + void update(const std::shared_ptr<object>& ptr, size_t& i, const Ns& dt) override; void update_movement(size_t& i, const Ns& dt, rotation r); void update_nonplayable(size_t& i, const Ns& dt); diff --git a/src/light.cpp b/src/light.cpp index 4f280d97..e6de08a6 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -56,7 +56,7 @@ light::operator light_proto() const } object_type light::type() const noexcept { return object_type::light; } -void light::update(size_t&, const Ns&) {} +void light::update(const std::shared_ptr<object>&, size_t&, const Ns&) {} 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 ea65a23f..aeee5d88 100644 --- a/src/light.hpp +++ b/src/light.hpp @@ -35,7 +35,7 @@ struct light final : object Vector2 ordinal_offset(Vector2b offset) const override; float depth_offset() const override; object_type type() const noexcept override; - void update(size_t& i, const Ns& dt) override; + void update(const std::shared_ptr<object>& ptr, size_t& i, const Ns& dt) override; bool is_dynamic() const override; bool is_virtual() const override; diff --git a/src/object.cpp b/src/object.cpp index f4c803b7..1bc6e015 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -365,4 +365,39 @@ void object::init_script(const std::shared_ptr<object>&) {} void object::destroy_script_pre(const std::shared_ptr<object>&, script_destroy_reason) {} void object::destroy_script_post() {} +void object::check_script_update_1(script_lifecycle state) +{ + switch (state) + { + case script_lifecycle::no_init: + //return; // for tests? + case script_lifecycle::COUNT: + case script_lifecycle::destroying: + case script_lifecycle::initializing: + case script_lifecycle::torn_down: + break; + case script_lifecycle::created: + return; + } + fm_abort("bad script state %d in update() #1", (int)state); +} + +bool object::check_script_update_2(script_lifecycle state) +{ + switch (state) + { + case script_lifecycle::no_init: + // bad = false; break; // for tests? + case script_lifecycle::COUNT: + case script_lifecycle::destroying: + case script_lifecycle::initializing: + break; + case script_lifecycle::torn_down: + return true; + case script_lifecycle::created: + return false; + } + fm_abort("bad script state %d in update() #2", (int)state); +} + } // namespace floormat diff --git a/src/object.hpp b/src/object.hpp index d2607626..9de6e880 100644 --- a/src/object.hpp +++ b/src/object.hpp @@ -6,7 +6,7 @@ #include "src/object-type.hpp" #include "src/object-id.hpp" #include "src/point.hpp" -#include "src/script.hpp" +#include "src/script-enums.hpp" #include <memory> namespace floormat { @@ -75,7 +75,7 @@ struct object 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, const Ns& dt) = 0; + virtual void update(const std::shared_ptr<object>& self, size_t& i, const Ns& dt) = 0; void rotate(size_t i, rotation r); bool can_rotate(global_coords coord, rotation new_r, rotation old_r, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size); bool can_move_to(Vector2i delta, global_coords coord, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_aize); @@ -104,6 +104,9 @@ struct object protected: object(object_id id, class chunk& c, const object_proto& proto); void set_bbox_(Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, pass_mode pass); + + static void check_script_update_1(script_lifecycle state); + [[nodiscard]] static bool check_script_update_2(script_lifecycle state); }; } // namespace floormat diff --git a/src/scenery.cpp b/src/scenery.cpp index 442b712c..c7d3b51d 100644 --- a/src/scenery.cpp +++ b/src/scenery.cpp @@ -47,7 +47,7 @@ scenery::scenery(object_id id, class chunk& c, const scenery_proto& proto) : // ---------- generic_scenery ---------- -void generic_scenery::update(size_t&, const Ns&) {} +void generic_scenery::update(const std::shared_ptr<object>&, size_t&, const Ns&) {} Vector2 generic_scenery::ordinal_offset(Vector2b offset) const { return Vector2(offset); } bool generic_scenery::can_activate(size_t) const { return interactive; } bool generic_scenery::activate(size_t) { return false; } @@ -76,7 +76,7 @@ generic_scenery::generic_scenery(object_id id, class chunk& c, const generic_sce enum scenery_type door_scenery::scenery_type() const { return scenery_type::door; } -void door_scenery::update(size_t&, const Ns& dt) +void door_scenery::update(const std::shared_ptr<object>&, size_t&, const Ns& dt) { if (!atlas || !active) return; diff --git a/src/scenery.hpp b/src/scenery.hpp index beb06db5..56675a93 100644 --- a/src/scenery.hpp +++ b/src/scenery.hpp @@ -27,7 +27,7 @@ struct generic_scenery final : scenery bool active : 1 = false; bool interactive : 1 = false; - void update(size_t& i, const Ns& dt) override; + void update(const std::shared_ptr<object>& ptr, size_t& i, const Ns& dt) override; Vector2 ordinal_offset(Vector2b offset) const override; bool can_activate(size_t i) const override; bool activate(size_t i) override; @@ -47,7 +47,7 @@ struct door_scenery final : scenery bool active : 1 = false; bool interactive : 1 = false; - void update(size_t& i, const Ns& dt) override; + void update(const std::shared_ptr<object>& ptr, size_t& i, const Ns& dt) override; Vector2 ordinal_offset(Vector2b offset) const override; bool can_activate(size_t i) const override; bool activate(size_t i) override; diff --git a/src/script-enums.hpp b/src/script-enums.hpp new file mode 100644 index 00000000..0cf9548d --- /dev/null +++ b/src/script-enums.hpp @@ -0,0 +1,18 @@ +#pragma once + +namespace floormat { + +enum class script_lifecycle : uint8_t +{ + no_init, initializing, created, destroying, torn_down, COUNT, +}; + +enum class script_destroy_reason : uint8_t +{ + quit, // game is being shut down + kill, // object is being deleted from the gameworld + unassign, // script is unassigned from object + COUNT, +}; + +} // namespace floormat diff --git a/src/script.hpp b/src/script.hpp index 5f657e28..b67553ec 100644 --- a/src/script.hpp +++ b/src/script.hpp @@ -1,4 +1,5 @@ #pragma once +#include "script-enums.hpp" #include "compat/defs.hpp" #include <memory> @@ -7,11 +8,6 @@ namespace floormat struct object; struct Ns; -enum class script_lifecycle : uint8_t -{ - no_init, initializing, created, destroying, torn_down, COUNT, -}; - struct base_script { fm_DECLARE_DELETED_COPY_ASSIGNMENT(base_script); @@ -23,19 +19,11 @@ struct base_script static StringView state_name(script_lifecycle x); }; -enum class script_destroy_reason : uint8_t -{ - quit, // game is being shut down - kill, // object is being deleted from the gameworld - unassign, // script is unassigned from object - COUNT, -}; - template<typename S, typename Obj> class Script final { S* ptr; - script_lifecycle state; + script_lifecycle _state; void _assert_state(script_lifecycle s, const char* file, int line); static S* make_empty(); @@ -55,7 +43,9 @@ public: // [torn-down] -> do_ensure_torn_down() -> [torn-down] // * -> do_error_unwind() -> [torn-down] // [torn-down] -> ~script() + // [no-init] -> ~script() // for tests + script_lifecycle state() const; S* operator->(); void do_create(S* ptr); diff --git a/src/script.inl b/src/script.inl index a756bb08..e5057039 100644 --- a/src/script.inl +++ b/src/script.inl @@ -37,12 +37,12 @@ namespace floormat { template <typename S, typename Obj> Script<S, Obj>::~Script() noexcept { - fm_assert(state < script_lifecycle::COUNT); - switch (state) + fm_assert(_state < script_lifecycle::COUNT); + switch (_state) { case script_lifecycle::no_init: case script_lifecycle::torn_down: - state = (script_lifecycle)-1; + _state = (script_lifecycle)-1; break; case script_lifecycle::COUNT: std::unreachable(); @@ -50,13 +50,12 @@ template <typename S, typename Obj> Script<S, Obj>::~Script() noexcept case script_lifecycle::destroying: case script_lifecycle::initializing: fm_abort("invalid state '%s' in script destructor", - base_script::state_name(state).data()); + base_script::state_name(_state).data()); } } template <typename S, typename Obj> - -Script<S, Obj>::Script(): ptr{nullptr}, state{script_lifecycle::no_init} +Script<S, Obj>::Script(): ptr{nullptr}, _state{script_lifecycle::no_init} { detail_Script::concept_check<S, Obj>(); } @@ -64,17 +63,19 @@ Script<S, Obj>::Script(): ptr{nullptr}, state{script_lifecycle::no_init} template <typename S, typename Obj> void Script<S, Obj>::_assert_state(script_lifecycle s, const char* file, int line) { - if (state != s) + if (_state != s) { fm_EMIT_DEBUG2("fatal: ", "invalid state transition from '%s' to '%s'", - base_script::state_name(state).data(), + base_script::state_name(_state).data(), base_script::state_name(s).data()); fm_EMIT_DEBUG("", " in %s:%d", file, line); fm_EMIT_ABORT(); } } +template <typename S, typename Obj> script_lifecycle Script<S, Obj>::state() const { return _state; } + template <typename S, typename Obj> S* Script<S, Obj>::operator->() { @@ -88,14 +89,14 @@ void Script<S, Obj>::do_create(S* p) { fm_assert(p); FM_ASSERT_SCRIPT_STATE(script_lifecycle::no_init); - state = script_lifecycle::initializing; + _state = script_lifecycle::initializing; ptr = p; } template <typename S, typename Obj> void Script<S, Obj>::do_initialize(const std::shared_ptr<Obj>& obj) { - switch (state) + switch (_state) { default: FM_ASSERT_SCRIPT_STATE(script_lifecycle::initializing); @@ -104,7 +105,7 @@ void Script<S, Obj>::do_initialize(const std::shared_ptr<Obj>& obj) ptr = make_empty(); [[fallthrough]]; case script_lifecycle::initializing: - state = script_lifecycle::created; + _state = script_lifecycle::created; ptr->on_init(obj); return; } @@ -127,7 +128,7 @@ template <typename S, typename Obj> void Script<S, Obj>::do_destroy_pre(const std::shared_ptr<Obj>& obj, script_destroy_reason r) { FM_ASSERT_SCRIPT_STATE(script_lifecycle::created); - state = script_lifecycle::destroying; + _state = script_lifecycle::destroying; ptr->on_destroy(obj, r); } @@ -135,7 +136,7 @@ template <typename S, typename Obj> void Script<S, Obj>::do_finish_destroy() { FM_ASSERT_SCRIPT_STATE(script_lifecycle::destroying); - state = script_lifecycle::torn_down; + _state = script_lifecycle::torn_down; ptr->delete_self(); ptr = nullptr; } @@ -149,8 +150,8 @@ void Script<S, Obj>::do_ensure_torn_down() template <typename S, typename Obj> void Script<S, Obj>::do_error_unwind() { - fm_assert(state < script_lifecycle::COUNT); - switch (state) + fm_assert(_state < script_lifecycle::COUNT); + switch (_state) { using enum script_lifecycle; case COUNT: std::unreachable(); diff --git a/src/world.hpp b/src/world.hpp index 2a3a26f1..91df9f8d 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -105,6 +105,8 @@ public: void init_scripts(); void finish_scripts(); + void ensure_scripts_created(); // todo! + void ensure_scripts_town_down(); // todo! bool is_teardown() const; object_id object_counter() const { return _object_counter; } [[nodiscard]] object_id make_id() { return ++_object_counter; } diff --git a/test/save.cpp b/test/save.cpp index 675041c7..2df1d296 100644 --- a/test/save.cpp +++ b/test/save.cpp @@ -61,10 +61,10 @@ chunk& test_app::make_test_chunk(world& w, chunk_coords_ ch) { fm_assert(!e.active); e.activate(e.index()); fm_assert(e.active); - { auto index = e.index(); e.update(index, dt); } + { auto index = e.index(); e.update(eʹ, index, dt); } fm_assert(e.frame != end); for (int i = 0; i < 60*3; i++) - { auto index = e.index(); e.update(index, dt); } + { auto index = e.index(); e.update(eʹ, index, dt); } fm_assert(e.frame == 0); fm_assert(!e.active); } |