summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2024-05-02 16:34:05 +0200
committerStanislaw Halik <sthalik@misaki.pl>2024-05-02 22:35:39 +0200
commit6abcd7d52cda334c58ec999d212491fc24f13c9d (patch)
tree86998508afe8eb7447ad70a2d5beebdbc9995a8f
parent03b67a512ec9ef1cf5c337aa5c47a5a76d4a8a61 (diff)
script lifecycle mostly implemented
-rw-r--r--editor/app.cpp34
-rw-r--r--editor/app.hpp2
-rw-r--r--editor/ctor.cpp9
-rw-r--r--editor/imgui.cpp3
-rw-r--r--editor/scenery-editor.cpp9
-rw-r--r--editor/vobj-editor.cpp6
-rw-r--r--main/ctor.cpp6
-rw-r--r--src/chunk.cpp1
-rw-r--r--src/critter-script.cpp12
-rw-r--r--src/critter-script.hpp2
-rw-r--r--src/critter.cpp15
-rw-r--r--src/critter.hpp4
-rw-r--r--src/object.cpp4
-rw-r--r--src/object.hpp4
-rw-r--r--src/script.hpp4
-rw-r--r--src/script.inl34
-rw-r--r--src/world.cpp31
-rw-r--r--src/world.hpp7
18 files changed, 138 insertions, 49 deletions
diff --git a/editor/app.cpp b/editor/app.cpp
index c8c5aa0f..36d4ad1b 100644
--- a/editor/app.cpp
+++ b/editor/app.cpp
@@ -31,30 +31,46 @@ shared_ptr_wrapper<critter> app::ensure_player_character(world& w)
{
return w.ensure_player_character(_character_id);
}
-
-void app::reset_world(class world&& wʹ)
+void app::reset_world()
{
- if (!M)
- return;
+ if (M)
+ reset_world(world{});
+}
+void app::reset_world_pre()
+{
+ auto& w = M->world();
+ w.finish_scripts();
_editor->on_release();
//_editor->clear_selection();
kill_popups(true);
tested_light_chunk = {};
tests_reset_mode();
-
clear_keys();
- const auto pixel = cursor.pixel;
- cursor = {};
_character_id = 0;
_render_vobjs = true;
_render_all_z_levels = true;
_timestamp = 0;
+ const auto pixel = cursor.pixel;
+ cursor = {};
+ cursor.pixel = pixel;
+}
- auto& w = M->reset_world(move(wʹ));
+void app::reset_world_post()
+{
+ auto& w = M->world();
w.collect(true);
ensure_player_character(w);
- update_cursor_tile(pixel);
+ update_cursor_tile(cursor.pixel);
+ w.init_scripts();
+}
+
+void app::reset_world(class world&& wʹ)
+{
+ fm_assert(M);
+ reset_world_pre();
+ M->reset_world(move(wʹ));
+ reset_world_post();
}
int app::exec()
diff --git a/editor/app.hpp b/editor/app.hpp
index 32d6ce56..4476fb91 100644
--- a/editor/app.hpp
+++ b/editor/app.hpp
@@ -100,6 +100,8 @@ private:
void maybe_initialize_chunk(const chunk_coords_& pos, chunk& c) override;
void maybe_initialize_chunk_(const chunk_coords_& pos, chunk& c);
void update_character(Ns dt);
+ void reset_world_pre();
+ void reset_world_post();
void reset_world();
void reset_world(class world&& w);
diff --git a/editor/ctor.cpp b/editor/ctor.cpp
index 6e7e435f..a10f94cf 100644
--- a/editor/ctor.cpp
+++ b/editor/ctor.cpp
@@ -18,7 +18,7 @@ app::app(fm_settings&& opts) :
keys_{InPlaceInit, 0u},
key_modifiers{}
{
- reset_world();
+ reset_world_post();
auto& w = M->world();
constexpr chunk_coords_ coord{0, 0, 0};
maybe_initialize_chunk_(coord, w[coord]);
@@ -29,12 +29,7 @@ app::app(fm_settings&& opts) :
app::~app()
{
+ reset_world_pre();
}
-void app::reset_world()
-{
- reset_world(world{});
-}
-
-
} // namespace floormat
diff --git a/editor/imgui.cpp b/editor/imgui.cpp
index f35f6329..c8b0dcbd 100644
--- a/editor/imgui.cpp
+++ b/editor/imgui.cpp
@@ -389,8 +389,9 @@ void app::do_popup_menu()
e.rotate(i, next_rot);
if (ImGui::MenuItem("Delete", nullptr, false))
{
- //e.on_destroy(eʹ, false);
+ e.destroy_script_pre(eʹ, script_destroy_reason::kill);
e.chunk().remove_object(e.index());
+ e.destroy_script_post();
}
}
else
diff --git a/editor/scenery-editor.cpp b/editor/scenery-editor.cpp
index 55e194bf..b472fca5 100644
--- a/editor/scenery-editor.cpp
+++ b/editor/scenery-editor.cpp
@@ -5,6 +5,8 @@
#include "src/RTree-search.hpp"
#include "src/rotation.inl"
#include "app.hpp"
+#include "src/scenery.hpp"
+
#include <Magnum/Math/Range.h>
namespace floormat {
@@ -94,8 +96,9 @@ start:
for (auto i = 0uz; i < sz; i++)
if (const auto eʹ = es[i]; eʹ->id == id)
{
- //eʹ->on_destroy(eʹ, false);
+ eʹ->destroy_script_pre(eʹ, script_destroy_reason::kill);
c.remove_object(i);
+ eʹ->destroy_script_post();
goto start;
}
break;
@@ -103,8 +106,8 @@ start:
}
else
{
- // todo check collision at pos
- w.make_scenery(w.make_id(), pos, scenery_proto(s.proto));
+ auto sc = w.make_scenery(w.make_id(), pos, scenery_proto(s.proto));
+ sc->init_script(sc);
}
}
diff --git a/editor/vobj-editor.cpp b/editor/vobj-editor.cpp
index 52365fd5..916f303b 100644
--- a/editor/vobj-editor.cpp
+++ b/editor/vobj-editor.cpp
@@ -53,9 +53,11 @@ start: while (auto id = a.get_object_colliding_with_cursor())
{
for (auto i = (int)(es.size()-1); i >= 0; i--)
{
- if (const auto eʹ = es[i]; eʹ->id == id)
+ const auto eʹ = es[i];
+ if (eʹ->id == id && eʹ->is_virtual())
{
- //eʹ->on_destroy(eʹ);
+ eʹ->destroy_script_pre(eʹ, script_destroy_reason::kill);
+ eʹ->destroy_script_post();
c.remove_object((unsigned)i);
goto start;
}
diff --git a/main/ctor.cpp b/main/ctor.cpp
index 35968535..3508b7cd 100644
--- a/main/ctor.cpp
+++ b/main/ctor.cpp
@@ -2,6 +2,7 @@
#include "compat/fpu.hpp"
#include "src/search-astar.hpp"
#include "src/search.hpp"
+#include "src/chunk.hpp"
#include <algorithm>
#include <Corrade/Containers/GrowableArray.h>
@@ -29,6 +30,11 @@ main_impl::main_impl(floormat_app& app, fm_settings&& se, int& argc, char** argv
class world& main_impl::reset_world(class world&& w) noexcept
{
arrayResize(_clickable_scenery, 0);
+
+ for (auto& [_, cʹ] : _world.chunks())
+ for (const auto& eʹ : cʹ.objects())
+ fm_assert(eʹ.use_count() == 1);
+
_world = move(w);
_first_frame = true;
return _world;
diff --git a/src/chunk.cpp b/src/chunk.cpp
index e2b26e72..9f6fe993 100644
--- a/src/chunk.cpp
+++ b/src/chunk.cpp
@@ -173,7 +173,6 @@ void chunk::add_object(const std::shared_ptr<object>& e)
void chunk::on_teardown()
{
fm_assert(!_teardown); // too late, some chunks were already erased
- //for (const auto& eʹ : _objects) eʹ->on_destroy(eʹ, true); // todo!
}
void chunk::remove_object(size_t i)
diff --git a/src/critter-script.cpp b/src/critter-script.cpp
index 7b80234f..b222f628 100644
--- a/src/critter-script.cpp
+++ b/src/critter-script.cpp
@@ -34,24 +34,28 @@ 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)
{
- DBG_nospace << "> destroy critter:" << (void*)&*p << " id:" << p->id << " reason:" << (int)r << (p->name ? " name:" : "") << p->name;
+ DBG_nospace << " destroy critter:" << (void*)&*p << " id:" << p->id << " reason:" << (int)r << (p->name ? " name:" : "") << p->name;
touch_ptr(p);
}
void empty_critter_script::delete_self() noexcept
{
- DBG_nospace << "> delete critter";
+ DBG_nospace << "< delete critter";
}
empty_critter_script empty_script_ = {};
} // namespace
-critter_script* const critter_script::empty_script = &empty_script_;
+template <>
+critter_script* Script<critter_script, critter>::make_empty()
+{
+ return &empty_script_;
+}
critter_script::critter_script(const std::shared_ptr<critter>&) {}
critter_script::~critter_script() noexcept {}
diff --git a/src/critter-script.hpp b/src/critter-script.hpp
index 75f8156d..629d9d1b 100644
--- a/src/critter-script.hpp
+++ b/src/critter-script.hpp
@@ -17,8 +17,6 @@ struct critter_script : base_script
virtual void on_destroy(const std::shared_ptr<critter>& c, script_destroy_reason reason) = 0;
virtual void delete_self() = 0;
// todo can_activate, activate
-
- static critter_script* const empty_script;
};
} // namespace floormat
diff --git a/src/critter.cpp b/src/critter.cpp
index ece278b2..f743f614 100644
--- a/src/critter.cpp
+++ b/src/critter.cpp
@@ -549,4 +549,19 @@ critter::~critter() noexcept
//fm_assert(!script);
}
+void critter::init_script(const std::shared_ptr<object>& ptrʹ)
+{
+ script.do_initialize(std::static_pointer_cast<critter>(ptrʹ));
+}
+
+void critter::destroy_script_pre(const std::shared_ptr<object>& ptrʹ, script_destroy_reason r)
+{
+ script.do_destroy_pre(std::static_pointer_cast<critter>(ptrʹ), r);
+}
+
+void critter::destroy_script_post()
+{
+ script.do_finish_destroy();
+}
+
} // namespace floormat
diff --git a/src/critter.hpp b/src/critter.hpp
index 0ac56578..954499c3 100644
--- a/src/critter.hpp
+++ b/src/critter.hpp
@@ -44,6 +44,10 @@ struct critter final : object
Vector2 ordinal_offset(Vector2b offset) const override;
float depth_offset() const override;
+ void init_script(const std::shared_ptr<object>& ptr) override;
+ void destroy_script_pre(const std::shared_ptr<object>& ptr, script_destroy_reason r) override;
+ void destroy_script_post() override;
+
Script<critter_script, critter> script;
String name;
float speed = 1;
diff --git a/src/object.cpp b/src/object.cpp
index cd883795..f4c803b7 100644
--- a/src/object.cpp
+++ b/src/object.cpp
@@ -361,4 +361,8 @@ bool object::is_dynamic() const
return atlas->info().fps > 0;
}
+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() {}
+
} // namespace floormat
diff --git a/src/object.hpp b/src/object.hpp
index 9d842572..d2607626 100644
--- a/src/object.hpp
+++ b/src/object.hpp
@@ -97,6 +97,10 @@ struct object
requires std::is_unsigned_v<T>
static uint32_t alloc_frame_time(const Ns& dt, T& accum, uint32_t hz, float speed);
+ virtual void init_script(const std::shared_ptr<object>& ptr);
+ virtual void destroy_script_pre(const std::shared_ptr<object>& ptr, script_destroy_reason r);
+ virtual void destroy_script_post();
+
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);
diff --git a/src/script.hpp b/src/script.hpp
index c37cf448..5f657e28 100644
--- a/src/script.hpp
+++ b/src/script.hpp
@@ -37,6 +37,7 @@ class Script final
S* ptr;
script_lifecycle state;
void _assert_state(script_lifecycle s, const char* file, int line);
+ static S* make_empty();
public:
fm_DECLARE_DELETED_COPY_ASSIGNMENT(Script);
@@ -60,8 +61,7 @@ public:
void do_create(S* ptr);
void do_initialize(const std::shared_ptr<Obj>& obj);
void do_reassign(S* ptr, const std::shared_ptr<Obj>& obj);
- void do_destroy_1(const std::shared_ptr<Obj>& obj);
- void do_destroy_pre(const std::shared_ptr<Obj>& obj);
+ void do_destroy_pre(const std::shared_ptr<Obj>& obj, script_destroy_reason r);
void do_finish_destroy();
void do_ensure_torn_down();
void do_error_unwind();
diff --git a/src/script.inl b/src/script.inl
index d2e0bcd4..a756bb08 100644
--- a/src/script.inl
+++ b/src/script.inl
@@ -35,8 +35,7 @@ namespace floormat {
#define FM_ASSERT_SCRIPT_STATE(new_state) (Script<S, Obj>::_assert_state((new_state), __FILE__, __LINE__))
-template <typename S, typename Obj>
-Script<S, Obj>::~Script() noexcept
+template <typename S, typename Obj> Script<S, Obj>::~Script() noexcept
{
fm_assert(state < script_lifecycle::COUNT);
switch (state)
@@ -96,9 +95,20 @@ void Script<S, Obj>::do_create(S* p)
template <typename S, typename Obj>
void Script<S, Obj>::do_initialize(const std::shared_ptr<Obj>& obj)
{
- FM_ASSERT_SCRIPT_STATE(script_lifecycle::initializing);
- state = script_lifecycle::created;
- ptr->on_init(obj);
+ switch (state)
+ {
+ default:
+ FM_ASSERT_SCRIPT_STATE(script_lifecycle::initializing);
+ std::unreachable();
+ case script_lifecycle::no_init:
+ ptr = make_empty();
+ [[fallthrough]];
+ case script_lifecycle::initializing:
+ state = script_lifecycle::created;
+ ptr->on_init(obj);
+ return;
+ }
+ std::unreachable();
}
template <typename S, typename Obj>
@@ -114,21 +124,11 @@ void Script<S, Obj>::do_reassign(S* p, const std::shared_ptr<Obj>& obj)
}
template <typename S, typename Obj>
-void Script<S, Obj>::do_destroy_1(const std::shared_ptr<Obj>& obj)
-{
- FM_ASSERT_SCRIPT_STATE(script_lifecycle::created);
- state = script_lifecycle::torn_down;
- ptr->on_destroy(obj, script_destroy_reason::kill);
- ptr->delete_self();
- ptr = nullptr;
-}
-
-template <typename S, typename Obj>
-void Script<S, Obj>::do_destroy_pre(const std::shared_ptr<Obj>& 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;
- ptr->on_destroy(obj, script_destroy_reason::quit);
+ ptr->on_destroy(obj, r);
}
template <typename S, typename Obj>
diff --git a/src/world.cpp b/src/world.cpp
index e3fae3c3..975181c0 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -44,6 +44,11 @@ world::world(std::unordered_map<chunk_coords_, chunk>&& chunks) :
world& world::operator=(world&& w) noexcept
{
fm_debug_assert(&w != this);
+ fm_assert(!w._script_initialized);
+ fm_assert(!w._script_finalized);
+ fm_assert(!_script_initialized || _script_finalized);
+ _script_initialized = false;
+ _script_finalized = false;
fm_assert(!w._teardown);
fm_assert(!_teardown);
fm_assert(w._unique_id);
@@ -69,6 +74,7 @@ world::world() : world{initial_capacity}
world::~world() noexcept
{
+ fm_assert(_script_finalized || !_script_initialized);
for (auto& [k, c] : _chunks)
c.on_teardown();
_teardown = true;
@@ -231,6 +237,31 @@ critter_proto world::make_player_proto()
return cproto;
}
+bool world::is_teardown() const { return _teardown; }
+
+void world::init_scripts()
+{
+ fm_assert(!_script_initialized);
+ _script_initialized = true;
+ for (auto& [k, c] : _chunks)
+ for (const auto& obj : c.objects())
+ obj->init_script(obj);
+}
+
+void world::finish_scripts()
+{
+ fm_assert(_script_initialized);
+ fm_assert(!_script_finalized);
+ _script_finalized = true;
+
+ for (auto& [k, c] : _chunks)
+ for (const auto& obj : c.objects())
+ obj->destroy_script_pre(obj, script_destroy_reason::quit);
+ for (auto& [k, c] : _chunks)
+ for (const auto& obj : c.objects())
+ obj->destroy_script_post();
+}
+
shared_ptr_wrapper<critter> world::ensure_player_character(object_id& id)
{
return ensure_player_character(id, make_player_proto());
diff --git a/src/world.hpp b/src/world.hpp
index 78fdd690..2a3a26f1 100644
--- a/src/world.hpp
+++ b/src/world.hpp
@@ -44,6 +44,8 @@ private:
object_id _object_counter = object_counter_init;
uint64_t _current_frame = 1; // zero is special for struct object
bool _teardown : 1 = false;
+ bool _script_initialized : 1 = false;
+ bool _script_finalized : 1 = false;
explicit world(size_t capacity);
@@ -92,6 +94,7 @@ public:
do_make_object(std::static_pointer_cast<object>(ret), pos, sorted);
return ret;
}
+
template<bool sorted = true> std::shared_ptr<scenery> make_scenery(object_id id, global_coords pos, scenery_proto&& proto);
template<typename T = object> std::shared_ptr<T> find_object(object_id id);
template<typename T> requires is_strict_base_of<scenery, T> std::shared_ptr<T> find_object(object_id id);
@@ -100,7 +103,9 @@ public:
shared_ptr_wrapper<critter> ensure_player_character(object_id& id);
static critter_proto make_player_proto();
- bool is_teardown() const { return _teardown; }
+ void init_scripts();
+ void finish_scripts();
+ bool is_teardown() const;
object_id object_counter() const { return _object_counter; }
[[nodiscard]] object_id make_id() { return ++_object_counter; }
void set_object_counter(object_id value);