feat: loading entities (WIP)

This commit is contained in:
MihailRis 2024-07-05 22:51:03 +03:00
parent 08cc78289d
commit c8666910ce
16 changed files with 129 additions and 38 deletions

View File

@ -6,15 +6,21 @@ inair = true
ready = false
target = -1
local dropitem = ARGS.item
ARGS = ARGS or {}
local dropitem = ARGS.item or {}
if SAVED_DATA.item then
dropitem.id = item.index(SAVED_DATA.item)
dropitem.count = SAVED_DATA.count
end
local scale = {1, 1, 1}
local rotation = mat4.rotate({
math.random(), math.random(), math.random()
}, 360)
function on_save()
SAVED_DATA.test = 5
print("SAVE ENTITY")
SAVED_DATA.item = item.name(dropitem.id)
SAVED_DATA.count = dropitem.count
end
do -- setup visuals

View File

@ -144,7 +144,7 @@ void ContentLoader::loadBlock(Block& def, const std::string& name, const fs::pat
else if (model == "custom") {
def.model = BlockModel::custom;
if (root->has("model-primitives")) {
loadCustomBlockModel(def, root->map("model-primitives"));
loadCustomBlockModel(def, root->map("model-primitives").get());
} else {
logger.error() << name << ": no 'model-primitives' found";
}

View File

@ -55,9 +55,9 @@ integer_t List::integer(size_t index) const {
}
}
Map* List::map(size_t index) const {
const Map_sptr& List::map(size_t index) const {
if (auto* val = std::get_if<Map_sptr>(&values[index])) {
return val->get();
return *val;
} else {
throw std::runtime_error("type error");
}
@ -192,11 +192,11 @@ void Map::num(const std::string& key, uint& dst) const {
dst = get(key, static_cast<integer_t>(dst));
}
Map* Map::map(const std::string& key) const {
Map_sptr Map::map(const std::string& key) const {
auto found = values.find(key);
if (found != values.end()) {
if (auto* val = std::get_if<Map_sptr>(&found->second)) {
return val->get();
return *val;
}
}
return nullptr;

View File

@ -47,7 +47,7 @@ namespace dynamic {
std::string str(size_t index) const;
number_t num(size_t index) const;
integer_t integer(size_t index) const;
Map* map(size_t index) const;
const Map_sptr& map(size_t index) const;
List* list(size_t index) const;
bool flag(size_t index) const;
@ -114,7 +114,7 @@ namespace dynamic {
void num(const std::string& key, uint64_t& dst) const;
void num(const std::string& key, ubyte& dst) const;
void num(const std::string& key, double& dst) const;
Map* map(const std::string& key) const;
Map_sptr map(const std::string& key) const;
List* list(const std::string& key) const;
void flag(const std::string& key, bool& dst) const;

View File

@ -25,6 +25,15 @@ namespace dynamic {
}
return list;
}
template<int n>
void get_vec(const dynamic::Map_sptr& root, const std::string& name, glm::vec<n, float>& vec) {
if (const auto& list = root->list(name)) {
for (size_t i = 0; i < n; i++) {
vec[i] = list->num(i);
}
}
}
}
#endif // DATA_DYNAMIC_UTIL_HPP_

View File

@ -435,6 +435,15 @@ chunk_inventories_map WorldRegions::fetchInventories(int x, int z) {
return meta;
}
dynamic::Map_sptr WorldRegions::fetchEntities(int x, int z) {
uint32_t bytesSize;
const ubyte* data = getData(x, z, REGION_LAYER_ENTITIES, bytesSize);
if (data == nullptr) {
return nullptr;
}
return json::from_binary(data, bytesSize);
}
void WorldRegions::processRegionVoxels(int x, int z, const regionproc& func) {
if (getRegion(x, z, REGION_LAYER_VOXELS)) {
throw std::runtime_error("not implemented for in-memory regions");

View File

@ -5,6 +5,7 @@
#include "../typedefs.hpp"
#include "../util/BufferPool.hpp"
#include "../voxels/Chunk.hpp"
#include "../data/dynamic_fwd.hpp"
#include <mutex>
#include <memory>
@ -185,6 +186,7 @@ public:
std::unique_ptr<ubyte[]> getChunk(int x, int z);
std::unique_ptr<light_t[]> getLights(int x, int z);
chunk_inventories_map fetchInventories(int x, int z);
dynamic::Map_sptr fetchEntities(int x, int z);
void processRegionVoxels(int x, int z, const regionproc& func);

View File

@ -37,7 +37,10 @@ static int l_spawn(lua::State* L) {
if (lua::gettop(L) > 2) {
args = lua::tovalue(L, 3);
}
level->entities->spawn(scripting::engine->getAssets(), def, pos, args);
Transform transform {
pos, glm::vec3(1.0f), glm::mat3(1.0f), {}, true
};
level->entities->spawn(scripting::engine->getAssets(), def, transform, args);
return 1;
}

View File

@ -276,7 +276,8 @@ void scripting::on_entity_spawn(
const EntityDef& def,
entityid_t eid,
const std::vector<std::unique_ptr<UserComponent>>& components,
dynamic::Value args
dynamic::Value args,
dynamic::Map_sptr saved
) {
auto L = lua::get_main_thread();
lua::requireglobal(L, STDCOMP);
@ -296,7 +297,15 @@ void scripting::on_entity_spawn(
lua::pushvalue(L, args);
lua::setfield(L, "ARGS");
lua::createtable(L, 0, 0);
if (saved == nullptr) {
lua::createtable(L, 0, 0);
} else {
if (auto datamap = saved->map(component->name)) {
lua::pushvalue(L, datamap);
} else {
lua::createtable(L, 0, 0);
}
}
lua::setfield(L, "SAVED_DATA");
lua::setfenv(L);

View File

@ -81,7 +81,8 @@ namespace scripting {
const EntityDef& def,
entityid_t eid,
const std::vector<std::unique_ptr<UserComponent>>& components,
dynamic::Value args
dynamic::Value args,
dynamic::Map_sptr saved
);
bool on_entity_despawn(const EntityDef& def, const Entity& entity);
bool on_entity_grounded(const Entity& entity, float force);

View File

@ -1,8 +1,10 @@
#include "Entities.hpp"
#include "../debug/Logger.hpp"
#include "../data/dynamic_util.hpp"
#include "../assets/Assets.hpp"
#include "../world/Level.hpp"
#include "../content/Content.hpp"
#include "../physics/Hitbox.hpp"
#include "../physics/PhysicsSolver.hpp"
#include "../graphics/render/ModelBatch.hpp"
@ -12,9 +14,12 @@
#include "../objects/EntityDef.hpp"
#include "../objects/rigging.hpp"
#include "../logic/scripting/scripting.hpp"
#include "../engine.hpp"
#include <glm/ext/matrix_transform.hpp>
static debug::Logger logger("entities");
void Transform::refresh() {
combined = glm::mat4(1.0f);
combined = glm::translate(combined, pos);
@ -57,20 +62,26 @@ static triggercallback create_trigger_callback(Entities* entities) {
entityid_t Entities::spawn(
Assets* assets,
EntityDef& def,
glm::vec3 pos,
dynamic::Value args)
Transform transform,
dynamic::Value args,
dynamic::Map_sptr saved,
entityid_t uid)
{
auto rig = assets->get<rigging::RigConfig>(def.rigName);
if (rig == nullptr) {
throw std::runtime_error("rig "+def.rigName+" not found");
}
auto entity = registry.create();
glm::vec3 size(1);
auto id = nextID++;
entityid_t id;
if (uid == 0) {
id = nextID++;
} else {
id = uid;
}
registry.emplace<EntityId>(entity, static_cast<entityid_t>(id), def);
registry.emplace<Transform>(entity, pos, size, glm::mat3(1.0f));
registry.emplace<Transform>(entity, transform);
auto& body = registry.emplace<Rigidbody>(
entity, true, Hitbox {pos, def.hitbox}, std::vector<Trigger>{});
entity, true, Hitbox {transform.pos, def.hitbox}, std::vector<Trigger>{});
body.triggers.resize(def.radialTriggers.size() + def.boxTriggers.size());
for (auto& [i, box] : def.boxTriggers) {
@ -98,7 +109,8 @@ entityid_t Entities::spawn(
componentName, entity_funcs_set {}, nullptr);
scripting.components.emplace_back(std::move(component));
}
scripting::on_entity_spawn(def, id, scripting.components, std::move(args));
scripting::on_entity_spawn(
def, id, scripting.components, std::move(args), std::move(saved));
return id;
}
@ -112,6 +124,37 @@ void Entities::despawn(entityid_t id) {
}
}
void Entities::loadEntity(const dynamic::Map_sptr& map) {
entityid_t uid = 0;
std::string defname;
map->num("uid", uid);
map->str("def", defname);
if (uid == 0) {
throw std::runtime_error("could not read entity - invalid UID");
}
auto& def = level->content->entities.require(defname);
Transform transform {
glm::vec3(), glm::vec3(1.0f), glm::mat3(1.0f), {}, true
};
if (auto tsfmap = map->map("transform")) {
dynamic::get_vec(tsfmap, "pos", transform.pos);
}
dynamic::Map_sptr savedMap = map->map("comps");
auto assets = scripting::engine->getAssets();
spawn(assets, def, transform, dynamic::NONE, savedMap, uid);
}
void Entities::loadEntities(dynamic::Map_sptr root) {
auto list = root->list("data");
for (size_t i = 0; i < list->size(); i++) {
try {
loadEntity(list->map(i));
} catch (const std::runtime_error& err) {
logger.error() << "could not read entity: " << err.what();
}
}
}
void Entities::onSave(const Entity& entity) {
scripting::on_entity_save(entity);
}
@ -129,7 +172,9 @@ dynamic::Value Entities::serialize(const Entity& entity) {
if (transform.size != glm::vec3(1.0f)) {
tsfmap.put("size", dynamic::to_value(transform.size));
}
tsfmap.put("rot", dynamic::to_value(transform.rot));
if (transform.rot != glm::mat3(1.0f)) {
tsfmap.put("rot", dynamic::to_value(transform.rot));
}
}
{
auto& rigidbody = entity.getRigidbody();
@ -166,6 +211,7 @@ dynamic::Value Entities::serialize(const Entity& entity) {
auto data = scripting::get_component_value(comp->env, "SAVED_DATA");
compsMap.put(comp->name, data);
}
std::cout << root << std::endl;
}
return root;
}

View File

@ -172,8 +172,10 @@ public:
entityid_t spawn(
Assets* assets,
EntityDef& def,
glm::vec3 pos,
dynamic::Value args=dynamic::NONE);
Transform transform,
dynamic::Value args=dynamic::NONE,
dynamic::Map_sptr saved=nullptr,
entityid_t uid=0);
std::optional<Entity> get(entityid_t id) {
const auto& found = entities.find(id);
@ -183,6 +185,8 @@ public:
return std::nullopt;
}
void loadEntities(dynamic::Map_sptr map);
void loadEntity(const dynamic::Map_sptr& map);
void onSave(const Entity& entity);
std::vector<Entity> getAllInside(AABB aabb);
void despawn(entityid_t id);

View File

@ -251,10 +251,9 @@ void Player::deserialize(dynamic::Map *src) {
src->flag("flight", flight);
src->flag("noclip", noclip);
setChosenSlot(src->get("chosen-slot", getChosenSlot()));
auto invmap = src->map("inventory");
if (invmap) {
getInventory()->deserialize(invmap);
if (auto invmap = src->map("inventory")) {
getInventory()->deserialize(invmap.get());
}
}
@ -264,16 +263,14 @@ void Player::convert(dynamic::Map* data, const ContentLUT* lut) {
if (players) {
for (uint i = 0; i < players->size(); i++) {
auto playerData = players->map(i);
auto inventory = playerData->map("inventory");
if (inventory) {
Inventory::convert(inventory, lut);
if (auto inventory = playerData->map("inventory")) {
Inventory::convert(inventory.get(), lut);
}
}
} else {
auto inventory = data->map("inventory");
if (inventory) {
Inventory::convert(inventory, lut);
if (auto inventory = data->map("inventory")) {
Inventory::convert(inventory.get(), lut);
}
}
}

View File

@ -94,8 +94,8 @@ static std::tuple<size_t, std::unique_ptr<RigNode>> read_node(
size_t count = 1;
if (auto nodesList = root->list("nodes")) {
for (size_t i = 0; i < nodesList->size(); i++) {
if (auto map = nodesList->map(i)) {
auto [subcount, subNode] = read_node(map, index+count);
if (const auto& map = nodesList->map(i)) {
auto [subcount, subNode] = read_node(map.get(), index+count);
subcount += count;
subnodes.push_back(std::move(subNode));
}
@ -114,6 +114,6 @@ std::unique_ptr<RigConfig> RigConfig::parse(
if (rootNodeMap == nullptr) {
throw std::runtime_error("missing 'root' element");
}
auto [count, rootNode] = read_node(rootNodeMap, 0);
auto [count, rootNode] = read_node(rootNodeMap.get(), 0);
return std::make_unique<RigConfig>(std::string(name), std::move(rootNode), count);
}

View File

@ -5,6 +5,7 @@
#include "Block.hpp"
#include "../content/Content.hpp"
#include "../files/WorldFiles.hpp"
#include "../objects/Entities.hpp"
#include "../world/Level.hpp"
#include "../world/World.hpp"
#include "../maths/voxmaths.hpp"
@ -63,6 +64,10 @@ std::shared_ptr<Chunk> ChunksStorage::create(int x, int z) {
auto invs = regions.fetchInventories(chunk->x, chunk->z);
chunk->setBlockInventories(std::move(invs));
if (auto map = regions.fetchEntities(chunk->x, chunk->z)) {
level->entities->loadEntities(std::move(map));
}
chunk->flags.loaded = true;
for(auto& entry : chunk->inventories) {
level->inventories->store(entry.second);

View File

@ -110,7 +110,7 @@ std::unique_ptr<Level> World::load(
DEF_PLAYER_SPEED,
level->inventories->create(DEF_PLAYER_INVENTORY_SIZE)
);
player->deserialize(players->map(i));
player->deserialize(players->map(i).get());
level->inventories->store(player->getInventory());
}
} else {