diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
index a55e7a17..79ee123c 100644
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7d518a1c..117e4c61 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -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 .)
\ No newline at end of file
diff --git a/src/lua/LocalLuaParser.cpp b/src/lua/LocalLuaParser.cpp
index 6afc35d3..71acbdd3 100644
--- a/src/lua/LocalLuaParser.cpp
+++ b/src/lua/LocalLuaParser.cpp
@@ -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::State::CLIENT, lua, core));
- modules.emplace_back(std::make_unique(Api::State::CLIENT, core, game, **world));
modules.emplace_back(std::make_unique(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(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(game);
- RegisterBlocks ::client(core, local);
+// RegisterBlocks ::client(core, local);
RegisterItems ::client(core, local);
RegisterBiomes ::client(core, local);
RegisterKeybinds::client(core, keybinds);
diff --git a/src/lua/ServerLuaParser.cpp b/src/lua/ServerLuaParser.cpp
index 72f28050..4b2b6b20 100644
--- a/src/lua/ServerLuaParser.cpp
+++ b/src/lua/ServerLuaParser.cpp
@@ -3,35 +3,36 @@
//
#include
-#include
#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::State::SERVER, lua, core));
- modules.emplace_back(std::make_unique(Api::State::SERVER, core, game, *world.s()));
modules.emplace_back(std::make_unique(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(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(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.");
}
diff --git a/src/lua/ServerLuaParser.h b/src/lua/ServerLuaParser.h
index 5c742c8d..7ea4d102 100644
--- a/src/lua/ServerLuaParser.h
+++ b/src/lua/ServerLuaParser.h
@@ -10,9 +10,9 @@
#include "ServerModHandler.h"
-class ServerSubgame;
class ServerWorld;
class ServerPlayer;
+class ServerSubgame;
class ServerLuaParser : public LuaParser {
public:
diff --git a/src/lua/modules/Register.cpp b/src/lua/modules/Register.cpp
deleted file mode 100644
index 22c5841d..00000000
--- a/src/lua/modules/Register.cpp
+++ /dev/null
@@ -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(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(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("_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;
-}
diff --git a/src/lua/modules/Register.h b/src/lua/modules/Register.h
deleted file mode 100644
index 38d433e4..00000000
--- a/src/lua/modules/Register.h
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// Created by aurailus on 2020-07-24.
-//
-
-#pragma once
-
-#include
-
-#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);
- };
-}
\ No newline at end of file
diff --git a/src/lua/modules/mStartGame.h b/src/lua/modules/mStartGame.h
index f56ea043..9d6493c2 100644
--- a/src/lua/modules/mStartGame.h
+++ b/src/lua/modules/mStartGame.h
@@ -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(client, Address::fromString(address)));
});
diff --git a/src/lua/register/CreateRegister.cpp b/src/lua/register/CreateRegister.cpp
new file mode 100644
index 00000000..448f795a
--- /dev/null
+++ b/src/lua/register/CreateRegister.cpp
@@ -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 after, const std::string& identifier, const sol::table& data) {
+
+ auto modName = env.get("_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 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(env), after, identifier, data); });
+}
\ No newline at end of file
diff --git a/src/lua/register/CreateRegister.h b/src/lua/register/CreateRegister.h
new file mode 100644
index 00000000..8ed955df
--- /dev/null
+++ b/src/lua/register/CreateRegister.h
@@ -0,0 +1,16 @@
+/*
+ * A Utility Function that creates register functions for Lua.
+ *
+ * - Auri, 03/11/20
+ */
+
+#pragma once
+
+#include
+#include
+#include
+
+namespace Api::Util {
+ void createRegister(sol::state& lua, sol::table& core, const std::string& name,
+ std::function after = nullptr, const std::string& table = "");
+}
\ No newline at end of file
diff --git a/src/lua/register/RegisterBlock.h b/src/lua/register/RegisterBlock.h
new file mode 100644
index 00000000..e5fb300c
--- /dev/null
+++ b/src/lua/register/RegisterBlock.h
@@ -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 parseBoxes(sol::table boxesTable) {
+ std::vector boxes{};
+
+ for (auto pair : boxesTable) {
+ if (!pair.second.is()) 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 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
+ createBlockModel(sol::table blockTable, sol::table blockModels, TextureAtlas *atlas) {
+ // Get the specified block model
+ auto modelStr = blockTable.get_or("model", "default:cube");
+ auto modelOpt = blockModels.get>(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>("textures");
+ auto ldTexturesOpt = blockTable.get>("lowdef_textures");
+
+ if (!texturesOpt) throw std::runtime_error("Missing textures property");
+
+ std::vector textures;
+ for (auto pair : *texturesOpt) {
+ if (!pair.second.is()) throw std::runtime_error("textures table contains non-string value");
+ textures.push_back(pair.second.as());
+ }
+ if (textures.size() == 0) textures.push_back("_missing");
+
+ std::vector lowdef_textures;
+ if (!ldTexturesOpt) lowdef_textures = textures;
+ else {
+ for (auto pair : *ldTexturesOpt) {
+ if (!pair.second.is()) throw std::runtime_error("lowdef_textures table has non-string value!");
+ lowdef_textures.push_back(pair.second.as());
+ }
+ }
+ if (lowdef_textures.size() == 0) lowdef_textures.push_back("_missing");
+
+ // Parse through mesh mods and add them
+ sol::optional meshModTable = modelTable.get>("mesh_mods");
+ if (meshModTable) {
+ for (auto &modEntry : *meshModTable) {
+ auto modTable = modEntry.second.as();
+ std::string meshMod = modTable.get_or("type", "none");
+
+ if (meshMod == "none") continue;
+ else if (meshMod == "offset_x")
+ model.meshMods.emplace_back(MeshMod::OFFSET_X, modTable.get_or("amplitude", 1));
+ else if (meshMod == "offset_y")
+ model.meshMods.emplace_back(MeshMod::OFFSET_Y, modTable.get_or("amplitude", 1));
+ else if (meshMod == "offset_z")
+ model.meshMods.emplace_back(MeshMod::OFFSET_Z, modTable.get_or("amplitude", 1));
+ }
+ }
+
+ // Parse through all of the parts and add them to the model
+ auto partsOpt = modelTable.get>("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()) throw std::runtime_error("meshpart must be a table");
+ sol::table meshPartTable = value.as();
+
+ auto points_optional = meshPartTable.get>("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 vertices;
+ std::vector 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(meshPartTable.get_or("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 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 shaderModTable = meshPartTable.get>("shader_mod");
+ if (shaderModTable) {
+ std::string shaderMod = shaderModTable->get_or("type", "none");
+
+ if (shaderMod == "none") meshPart.shaderMod = ShaderMod::NONE;
+ else if (shaderMod == "rotate_x") {
+ meshPart.shaderMod = ShaderMod::ROTATE_X;
+ meshPart.modValue = (*shaderModTable).get_or("speed", 1);
+ }
+ else if (shaderMod == "rotate_y") {
+ meshPart.shaderMod = ShaderMod::ROTATE_Y;
+ meshPart.modValue = (*shaderModTable).get_or("speed", 1);
+ }
+ else if (shaderMod == "rotate_z") {
+ meshPart.shaderMod = ShaderMod::ROTATE_Z;
+ meshPart.modValue = (*shaderModTable).get_or("speed", 1);
+ }
+ else if (shaderMod == "sway_attached") {
+ meshPart.shaderMod = ShaderMod::SWAY_ATTACHED;
+ meshPart.modValue = (*shaderModTable).get_or("amplitude", 1);
+ }
+ else if (shaderMod == "sway_full_block") {
+ meshPart.shaderMod = ShaderMod::SWAY_FULL_BLOCK;
+ meshPart.modValue = (*shaderModTable).get_or("amplitude", 1);
+ }
+ }
+
+ //Add the meshpart to the proper face of the model
+ std::string face = meshPartTable.get_or("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(d)].push_back(meshPart);
+ });
+
+ // Create the far model
+ BlockModel farModel;
+ auto ldRender = blockTable.get_or("lowdef_render", true);
+
+ if (atlas) {
+ std::vector> textureRefs;
+ std::vector blendInds;
+ std::vector> 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>(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>("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>("tool_props");
+ if (toolOpt) {
+ health = toolOpt->get_or("health", INT32_MAX);
+ defense = toolOpt->get_or("defense", 0);
+ }
+
+ glm::vec3 lightSource{};
+ if (blockTable.get>("light_source")) {
+ auto light = blockTable.get("light_source");
+ lightSource = {light[1], light[2], light[3]};
+ } else if (blockTable.get_or("light_source", -1) != -1) {
+ auto light = blockTable.get("light_source");
+ lightSource = {light, light, light};
+ }
+
+ // Parse through selection boxes and collision boxes
+ auto selectionOpt = blockTable.get>("selection_box");
+ auto collisionOpt = blockTable.get>("collision_box");
+
+ std::vector 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 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 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);
+ }
+};
diff --git a/src/lua/register/RegisterBlocks.h b/src/lua/register/RegisterBlocks.h
deleted file mode 100644
index c5506ec4..00000000
--- a/src/lua/register/RegisterBlocks.h
+++ /dev/null
@@ -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 parseBoxes(sol::table boxesTable) {
- std::vector boxes {};
-
- for (auto pair : boxesTable) {
- if (!pair.second.is()) 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 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 createBlockModel(sol::table blockTable, sol::table blockModels, TextureAtlas* atlas) {
- // Get the specified block model
- auto modelStr = blockTable.get_or("model", "default:cube");
- auto modelOpt = blockModels.get>(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>("textures");
- auto ldTexturesOpt = blockTable.get>("lowdef_textures");
-
- if (!texturesOpt) throw std::runtime_error("Missing textures property");
-
- std::vector textures;
- for (auto pair : *texturesOpt) {
- if (!pair.second.is()) throw std::runtime_error("textures table contains non-string value");
- textures.push_back(pair.second.as());
- }
- if (textures.size() == 0) textures.push_back("_missing");
-
- std::vector lowdef_textures;
- if (!ldTexturesOpt) lowdef_textures = textures;
- else {
- for (auto pair : *ldTexturesOpt) {
- if (!pair.second.is()) throw std::runtime_error("lowdef_textures table has non-string value!");
- lowdef_textures.push_back(pair.second.as());
- }
- }
- if (lowdef_textures.size() == 0) lowdef_textures.push_back("_missing");
-
- // Parse through mesh mods and add them
- sol::optional meshModTable = modelTable.get> ("mesh_mods");
- if (meshModTable) {
- for (auto& modEntry : *meshModTable) {
- auto modTable = modEntry.second.as();
- std::string meshMod = modTable.get_or("type", "none");
-
- if (meshMod == "none") continue;
- else if (meshMod == "offset_x")
- model.meshMods.emplace_back(MeshMod::OFFSET_X, modTable.get_or("amplitude", 1));
- else if (meshMod == "offset_y")
- model.meshMods.emplace_back(MeshMod::OFFSET_Y, modTable.get_or("amplitude", 1));
- else if (meshMod == "offset_z")
- model.meshMods.emplace_back(MeshMod::OFFSET_Z, modTable.get_or("amplitude", 1));
- }
- }
-
- // Parse through all of the parts and add them to the model
- auto partsOpt = modelTable.get>("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()) throw std::runtime_error("meshpart must be a table");
- sol::table meshPartTable = value.as();
-
- auto points_optional = meshPartTable.get>("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 vertices;
- std::vector 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(meshPartTable.get_or("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 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 shaderModTable = meshPartTable.get>("shader_mod");
- if (shaderModTable) {
- std::string shaderMod = shaderModTable->get_or("type", "none");
-
- if (shaderMod == "none") meshPart.shaderMod = ShaderMod::NONE;
- else if (shaderMod == "rotate_x") {
- meshPart.shaderMod = ShaderMod::ROTATE_X;
- meshPart.modValue = (*shaderModTable).get_or("speed", 1);
- }
- else if (shaderMod == "rotate_y") {
- meshPart.shaderMod = ShaderMod::ROTATE_Y;
- meshPart.modValue = (*shaderModTable).get_or("speed", 1);
- }
- else if (shaderMod == "rotate_z") {
- meshPart.shaderMod = ShaderMod::ROTATE_Z;
- meshPart.modValue = (*shaderModTable).get_or("speed", 1);
- }
- else if (shaderMod == "sway_attached") {
- meshPart.shaderMod = ShaderMod::SWAY_ATTACHED;
- meshPart.modValue = (*shaderModTable).get_or("amplitude", 1);
- }
- else if (shaderMod == "sway_full_block") {
- meshPart.shaderMod = ShaderMod::SWAY_FULL_BLOCK;
- meshPart.modValue = (*shaderModTable).get_or("amplitude", 1);
- }
- }
-
- //Add the meshpart to the proper face of the model
- std::string face = meshPartTable.get_or("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(d)].push_back(meshPart);
- });
-
- // Create the far model
- BlockModel farModel;
- auto ldRender = blockTable.get_or("lowdef_render", true);
-
- if (atlas) {
- std::vector> textureRefs;
- std::vector blendInds;
- std::vector> 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>(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();
-
- if (!blockRef.second || !blockRef.second.is())
- throw std::runtime_error("register_block expects a table as the second parameter");
- sol::table blockTable = blockRef.second.as();
-
- // Basic Block Properties
- auto nameOpt = blockTable.get>("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>("tool_props");
- if (toolOpt) {
- health = toolOpt->get_or("health", INT32_MAX);
- defense = toolOpt->get_or("defense", 0);
- }
-
- glm::vec3 lightSource {};
- if (blockTable.get>("light_source")) {
- auto light = blockTable.get("light_source");
- lightSource = { light[1], light[2], light[3] };
- }
- else if (blockTable.get_or("light_source", -1) != -1) {
- auto light = blockTable.get("light_source");
- lightSource = { light, light, light };
- }
-
- // Parse through selection boxes and collision boxes
- auto selectionOpt = blockTable.get>("selection_box");
- auto collisionOpt = blockTable.get>("collision_box");
-
- std::vector 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 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 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("registered_blocks"),
- core.get("registered_blockmodels"), game.getDefs(), nullptr);
- }
-
- static void client(sol::table& core, LocalSubgame& game) {
- registerBlocks(core.get("registered_blocks"),
- core.get("registered_blockmodels"), game.getDefs(), &game.textures);
- }
-};
diff --git a/src/lua/usertype/Dimension.cpp b/src/lua/usertype/Dimension.cpp
index c8709d3d..59047416 100644
--- a/src/lua/usertype/Dimension.cpp
+++ b/src/lua/usertype/Dimension.cpp
@@ -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;