Browse Source

allow despawning entities

opengl-renderer-broken
Martin Dørum 4 years ago
parent
commit
93ecc0a214

+ 1
- 1
core.mod/src/entities/ItemStackEntity.cc View File

@@ -33,7 +33,7 @@ void ItemStackEntity::draw(const Swan::Context &ctx, Swan::Win &win) {
void ItemStackEntity::tick(const Swan::Context &ctx, float dt) {
despawn_timer_ -= dt;
if (despawn_timer_ <= 0)
ctx.plane.despawnEntity(*this);
despawn(ctx);
}

void ItemStackEntity::deserialize(const Swan::Context &ctx, const PackObject &obj) {

+ 1
- 0
libswan/CMakeLists.txt View File

@@ -4,6 +4,7 @@ add_library(libswan SHARED
src/Chunk.cc
src/Clock.cc
src/drawutil.cc
src/Entity.cc
src/Game.cc
src/gfxutil.cc
src/Item.cc

+ 37
- 32
libswan/include/swan/Collection.h View File

@@ -5,6 +5,7 @@
#include <typeindex>

#include "common.h"
#include "log.h"
#include "Entity.h"
#include "SlotVector.h"
#include "SmallOptional.h"
@@ -39,26 +40,10 @@ public:
};

template<typename Ent>
struct EntWrapper {
size_t generation;
Ent ent;
bool operator==(const EntWrapper &other) const {
return generation == other.generation;
}
};

template<typename Ent>
struct OptionalPolicy {
static void setEmpty(unsigned char *ptr) {
((EntWrapper<Ent> *)ptr)->generation = ~0ull;
}
static bool isEmpty(const unsigned char *ptr) {
return ((EntWrapper<Ent> *)ptr)->generation == ~0ull;
}
};

using OptEnt = SmallOptional<
Ent, SmallOptionalInitialBytesPolicy<Ent, sizeof(void *)>>;
template<typename Ent>
using OptEnt = SmallOptional<EntWrapper<Ent>, OptionalPolicy<Ent>>;
using SlotPolicy = SlotVectorDefaultSentinel<SmallNullOpt>;

virtual ~EntityCollection() = default;

@@ -70,12 +55,13 @@ public:

virtual size_t size() = 0;
virtual Entity *get(size_t idx) = 0;
virtual Entity *get(size_t idx, size_t version) = 0;
virtual Entity *get(size_t idx, size_t generation) = 0;

virtual EntityRef spawn(const Context &ctx, const Entity::PackObject &obj) = 0;
virtual void update(const Context &ctx, float dt) = 0;
virtual void tick(const Context &ctx, float dt) = 0;
virtual void draw(const Context &ctx, Win &win) = 0;
virtual void erase(size_t idx, size_t generation) = 0;

private:
virtual void *getEntityVector() = 0;
@@ -88,7 +74,7 @@ public:
EntityCollectionImpl(std::string name): name_(std::move(name)) {}

size_t size() override { return entities_.size(); }
Entity *get(size_t idx) override { return &entities_[idx]->ent; }
Entity *get(size_t idx) override { return entities_[idx].get(); }
Entity *get(size_t idx, size_t generation) override;

const std::string &name() override { return name_; }
@@ -98,13 +84,14 @@ public:
void update(const Context &ctx, float dt) override;
void tick(const Context &ctx, float dt) override;
void draw(const Context &ctx, Win &win) override;
void erase(size_t idx, size_t generation) override;

private:
void *getEntityVector() override { return (void *)&entities_; }
size_t nextGeneration() override { return generation_++; }

const std::string name_;
SlotVector<EntityCollection::OptEnt<Ent>> entities_;
SlotVector<OptEnt<Ent>, SlotPolicy<Ent>> entities_;
size_t generation_ = 0;
};

@@ -135,11 +122,14 @@ inline bool EntityRef::hasValue() {

template<typename Ent, typename... Args>
inline EntityRef EntityCollection::spawn(Args&&... args) {
auto entities = (SlotVector<OptEnt<Ent>> *)getEntityVector();
auto entities = (SlotVector<OptEnt<Ent>, SlotPolicy<Ent>> *)getEntityVector();

size_t generation = nextGeneration();
size_t idx = entities->emplace(EntWrapper<Ent>{
generation, std::move(Ent(std::forward<Args>(args)...)) });
size_t idx = entities->emplace();
OptEnt<Ent> &ent = (*entities)[idx];
ent.emplace(std::forward<Args>(args)...);
ent->index_ = idx;
ent->generation_ = generation;

return { this, idx, generation };
}
@@ -157,17 +147,20 @@ inline Entity *EntityCollectionImpl<Ent>::get(size_t idx, size_t generation) {
// We don't even need to check if e.hasValue(), because if it doesn't,
// its generation will be 0xffff... and the check will fail

if (e->generation != generation)
if (e->generation_ != generation)
return nullptr;

return &e->ent;
return e.get();
}

template<typename Ent>
inline EntityRef EntityCollectionImpl<Ent>::spawn(const Context &ctx, const Entity::PackObject &obj) {
size_t generation = nextGeneration();
size_t idx = entities_.emplace(EntWrapper<Ent>{
generation, std::move(Ent(ctx, obj)) });
size_t idx = entities_.emplace();
OptEnt<Ent> &ent = entities_[idx];
ent.emplace(ctx, obj);
ent->index_ = idx;
ent->generation_ = generation;

return { this, idx, generation };
}
@@ -177,7 +170,7 @@ inline void EntityCollectionImpl<Ent>::update(const Context &ctx, float dt) {
ZoneScopedN(typeid(Ent).name());
for (auto &ent: entities_) {
ZoneScopedN("update");
ent->ent.update(ctx, dt);
ent->update(ctx, dt);
}
}

@@ -186,7 +179,7 @@ inline void EntityCollectionImpl<Ent>::tick(const Context &ctx, float dt) {
ZoneScopedN(typeid(Ent).name());
for (auto &ent: entities_) {
ZoneScopedN("tick");
ent->ent.tick(ctx, dt);
ent->tick(ctx, dt);
}
}

@@ -195,8 +188,20 @@ inline void EntityCollectionImpl<Ent>::draw(const Context &ctx, Win &win) {
ZoneScopedN(typeid(Ent).name());
for (auto &ent: entities_) {
ZoneScopedN("draw");
ent->ent.draw(ctx, win);
ent->draw(ctx, win);
}
}

template<typename Ent>
inline void EntityCollectionImpl<Ent>::erase(size_t idx, size_t generation) {
ZoneScopedN(typeid(Ent).name());
OptEnt<Ent> &ent = entities_[idx];
if (!ent.hasValue() || ent->generation_ != generation) {
warn << "Erasing wrong entity " << typeid(Ent).name() << '[' << idx << "]!";
return;
}

entities_.erase(idx);
}

}

+ 8
- 1
libswan/include/swan/Entity.h View File

@@ -26,15 +26,22 @@ public:
Entity() = default;
Entity(Entity &&) = default;

Entity &operator=(Entity &&) = default;

void despawn(const Swan::Context &ctx);

virtual ~Entity() = default;

virtual void draw(const Context &ctx, Win &win) {}
virtual void update(const Context &ctx, float dt) {}
virtual void tick(const Context &ctx, float dt) {}
virtual void despawn() {}
virtual void onDespawn(const Context &ctx) {}

virtual void deserialize(const Swan::Context &ctx, const PackObject &obj) {}
virtual PackObject serialize(const Swan::Context &ctx, msgpack::zone &zone) { return {}; }

size_t index_;
size_t generation_;
};

class PhysicsEntity: public Entity, public BodyTrait::HasBody {

+ 10
- 0
libswan/include/swan/SmallOptional.h View File

@@ -40,6 +40,8 @@ struct SmallOptionalValuePolicy {
}
};

struct SmallNullOpt {};

// This is probably UB but I don't care, it avoids wasting 8 bytes per entity
template<typename T, typename Policy = SmallOptionalInitialBytesPolicy<T>>
class SmallOptional {
@@ -47,6 +49,7 @@ public:
SmallOptional() {
Policy::setEmpty(data_);
}
SmallOptional(SmallNullOpt): SmallOptional() {}
SmallOptional(const T &other) {
new (data_) T(other);
}
@@ -101,6 +104,10 @@ public:
return !Policy::isEmpty(data_);
}

SmallOptional<T, Policy> &operator=(SmallNullOpt) {
reset();
return *this;
}
SmallOptional<T, Policy> &operator=(const T &other) {
if (hasValue()) {
*get() = other;
@@ -142,6 +149,9 @@ public:
return *this;
}

bool operator==(const SmallNullOpt &other) const {
return !hasValue();
}
bool operator==(const SmallOptional<T, Policy> &other) const {
bool a = hasValue(), b = other.hasValue();
if (!a && !b) return true;

+ 19
- 2
libswan/include/swan/WorldPlane.h View File

@@ -33,7 +33,6 @@ public:
EntityRef spawnEntity(const std::string &name, const Entity::PackObject &params);
template<typename Ent, typename... Args>
EntityRef spawnEntity(Args&&... args);
void despawnEntity(Entity &ent);

Context getContext();

@@ -43,6 +42,11 @@ public:
void setTileID(TilePos pos, Tile::ID id);
void setTile(TilePos pos, const std::string &name);

template<typename Ent>
EntityCollection &getCollectionOf();
EntityCollection &getCollectionOf(std::string name);
EntityCollection &getCollectionOf(std::type_index type);

Tile::ID getTileID(TilePos pos);
Tile &getTile(TilePos pos);

@@ -92,7 +96,20 @@ private:

template<typename Ent, typename... Args>
inline EntityRef WorldPlane::spawnEntity(Args&&... args) {
return ent_colls_by_type_.at(typeid(Ent))->spawn<Ent, Args...>(std::forward<Args>(args)...);
return getCollectionOf(typeid(Ent)).spawn<Ent, Args...>(std::forward<Args>(args)...);
}

template<typename Ent>
inline EntityCollection &WorldPlane::getCollectionOf() {
return *ent_colls_by_type_.at(typeid(Ent));
}

inline EntityCollection &WorldPlane::getCollectionOf(std::string name) {
return *ent_colls_by_name_.at(name);
}

inline EntityCollection &WorldPlane::getCollectionOf(std::type_index type) {
return *ent_colls_by_type_.at(type);
}

}

+ 2
- 1
libswan/include/swan/util.h View File

@@ -14,8 +14,9 @@ namespace Swan {
class NonCopyable {
public:
NonCopyable(const NonCopyable &) = delete;
NonCopyable &operator=(const NonCopyable &) = delete;
NonCopyable(NonCopyable &&) noexcept = default;
NonCopyable &operator=(const NonCopyable &) = delete;
NonCopyable &operator=(NonCopyable &&) = default;

protected:
NonCopyable() = default;

+ 12
- 0
libswan/src/Entity.cc View File

@@ -0,0 +1,12 @@
#include "Entity.h"

#include "WorldPlane.h"

namespace Swan {

void Entity::despawn(const Swan::Context &ctx) {
onDespawn(ctx);
ctx.plane.getCollectionOf(typeid(*this)).erase(index_, generation_);
}

}

+ 0
- 5
libswan/src/WorldPlane.cc View File

@@ -57,11 +57,6 @@ EntityRef WorldPlane::spawnEntity(const std::string &name, const Entity::PackObj
return ent_colls_by_name_.at(name)->spawn(getContext(), obj);
}

void WorldPlane::despawnEntity(Entity &ent) {
// TODO: this
info << "Despawned entity.";
}

bool WorldPlane::hasChunk(ChunkPos pos) {
return chunks_.find(pos) != chunks_.end();
}

Loading…
Cancel
Save