OpenMiner/source/server/lua/loader/LuaEntityLoader.cpp
2020-05-20 13:39:06 +02:00

153 lines
5.6 KiB
C++

/*
* =====================================================================================
*
* OpenMiner
*
* Copyright (C) 2018-2020 Unarelith, Quentin Bazin <openminer@unarelith.net>
* Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md)
*
* This file is part of OpenMiner.
*
* OpenMiner is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* OpenMiner is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OpenMiner; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* =====================================================================================
*/
#include <gk/core/Debug.hpp>
#include "AnimationComponent.hpp"
#include "DrawableDef.hpp"
#include "LuaCallbackComponent.hpp"
#include "LuaEntityLoader.hpp"
#include "LuaMod.hpp"
#include "NetworkComponent.hpp"
#include "PositionComponent.hpp"
#include "Registry.hpp"
#include "RotationComponent.hpp"
#include "WorldController.hpp"
void LuaEntityLoader::loadEntity(const sol::table &table) const {
std::string stringID = m_mod.id() + ":" + table["id"].get<std::string>();
entt::registry &registry = Registry::getInstance().entityRegistry();
entt::entity entity = Registry::getInstance().registerEntity(stringID);
sol::optional<sol::unsafe_function> onCollision = table["on_collision"];
if (onCollision != sol::nullopt) {
auto &luaCallbackComponent = registry.emplace<LuaCallbackComponent>(entity);
luaCallbackComponent.collisionCallback = onCollision.value();
}
sol::optional<sol::table> properties = table["properties"];
if (properties != sol::nullopt) {
sol::optional<sol::table> visual = properties.value()["visual"];
if (visual != sol::nullopt) {
std::string type = visual.value()["type"];
if (type == "inventorycube") {
auto &drawable = registry.emplace<DrawableDef>(entity);
auto &cube = drawable.addInventoryCube();
cube.size = visual.value()["size"].get_or(1.0f);
sol::optional<sol::table> origin = visual.value()["origin"];
if (origin != sol::nullopt) {
cube.origin = {origin.value()[1], origin.value()[2], origin.value()[3]};
}
}
else
gkError() << "For entity '" + stringID + "': Visual type '" + type + "' unknown";
}
bool isRotatable = properties.value()["is_rotatable"].get_or(false);
if (isRotatable)
registry.emplace<RotationComponent>(entity);
sol::optional<sol::table> animation = properties.value()["animation"];
if (animation != sol::nullopt) {
auto &animationComponent = registry.emplace<AnimationComponent>(entity);
for (auto &it : animation.value()) {
sol::table anim = it.second.as<sol::table>();
std::string type = anim["type"];
if (type == "rotation") {
sol::table axis = anim["axis"];
animationComponent.addRotation(axis[1], axis[2], axis[3], anim["angle"]);
}
else if (type == "translation") {
sol::table delta = anim["delta"];
animationComponent.addTranslation(delta[1], delta[2], delta[3], anim["min"], anim["max"], anim["loop"].get_or(true));
}
else
gkError() << "For entity '" + stringID + "': Animation type '" + type + "' unknown";
}
}
sol::optional<sol::table> hitboxTable = properties.value()["hitbox"];
if (hitboxTable != sol::nullopt) {
registry.emplace<gk::DoubleBox>(entity,
hitboxTable.value()[1], hitboxTable.value()[2], hitboxTable.value()[3],
hitboxTable.value()[4], hitboxTable.value()[5], hitboxTable.value()[6]
);
}
}
}
void LuaEntityLoader::spawnEntity(const std::string &entityID, const sol::table &table) const {
gk::Vector3f pos;
u16 dim;
sol::optional<sol::table> position = table["position"];
sol::optional<u16> dimension = table["dimension"];
if (position != sol::nullopt && dimension != sol::nullopt) {
pos = {position.value()[1], position.value()[2], position.value()[3]};
dim = dimension.value();
}
else {
gkError() << "In mod '" + m_mod.id() + "': Cannot spawn entity '" + entityID + "' without a position and a dimension";
return;
}
ItemStack stack;
sol::optional<sol::table> itemStack = table["item_stack"];
if (itemStack != sol::nullopt) {
stack.setItem(itemStack.value()[1]);
stack.setAmount(itemStack.value()[2].get_or(1));
}
entt::registry &modelRegistry = Registry::getInstance().entityRegistry();
entt::entity modelEntity = Registry::getInstance().getEntityFromStringID(entityID);
if (modelEntity != entt::null) {
ServerWorld &world = m_worldController.getWorld(dim);
Scene &scene = world.scene();
entt::registry &registry = scene.registry();
entt::entity entity = scene.createEntityFromModel(modelRegistry, modelEntity);
registry.emplace<PositionComponent>(entity, pos.x, pos.y, pos.z, dim);
registry.emplace<NetworkComponent>(entity, entity);
// FIXME: This code is too specific to the item drop entity
if (stack.amount()) {
auto *drawable = registry.try_get<DrawableDef>(entity);
if (drawable) {
auto &cube = drawable->getInventoryCubeDef();
cube.blockID = stack.item().stringID();
}
registry.emplace<ItemStack>(entity, stack);
}
}
else
gkError() << "In mod '" + m_mod.id() + "': Cannot find entity with id '" + entityID + "'";
}