summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--editor/update.cpp40
-rw-r--r--src/critter.cpp2
-rw-r--r--src/critter.hpp2
-rw-r--r--src/light.cpp2
-rw-r--r--src/light.hpp2
-rw-r--r--src/object.hpp3
-rw-r--r--src/scenery.cpp6
-rw-r--r--src/scenery.hpp6
-rw-r--r--test/serializer.cpp5
9 files changed, 50 insertions, 18 deletions
diff --git a/editor/update.cpp b/editor/update.cpp
index 55d0ec4a..a4b9bbcd 100644
--- a/editor/update.cpp
+++ b/editor/update.cpp
@@ -225,7 +225,7 @@ void app::apply_commands(const key_set& keys)
void app::update_world(Ns dt)
{
auto& world = M->world();
- world.increment_frame_no();
+ const auto frame_no = world.increment_frame_no();
auto [minx, maxx, miny, maxy] = M->get_draw_bounds();
minx--; miny--; maxx++; maxy++;
for (int8_t z = chunk_z_min; z <= chunk_z_max; z++)
@@ -237,10 +237,42 @@ void app::update_world(Ns dt)
continue;
auto& c = *cʹ;
const auto& es = c.objects();
- const auto size = es.size();
- for (auto i = (int)(size-1); i >= 0; i--)
- es[i]->update((unsigned)i, dt);
+ auto size = es.size();
+ for (auto i = 0uz; 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]]
+ {
+ i--;
+ size = es.size();
+ }
+ }
+ }
+
+#ifndef FM_NO_DEBUG
+ for (int8_t z = chunk_z_min; z <= chunk_z_max; z++)
+ for (int16_t y = miny; y <= maxy; y++)
+ for (int16_t x = minx; x <= maxx; x++)
+ {
+ auto* cʹ = world.at({x, y, z});
+ if (!cʹ)
+ continue;
+ auto& c = *cʹ;
+ const auto& es = c.objects();
+ auto size = es.size();
+ for (auto i = 0uz; i < size; i++)
+ {
+ auto& e = *es[i];
+ fm_assert(e.last_frame_no == frame_no);
+ }
}
+#endif
}
void app::update_character([[maybe_unused]] Ns dt)
diff --git a/src/critter.cpp b/src/critter.cpp
index 21dc74bd..5b80ab81 100644
--- a/src/critter.cpp
+++ b/src/critter.cpp
@@ -362,7 +362,7 @@ Vector2 critter::ordinal_offset(Vector2b offset) const
return Vector2(offset);
}
-void critter::update(size_t i, const Ns& dt)
+void critter::update(size_t& i, const Ns& dt)
{
if (playable) [[unlikely]]
{
diff --git a/src/critter.hpp b/src/critter.hpp
index 18f714e5..40423b3f 100644
--- a/src/critter.hpp
+++ b/src/critter.hpp
@@ -29,7 +29,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; // todo! return true when the position changed
+ void update(size_t& i, const Ns& dt) override;
// todo!
// add a field: last_update_frame. if doesn't equal to the current world's update
// frame, update() gets called and last_update_frame is set to current frame.
diff --git a/src/light.cpp b/src/light.cpp
index 0e36fd6d..3e25dfc5 100644
--- a/src/light.cpp
+++ b/src/light.cpp
@@ -53,7 +53,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(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 3d0d3546..ecc45d31 100644
--- a/src/light.hpp
+++ b/src/light.hpp
@@ -33,7 +33,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(size_t& i, const Ns& dt) override;
bool is_dynamic() const override;
bool is_virtual() const override;
diff --git a/src/object.hpp b/src/object.hpp
index ae930259..66cf4d6b 100644
--- a/src/object.hpp
+++ b/src/object.hpp
@@ -43,6 +43,7 @@ struct object
fm_DECLARE_DELETED_COPY_ASSIGNMENT(object);
const object_id id = 0;
+ uint64_t last_frame_no = 0;
class chunk* const c;
const std::shared_ptr<anim_atlas> atlas;
const global_coords coord;
@@ -71,7 +72,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(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);
diff --git a/src/scenery.cpp b/src/scenery.cpp
index 701dde1f..fb3010f1 100644
--- a/src/scenery.cpp
+++ b/src/scenery.cpp
@@ -50,7 +50,7 @@ scenery_proto::operator bool() const { return atlas != nullptr; }
bool generic_scenery_proto::operator==(const generic_scenery_proto& p) const = default;
enum scenery_type generic_scenery_proto::scenery_type() const { return scenery_type::generic; }
-void generic_scenery::update(scenery&, size_t, Ns) {}
+void generic_scenery::update(scenery&, size_t&, Ns) {}
Vector2 generic_scenery::ordinal_offset(const scenery&, Vector2b offset) const { return Vector2(offset); }
bool generic_scenery::can_activate(const scenery&, size_t) const { return interactive; }
bool generic_scenery::activate(floormat::scenery&, size_t) { return false; }
@@ -80,7 +80,7 @@ door_scenery::door_scenery(object_id, class chunk&, const door_scenery_proto& p)
closing{p.closing}, active{p.active}, interactive{p.interactive}
{}
-void door_scenery::update(scenery& s, size_t, Ns dt)
+void door_scenery::update(scenery& s, size_t&, Ns dt)
{
if (!s.atlas || !active)
return;
@@ -146,7 +146,7 @@ bool scenery::can_activate(size_t i) const
);
}
-void scenery::update(size_t i, const Ns& dt)
+void scenery::update(size_t& i, const Ns& dt)
{
return std::visit(
[&]<typename T>(T& sc) { sc.update(*this, i, dt); },
diff --git a/src/scenery.hpp b/src/scenery.hpp
index cb952320..cc728a4b 100644
--- a/src/scenery.hpp
+++ b/src/scenery.hpp
@@ -63,7 +63,7 @@ struct generic_scenery
unsigned char active : 1 = false;
unsigned char interactive : 1 = false;
- void update(scenery& sc, size_t i, Ns dt);
+ void update(scenery& sc, size_t& i, Ns dt);
Vector2 ordinal_offset(const scenery& sc, Vector2b offset) const;
bool can_activate(const scenery& sc, size_t i) const;
bool activate(scenery& sc, size_t i);
@@ -80,7 +80,7 @@ struct door_scenery
unsigned char active : 1 = false;
unsigned char interactive : 1 = false;
- void update(scenery& sc, size_t i, Ns dt);
+ void update(scenery& sc, size_t& i, Ns dt);
Vector2 ordinal_offset(const scenery& sc, Vector2b offset) const;
bool can_activate(const scenery& sc, size_t i) const;
bool activate(scenery& sc, size_t i);
@@ -97,7 +97,7 @@ struct scenery final : object
{
scenery_variants subtype;
- void update(size_t i, const Ns& dt) override;
+ void update(size_t& i, const Ns& dt) override;
Vector2 ordinal_offset(Vector2b offset) const override;
float depth_offset() const override;
bool can_activate(size_t i) const override;
diff --git a/test/serializer.cpp b/test/serializer.cpp
index 5179342c..86105d3b 100644
--- a/test/serializer.cpp
+++ b/test/serializer.cpp
@@ -51,7 +51,6 @@ chunk& test_app::make_test_chunk(world& w, chunk_coords_ ch)
{
auto& e = *w.make_object<scenery>(w.make_id(), {ch, {K+3, K+1}}, door);
- const auto index = e.index();
const auto end = e.atlas->info().nframes-1;
constexpr auto dt = Second / 60;
fm_assert(e.frame == end);
@@ -59,10 +58,10 @@ chunk& test_app::make_test_chunk(world& w, chunk_coords_ ch)
fm_assert(!x.active);
e.activate(e.index());
fm_assert(x.active);
- e.update(index, dt);
+ { auto index = e.index(); e.update(index, dt); }
fm_assert(e.frame != end);
for (int i = 0; i < 60*3; i++)
- e.update(index, dt);
+ { auto index = e.index(); e.update(index, dt); }
fm_assert(e.frame == 0);
fm_assert(!x.active);
}