optimizations + bugfixes

* Bombs explode on damage/explosion
* Orbits spell fixed
* Performance: implemented shared component indexes,
compiled Lua caching, and updates only for changed projectile fields.
Also removed accumulating hidden entity slots.
This commit is contained in:
Gaël committed 2026-10-20 11:02:18 +02:00
1 parent 87bff164f1
commit a34f42d53e
17 files changed
+727 -131

No files matched your search

+45 -2
View File
@@ -4,8 +4,12 @@
// synchronised by the host; item pickup, chest opening and loot spawning run here, through the original scripts.
#include <functional>
#include <map>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <tuple>
#include <unordered_map>
#include <vector>
#include "entity/entity.h"
@@ -19,6 +23,9 @@ struct RtComponent {
std::string type;
std::map<std::string, std::string> attrs;
bool enabled = true;
uint64_t value_revision = 0;
int gpu_lifetime = 0;
bool gpu_lifetime_pending = false; // comp() materializes this GPU mirror before exposing the component
std::set<std::string> tags;
};
@@ -29,6 +36,9 @@ struct RtEntity {
double x = 0, y = 0, rot = 0, sx = 1, sy = 1;
bool alive = true;
std::vector<int> comps;
uint64_t component_revision = 0;
int single_lua_component = 0, lua_component_count = 0, collision_component_count = 0;
std::map<std::string, std::vector<int>, std::less<>> comps_by_type;
int parent = 0;
int born = 0;
int died = -1; // the frame of kill(); the record and its components are erased a few frames later (tick)
@@ -95,6 +105,8 @@ public:
void tick();
void load_entities(int id, int lc, bool notify); // a LoadEntitiesComponent loads its entities (at spawn, or when its timeout_frames timer comes)
long script_runs() const { return script_runs_; } // periodic script executions so far (debug)
bool native_projectile_scripts = true;
long native_script_runs() const { return native_script_runs_; }
// The area whose entities run their scripts (the loaded world around the camera): LuaComponents with execute_every_n_frame, CollisionTriggerComponents.
void set_active_area(double cx, double cy, double hw, double hh) { act_cx_ = cx; act_cy_ = cy; act_hw_ = hw; act_hh_ = hh; scripts_on_ = true; }
// Runs the script_death scripts of an entity (death(damage types, message, killer, drop_items)): the gold drop, loot, ... The caller kills the entity afterwards.
@@ -137,7 +149,9 @@ public:
// Kills every entity of the world except the player and what the player carries (the area was left).
void clear_world_entities();
std::vector<int> with_file(const std::string& part);
std::vector<int> with_component(const std::string& type); // living entities with a component of the type // living entities whose file name contains the text
std::vector<int> with_component(std::string_view type); // living entities with a component of the type
// Incremental indexes for fields changed through set_value (null value: nonempty).
std::vector<int> with_component_field(const std::string& type, const std::string& key, const std::optional<std::string>& value = std::nullopt);
int player() const { return player_id_; }
void set_player(int id) { player_id_ = id; }
@@ -174,6 +188,7 @@ public:
void assign_card_slot(int wand, int card); // a spell card that becomes a child of a wand takes the first free slot of the wand
int add_gun_action(int wand, const std::string& action_id, bool permanent) override;
std::vector<int> components(int entity, const std::string& type, const std::string& tag, bool include_disabled) override;
std::vector<int> components(int entity, const char* type, const std::string& tag, bool include_disabled) { return components_view(entity, type, tag, include_disabled); }
int add_component(int entity, const std::string& type, const std::map<std::string, std::string>& attrs) override;
void remove_component(int comp) override;
void set_component_enabled(int comp, bool enabled) override;
@@ -229,19 +244,47 @@ public:
private:
int add_comp_internal(int entity, const std::string& type, std::map<std::string, std::string> attrs);
void erase_comp_internal(int component);
std::vector<int> components_view(int entity, std::string_view type, const std::string& tag, bool include_disabled);
bool run_script_callback(int entity, int comp, const std::string& file, const std::string& function, const std::vector<LVal>& args);
bool run_native_guard(int entity, const std::string& file);
void update_component_fields(const RtComponent& component, int delta, std::string_view key = {});
const Wak& wak_;
LuaHost& host_;
EntityDb db_;
std::map<int, RtEntity> ents_;
std::map<int, RtComponent> comps_;
std::unordered_map<int, RtComponent> comps_;
std::map<std::string, std::map<int, int>, std::less<>> entities_by_component_;
using FieldQuery = std::tuple<std::string, std::string, std::optional<std::string>>;
std::map<FieldQuery, std::map<int, int>> component_fields_;
struct LuaSchedule {
uint64_t revision = uint64_t(-1);
std::string file;
int every = 1, times = 0, done = 0, next = -1;
bool call_init = false, inited = false, remove = false;
};
std::unordered_map<int, LuaSchedule> lua_schedules_;
struct NativeGuardState {
uint64_t revision = uint64_t(-1);
int angle_component = 0;
const std::string *angle = nullptr, *rotation = nullptr, *owner = nullptr;
std::string rotation_text, owner_text;
double rotation_value = 0, owner_value = 0;
bool has_storage = false;
};
std::unordered_map<int, NativeGuardState> native_guard_states_;
double act_cx_ = 0, act_cy_ = 0, act_hw_ = 0, act_hh_ = 0;
bool scripts_on_ = false;
long script_runs_ = 0;
long native_script_runs_ = 0;
uint64_t native_source_revision_ = uint64_t(-1), native_api_revision_ = uint64_t(-1);
bool native_guard_source_ = false, native_guard_api_ = false;
std::string native_guard_env_;
static constexpr int kDynamicIdBase = 1 << 16; // ids below are reserved for forced ids (the initial world entities: GPU slot + 1, the player 1)
int next_ent_ = kDynamicIdBase, next_comp_ = 1, frame_ = 0, player_id_ = 0, world_state_ = 0;
int updated_entity_ = 0, updated_comp_ = 0;
uint64_t component_revision_ = 0;
std::vector<GameMessage> messages_;
std::vector<std::string> errors_;
std::vector<int> pending_scripts_; // entities whose on-added scripts still have to run