Immediate mode for block instantiation.
parent
c011641b0a
commit
54b3cd072f
|
@ -1,5 +1,5 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
|
@ -167,8 +167,6 @@ add_library(Zepha_Core
|
|||
lua/modules/Dimension.h
|
||||
lua/modules/mSetGui.h
|
||||
lua/modules/mStartGame.h
|
||||
lua/modules/Register.cpp
|
||||
lua/modules/Register.h
|
||||
lua/modules/SubgameModule.cpp
|
||||
lua/modules/SubgameModule.h
|
||||
lua/modules/Time.cpp
|
||||
|
@ -176,7 +174,7 @@ add_library(Zepha_Core
|
|||
lua/register/CreateBlockModel.cpp
|
||||
lua/register/CreateBlockModel.h
|
||||
lua/register/RegisterBiomes.h
|
||||
lua/register/RegisterBlocks.h
|
||||
lua/register/RegisterBlock.h
|
||||
lua/register/RegisterItems.h
|
||||
lua/register/RegisterKeybinds.h
|
||||
lua/ServerLuaParser.cpp
|
||||
|
@ -321,6 +319,6 @@ add_library(Zepha_Core
|
|||
world/ServerWorld.h
|
||||
world/World.cpp
|
||||
world/World.h
|
||||
util/net/Address.cpp util/Bounds.cpp util/Bounds.h)
|
||||
util/net/Address.cpp util/Bounds.cpp util/Bounds.h lua/register/CreateRegister.h lua/register/CreateRegister.cpp)
|
||||
|
||||
target_include_directories(Zepha_Core PUBLIC .)
|
|
@ -6,9 +6,8 @@
|
|||
|
||||
#include "client/Client.h"
|
||||
#include "ErrorFormatter.h"
|
||||
#include "client/graph/Renderer.h"
|
||||
#include "register/RegisterItems.h"
|
||||
#include "register/RegisterBlocks.h"
|
||||
#include "register/RegisterBlock.h"
|
||||
#include "register/RegisterBiomes.h"
|
||||
#include "register/RegisterKeybinds.h"
|
||||
|
||||
|
@ -26,11 +25,13 @@
|
|||
|
||||
// Modules
|
||||
#include "modules/Time.h"
|
||||
#include "modules/Register.h"
|
||||
#include "modules/Dimension.h"
|
||||
|
||||
#include "modules/create_structure.h"
|
||||
|
||||
// Util
|
||||
#include "lua/register/CreateRegister.h"
|
||||
|
||||
LocalLuaParser::LocalLuaParser(LocalSubgame& game): LuaParser(game), keybinds(this) {}
|
||||
|
||||
void LocalLuaParser::init(WorldPtr world, PlayerPtr player, Client& client) {
|
||||
|
@ -79,9 +80,30 @@ void LocalLuaParser::loadApi(WorldPtr world, PlayerPtr player) {
|
|||
|
||||
// Modules
|
||||
modules.emplace_back(std::make_unique<Api::Module::Time>(Api::State::CLIENT, lua, core));
|
||||
modules.emplace_back(std::make_unique<Api::Module::Register>(Api::State::CLIENT, core, game, **world));
|
||||
modules.emplace_back(std::make_unique<Api::Module::Dimension>(Api::State::CLIENT, core, game, **world));
|
||||
|
||||
// Register
|
||||
Api::Util::createRegister(lua, core, "mesh");
|
||||
Api::Util::createRegister(lua, core, "item");
|
||||
Api::Util::createRegister(lua, core, "block",
|
||||
[&](const std::string& iden) { RegisterBlock::client(core, static_cast<LocalSubgame&>(game), iden); });
|
||||
Api::Util::createRegister(lua, core, "biome");
|
||||
Api::Util::createRegister(lua, core, "keybind");
|
||||
Api::Util::createRegister(lua, core, "blockmodel");
|
||||
Api::Util::createRegister(lua, core, "entity", nullptr, "entities");
|
||||
|
||||
// Define keybind variables
|
||||
core["keys"] = lua.create_table();
|
||||
core["keycodes"] = lua.create_table();
|
||||
|
||||
for (unsigned short i = 0; i < 350; i++) {
|
||||
auto key = ::Util::getKeyStr(i);
|
||||
if (!key.empty()) {
|
||||
core["keys"][key] = i;
|
||||
core["keycodes"][i] = key;
|
||||
}
|
||||
}
|
||||
|
||||
bindModules();
|
||||
|
||||
Api::create_structure (lua, core);
|
||||
|
@ -93,7 +115,7 @@ void LocalLuaParser::loadApi(WorldPtr world, PlayerPtr player) {
|
|||
|
||||
void LocalLuaParser::registerDefs() {
|
||||
auto& local = static_cast<LocalSubgame&>(game);
|
||||
RegisterBlocks ::client(core, local);
|
||||
// RegisterBlocks ::client(core, local);
|
||||
RegisterItems ::client(core, local);
|
||||
RegisterBiomes ::client(core, local);
|
||||
RegisterKeybinds::client(core, keybinds);
|
||||
|
|
|
@ -3,35 +3,36 @@
|
|||
//
|
||||
|
||||
#include <gzip/compress.hpp>
|
||||
#include <enet/enet.h>
|
||||
|
||||
#include "ServerLuaParser.h"
|
||||
|
||||
#include "ErrorFormatter.h"
|
||||
#include "world/ServerWorld.h"
|
||||
#include "util/net/Serializer.h"
|
||||
#include "register/RegisterItems.h"
|
||||
#include "register/RegisterBiomes.h"
|
||||
#include "register/RegisterBlocks.h"
|
||||
#include "world/player/ServerPlayer.h"
|
||||
#include "lua/register/RegisterItems.h"
|
||||
#include "lua/register/RegisterBiomes.h"
|
||||
#include "lua/register/RegisterBlock.h"
|
||||
|
||||
// Usertypes
|
||||
#include "usertype/Target.h"
|
||||
#include "usertype/Player.h"
|
||||
#include "usertype/Entity.h"
|
||||
#include "usertype/Inventory.h"
|
||||
#include "usertype/Dimension.h"
|
||||
#include "usertype/ItemStack.h"
|
||||
#include "usertype/InventoryList.h"
|
||||
#include "usertype/AnimationManager.h"
|
||||
#include "lua/usertype/Target.h"
|
||||
#include "lua/usertype/Player.h"
|
||||
#include "lua/usertype/Entity.h"
|
||||
#include "lua/usertype/Inventory.h"
|
||||
#include "lua/usertype/Dimension.h"
|
||||
#include "lua/usertype/ItemStack.h"
|
||||
#include "lua/usertype/InventoryList.h"
|
||||
#include "lua/usertype/AnimationManager.h"
|
||||
|
||||
// Modules
|
||||
#include "modules/Time.h"
|
||||
#include "modules/Register.h"
|
||||
#include "modules/Dimension.h"
|
||||
#include "lua/modules/Time.h"
|
||||
#include "lua/modules/Dimension.h"
|
||||
|
||||
#include "modules/create_structure.h"
|
||||
|
||||
// Util
|
||||
#include "lua/register/CreateRegister.h"
|
||||
|
||||
ServerLuaParser::ServerLuaParser(ServerSubgame& game) : LuaParser(game) {}
|
||||
|
||||
void ServerLuaParser::init(WorldPtr world, const std::string& path) {
|
||||
|
@ -109,9 +110,30 @@ void ServerLuaParser::loadApi(WorldPtr world) {
|
|||
|
||||
// Modules
|
||||
modules.emplace_back(std::make_unique<Api::Module::Time>(Api::State::SERVER, lua, core));
|
||||
modules.emplace_back(std::make_unique<Api::Module::Register>(Api::State::SERVER, core, game, *world.s()));
|
||||
modules.emplace_back(std::make_unique<Api::Module::Dimension>(Api::State::SERVER, core, game, *world.s()));
|
||||
|
||||
// Register
|
||||
Api::Util::createRegister(lua, core, "mesh");
|
||||
Api::Util::createRegister(lua, core, "item");
|
||||
Api::Util::createRegister(lua, core, "block",
|
||||
[&](const std::string& iden) { RegisterBlock::server(core, static_cast<ServerSubgame&>(game), iden); });
|
||||
Api::Util::createRegister(lua, core, "biome");
|
||||
Api::Util::createRegister(lua, core, "keybind");
|
||||
Api::Util::createRegister(lua, core, "blockmodel");
|
||||
Api::Util::createRegister(lua, core, "entity", nullptr, "entities");
|
||||
|
||||
// Define keybind variables
|
||||
core["keys"] = lua.create_table();
|
||||
core["keycodes"] = lua.create_table();
|
||||
|
||||
for (unsigned short i = 0; i < 350; i++) {
|
||||
auto key = ::Util::getKeyStr(i);
|
||||
if (!key.empty()) {
|
||||
core["keys"][key] = i;
|
||||
core["keycodes"][i] = key;
|
||||
}
|
||||
}
|
||||
|
||||
Api::create_structure (lua, core);
|
||||
|
||||
bindModules();
|
||||
|
@ -123,7 +145,7 @@ void ServerLuaParser::loadApi(WorldPtr world) {
|
|||
|
||||
void ServerLuaParser::registerDefs() {
|
||||
auto& server = static_cast<ServerSubgame&>(game);
|
||||
RegisterBlocks::server(core, server);
|
||||
// RegisterBlocks::server(core, server);
|
||||
RegisterItems ::server(core, server);
|
||||
RegisterBiomes::server(core, server);
|
||||
}
|
||||
|
@ -141,7 +163,7 @@ sol::protected_function_result ServerLuaParser::errorCallback(sol::protected_fun
|
|||
std::string::size_type lineNumStart = errString.find(':', slash);
|
||||
if (lineNumStart != std::string::npos) throw "lineNumStart";
|
||||
std::string::size_type lineNumEnd = errString.find(':', lineNumStart + 1);
|
||||
if (lineNumStart != std::string::npos) throw "lineNumEnd";
|
||||
if (lineNumEnd != std::string::npos) throw "lineNumEnd";
|
||||
|
||||
std::string fileName = errString.substr(0, lineNumStart);
|
||||
int lineNum = std::stoi(errString.substr(lineNumStart + 1, lineNumEnd - lineNumStart - 1));
|
||||
|
@ -181,7 +203,8 @@ sol::protected_function_result ServerLuaParser::runFileSandboxed(const std::stri
|
|||
env["_FILE"] = f.path;
|
||||
env["_MODNAME"] = mod.config.name;
|
||||
|
||||
return lua.safe_script(f.file, env, std::bind(&ServerLuaParser::errorCallback, this, std::placeholders::_2), "@" + f.path, sol::load_mode::text);
|
||||
return lua.safe_script(f.file, env, std::bind(&ServerLuaParser::errorCallback, this,
|
||||
std::placeholders::_2), "@" + f.path, sol::load_mode::text);
|
||||
}
|
||||
throw std::runtime_error("Error opening \"" + file + "\", file not found.");
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
#include "ServerModHandler.h"
|
||||
|
||||
class ServerSubgame;
|
||||
class ServerWorld;
|
||||
class ServerPlayer;
|
||||
class ServerSubgame;
|
||||
|
||||
class ServerLuaParser : public LuaParser {
|
||||
public:
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
//
|
||||
// Created by aurailus on 2020-07-24.
|
||||
//
|
||||
|
||||
#include "Register.h"
|
||||
|
||||
#include "../Lua.h"
|
||||
|
||||
void Api::Module::Register::bind() {
|
||||
|
||||
// Basic
|
||||
|
||||
createRegisterFn("mesh");
|
||||
createRegisterFn("item");
|
||||
createRegisterFn("block");
|
||||
createRegisterFn("biome");
|
||||
createRegisterFn("blockmodel");
|
||||
|
||||
// Keybinds
|
||||
|
||||
core["keys"] = lua.create_table();
|
||||
core["keycodes"] = lua.create_table();
|
||||
|
||||
for (unsigned short i = 0; i < 350; i++) {
|
||||
auto key = Util::getKeyStr(i);
|
||||
if (!key.empty()) {
|
||||
core["keys"][key] = i;
|
||||
core["keycodes"][i] = key;
|
||||
}
|
||||
}
|
||||
|
||||
createRegisterFn("keybind");
|
||||
|
||||
// Entities
|
||||
|
||||
core["registered_entities"] = lua.create_table();
|
||||
core.set_function("register_entity", [=](sol::this_environment env, std::string identifier, sol::table data) {
|
||||
data["__index"] = data;
|
||||
registerFn("registered_entities", static_cast<sol::environment>(env), identifier, data);
|
||||
});
|
||||
}
|
||||
|
||||
void Api::Module::Register::createRegisterFn(const std::string& name, const std::string& table) {
|
||||
std::string tableName = "registered_" + (table.empty() ? name + "s" : table);
|
||||
|
||||
core[tableName] = lua.create_table();
|
||||
|
||||
core.set_function("register_" + name, [=](sol::this_environment env, std::string identifier, sol::table data)
|
||||
{ registerFn(tableName, static_cast<sol::environment>(env), identifier, data); });
|
||||
}
|
||||
|
||||
void Api::Module::Register::registerFn(const std::string& table, sol::environment env, const std::string& identifier, const sol::table& data) {
|
||||
auto modName = env.get<std::string>("_MODNAME");
|
||||
|
||||
if (identifier[0] != ':' && strncmp(identifier.data(), modName.data(), modName.length()))
|
||||
throw std::runtime_error(identifier + " does not match calling mod name.");
|
||||
|
||||
std::string iden = (identifier[0] == ':' ? modName + identifier : identifier);
|
||||
unsigned int splitters = std::count_if(iden.begin(), iden.end(), [](char c) { return c == ':'; });
|
||||
|
||||
if (splitters > 2) throw std::runtime_error("Too many splitters in identifier " + iden + ".");
|
||||
|
||||
core[table][iden] = data;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
//
|
||||
// Created by aurailus on 2020-07-24.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "SubgameModule.h"
|
||||
|
||||
namespace Api::Module {
|
||||
class Register : public Api::Module::SubgameModule {
|
||||
public:
|
||||
using SubgameModule::SubgameModule;
|
||||
void bind() override;
|
||||
|
||||
protected:
|
||||
void createRegisterFn(const std::string& name, const std::string& table = "");
|
||||
void registerFn(const std::string& table, sol::environment env, const std::string& identifier, const sol::table& data);
|
||||
};
|
||||
}
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
namespace MenuApi {
|
||||
void start_game(Client& client, sol::table& core) {
|
||||
//TODO: Don't hardcode the subgame
|
||||
|
||||
core.set_function("game_connect", [&](std::string address) {
|
||||
client.scene.setScene(std::make_unique<ConnectScene>(client, Address::fromString(address)));
|
||||
});
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
#include "CreateRegister.h"
|
||||
|
||||
#include "lua/Lua.h"
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Handles a register request from Lua. Accepts an identifier and a data table,
|
||||
* adds it to the registered table, and calls the after function, if it exists.
|
||||
*
|
||||
* @param core - The core table, i.e. `_G['zepha']`.
|
||||
* @param table - The register table, e.g `_G['registered_blocks']`.
|
||||
* @param env - The sol::environment that the function is being called from.
|
||||
* @param after - The function to execute after the element is added to the register table.
|
||||
* @param identifier - The identifier of the element to add.
|
||||
* @param data - The data table of the element to add.
|
||||
*/
|
||||
|
||||
void registerFn(sol::table& core, const std::string& table, sol::environment env,
|
||||
std::function<void(std::string)> after, const std::string& identifier, const sol::table& data) {
|
||||
|
||||
auto modName = env.get<std::string>("_MODNAME");
|
||||
|
||||
if (identifier[0] != ':' && strncmp(identifier.data(), modName.data(), modName.length()))
|
||||
throw std::runtime_error(identifier + " does not match calling mod name.");
|
||||
|
||||
std::string iden = (identifier[0] == ':' ? modName + identifier : identifier);
|
||||
unsigned int splitters = std::count_if(iden.begin(), iden.end(), [](char c) { return c == ':'; });
|
||||
|
||||
if (splitters > 2) throw std::runtime_error("Too many splitters in identifier " + iden + ".");
|
||||
|
||||
core[table][iden] = data;
|
||||
|
||||
if (after) after(iden);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new register_* function in the core namespace and an associated registered_* table.
|
||||
* The passed in function will be called after a new element has been inserted into the table using the
|
||||
* generated function.
|
||||
*
|
||||
* @param lua - The Sol Lua State.
|
||||
* @param core - The core table, i.e. `_G['zepha']`.
|
||||
* @param name - The name of the element being registered. The name of the generated function will be 'register_[name]'.
|
||||
* @param after - The function to run every time an element is registered.
|
||||
* @param table - Optional, overrides the default table name and changes it to 'register_[table]'.
|
||||
*/
|
||||
|
||||
void Api::Util::createRegister(sol::state& lua, sol::table& core,
|
||||
const std::string& name, std::function<void(std::string)> after, const std::string& table) {
|
||||
|
||||
std::string tableName = "registered_" + (table.empty() ? name + "s" : table);
|
||||
|
||||
core[tableName] = lua.create_table();
|
||||
|
||||
core.set_function("register_" + name, [=, &core](sol::this_environment env, std::string identifier, sol::table data)
|
||||
{ registerFn(core, tableName, static_cast<sol::environment>(env), after, identifier, data); });
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* A Utility Function that creates register functions for Lua.
|
||||
*
|
||||
* - Auri, 03/11/20
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <sol/forward.hpp>
|
||||
|
||||
namespace Api::Util {
|
||||
void createRegister(sol::state& lua, sol::table& core, const std::string& name,
|
||||
std::function<void(std::string)> after = nullptr, const std::string& table = "");
|
||||
}
|
|
@ -0,0 +1,366 @@
|
|||
//
|
||||
// Created by aurailus on 2020-01-10.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lua/Lua.h"
|
||||
#include "lua/Callback.h"
|
||||
#include "game/def/ItemDef.h"
|
||||
#include "game/LocalSubgame.h"
|
||||
#include "game/def/BiomeDef.h"
|
||||
#include "game/def/BlockDef.h"
|
||||
#include "game/ServerSubgame.h"
|
||||
#include "game/def/CraftItemDef.h"
|
||||
#include "game/def/mesh/BlockModel.h"
|
||||
#include "game/def/mesh/SelectionBox.h"
|
||||
#include "game/atlas/LocalDefinitionAtlas.h"
|
||||
#include "game/atlas/ServerDefinitionAtlas.h"
|
||||
|
||||
namespace RegisterBlock {
|
||||
|
||||
static std::vector<SelectionBox> parseBoxes(sol::table boxesTable) {
|
||||
std::vector<SelectionBox> boxes{};
|
||||
|
||||
for (auto pair : boxesTable) {
|
||||
if (!pair.second.is<sol::table>()) throw std::runtime_error("must be a table");
|
||||
sol::table table = pair.second;
|
||||
|
||||
if (table.size() != 6) throw std::runtime_error("must contain exactly 6 elements");
|
||||
boxes.emplace_back(glm::vec3{table[1], table[2], table[3]}, glm::vec3{table[4], table[5], table[6]});
|
||||
}
|
||||
|
||||
return boxes;
|
||||
}
|
||||
|
||||
static inline void getMeshPartTexture(std::string &texture, unsigned int &blendInd, std::string &blendMask) {
|
||||
if (strncmp(texture.data(), "tint(", 5) == 0 && texture.find_last_of(')') != std::string::npos) {
|
||||
// Biome tinting time
|
||||
texture.erase(std::remove(texture.begin(), texture.end(), ' '), texture.end());
|
||||
|
||||
std::string::size_type paramsBegin = texture.find_first_of('(');
|
||||
std::string::size_type paramsEnd = texture.find_last_of(')');
|
||||
|
||||
std::string paramsString = texture.substr(paramsBegin + 1, paramsEnd - paramsBegin - 1);
|
||||
|
||||
std::vector<std::string> params;
|
||||
std::string::size_type pos = 0;
|
||||
while ((pos = paramsString.find(',')) != std::string::npos) {
|
||||
params.push_back(paramsString.substr(0, pos));
|
||||
paramsString.erase(0, pos + 1);
|
||||
}
|
||||
params.push_back(paramsString);
|
||||
|
||||
if (params.size() < 2) throw std::runtime_error("Invalid biome tint values. Must have at least 2 params.");
|
||||
|
||||
texture = params[1];
|
||||
blendInd = atoi(params[0].data()) + 1; //TODO: support multiple blend colors
|
||||
blendMask = (params.size() >= 3 ? params[2] : "");
|
||||
}
|
||||
}
|
||||
|
||||
static std::pair<BlockModel, BlockModel>
|
||||
createBlockModel(sol::table blockTable, sol::table blockModels, TextureAtlas *atlas) {
|
||||
// Get the specified block model
|
||||
auto modelStr = blockTable.get_or<std::string>("model", "default:cube");
|
||||
auto modelOpt = blockModels.get<sol::optional<sol::table>>(modelStr);
|
||||
if (!modelOpt) throw std::runtime_error("Non-existent model \"" + modelStr + "\" specified");
|
||||
|
||||
sol::table modelTable = *modelOpt;
|
||||
BlockModel model;
|
||||
|
||||
// Apply basic properties
|
||||
model.culls = blockTable.get_or("culls", true);
|
||||
model.visible = blockTable.get_or("visible", true);
|
||||
|
||||
// Convert textures and low-def textures into vectors
|
||||
auto texturesOpt = blockTable.get<sol::optional<sol::table >>("textures");
|
||||
auto ldTexturesOpt = blockTable.get<sol::optional<sol::table >>("lowdef_textures");
|
||||
|
||||
if (!texturesOpt) throw std::runtime_error("Missing textures property");
|
||||
|
||||
std::vector<std::string> textures;
|
||||
for (auto pair : *texturesOpt) {
|
||||
if (!pair.second.is<std::string>()) throw std::runtime_error("textures table contains non-string value");
|
||||
textures.push_back(pair.second.as<std::string>());
|
||||
}
|
||||
if (textures.size() == 0) textures.push_back("_missing");
|
||||
|
||||
std::vector<std::string> lowdef_textures;
|
||||
if (!ldTexturesOpt) lowdef_textures = textures;
|
||||
else {
|
||||
for (auto pair : *ldTexturesOpt) {
|
||||
if (!pair.second.is<std::string>()) throw std::runtime_error("lowdef_textures table has non-string value!");
|
||||
lowdef_textures.push_back(pair.second.as<std::string>());
|
||||
}
|
||||
}
|
||||
if (lowdef_textures.size() == 0) lowdef_textures.push_back("_missing");
|
||||
|
||||
// Parse through mesh mods and add them
|
||||
sol::optional<sol::table> meshModTable = modelTable.get<sol::optional<sol::table>>("mesh_mods");
|
||||
if (meshModTable) {
|
||||
for (auto &modEntry : *meshModTable) {
|
||||
auto modTable = modEntry.second.as<sol::table>();
|
||||
std::string meshMod = modTable.get_or<std::string>("type", "none");
|
||||
|
||||
if (meshMod == "none") continue;
|
||||
else if (meshMod == "offset_x")
|
||||
model.meshMods.emplace_back(MeshMod::OFFSET_X, modTable.get_or<float>("amplitude", 1));
|
||||
else if (meshMod == "offset_y")
|
||||
model.meshMods.emplace_back(MeshMod::OFFSET_Y, modTable.get_or<float>("amplitude", 1));
|
||||
else if (meshMod == "offset_z")
|
||||
model.meshMods.emplace_back(MeshMod::OFFSET_Z, modTable.get_or<float>("amplitude", 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Parse through all of the parts and add them to the model
|
||||
auto partsOpt = modelTable.get<sol::optional<sol::table>>("parts");
|
||||
if (!partsOpt) throw std::runtime_error("blockmodel is missing parts table");
|
||||
partsOpt->for_each([&](sol::object key, sol::object value) {
|
||||
|
||||
// Validate that variables are what we expect them to be
|
||||
if (!value.is<sol::table>()) throw std::runtime_error("meshpart must be a table");
|
||||
sol::table meshPartTable = value.as<sol::table>();
|
||||
|
||||
auto points_optional = meshPartTable.get<sol::optional<sol::table>>("points");
|
||||
if (!points_optional) throw std::runtime_error("Meshpart is missing a points table");
|
||||
sol::table points = *points_optional;
|
||||
|
||||
if (points.size() % 20 != 0) throw std::runtime_error("Points table must contain a multiple of 20 values");
|
||||
|
||||
// Populate the Vertices and Indices vectors from the points table
|
||||
std::vector<BlockModelVertex> vertices;
|
||||
std::vector<unsigned int> indices;
|
||||
|
||||
for (int i = 1; i <= points.size() / 5; i++) {
|
||||
int offset = (i - 1) * 5 + 1;
|
||||
|
||||
glm::vec3 pos(points[offset], points[offset + 1], points[offset + 2]);
|
||||
glm::vec2 tex(points[offset + 3], points[offset + 4]);
|
||||
|
||||
vertices.push_back(BlockModelVertex{pos, {}, tex, tex, {}, {}});
|
||||
}
|
||||
|
||||
int ind = 0;
|
||||
for (int i = 1; i <= points.size() / 20; i++) {
|
||||
indices.push_back(ind);
|
||||
indices.push_back(ind + 1);
|
||||
indices.push_back(ind + 2);
|
||||
indices.push_back(ind + 2);
|
||||
indices.push_back(ind + 3);
|
||||
indices.push_back(ind);
|
||||
ind += 4;
|
||||
}
|
||||
|
||||
// Get the part's texture
|
||||
int tex = std::max(static_cast<int>(meshPartTable.get_or<float>("tex", 1)), 1);
|
||||
|
||||
auto texture = textures[std::min(tex - 1, (int) textures.size() - 1)];
|
||||
unsigned int blendInd = 0;
|
||||
std::string blendMask = "";
|
||||
getMeshPartTexture(texture, blendInd, blendMask);
|
||||
|
||||
// Add texture refs to blockModel if the textures table is provided
|
||||
std::shared_ptr<AtlasRef> textureRef = nullptr, blendMaskRef = nullptr;
|
||||
if (atlas) {
|
||||
textureRef = (*atlas)[texture];
|
||||
model.textureRefs.insert(textureRef);
|
||||
|
||||
if (blendInd && !blendMask.empty()) {
|
||||
blendMaskRef = (*atlas)[blendMask];
|
||||
model.textureRefs.insert(blendMaskRef);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the meshpart object
|
||||
MeshPart meshPart(std::move(vertices), std::move(indices), textureRef, blendInd, blendMaskRef);
|
||||
|
||||
// Add the shader mod, if it exists
|
||||
sol::optional<sol::table> shaderModTable = meshPartTable.get<sol::optional<sol::table>>("shader_mod");
|
||||
if (shaderModTable) {
|
||||
std::string shaderMod = shaderModTable->get_or<std::string>("type", "none");
|
||||
|
||||
if (shaderMod == "none") meshPart.shaderMod = ShaderMod::NONE;
|
||||
else if (shaderMod == "rotate_x") {
|
||||
meshPart.shaderMod = ShaderMod::ROTATE_X;
|
||||
meshPart.modValue = (*shaderModTable).get_or<float>("speed", 1);
|
||||
}
|
||||
else if (shaderMod == "rotate_y") {
|
||||
meshPart.shaderMod = ShaderMod::ROTATE_Y;
|
||||
meshPart.modValue = (*shaderModTable).get_or<float>("speed", 1);
|
||||
}
|
||||
else if (shaderMod == "rotate_z") {
|
||||
meshPart.shaderMod = ShaderMod::ROTATE_Z;
|
||||
meshPart.modValue = (*shaderModTable).get_or<float>("speed", 1);
|
||||
}
|
||||
else if (shaderMod == "sway_attached") {
|
||||
meshPart.shaderMod = ShaderMod::SWAY_ATTACHED;
|
||||
meshPart.modValue = (*shaderModTable).get_or<float>("amplitude", 1);
|
||||
}
|
||||
else if (shaderMod == "sway_full_block") {
|
||||
meshPart.shaderMod = ShaderMod::SWAY_FULL_BLOCK;
|
||||
meshPart.modValue = (*shaderModTable).get_or<float>("amplitude", 1);
|
||||
}
|
||||
}
|
||||
|
||||
//Add the meshpart to the proper face of the model
|
||||
std::string face = meshPartTable.get_or<std::string>("face", "nocull");
|
||||
|
||||
EVec d =
|
||||
face == "top" ? EVec::TOP :
|
||||
face == "bottom" ? EVec::BOTTOM :
|
||||
face == "left" ? EVec::LEFT :
|
||||
face == "right" ? EVec::RIGHT :
|
||||
face == "front" ? EVec::FRONT :
|
||||
face == "back" ? EVec::BACK :
|
||||
face == "nocull" ? EVec::NO_CULL :
|
||||
EVec::INVALID;
|
||||
|
||||
if (d == EVec::INVALID) throw std::runtime_error("face value is unrecognized");
|
||||
model.parts[static_cast<int>(d)].push_back(meshPart);
|
||||
});
|
||||
|
||||
// Create the far model
|
||||
BlockModel farModel;
|
||||
auto ldRender = blockTable.get_or("lowdef_render", true);
|
||||
|
||||
if (atlas) {
|
||||
std::vector<std::shared_ptr<AtlasRef>> textureRefs;
|
||||
std::vector<unsigned int> blendInds;
|
||||
std::vector<std::shared_ptr<AtlasRef>> blendMaskRefs;
|
||||
|
||||
for (auto i = 0; i < lowdef_textures.size(); i++) {
|
||||
std::string texture = lowdef_textures[i];
|
||||
unsigned int blendInd = 0;
|
||||
std::string blendMask = "";
|
||||
getMeshPartTexture(texture, blendInd, blendMask);
|
||||
|
||||
textureRefs.push_back((*atlas)[texture]);
|
||||
blendInds.push_back(blendInd);
|
||||
blendMaskRefs.push_back(blendMask != "" ? (*atlas)[blendMask] : nullptr);
|
||||
}
|
||||
|
||||
farModel = BlockModel::createCube(textureRefs, blendInds, blendMaskRefs);
|
||||
}
|
||||
else {
|
||||
farModel = BlockModel::createCube({}, {}, {});
|
||||
}
|
||||
|
||||
farModel.culls = ldRender;
|
||||
farModel.visible = ldRender;
|
||||
|
||||
return {model, farModel};
|
||||
}
|
||||
|
||||
static void addCallback(BlockDef *blockDef, sol::table &blockTable, const std::string &name, Callback enumType) {
|
||||
auto cb = blockTable.get<sol::optional<sol::protected_function>>(name);
|
||||
if (cb) blockDef->callbacks.insert({enumType, *cb});
|
||||
}
|
||||
|
||||
static void registerBlock(sol::table blocks, sol::table blockModels,
|
||||
const std::string &identifier, DefinitionAtlas &defs, TextureAtlas *atlas) {
|
||||
|
||||
sol::table blockTable = blocks[identifier];
|
||||
|
||||
// Basic Block Properties
|
||||
auto nameOpt = blockTable.get<sol::optional<std::string>>("name");
|
||||
if (!nameOpt) throw std::runtime_error(identifier + " is missing name property!");
|
||||
|
||||
bool culls = blockTable.get_or("culls", true);
|
||||
bool solid = blockTable.get_or("solid", true);
|
||||
bool lightPropagates = blockTable.get_or("light_propagates", false);
|
||||
auto maxStack = blockTable.get_or("stack", 64);
|
||||
|
||||
unsigned int health = INT32_MAX, defense = 0;
|
||||
auto toolOpt = blockTable.get<sol::optional<sol::table>>("tool_props");
|
||||
if (toolOpt) {
|
||||
health = toolOpt->get_or<unsigned int>("health", INT32_MAX);
|
||||
defense = toolOpt->get_or<unsigned int>("defense", 0);
|
||||
}
|
||||
|
||||
glm::vec3 lightSource{};
|
||||
if (blockTable.get<sol::optional<sol::table>>("light_source")) {
|
||||
auto light = blockTable.get<sol::table>("light_source");
|
||||
lightSource = {light[1], light[2], light[3]};
|
||||
} else if (blockTable.get_or<float>("light_source", -1) != -1) {
|
||||
auto light = blockTable.get<float>("light_source");
|
||||
lightSource = {light, light, light};
|
||||
}
|
||||
|
||||
// Parse through selection boxes and collision boxes
|
||||
auto selectionOpt = blockTable.get<sol::optional<sol::table>>("selection_box");
|
||||
auto collisionOpt = blockTable.get<sol::optional<sol::table>>("collision_box");
|
||||
|
||||
std::vector<SelectionBox> selectionBoxes{};
|
||||
try { if (selectionOpt) selectionBoxes = parseBoxes(*selectionOpt); }
|
||||
catch (const char *error) { throw std::string("selection boxes " + std::string(error)).c_str(); }
|
||||
if (selectionBoxes.size() == 0) selectionBoxes.emplace_back(glm::vec3{0, 0, 0}, glm::vec3{1, 1, 1});
|
||||
|
||||
std::vector<SelectionBox> collisionBoxes{};
|
||||
try { if (collisionOpt) collisionBoxes = parseBoxes(*collisionOpt); }
|
||||
catch (const char *error) { throw std::string("collision boxes " + std::string(error)).c_str(); }
|
||||
if (collisionBoxes.size() == 0) collisionBoxes.emplace_back(glm::vec3{0, 0, 0}, glm::vec3{1, 1, 1});
|
||||
|
||||
// Create the block model
|
||||
std::pair<BlockModel, BlockModel> models = createBlockModel(blockTable, blockModels, atlas);
|
||||
|
||||
BlockDef *def = new BlockDef();
|
||||
def->identifier = identifier;
|
||||
def->name = *nameOpt;
|
||||
def->index = defs.size();
|
||||
|
||||
def->culls = culls;
|
||||
def->solid = solid;
|
||||
def->lightSource = lightSource;
|
||||
def->lightPropagates = lightPropagates;
|
||||
|
||||
def->health = health;
|
||||
def->defense = defense;
|
||||
|
||||
def->maxStackSize = maxStack;
|
||||
|
||||
def->model = models.first;
|
||||
def->farModel = models.second;
|
||||
|
||||
def->sBoxes = std::move(selectionBoxes);
|
||||
def->cBoxes = std::move(collisionBoxes);
|
||||
|
||||
// Create entity model
|
||||
if (atlas) def->createModel();
|
||||
|
||||
// Bind Callbacks
|
||||
addCallback(def, blockTable, "on_construct", Callback::CONSTRUCT);
|
||||
addCallback(def, blockTable, "after_construct", Callback::AFTER_CONSTRUCT);
|
||||
|
||||
addCallback(def, blockTable, "on_destruct", Callback::DESTRUCT);
|
||||
addCallback(def, blockTable, "after_destruct", Callback::AFTER_DESTRUCT);
|
||||
|
||||
addCallback(def, blockTable, "on_place", Callback::PLACE);
|
||||
addCallback(def, blockTable, "on_place_client", Callback::PLACE_CLIENT);
|
||||
|
||||
addCallback(def, blockTable, "after_place", Callback::AFTER_PLACE);
|
||||
addCallback(def, blockTable, "after_place_client", Callback::AFTER_PLACE_CLIENT);
|
||||
|
||||
addCallback(def, blockTable, "on_break", Callback::BREAK);
|
||||
addCallback(def, blockTable, "on_break_client", Callback::BREAK_CLIENT);
|
||||
|
||||
addCallback(def, blockTable, "after_break", Callback::AFTER_BREAK);
|
||||
addCallback(def, blockTable, "after_break_client", Callback::AFTER_BREAK_CLIENT);
|
||||
|
||||
addCallback(def, blockTable, "on_interact", Callback::INTERACT);
|
||||
addCallback(def, blockTable, "on_interact_client", Callback::INTERACT_CLIENT);
|
||||
|
||||
// Add Block Definition to the Atlas
|
||||
defs.registerDef(def);
|
||||
}
|
||||
|
||||
static void server(sol::table &core, ServerSubgame &game, const std::string &identifier) {
|
||||
registerBlock(core["registered_blocks"], core["registered_blockmodels"],
|
||||
identifier, game.getDefs(), nullptr);
|
||||
}
|
||||
|
||||
static void client(sol::table &core, LocalSubgame &game, const std::string &identifier) {
|
||||
registerBlock(core["registered_blocks"], core["registered_blockmodels"],
|
||||
identifier, game.getDefs(), &game.textures);
|
||||
}
|
||||
};
|
|
@ -1,373 +0,0 @@
|
|||
//
|
||||
// Created by aurailus on 2020-01-10.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lua/Lua.h"
|
||||
#include "lua/Callback.h"
|
||||
#include "game/def/ItemDef.h"
|
||||
#include "game/LocalSubgame.h"
|
||||
#include "game/def/BiomeDef.h"
|
||||
#include "game/def/BlockDef.h"
|
||||
#include "game/ServerSubgame.h"
|
||||
#include "game/def/CraftItemDef.h"
|
||||
#include "game/def/mesh/BlockModel.h"
|
||||
#include "game/def/mesh/SelectionBox.h"
|
||||
#include "game/atlas/LocalDefinitionAtlas.h"
|
||||
#include "game/atlas/ServerDefinitionAtlas.h"
|
||||
|
||||
namespace RegisterBlocks {
|
||||
|
||||
static std::vector<SelectionBox> parseBoxes(sol::table boxesTable) {
|
||||
std::vector<SelectionBox> boxes {};
|
||||
|
||||
for (auto pair : boxesTable) {
|
||||
if (!pair.second.is<sol::table>()) throw std::runtime_error("must be a table");
|
||||
sol::table table = pair.second;
|
||||
|
||||
if (table.size() != 6) throw std::runtime_error("must contain exactly 6 elements");
|
||||
boxes.emplace_back(glm::vec3 {table[1], table[2], table[3]}, glm::vec3 {table[4], table[5], table[6]});
|
||||
}
|
||||
|
||||
return boxes;
|
||||
}
|
||||
|
||||
static inline void getMeshPartTexture(std::string& texture, unsigned int& blendInd, std::string& blendMask) {
|
||||
if (strncmp(texture.data(), "tint(", 5) == 0 && texture.find_last_of(')') != std::string::npos) {
|
||||
// Biome tinting time
|
||||
texture.erase(std::remove(texture.begin(), texture.end(), ' '), texture.end());
|
||||
|
||||
std::string::size_type paramsBegin = texture.find_first_of('(');
|
||||
std::string::size_type paramsEnd = texture.find_last_of(')');
|
||||
|
||||
std::string paramsString = texture.substr(paramsBegin + 1, paramsEnd - paramsBegin - 1);
|
||||
|
||||
std::vector<std::string> params;
|
||||
std::string::size_type pos = 0;
|
||||
while ((pos = paramsString.find(',')) != std::string::npos) {
|
||||
params.push_back(paramsString.substr(0, pos));
|
||||
paramsString.erase(0, pos + 1);
|
||||
}
|
||||
params.push_back(paramsString);
|
||||
|
||||
if (params.size() < 2) throw std::runtime_error("Invalid biome tint values. Must have at least 2 params.");
|
||||
|
||||
texture = params[1];
|
||||
blendInd = atoi(params[0].data()) + 1; //TODO: support multiple blend colors
|
||||
blendMask = (params.size() >= 3 ? params[2] : "");
|
||||
}
|
||||
}
|
||||
|
||||
static std::pair<BlockModel, BlockModel> createBlockModel(sol::table blockTable, sol::table blockModels, TextureAtlas* atlas) {
|
||||
// Get the specified block model
|
||||
auto modelStr = blockTable.get_or<std::string>("model", "default:cube");
|
||||
auto modelOpt = blockModels.get<sol::optional<sol::table>>(modelStr);
|
||||
if (!modelOpt) throw std::runtime_error("Non-existent model \"" + modelStr + "\" specified");
|
||||
|
||||
sol::table modelTable = *modelOpt;
|
||||
BlockModel model;
|
||||
|
||||
// Apply basic properties
|
||||
model.culls = blockTable.get_or("culls", true);
|
||||
model.visible = blockTable.get_or("visible", true);
|
||||
|
||||
// Convert textures and low-def textures into vectors
|
||||
auto texturesOpt = blockTable.get<sol::optional<sol::table >>("textures");
|
||||
auto ldTexturesOpt = blockTable.get<sol::optional<sol::table >>("lowdef_textures");
|
||||
|
||||
if (!texturesOpt) throw std::runtime_error("Missing textures property");
|
||||
|
||||
std::vector<std::string> textures;
|
||||
for (auto pair : *texturesOpt) {
|
||||
if (!pair.second.is<std::string>()) throw std::runtime_error("textures table contains non-string value");
|
||||
textures.push_back(pair.second.as<std::string>());
|
||||
}
|
||||
if (textures.size() == 0) textures.push_back("_missing");
|
||||
|
||||
std::vector<std::string> lowdef_textures;
|
||||
if (!ldTexturesOpt) lowdef_textures = textures;
|
||||
else {
|
||||
for (auto pair : *ldTexturesOpt) {
|
||||
if (!pair.second.is<std::string>()) throw std::runtime_error("lowdef_textures table has non-string value!");
|
||||
lowdef_textures.push_back(pair.second.as<std::string>());
|
||||
}
|
||||
}
|
||||
if (lowdef_textures.size() == 0) lowdef_textures.push_back("_missing");
|
||||
|
||||
// Parse through mesh mods and add them
|
||||
sol::optional<sol::table> meshModTable = modelTable.get<sol::optional<sol::table>> ("mesh_mods");
|
||||
if (meshModTable) {
|
||||
for (auto& modEntry : *meshModTable) {
|
||||
auto modTable = modEntry.second.as<sol::table>();
|
||||
std::string meshMod = modTable.get_or<std::string>("type", "none");
|
||||
|
||||
if (meshMod == "none") continue;
|
||||
else if (meshMod == "offset_x")
|
||||
model.meshMods.emplace_back(MeshMod::OFFSET_X, modTable.get_or<float>("amplitude", 1));
|
||||
else if (meshMod == "offset_y")
|
||||
model.meshMods.emplace_back(MeshMod::OFFSET_Y, modTable.get_or<float>("amplitude", 1));
|
||||
else if (meshMod == "offset_z")
|
||||
model.meshMods.emplace_back(MeshMod::OFFSET_Z, modTable.get_or<float>("amplitude", 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Parse through all of the parts and add them to the model
|
||||
auto partsOpt = modelTable.get<sol::optional<sol::table>>("parts");
|
||||
if (!partsOpt) throw std::runtime_error("blockmodel is missing parts table");
|
||||
partsOpt->for_each([&](sol::object key, sol::object value) {
|
||||
|
||||
// Validate that variables are what we expect them to be
|
||||
if (!value.is<sol::table>()) throw std::runtime_error("meshpart must be a table");
|
||||
sol::table meshPartTable = value.as<sol::table>();
|
||||
|
||||
auto points_optional = meshPartTable.get<sol::optional<sol::table>>("points");
|
||||
if (!points_optional) throw std::runtime_error("Meshpart is missing a points table");
|
||||
sol::table points = *points_optional;
|
||||
|
||||
if (points.size() % 20 != 0) throw std::runtime_error("Points table must contain a multiple of 20 values");
|
||||
|
||||
// Populate the Vertices and Indices vectors from the points table
|
||||
std::vector<BlockModelVertex> vertices;
|
||||
std::vector<unsigned int> indices;
|
||||
|
||||
for (int i = 1; i <= points.size() / 5; i++) {
|
||||
int offset = (i - 1) * 5 + 1;
|
||||
|
||||
glm::vec3 pos(points[offset], points[offset + 1], points[offset + 2]);
|
||||
glm::vec2 tex(points[offset + 3], points[offset + 4]);
|
||||
|
||||
vertices.push_back(BlockModelVertex {pos, {}, tex, tex, {}, {}});
|
||||
}
|
||||
|
||||
int ind = 0;
|
||||
for (int i = 1; i <= points.size() / 20; i++) {
|
||||
indices.push_back(ind);
|
||||
indices.push_back(ind + 1);
|
||||
indices.push_back(ind + 2);
|
||||
indices.push_back(ind + 2);
|
||||
indices.push_back(ind + 3);
|
||||
indices.push_back(ind);
|
||||
ind += 4;
|
||||
}
|
||||
|
||||
// Get the part's texture
|
||||
int tex = std::max(static_cast<int>(meshPartTable.get_or<float>("tex", 1)), 1);
|
||||
|
||||
auto texture = textures[std::min(tex - 1, (int) textures.size() - 1)];
|
||||
unsigned int blendInd = 0;
|
||||
std::string blendMask = "";
|
||||
getMeshPartTexture(texture, blendInd, blendMask);
|
||||
|
||||
// Add texture refs to blockModel if the textures table is provided
|
||||
std::shared_ptr<AtlasRef> textureRef = nullptr, blendMaskRef = nullptr;
|
||||
if (atlas) {
|
||||
textureRef = (*atlas)[texture];
|
||||
model.textureRefs.insert(textureRef);
|
||||
|
||||
if (blendInd && !blendMask.empty()) {
|
||||
blendMaskRef = (*atlas)[blendMask];
|
||||
model.textureRefs.insert(blendMaskRef);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the meshpart object
|
||||
MeshPart meshPart(std::move(vertices), std::move(indices), textureRef, blendInd, blendMaskRef);
|
||||
|
||||
// Add the shader mod, if it exists
|
||||
sol::optional<sol::table> shaderModTable = meshPartTable.get<sol::optional<sol::table>>("shader_mod");
|
||||
if (shaderModTable) {
|
||||
std::string shaderMod = shaderModTable->get_or<std::string>("type", "none");
|
||||
|
||||
if (shaderMod == "none") meshPart.shaderMod = ShaderMod::NONE;
|
||||
else if (shaderMod == "rotate_x") {
|
||||
meshPart.shaderMod = ShaderMod::ROTATE_X;
|
||||
meshPart.modValue = (*shaderModTable).get_or<float>("speed", 1);
|
||||
}
|
||||
else if (shaderMod == "rotate_y") {
|
||||
meshPart.shaderMod = ShaderMod::ROTATE_Y;
|
||||
meshPart.modValue = (*shaderModTable).get_or<float>("speed", 1);
|
||||
}
|
||||
else if (shaderMod == "rotate_z") {
|
||||
meshPart.shaderMod = ShaderMod::ROTATE_Z;
|
||||
meshPart.modValue = (*shaderModTable).get_or<float>("speed", 1);
|
||||
}
|
||||
else if (shaderMod == "sway_attached") {
|
||||
meshPart.shaderMod = ShaderMod::SWAY_ATTACHED;
|
||||
meshPart.modValue = (*shaderModTable).get_or<float>("amplitude", 1);
|
||||
}
|
||||
else if (shaderMod == "sway_full_block") {
|
||||
meshPart.shaderMod = ShaderMod::SWAY_FULL_BLOCK;
|
||||
meshPart.modValue = (*shaderModTable).get_or<float>("amplitude", 1);
|
||||
}
|
||||
}
|
||||
|
||||
//Add the meshpart to the proper face of the model
|
||||
std::string face = meshPartTable.get_or<std::string>("face", "nocull");
|
||||
|
||||
EVec d =
|
||||
face == "top" ? EVec::TOP :
|
||||
face == "bottom" ? EVec::BOTTOM :
|
||||
face == "left" ? EVec::LEFT :
|
||||
face == "right" ? EVec::RIGHT :
|
||||
face == "front" ? EVec::FRONT :
|
||||
face == "back" ? EVec::BACK :
|
||||
face == "nocull" ? EVec::NO_CULL :
|
||||
EVec::INVALID ;
|
||||
|
||||
if (d == EVec::INVALID) throw std::runtime_error("face value is unrecognized");
|
||||
model.parts[static_cast<int>(d)].push_back(meshPart);
|
||||
});
|
||||
|
||||
// Create the far model
|
||||
BlockModel farModel;
|
||||
auto ldRender = blockTable.get_or("lowdef_render", true);
|
||||
|
||||
if (atlas) {
|
||||
std::vector<std::shared_ptr<AtlasRef>> textureRefs;
|
||||
std::vector<unsigned int> blendInds;
|
||||
std::vector<std::shared_ptr<AtlasRef>> blendMaskRefs;
|
||||
|
||||
for (auto i = 0; i < lowdef_textures.size(); i++) {
|
||||
std::string texture = lowdef_textures[i];
|
||||
unsigned int blendInd = 0;
|
||||
std::string blendMask = "";
|
||||
getMeshPartTexture(texture, blendInd, blendMask);
|
||||
|
||||
textureRefs.push_back((*atlas)[texture]);
|
||||
blendInds.push_back(blendInd);
|
||||
blendMaskRefs.push_back(blendMask != "" ? (*atlas)[blendMask] : nullptr);
|
||||
}
|
||||
|
||||
farModel = BlockModel::createCube(textureRefs, blendInds, blendMaskRefs);
|
||||
}
|
||||
else {
|
||||
farModel = BlockModel::createCube({}, {}, {});
|
||||
}
|
||||
|
||||
farModel.culls = ldRender;
|
||||
farModel.visible = ldRender;
|
||||
|
||||
return {model, farModel};
|
||||
}
|
||||
|
||||
static void addCallback(BlockDef* blockDef, sol::table& blockTable, const std::string& name, Callback enumType) {
|
||||
auto cb = blockTable.get<sol::optional<sol::protected_function>>(name);
|
||||
if (cb) blockDef->callbacks.insert({enumType, *cb});
|
||||
}
|
||||
|
||||
static void registerBlocks(sol::table source, sol::table blockModels, DefinitionAtlas& defs, TextureAtlas* atlas) {
|
||||
// Parses through all of the zepha.registered_blocks and makes BlockDefs.
|
||||
for (auto blockRef : source) {
|
||||
|
||||
// Validate that the identifier and definition table exist
|
||||
std::string identifier = blockRef.first.as<std::string>();
|
||||
|
||||
if (!blockRef.second || !blockRef.second.is<sol::table>())
|
||||
throw std::runtime_error("register_block expects a table as the second parameter");
|
||||
sol::table blockTable = blockRef.second.as<sol::table>();
|
||||
|
||||
// Basic Block Properties
|
||||
auto nameOpt = blockTable.get<sol::optional<std::string>>("name");
|
||||
if (!nameOpt) throw std::runtime_error(identifier + " is missing name property!");
|
||||
|
||||
bool culls = blockTable.get_or("culls", true);
|
||||
bool solid = blockTable.get_or("solid", true);
|
||||
bool lightPropagates = blockTable.get_or("light_propagates", false);
|
||||
auto maxStack = blockTable.get_or("stack", 64);
|
||||
|
||||
unsigned int health = INT32_MAX, defense = 0;
|
||||
auto toolOpt = blockTable.get<sol::optional<sol::table>>("tool_props");
|
||||
if (toolOpt) {
|
||||
health = toolOpt->get_or<unsigned int>("health", INT32_MAX);
|
||||
defense = toolOpt->get_or<unsigned int>("defense", 0);
|
||||
}
|
||||
|
||||
glm::vec3 lightSource {};
|
||||
if (blockTable.get<sol::optional<sol::table>>("light_source")) {
|
||||
auto light = blockTable.get<sol::table>("light_source");
|
||||
lightSource = { light[1], light[2], light[3] };
|
||||
}
|
||||
else if (blockTable.get_or<float>("light_source", -1) != -1) {
|
||||
auto light = blockTable.get<float>("light_source");
|
||||
lightSource = { light, light, light };
|
||||
}
|
||||
|
||||
// Parse through selection boxes and collision boxes
|
||||
auto selectionOpt = blockTable.get<sol::optional<sol::table>>("selection_box");
|
||||
auto collisionOpt = blockTable.get<sol::optional<sol::table>>("collision_box");
|
||||
|
||||
std::vector<SelectionBox> selectionBoxes {};
|
||||
try { if (selectionOpt) selectionBoxes = parseBoxes(*selectionOpt); }
|
||||
catch (const char* error) { throw std::string("selection boxes " + std::string(error)).c_str(); }
|
||||
if (selectionBoxes.size() == 0) selectionBoxes.emplace_back(glm::vec3 {0, 0, 0}, glm::vec3 {1, 1, 1});
|
||||
|
||||
std::vector<SelectionBox> collisionBoxes {};
|
||||
try { if (collisionOpt) collisionBoxes = parseBoxes(*collisionOpt); }
|
||||
catch (const char* error) { throw std::string("collision boxes " + std::string(error)).c_str(); }
|
||||
if (collisionBoxes.size() == 0) collisionBoxes.emplace_back(glm::vec3 {0, 0, 0}, glm::vec3 {1, 1, 1});
|
||||
|
||||
// Create the block model
|
||||
std::pair<BlockModel, BlockModel> models = createBlockModel(blockTable, blockModels, atlas);
|
||||
|
||||
BlockDef* def = new BlockDef();
|
||||
def->identifier = identifier;
|
||||
def->name = *nameOpt;
|
||||
def->index = defs.size();
|
||||
|
||||
def->culls = culls;
|
||||
def->solid = solid;
|
||||
def->lightSource = lightSource;
|
||||
def->lightPropagates = lightPropagates;
|
||||
|
||||
def->health = health;
|
||||
def->defense = defense;
|
||||
|
||||
def->maxStackSize = maxStack;
|
||||
|
||||
def->model = models.first;
|
||||
def->farModel = models.second;
|
||||
|
||||
def->sBoxes = std::move(selectionBoxes);
|
||||
def->cBoxes = std::move(collisionBoxes);
|
||||
|
||||
// Create entity model
|
||||
if (atlas) def->createModel();
|
||||
|
||||
// Bind Callbacks
|
||||
addCallback(def, blockTable, "on_construct", Callback::CONSTRUCT);
|
||||
addCallback(def, blockTable, "after_construct", Callback::AFTER_CONSTRUCT);
|
||||
|
||||
addCallback(def, blockTable, "on_destruct", Callback::DESTRUCT);
|
||||
addCallback(def, blockTable, "after_destruct", Callback::AFTER_DESTRUCT);
|
||||
|
||||
addCallback(def, blockTable, "on_place", Callback::PLACE);
|
||||
addCallback(def, blockTable, "on_place_client", Callback::PLACE_CLIENT);
|
||||
|
||||
addCallback(def, blockTable, "after_place", Callback::AFTER_PLACE);
|
||||
addCallback(def, blockTable, "after_place_client", Callback::AFTER_PLACE_CLIENT);
|
||||
|
||||
addCallback(def, blockTable, "on_break", Callback::BREAK);
|
||||
addCallback(def, blockTable, "on_break_client", Callback::BREAK_CLIENT);
|
||||
|
||||
addCallback(def, blockTable, "after_break", Callback::AFTER_BREAK);
|
||||
addCallback(def, blockTable, "after_break_client", Callback::AFTER_BREAK_CLIENT);
|
||||
|
||||
addCallback(def, blockTable, "on_interact", Callback::INTERACT);
|
||||
addCallback(def, blockTable, "on_interact_client", Callback::INTERACT_CLIENT);
|
||||
|
||||
// Add Block Definition to the AtlasK
|
||||
defs.registerDef(def);
|
||||
}
|
||||
}
|
||||
|
||||
static void server(sol::table& core, ServerSubgame& game) {
|
||||
registerBlocks(core.get<sol::table>("registered_blocks"),
|
||||
core.get<sol::table>("registered_blockmodels"), game.getDefs(), nullptr);
|
||||
}
|
||||
|
||||
static void client(sol::table& core, LocalSubgame& game) {
|
||||
registerBlocks(core.get<sol::table>("registered_blocks"),
|
||||
core.get<sol::table>("registered_blockmodels"), game.getDefs(), &game.textures);
|
||||
}
|
||||
};
|
|
@ -55,6 +55,7 @@ sol::table Api::Usertype::Dimension::add_entity_c(sol::this_state s, glm::vec3 p
|
|||
|
||||
if (core["registered_entities"][identifier] == sol::nil) throw std::runtime_error(identifier + " is not a valid entity identifier.");
|
||||
sol::table def = core["registered_entities"][identifier];
|
||||
def["__index"] = def;
|
||||
|
||||
sol::table luaEntity = lua.create_table();
|
||||
luaEntity[sol::metatable_key] = def;
|
||||
|
@ -92,6 +93,7 @@ sol::table Api::Usertype::Dimension::add_entity_s(sol::this_state s, glm::vec3 p
|
|||
|
||||
if (core["registered_entities"][identifier] == sol::nil) throw std::runtime_error(identifier + " is not a valid entity identifier.");
|
||||
sol::table def = core["registered_entities"][identifier];
|
||||
def["__index"] = def;
|
||||
|
||||
sol::table luaEntity = lua.create_table();
|
||||
luaEntity[sol::metatable_key] = def;
|
||||
|
|
Loading…
Reference in New Issue