Merge pull request #216 from GentenStudios/feat-mods
Improve CMS through enhanced error handling.develop
commit
b5e0e267a4
|
@ -37,6 +37,8 @@
|
|||
#include <Client/Player.hpp>
|
||||
#include <Client/EscapeMenu.hpp>
|
||||
|
||||
#include <Common/CMS/ModManager.hpp>
|
||||
|
||||
namespace phx::client
|
||||
{
|
||||
/**
|
||||
|
@ -77,6 +79,8 @@ namespace phx::client
|
|||
|
||||
ui::ChatWindow* m_chat = nullptr;
|
||||
|
||||
cms::ModManager* m_modManager;
|
||||
|
||||
EscapeMenu* m_escapeMenu = nullptr;
|
||||
GameTools* m_gameDebug = nullptr;
|
||||
bool m_followCam = true;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <Client/Events/IEventListener.hpp>
|
||||
|
||||
#include <Common/Singleton.hpp>
|
||||
#include <Common/CMS/ModManager.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
@ -64,10 +65,7 @@ namespace phx::client
|
|||
InputMap();
|
||||
~InputMap();
|
||||
|
||||
/**
|
||||
* @brief Initializes the Lua API for the inputMap
|
||||
*/
|
||||
void initialize();
|
||||
void registerAPI(cms::ModManager* manager);
|
||||
|
||||
/**
|
||||
* @brief Forwards call to any matching registered callbacks
|
||||
|
|
|
@ -36,10 +36,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <Client/Graphics/ChunkView.hpp>
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <Client/Graphics/ShaderPipeline.hpp>
|
||||
|
||||
#include <Common/CMS/ModManager.hpp>
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
namespace phx
|
||||
|
@ -55,18 +56,22 @@ namespace phx
|
|||
{
|
||||
public:
|
||||
// temporary until a proper management system is put in place.
|
||||
explicit Player(voxels::ChunkView* world, entt::registry* registry);
|
||||
explicit Player(entt::registry* registry);
|
||||
|
||||
void registerAPI(cms::ModManager* manager);
|
||||
|
||||
void setWorld(voxels::ChunkView* world);
|
||||
|
||||
math::Ray getTarget() const;
|
||||
|
||||
bool action1();
|
||||
bool action2();
|
||||
|
||||
/// @brief Gets the entity for the player used in ECS
|
||||
entt::entity getEntity() {return m_entity;};
|
||||
entt::entity getEntity() { return m_entity; }
|
||||
|
||||
/// @brief Gets the direction something is facing based on its rotation
|
||||
static math::vec3 rotToDir(math::vec3 m_rotation);
|
||||
/// @brief Gets the direction something is facing based on its rotation
|
||||
static math::vec3 rotToDir(math::vec3 m_rotation);
|
||||
|
||||
/// @brief Render the selection box around the pointed block
|
||||
void renderSelectionBox(const math::mat4 view, const math::mat4 proj);
|
||||
|
|
|
@ -30,8 +30,7 @@
|
|||
#include <Client/Game.hpp>
|
||||
#include <Client/SplashScreen.hpp>
|
||||
|
||||
#include <Common/Commander.hpp>
|
||||
#include <Common/ContentLoader.hpp>
|
||||
#include <Common/Logger.hpp>
|
||||
#include <Common/Settings.hpp>
|
||||
|
||||
using namespace phx::client;
|
||||
|
@ -119,6 +118,8 @@ void Client::onEvent(events::Event e)
|
|||
|
||||
void Client::run()
|
||||
{
|
||||
Logger::get()->initialize({});
|
||||
|
||||
Settings::get()->load("settings.txt");
|
||||
|
||||
SplashScreen* splashScreen = new SplashScreen();
|
||||
|
|
|
@ -30,13 +30,11 @@
|
|||
#include <Client/Crosshair.hpp>
|
||||
#include <Client/Game.hpp>
|
||||
|
||||
#include <Common/Voxels/BlockRegistry.hpp>
|
||||
|
||||
#include <Common/Commander.hpp>
|
||||
#include <Common/ContentLoader.hpp>
|
||||
|
||||
#include <Common/Position.hpp>
|
||||
#include <Common/Actor.hpp>
|
||||
#include <Common/Commander.hpp>
|
||||
#include <Common/CMS/ModManager.hpp>
|
||||
#include <Common/Position.hpp>
|
||||
#include <Common/Voxels/BlockRegistry.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
@ -51,51 +49,74 @@ static void rawEcho(const std::string& input, std::ostringstream& cout)
|
|||
}
|
||||
|
||||
Game::Game(gfx::Window* window, entt::registry* registry)
|
||||
: Layer("Game"), m_window(window), m_registry(registry)
|
||||
: Layer("Game"), m_window(window), m_registry(registry)
|
||||
{
|
||||
ContentManager::get()->lua["core"]["print"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection coreprint core.print(text)
|
||||
* @brief Prints text to the players terminal
|
||||
*
|
||||
* @param text The text to be outputted to the terminal
|
||||
*
|
||||
*/
|
||||
[=](const std::string& text) { m_chat->cout << text << "\n"; };
|
||||
const std::string save = "save1";
|
||||
|
||||
voxels::BlockRegistry::get()->initialise();
|
||||
std::fstream fileStream;
|
||||
std::vector<std::string> toLoad;
|
||||
|
||||
fileStream.open("Saves/" + save + "/Mods.txt");
|
||||
if (!fileStream.is_open())
|
||||
{
|
||||
std::cout << "Error opening save file";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
std::string input;
|
||||
while (std::getline(fileStream, input))
|
||||
{
|
||||
toLoad.push_back(input);
|
||||
}
|
||||
|
||||
m_modManager = new cms::ModManager(toLoad, {"Modules"});
|
||||
|
||||
voxels::BlockRegistry::get()->registerAPI(m_modManager);
|
||||
|
||||
m_modManager->registerFunction("core.print", [=](const std::string& text) {
|
||||
m_chat->cout << text << "\n";
|
||||
});
|
||||
|
||||
Settings::get()->registerAPI(m_modManager);
|
||||
InputMap::get()->registerAPI(m_modManager);
|
||||
CommandBook::get()->registerAPI(m_modManager);
|
||||
}
|
||||
|
||||
Game::~Game() { delete m_chat; }
|
||||
|
||||
void Game::onAttach()
|
||||
{
|
||||
/// @todo Replace this with logger
|
||||
printf("%s", "Attaching game layer\n");
|
||||
/// @todo Replace this with logger
|
||||
printf("%s", "Attaching game layer\n");
|
||||
m_chat = new ui::ChatWindow("Chat Window", 5,
|
||||
"Type /help for a command list and help.");
|
||||
|
||||
m_chat->registerCallback(rawEcho);
|
||||
|
||||
const std::string save = "save1";
|
||||
m_player = new Player(m_registry);
|
||||
m_player->registerAPI(m_modManager);
|
||||
|
||||
printf("%s", "Loading Modules\n");
|
||||
if (!ContentManager::get()->loadModules(save))
|
||||
float progress = 0.f;
|
||||
auto result = m_modManager->load(&progress);
|
||||
|
||||
if (!result.ok)
|
||||
{
|
||||
signalRemoval();
|
||||
LOG_FATAL("MODDING") << "An error has occured.";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("%s", "Registering world\n");
|
||||
printf("%s", "Registering world\n");
|
||||
const std::string save = "save1";
|
||||
m_world = new voxels::ChunkView(3, voxels::Map(save, "map1"));
|
||||
m_player = new Player(m_world, m_registry);
|
||||
m_player->setWorld(m_world);
|
||||
m_camera = new gfx::FPSCamera(m_window, m_registry);
|
||||
m_camera->setActor(m_player->getEntity());
|
||||
|
||||
m_registry->emplace<Hand>(m_player->getEntity(), voxels::BlockRegistry::get()->getFromRegistryID(0));
|
||||
m_registry->emplace<Hand>(
|
||||
m_player->getEntity(),
|
||||
voxels::BlockRegistry::get()->getFromRegistryID(0));
|
||||
|
||||
printf("%s", "Prepare rendering\n");
|
||||
printf("%s", "Prepare rendering\n");
|
||||
m_renderPipeline.prepare("Assets/SimpleWorld.vert",
|
||||
"Assets/SimpleWorld.frag",
|
||||
gfx::ChunkRenderer::getRequiredShaderLayout());
|
||||
|
@ -105,16 +126,17 @@ void Game::onAttach()
|
|||
const math::mat4 model;
|
||||
m_renderPipeline.setMatrix("u_model", model);
|
||||
|
||||
printf("%s", "Register GUI\n");
|
||||
printf("%s", "Register GUI\n");
|
||||
Client::get()->pushLayer(new Crosshair(m_window));
|
||||
m_escapeMenu = new EscapeMenu(m_window);
|
||||
|
||||
if (Client::get()->isDebugLayerActive())
|
||||
{
|
||||
m_gameDebug = new GameTools(&m_followCam, &m_playerHand, m_player, m_registry);
|
||||
m_gameDebug =
|
||||
new GameTools(&m_followCam, &m_playerHand, m_player, m_registry);
|
||||
Client::get()->pushLayer(m_gameDebug);
|
||||
}
|
||||
printf("%s", "Game layer attached");
|
||||
printf("%s", "Game layer attached");
|
||||
}
|
||||
|
||||
void Game::onDetach()
|
||||
|
@ -149,13 +171,13 @@ void Game::onEvent(events::Event& e)
|
|||
break;
|
||||
case events::Keys::KEY_E:
|
||||
m_playerHand++;
|
||||
m_registry->get<Hand>(m_player->getEntity()).hand =
|
||||
m_registry->get<Hand>(m_player->getEntity()).hand =
|
||||
voxels::BlockRegistry::get()->getFromRegistryID(m_playerHand);
|
||||
e.handled = true;
|
||||
break;
|
||||
case events::Keys::KEY_R:
|
||||
m_playerHand--;
|
||||
m_registry->get<Hand>(m_player->getEntity()).hand =
|
||||
m_registry->get<Hand>(m_player->getEntity()).hand =
|
||||
voxels::BlockRegistry::get()->getFromRegistryID(m_playerHand);
|
||||
e.handled = true;
|
||||
break;
|
||||
|
@ -163,8 +185,8 @@ void Game::onEvent(events::Event& e)
|
|||
if (Client::get()->isDebugLayerActive())
|
||||
if (m_gameDebug == nullptr)
|
||||
{
|
||||
m_gameDebug =
|
||||
new GameTools(&m_followCam, &m_playerHand, m_player, m_registry);
|
||||
m_gameDebug = new GameTools(&m_followCam, &m_playerHand,
|
||||
m_player, m_registry);
|
||||
Client::get()->pushLayer(m_gameDebug);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
|
||||
#include <Client/InputMap.hpp>
|
||||
|
||||
#include <Common/ContentLoader.hpp>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
using namespace phx::client;
|
||||
|
@ -37,84 +35,34 @@ using namespace phx;
|
|||
|
||||
InputMap::InputMap()
|
||||
{
|
||||
ContentManager::get()->lua["core"]["input"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* ---
|
||||
* @subsection coreinput core.input
|
||||
* @brief Interfaces with the player
|
||||
*/
|
||||
ContentManager::get()->lua.create_table();
|
||||
ContentManager::get()->lua["core"]["input"]["registerInput"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection coreplayerregisterinput
|
||||
* core.player.registerInput(string uniqueName, string displayName,
|
||||
* string defaultKey)
|
||||
* @brief Registers a new input
|
||||
* @param uniqueName the unique name for the input in the format
|
||||
* "modname:inputname"
|
||||
* @param displayName the display name that is shown to the user when
|
||||
* binding keys
|
||||
* @param defaultKey the default key that is first registered if the
|
||||
* user does not set one
|
||||
* @warning The default key is currently not functional, it will be set
|
||||
* to 0 every time
|
||||
*
|
||||
* @return The input index (*Not functional at this time)
|
||||
*
|
||||
* @todo convert from string provided by lua to enum
|
||||
*/
|
||||
[this](std::string uniqueName, std::string displayName,
|
||||
std::string defaultKey) {
|
||||
registerInput(uniqueName, displayName, events::Keys::KEY_0);
|
||||
return m_currentInputRef;
|
||||
};
|
||||
ContentManager::get()->lua["core"]["input"]["getInput"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection coreplayergetInput core.player.getInput(int input)
|
||||
* @brief Gets the state of the input
|
||||
* @param input The reference of the input you are looking for
|
||||
*
|
||||
* @return The state of the input
|
||||
*/
|
||||
[this](int input) { return getState(input); };
|
||||
ContentManager::get()->lua["core"]["input"]["getInputRef"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection coreplayergetInputRef core.player.getInputRef(string
|
||||
* uniqueName)
|
||||
* @brief Gets the state of the input
|
||||
* @param uniqueName the unique name used when registering the input
|
||||
*
|
||||
* @return The reference of the input
|
||||
*/
|
||||
[this](std::string uniqueName) { return getReference(uniqueName); };
|
||||
ContentManager::get()->lua["core"]["input"]["registerCallback"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection coreplayerregisterCallback
|
||||
* core.player.getRegisterCallback(int input, function f)
|
||||
* @brief Registers a callback to be called when an input event happens
|
||||
* @param input The reference of the input you are looking for
|
||||
* @param f The function that is called
|
||||
*/
|
||||
[this](int input, sol::function f) { attachCallbackToInput(input, f); };
|
||||
m_uniqueInputs["core:none"] = m_currentInputRef;
|
||||
m_inputs[m_currentInputRef] = {"None", "core:none"};
|
||||
++m_currentInputRef;
|
||||
}
|
||||
|
||||
InputMap::~InputMap() = default;
|
||||
|
||||
void InputMap::initialize()
|
||||
void InputMap::registerAPI(cms::ModManager* manager)
|
||||
{
|
||||
m_uniqueInputs["core:none"] = m_currentInputRef;
|
||||
m_inputs[m_currentInputRef] = {"None", "core:none"};
|
||||
++m_currentInputRef;
|
||||
manager->registerFunction(
|
||||
"core.input.registerInput",
|
||||
[this](std::string uniqueName, std::string displayName,
|
||||
std::string defaultKey) {
|
||||
registerInput(uniqueName, displayName, events::Keys::KEY_0);
|
||||
return m_currentInputRef;
|
||||
});
|
||||
|
||||
manager->registerFunction("core.input.getInput",
|
||||
[this](int input) { return getState(input); });
|
||||
|
||||
manager->registerFunction(
|
||||
"core.input.getInputRef",
|
||||
[this](std::string uniqueName) { return getReference(uniqueName); });
|
||||
|
||||
manager->registerFunction("core.input.registerCallback",
|
||||
[this](int input, sol::function f) {
|
||||
attachCallbackToInput(input, f);
|
||||
});
|
||||
}
|
||||
|
||||
void InputMap::onEvent(events::Event e)
|
||||
|
@ -142,8 +90,9 @@ Input* InputMap::registerInput(const std::string& uniqueName,
|
|||
const std::string& displayName,
|
||||
events::Keys defaultKey)
|
||||
{
|
||||
m_uniqueInputs[uniqueName] = m_currentInputRef;
|
||||
m_inputs[m_currentInputRef] = {displayName, uniqueName, defaultKey, defaultKey};
|
||||
m_uniqueInputs[uniqueName] = m_currentInputRef;
|
||||
m_inputs[m_currentInputRef] = {displayName, uniqueName, defaultKey,
|
||||
defaultKey};
|
||||
++m_currentInputRef;
|
||||
return &m_inputs[m_currentInputRef - 1];
|
||||
}
|
||||
|
@ -194,8 +143,7 @@ bool InputMap::getState(InputRef primaryKey)
|
|||
|
||||
bool InputMap::getState(Input* input)
|
||||
{
|
||||
return SDL_GetKeyboardState(
|
||||
nullptr)[static_cast<SDL_Scancode>(input->key)];
|
||||
return SDL_GetKeyboardState(nullptr)[static_cast<SDL_Scancode>(input->key)];
|
||||
}
|
||||
|
||||
InputMap::InputRef InputMap::getReference(const std::string& uniqueName)
|
||||
|
|
|
@ -37,4 +37,3 @@ int main(int argc, char** argv)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,116 +28,66 @@
|
|||
|
||||
#include <Client/Player.hpp>
|
||||
|
||||
#include <Common/Voxels/BlockRegistry.hpp>
|
||||
#include <Common/ContentLoader.hpp>
|
||||
#include <Common/Commander.hpp>
|
||||
#include <Common/Voxels/BlockRegistry.hpp>
|
||||
|
||||
#include <Common/Actor.hpp>
|
||||
#include <Common/Movement.hpp>
|
||||
#include <Common/Position.hpp>
|
||||
#include <Common/Actor.hpp>
|
||||
|
||||
using namespace phx;
|
||||
|
||||
static const float RAY_INCREMENT = 0.5f;
|
||||
|
||||
Player::Player(voxels::ChunkView* world, entt::registry* registry)
|
||||
: m_world(world), m_registry(registry)
|
||||
Player::Player(entt::registry* registry)
|
||||
: m_registry(registry)
|
||||
{
|
||||
m_entity = m_registry->create();
|
||||
m_registry->emplace<Position>( m_entity,
|
||||
math::vec3{0, 0, 0}, math::vec3{0, 0, 0});
|
||||
m_registry->emplace<Movement>(m_entity, DEFAULT_MOVE_SPEED);
|
||||
m_entity = m_registry->create();
|
||||
m_registry->emplace<Position>(m_entity, math::vec3 {0, 0, 0},
|
||||
math::vec3 {0, 0, 0});
|
||||
m_registry->emplace<Movement>(m_entity, DEFAULT_MOVE_SPEED);
|
||||
|
||||
CommandBook::get()->add(
|
||||
"tp", "Teleports player to supplied coordinates \n /tp <x> <y> <z>",
|
||||
"all", [this](const std::vector<std::string>& args) {
|
||||
m_registry->get<Position>(m_entity).position = {
|
||||
std::stoi(args[0]), std::stoi(args[1]), std::stoi(args[2])};
|
||||
});
|
||||
|
||||
glGenVertexArrays(1, &m_vao);
|
||||
glGenBuffers(1, &m_vbo);
|
||||
|
||||
std::vector<gfx::ShaderLayout> layout;
|
||||
layout.emplace_back("position", 0);
|
||||
m_pipeline.prepare("Assets/SimpleLines.vert", "Assets/SimpleLines.frag", layout);
|
||||
|
||||
ContentManager::get()->lua["core"]["player"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* ---
|
||||
* @subsection coreplayer core.player
|
||||
* @brief Interfaces with the player
|
||||
*/
|
||||
ContentManager::get()->lua.create_table();
|
||||
ContentManager::get()->lua["core"]["player"]["getSpeed"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection coreplayergetspeed core.player.getSpeed()
|
||||
* @brief Gets the players speed
|
||||
*
|
||||
* @return The players speed
|
||||
*/
|
||||
[this]() {
|
||||
return m_registry->get<Movement>(m_entity).moveSpeed;
|
||||
};
|
||||
ContentManager::get()->lua["core"]["player"]["setSpeed"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection coreplayersetspeed core.player.setSpeed(speed)
|
||||
* @brief Sets the player speed
|
||||
*
|
||||
* @param key The new speed to set the player to
|
||||
*
|
||||
*/
|
||||
[this](int speed) {
|
||||
m_registry->get<Movement>(m_entity).moveSpeed = speed;
|
||||
};
|
||||
ContentManager::get()->lua["core"]["player"]["getPosition"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection coreplayergetposition core.player.getPosition()
|
||||
* @brief Gets the players position
|
||||
*
|
||||
* @return The players position in a table
|
||||
*
|
||||
* @par Example usage
|
||||
*
|
||||
* @code
|
||||
* print(core.player.getPosition().x)
|
||||
* print(core.player.getPosition().y)
|
||||
* print(core.player.getPosition().z)
|
||||
* @endcode
|
||||
*/
|
||||
[this]() {
|
||||
sol::table pos = ContentManager::get()->lua.create_table();
|
||||
pos["x"] = m_registry->get<Position>(m_entity).position.x;
|
||||
pos["y"] = m_registry->get<Position>(m_entity).position.y;
|
||||
pos["z"] = m_registry->get<Position>(m_entity).position.z;
|
||||
return pos;
|
||||
};
|
||||
ContentManager::get()->lua["core"]["player"]["setPosition"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection coreplayersetposition core.player.setPosition(position)
|
||||
* @brief Sets the player's position
|
||||
*
|
||||
* @param posx The x component of the players position
|
||||
* @param posy The y component of the players position
|
||||
* @param posz The z component of the players position
|
||||
*
|
||||
*/
|
||||
[this](int posx, int posy, int posz) {
|
||||
m_registry->get<Position>(m_entity).position = {posx, posy, posz};
|
||||
};
|
||||
|
||||
CommandBook::get()->add("tp",
|
||||
"Teleports player to supplied coordinates \n /tp <x> <y> <z>",
|
||||
"all",
|
||||
[this](const std::vector<std::string>& args){
|
||||
m_registry->get<Position>(m_entity).position =
|
||||
{std::stoi(args[0]), std::stoi(args[1]), std::stoi(args[2])};
|
||||
});
|
||||
}
|
||||
|
||||
void Player::registerAPI(cms::ModManager* manager)
|
||||
{
|
||||
manager->registerFunction("core.player.getSpeed", [this]() {
|
||||
return m_registry->get<Movement>(m_entity).moveSpeed;
|
||||
});
|
||||
|
||||
manager->registerFunction("core.player.setSpeed", [this](int speed) {
|
||||
m_registry->get<Movement>(m_entity).moveSpeed = speed;
|
||||
});
|
||||
|
||||
manager->registerFunction("core.player.getPosition", [this]() {
|
||||
sol::table pos;
|
||||
pos["x"] = m_registry->get<Position>(m_entity).position.x;
|
||||
pos["y"] = m_registry->get<Position>(m_entity).position.y;
|
||||
pos["z"] = m_registry->get<Position>(m_entity).position.z;
|
||||
return pos;
|
||||
});
|
||||
|
||||
manager->registerFunction(
|
||||
"core.player.setPosition", [this](int posx, int posy, int posz) {
|
||||
m_registry->get<Position>(m_entity).position = {posx, posy, posz};
|
||||
});
|
||||
}
|
||||
|
||||
void Player::setWorld(voxels::ChunkView* world) { m_world = world; }
|
||||
|
||||
math::Ray Player::getTarget() const
|
||||
{
|
||||
math::vec3 pos = (m_registry->get<Position>(m_entity).position / 2.f) + .5f;
|
||||
|
@ -198,8 +148,7 @@ bool Player::action2()
|
|||
math::vec3 back = ray.backtrace(RAY_INCREMENT);
|
||||
back.floor();
|
||||
|
||||
m_world->setBlockAt(
|
||||
back, m_registry->get<Hand>(getEntity()).hand);
|
||||
m_world->setBlockAt(back, m_registry->get<Hand>(getEntity()).hand);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -210,10 +159,11 @@ bool Player::action2()
|
|||
return false;
|
||||
}
|
||||
|
||||
math::vec3 Player::rotToDir(math::vec3 m_rotation){
|
||||
return {std::cos(m_rotation.y) * std::sin(m_rotation.x),
|
||||
std::sin(m_rotation.y),
|
||||
std::cos(m_rotation.y) * std::cos(m_rotation.x)};
|
||||
math::vec3 Player::rotToDir(math::vec3 m_rotation)
|
||||
{
|
||||
return {std::cos(m_rotation.y) * std::sin(m_rotation.x),
|
||||
std::sin(m_rotation.y),
|
||||
std::cos(m_rotation.y) * std::cos(m_rotation.x)};
|
||||
}
|
||||
|
||||
void Player::renderSelectionBox(const math::mat4 view, const math::mat4 proj)
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
set(currentDir ${CMAKE_CURRENT_LIST_DIR})
|
||||
set(cmsHeaders
|
||||
${currentDir}/Mod.hpp
|
||||
${currentDir}/ModAPI.hpp
|
||||
${currentDir}/ModManager.hpp
|
||||
${currentDir}/ModManager.inl
|
||||
|
||||
PARENT_SCOPE
|
||||
)
|
|
@ -26,65 +26,65 @@
|
|||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
/**
|
||||
* @file ContentLoader.hpp
|
||||
* @brief Implements Lua module loading system.
|
||||
*
|
||||
* @copyright Copyright (c) 2020 Genten Studios
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Common/Singleton.hpp>
|
||||
|
||||
#include <sol/sol.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace phx
|
||||
namespace phx::cms
|
||||
{
|
||||
/// @brief A lightweight struct to store a module and the list of
|
||||
/// dependencies that module has.
|
||||
struct Mod
|
||||
{
|
||||
/// @brief The name of the module, should match the folder name.
|
||||
std::string name;
|
||||
|
||||
/// @brief List of dependencies that the module needs in order to load.
|
||||
std::vector<std::string> dependencies;
|
||||
|
||||
/**
|
||||
* @brief Constructor for mod object, folder matching mod name with a
|
||||
* dependencies.txt inside modules folder must exist.
|
||||
*/
|
||||
explicit Mod(std::string name);
|
||||
~Mod() = default;
|
||||
};
|
||||
|
||||
class ContentManager : public Singleton<ContentManager>
|
||||
/**
|
||||
* @brief Class to encapsulate a "mod".
|
||||
*
|
||||
* This class is literally just to load dependencies and provide an easy way
|
||||
* to get the name and path of the mod. It's tidier to store a vector of
|
||||
* mods than a vector of names, paths, and dependencies.
|
||||
*/
|
||||
class Mod
|
||||
{
|
||||
public:
|
||||
using Dependencies = std::vector<std::string>;
|
||||
|
||||
public:
|
||||
Mod() = delete;
|
||||
|
||||
/**
|
||||
* @brief Loads necessary lua modules required to load a save file.
|
||||
* @brief Constructs a mod object and reads the dependency list.
|
||||
* @param modName The name of the mod.
|
||||
* @param modPath The path that the mod is found in.
|
||||
*
|
||||
* @param save The save file to be loaded.
|
||||
* @return true If the function successfully loaded all modules.
|
||||
* @return false If the function failed to load modules, details will
|
||||
* be outputted to the terminal.
|
||||
*
|
||||
* @todo Add proper error handling instead of returning a boolean.
|
||||
* Mod Path should be the path that the mod is found in, not the
|
||||
* directory of the mod itself.
|
||||
*/
|
||||
bool loadModules(const std::string& save);
|
||||
Mod(const std::string& modName, const std::string& modPath);
|
||||
|
||||
sol::state lua;
|
||||
/**
|
||||
* @brief Gets the name of the mod.
|
||||
* @return The name of the mod.
|
||||
*/
|
||||
const std::string& getName() const;
|
||||
|
||||
std::string currentMod;
|
||||
/**
|
||||
* @brief Gets the parent folder of the mod.
|
||||
* @return The path that the mod resides in.
|
||||
*
|
||||
* It will return the folder that the mod resides in, not the mod's
|
||||
* folder itself. Combine with getName() to make a whole path.
|
||||
*/
|
||||
const std::string& getPath() const;
|
||||
|
||||
ContentManager();
|
||||
/**
|
||||
* @brief Gets the mod's dependencies.
|
||||
* @return An array of dependencies for the mod.
|
||||
*/
|
||||
const Dependencies& getDependencies() const;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::string m_path;
|
||||
|
||||
Dependencies m_dependencies;
|
||||
};
|
||||
}; // namespace phx
|
||||
|
||||
|
||||
} // namespace phx::mods
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright 2019-20 Genten Studios
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace phx::cms
|
||||
{
|
||||
// not documenting since we don't have an exact lifetime on the existance of
|
||||
// these.
|
||||
|
||||
class Privileges
|
||||
{
|
||||
public:
|
||||
// each player object stores this, list of all privileges they have.
|
||||
using PrivList = std::vector<std::string>;
|
||||
|
||||
public:
|
||||
Privileges() = default;
|
||||
~Privileges() = default;
|
||||
|
||||
void registerPrivilege(const std::string& priv);
|
||||
void privilegeExists(const std::string& priv) const;
|
||||
const PrivList& getPrivileges() const { return m_privileges; }
|
||||
|
||||
///////////////////////
|
||||
// utility functions //
|
||||
///////////////////////
|
||||
|
||||
static bool hasPrivilege(const PrivList& privList,
|
||||
const std::string& priv);
|
||||
|
||||
static PrivList parsePrivList(const std::string& commaDelimList);
|
||||
|
||||
private:
|
||||
PrivList m_privileges;
|
||||
};
|
||||
|
||||
class CommandBook
|
||||
{
|
||||
public:
|
||||
using CommandFunction =
|
||||
std::function<std::string(std::vector<std::string>)>;
|
||||
|
||||
struct Command
|
||||
{
|
||||
std::string help;
|
||||
Privileges::PrivList privs;
|
||||
CommandFunction func;
|
||||
};
|
||||
|
||||
public:
|
||||
CommandBook();
|
||||
~CommandBook() = default;
|
||||
|
||||
// will allow for a command to work from multiple different privileges.
|
||||
void registerCommand(const std::string& command,
|
||||
const std::string& help,
|
||||
const Privileges::PrivList& privileges,
|
||||
const CommandFunction& func);
|
||||
|
||||
bool commandExists(const std::string& command) const;
|
||||
const Command* getCommand(const std::string& command) const;
|
||||
|
||||
private:
|
||||
// key is the actual command.
|
||||
std::unordered_map<std::string, Command> m_commands;
|
||||
};
|
||||
} // namespace phx::mods
|
|
@ -0,0 +1,143 @@
|
|||
// Copyright 2019-20 Genten Studios
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Common/Logger.hpp>
|
||||
|
||||
#include <sol/sol.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
namespace phx::cms
|
||||
{
|
||||
/**
|
||||
* @brief A class to handle all Mods that require loading.
|
||||
*
|
||||
* To be used in conjunction with saves. Each save stores a list of mods
|
||||
* associated to the world stored.
|
||||
*/
|
||||
class ModManager
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief The status of the ModManager during load.
|
||||
*
|
||||
* This will help tell if there was an error while loading mods.
|
||||
*/
|
||||
struct Status
|
||||
{
|
||||
/// @brief Boolean saying whether the operation was ok or not.
|
||||
bool ok;
|
||||
|
||||
/// @brief If the operation failed, the error message will be stored
|
||||
/// in this.
|
||||
std::string what;
|
||||
};
|
||||
|
||||
using ModList = std::vector<std::string>;
|
||||
|
||||
public:
|
||||
ModManager() = delete;
|
||||
|
||||
/**
|
||||
* @brief Constructs the manager by initializing the Lua state.
|
||||
* @param toLoad The list of mods to load.
|
||||
* @param paths The list of directories a mod could be found in.
|
||||
*
|
||||
* The allowance for extra paths to be used makes sure that someone can
|
||||
* have mods stored in different directories. This is especially helpful
|
||||
* for developers since they can work on their mod and store it
|
||||
* somewhere much more convenient for them while still being able to use
|
||||
* it.
|
||||
*/
|
||||
explicit ModManager(const ModList& toLoad, const ModList& paths);
|
||||
|
||||
/**
|
||||
* @brief Registers a C++ function into Lua.
|
||||
* @tparam F The function signature for the function being registered.
|
||||
* @param funcName The name the function should have in the Lua.
|
||||
* @param func The function itself, can be a lambda or std::function.
|
||||
*
|
||||
* FuncName should be laid out like so:
|
||||
* namespace.namespace.functionName
|
||||
*
|
||||
* Function hierarchies of greater than 3 sections are not allowed, so
|
||||
* only two namespaces are allowed as of right now. For example:
|
||||
* core.block.register(...)
|
||||
*/
|
||||
template <typename F>
|
||||
void registerFunction(const std::string& funcName, F func);
|
||||
|
||||
// unimplemented function, exists as a reminder for when we need it.
|
||||
template <typename T>
|
||||
void exposeVariable(const std::string& name, T var);
|
||||
|
||||
/**
|
||||
* @brief Loads the mods into the Lua state, ready for the game.
|
||||
* @param The current progress of the loading.
|
||||
* @return The status of the load, can dictate fail or success.
|
||||
*/
|
||||
Status load(float* progress);
|
||||
|
||||
/**
|
||||
* @brief Cleans up mods once ready.
|
||||
*
|
||||
* Currently unimplemented, but will be implemented with a mod.cleanup
|
||||
* function registered in lua for safely shutting down the game.
|
||||
*/
|
||||
void cleanup();
|
||||
|
||||
/**
|
||||
* @brief Gets the list of mods being loaded.
|
||||
* @return The list of loaded mods.
|
||||
*/
|
||||
const ModList& getModList() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the path of the currently loading mod.
|
||||
* @return The path of the mod being currently loaded.
|
||||
*
|
||||
* This is useful when loading mods since some functions don't have
|
||||
* information on the currently loading mod, making it difficult to use
|
||||
* things like textures that are packaged with the mod.
|
||||
*/
|
||||
const std::string& getCurrentModPath() const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_modsRequired;
|
||||
std::vector<std::string> m_modPaths;
|
||||
std::string m_currentModPath;
|
||||
|
||||
sol::state m_luaState;
|
||||
};
|
||||
} // namespace phx::cms
|
||||
|
||||
#include "ModManager.inl"
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2019-20 Genten Studios
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
// Header exists in ModManager.hpp
|
||||
|
||||
namespace phx::cms
|
||||
{
|
||||
// can do template<typename RtnType, typename... Args>
|
||||
// but allowing for anything makes sure you can capture lambdas.
|
||||
template <typename F>
|
||||
void ModManager::registerFunction(const std::string& funcName, F func)
|
||||
{
|
||||
// splitting the function name by periods.
|
||||
// something like core.block.register would be broken down into
|
||||
// core, block and register. core and block need to be created as
|
||||
// Lua tables, however register is just set to the function since
|
||||
// it's the actual name of it.
|
||||
std::vector<std::string> branches;
|
||||
std::stringstream sstream(funcName);
|
||||
std::string substr;
|
||||
while (std::getline(sstream, substr, '.'))
|
||||
{
|
||||
branches.push_back(substr);
|
||||
}
|
||||
|
||||
// malformed request.
|
||||
if (branches.empty())
|
||||
return;
|
||||
|
||||
// limiting to 3 levels of hierarchy for a v1. Otherwise deep
|
||||
// infinite recursion doesn't work.
|
||||
if (branches.size() == 1)
|
||||
{
|
||||
m_luaState[branches[0]] = func;
|
||||
return;
|
||||
}
|
||||
|
||||
if (branches.size() == 2)
|
||||
{
|
||||
if (!m_luaState[branches[0]].valid())
|
||||
{
|
||||
m_luaState[branches[0]] = m_luaState.create_table();
|
||||
}
|
||||
|
||||
m_luaState[branches[0]][branches[1]] = func;
|
||||
}
|
||||
|
||||
if (branches.size() == 3)
|
||||
{
|
||||
if (!m_luaState[branches[0]].valid())
|
||||
{
|
||||
m_luaState[branches[0]] = m_luaState.create_table();
|
||||
}
|
||||
|
||||
if (!m_luaState[branches[0]][branches[1]].valid())
|
||||
{
|
||||
m_luaState[branches[0]][branches[1]] =
|
||||
m_luaState.create_table();
|
||||
}
|
||||
|
||||
m_luaState[branches[0]][branches[1]][branches[2]] = func;
|
||||
}
|
||||
|
||||
if (branches.size() > 3)
|
||||
{
|
||||
LOG_WARNING("MODDING")
|
||||
<< "Function hierarchies of more than 3 are not currently "
|
||||
"supported. Please limit function names to the depth of "
|
||||
"\"core.block.register\".";
|
||||
}
|
||||
}
|
||||
} // namespace phx::mods
|
|
@ -1,22 +1,23 @@
|
|||
add_subdirectory(Math)
|
||||
add_subdirectory(Voxels)
|
||||
add_subdirectory(CMS)
|
||||
|
||||
set(currentDir ${CMAKE_CURRENT_LIST_DIR})
|
||||
set(Headers
|
||||
${mathHeaders}
|
||||
${voxelHeaders}
|
||||
${mathHeaders}
|
||||
${voxelHeaders}
|
||||
${cmsHeaders}
|
||||
|
||||
${currentDir}/CoreIntrinsics.hpp
|
||||
${currentDir}/EnumTools.hpp
|
||||
${currentDir}/Singleton.hpp
|
||||
${currentDir}/FileIO.hpp
|
||||
${currentDir}/Logger.hpp
|
||||
${currentDir}/CoreIntrinsics.hpp
|
||||
${currentDir}/EnumTools.hpp
|
||||
${currentDir}/Singleton.hpp
|
||||
${currentDir}/FileIO.hpp
|
||||
${currentDir}/Logger.hpp
|
||||
|
||||
${currentDir}/ContentLoader.hpp
|
||||
${currentDir}/Settings.hpp
|
||||
${currentDir}/Commander.hpp
|
||||
${currentDir}/Position.hpp
|
||||
${currentDir}/Movement.hpp
|
||||
${currentDir}/Settings.hpp
|
||||
${currentDir}/Commander.hpp
|
||||
${currentDir}/Position.hpp
|
||||
${currentDir}/Movement.hpp
|
||||
|
||||
PARENT_SCOPE
|
||||
)
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <Common/Singleton.hpp>
|
||||
#include <Common/CMS/ModManager.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <ostream>
|
||||
|
@ -68,7 +69,10 @@ namespace phx
|
|||
std::vector<std::string> m_permission;
|
||||
std::vector<CommandFunction> m_functions;
|
||||
|
||||
CommandBook();
|
||||
CommandBook() = default;
|
||||
~CommandBook() = default;
|
||||
|
||||
void registerAPI(cms::ModManager* manager);
|
||||
|
||||
/**
|
||||
* @brief Registers a command in the command registry.
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#include <utility>
|
||||
|
||||
#define LOGGER_INTERNAL(verbosity, component) \
|
||||
if (phx::Logger::get() == nullptr && \
|
||||
if (phx::Logger::get() == nullptr || \
|
||||
verbosity > phx::Logger::get()->getVerbosity()) \
|
||||
{ \
|
||||
; \
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <Common/Singleton.hpp>
|
||||
#include <Common/CMS/ModManager.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
@ -88,7 +89,7 @@ namespace phx
|
|||
* @param defaultValue The default value for the setting upon creation.
|
||||
*/
|
||||
Setting(std::string name, std::string key, int defaultValue, json* json_);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the value of an already existing setting.
|
||||
*
|
||||
|
@ -153,6 +154,8 @@ namespace phx
|
|||
public:
|
||||
Settings();
|
||||
|
||||
void registerAPI(cms::ModManager* manager);
|
||||
|
||||
/**
|
||||
* @brief Adds a new setting.
|
||||
*
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <Common/Singleton.hpp>
|
||||
#include <Common/Voxels/Block.hpp>
|
||||
#include <Common/Voxels/TextureRegistry.hpp>
|
||||
#include <Common/CMS/ModManager.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
@ -62,11 +63,11 @@ namespace phx::voxels
|
|||
class BlockRegistry : public Singleton<BlockRegistry>
|
||||
{
|
||||
public:
|
||||
/// @brief Registers respective Lua methods.
|
||||
BlockRegistry();
|
||||
~BlockRegistry() = default;
|
||||
|
||||
// @brief Initializes the registry.
|
||||
void initialise();
|
||||
void registerAPI(cms::ModManager* manager);
|
||||
|
||||
/**
|
||||
* @brief Registers a block in the registry.
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
set(currentDir ${CMAKE_CURRENT_LIST_DIR})
|
||||
set(cmsSources
|
||||
${currentDir}/Mod.cpp
|
||||
${currentDir}/ModAPI.cpp
|
||||
${currentDir}/ModManager.cpp
|
||||
|
||||
PARENT_SCOPE
|
||||
)
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2019-20 Genten Studios
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <Common/Logger.hpp>
|
||||
#include <Common/CMS/Mod.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
using namespace phx::cms;
|
||||
|
||||
Mod::Mod(const std::string& modName, const std::string& modPath)
|
||||
{
|
||||
m_name = modName;
|
||||
m_path = modPath;
|
||||
|
||||
{
|
||||
std::fstream deps;
|
||||
|
||||
deps.open(m_path + "/" + modName + "/Dependencies.txt");
|
||||
if (!deps.is_open())
|
||||
{
|
||||
LOG_WARNING("MODDING")
|
||||
<< "Mod " << modName << " does not include a Dependencies.txt!";
|
||||
|
||||
// assuming no deps, even if it causes failure further down.
|
||||
return;
|
||||
}
|
||||
|
||||
std::string input;
|
||||
while (std::getline(deps, input))
|
||||
{
|
||||
if (!input.empty())
|
||||
{
|
||||
m_dependencies.push_back(input);
|
||||
}
|
||||
}
|
||||
|
||||
deps.close();
|
||||
}
|
||||
}
|
||||
|
||||
const Mod::Dependencies& Mod::getDependencies() const { return m_dependencies; }
|
||||
const std::string& Mod::getPath() const { return m_path; }
|
||||
const std::string& Mod::getName() const { return m_name; }
|
|
@ -0,0 +1,156 @@
|
|||
// Copyright 2019-20 Genten Studios
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <Common/Logger.hpp>
|
||||
#include <Common/CMS/ModAPI.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
using namespace phx::cms;
|
||||
|
||||
void Privileges::registerPrivilege(const std::string& priv)
|
||||
{
|
||||
const auto it = std::find(m_privileges.begin(), m_privileges.end(), priv);
|
||||
if (it == m_privileges.end())
|
||||
{
|
||||
m_privileges.push_back(priv);
|
||||
}
|
||||
}
|
||||
|
||||
Privileges::PrivList Privileges::parsePrivList(
|
||||
const std::string& commaDelimList)
|
||||
{
|
||||
// split comma delimited list into array.
|
||||
PrivList privs;
|
||||
std::stringstream sstream(commaDelimList);
|
||||
std::string substr;
|
||||
while (std::getline(sstream, substr, ','))
|
||||
{
|
||||
privs.push_back(substr);
|
||||
}
|
||||
|
||||
return privs;
|
||||
}
|
||||
|
||||
bool Privileges::hasPrivilege(const PrivList& privList, const std::string& priv)
|
||||
{
|
||||
if (priv.length() == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// search array for privilege.
|
||||
const auto it = std::find(privList.begin(), privList.end(), priv);
|
||||
if (it == privList.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CommandBook::CommandBook()
|
||||
{
|
||||
m_commands["help"] = {"Type /help [command] to learn more about a command.",
|
||||
{},
|
||||
[=](std::vector<std::string> args) {
|
||||
if (args.empty())
|
||||
{
|
||||
return m_commands["help"].help;
|
||||
}
|
||||
|
||||
return m_commands[args[0]].help;
|
||||
}};
|
||||
|
||||
m_commands["list"] = {
|
||||
"Type /list to list every command, use a privilege as a parameter to "
|
||||
"see what commands are available to that role.",
|
||||
{},
|
||||
[=](std::vector<std::string> args) {
|
||||
if (args.empty())
|
||||
{
|
||||
std::string commands;
|
||||
for (auto& command : m_commands)
|
||||
{
|
||||
commands += command.first + "\n";
|
||||
}
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
std::string commands;
|
||||
for (auto& command : m_commands)
|
||||
{
|
||||
if (Privileges::hasPrivilege(command.second.privs, args[0]))
|
||||
{
|
||||
commands += command.first + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return commands;
|
||||
}};
|
||||
|
||||
m_commands["unknown"] = {
|
||||
"Unknown command", {}, [](std::vector<std::string> args) {
|
||||
return "An unknown command has been called";
|
||||
}};
|
||||
}
|
||||
|
||||
void CommandBook::registerCommand(const std::string& command,
|
||||
const std::string& help,
|
||||
const Privileges::PrivList& privilege,
|
||||
const CommandFunction& func)
|
||||
{
|
||||
auto it = m_commands.find(command);
|
||||
if (it == m_commands.end())
|
||||
{
|
||||
LOG_INFO("[MODDING]")
|
||||
<< "The command \" " << command
|
||||
<< "\" has already been defined by another mod, the formally "
|
||||
"registered command shall be overwritten.";
|
||||
}
|
||||
|
||||
m_commands[command] = {help, privilege, func};
|
||||
}
|
||||
|
||||
bool CommandBook::commandExists(const std::string& command) const
|
||||
{
|
||||
return m_commands.find(command) != m_commands.end();
|
||||
}
|
||||
|
||||
const CommandBook::Command* CommandBook::getCommand(const std::string& command) const
|
||||
{
|
||||
auto it = m_commands.find(command);
|
||||
if (it == m_commands.end())
|
||||
{
|
||||
return &m_commands.at("unknown");
|
||||
}
|
||||
|
||||
return &(it->second);
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
// Copyright 2019-20 Genten Studios
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <Common/CMS/ModManager.hpp>
|
||||
#include <Common/CMS/Mod.hpp>
|
||||
#include <Common/Logger.hpp>
|
||||
|
||||
using namespace phx::cms;
|
||||
|
||||
static void CustomPanicHandler(sol::optional<std::string> maybe_msg)
|
||||
{
|
||||
// \n for newline, \t for tab.
|
||||
std::string error;
|
||||
if (maybe_msg)
|
||||
{
|
||||
error += "\n\t";
|
||||
error += maybe_msg.value();
|
||||
error += "\n";
|
||||
}
|
||||
|
||||
LOG_FATAL("MODDING") << "An unexpected Lua error has occured. " << error
|
||||
<< "The application will now be aborted.";
|
||||
}
|
||||
|
||||
ModManager::ModManager(const ModList& toLoad, const ModList& paths)
|
||||
: m_modsRequired(toLoad), m_modPaths(paths)
|
||||
{
|
||||
m_luaState.open_libraries(sol::lib::base);
|
||||
m_luaState.set_panic(
|
||||
sol::c_call<decltype(&CustomPanicHandler), &CustomPanicHandler>);
|
||||
}
|
||||
|
||||
ModManager::Status ModManager::load(float* progress)
|
||||
{
|
||||
std::queue<Mod> toLoad;
|
||||
|
||||
for (auto& require : m_modsRequired)
|
||||
{
|
||||
bool found = false;
|
||||
for (auto& path : m_modPaths)
|
||||
{
|
||||
std::fstream file;
|
||||
file.open(path + "/" + require + "/Init.lua");
|
||||
if (file.is_open())
|
||||
{
|
||||
found = true;
|
||||
toLoad.emplace(require, path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
std::string pathList = "\n\t";
|
||||
for (auto& path : m_modPaths)
|
||||
{
|
||||
pathList += path;
|
||||
pathList += "\n\t";
|
||||
}
|
||||
|
||||
LOG_FATAL("MODDING")
|
||||
<< "The mod: " << require
|
||||
<< " was not found in any of the provided mod directories: "
|
||||
<< pathList;
|
||||
|
||||
return {false, "The mod: " + require + " was not found."};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> loadedMods;
|
||||
while (!toLoad.empty())
|
||||
{
|
||||
std::size_t lastPass = toLoad.size();
|
||||
|
||||
for (std::size_t i = 0; i < toLoad.size(); ++i)
|
||||
{
|
||||
Mod& mod = toLoad.front();
|
||||
bool satisfied = true;
|
||||
|
||||
for (auto& dependency : mod.getDependencies())
|
||||
{
|
||||
if (std::find(loadedMods.begin(), loadedMods.end(),
|
||||
dependency) == loadedMods.end())
|
||||
{
|
||||
satisfied = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (satisfied)
|
||||
{
|
||||
m_currentModPath = mod.getPath() + "/" + mod.getName() + "/";
|
||||
sol::protected_function_result pfr =
|
||||
m_luaState.safe_script_file(m_currentModPath + "Init.lua",
|
||||
&sol::script_pass_on_error);
|
||||
|
||||
loadedMods.push_back(mod.getName());
|
||||
|
||||
// error occured if return is not valid.
|
||||
if (!pfr.valid())
|
||||
{
|
||||
sol::error err = pfr;
|
||||
|
||||
std::string errString = "An error occured loading ";
|
||||
errString += mod.getName();
|
||||
errString += ": ";
|
||||
errString += err.what();
|
||||
|
||||
LOG_FATAL("MODDING") << errString;
|
||||
|
||||
return {false, errString};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
toLoad.push(toLoad.front());
|
||||
}
|
||||
|
||||
toLoad.pop();
|
||||
}
|
||||
|
||||
if (lastPass == toLoad.size())
|
||||
{
|
||||
std::string err = "The mod: ";
|
||||
err += toLoad.front().getName();
|
||||
err += " is missing one or more dependencies, please resolve this "
|
||||
"issue before continuing.";
|
||||
|
||||
LOG_FATAL("MODDING") << err;
|
||||
|
||||
return {false, err};
|
||||
}
|
||||
}
|
||||
|
||||
// no need to put in something for "what", since nothing went wrong.
|
||||
return {true};
|
||||
}
|
||||
|
||||
void ModManager::cleanup() {}
|
||||
|
||||
const ModManager::ModList& ModManager::getModList() const
|
||||
{
|
||||
return m_modsRequired;
|
||||
}
|
||||
|
||||
const std::string& ModManager::getCurrentModPath() const
|
||||
{
|
||||
return m_currentModPath;
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
add_subdirectory(Math)
|
||||
add_subdirectory(Voxels)
|
||||
add_subdirectory(CMS)
|
||||
|
||||
set(currentDir ${CMAKE_CURRENT_LIST_DIR})
|
||||
set(Sources
|
||||
${mathSources}
|
||||
${voxelSources}
|
||||
${mathSources}
|
||||
${voxelSources}
|
||||
${cmsSources}
|
||||
|
||||
${currentDir}/ContentLoader.cpp
|
||||
${currentDir}/Settings.cpp
|
||||
${currentDir}/Logger.cpp
|
||||
${currentDir}/Commander.cpp
|
||||
${currentDir}/Settings.cpp
|
||||
${currentDir}/Logger.cpp
|
||||
${currentDir}/Commander.cpp
|
||||
|
||||
PARENT_SCOPE
|
||||
)
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
*/
|
||||
|
||||
#include <Common/Commander.hpp>
|
||||
#include <Common/ContentLoader.hpp>
|
||||
|
||||
using namespace phx;
|
||||
|
||||
|
@ -72,54 +71,13 @@ void CommandBook::add(const std::string& command, const std::string& help,
|
|||
|
||||
int CommandBook::getPage() { return m_page; }
|
||||
|
||||
CommandBook::CommandBook()
|
||||
void CommandBook::registerAPI(cms::ModManager* manager)
|
||||
{
|
||||
ContentManager::get()->lua["core"]["command"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* ---
|
||||
* @subsection corecmd core.command
|
||||
* @brief Interfaces with the commander
|
||||
*
|
||||
*/
|
||||
ContentManager::get()->lua.create_table();
|
||||
ContentManager::get()->lua["core"]["command"]["register"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection corecmdreg core.command.register
|
||||
* @brief Registers a new command
|
||||
*
|
||||
* In the terminal typing "/" followed by a command will execute the
|
||||
*command
|
||||
*
|
||||
* @param command The command to register
|
||||
* @param help A helpstring that is printed to terminal when typing
|
||||
*"/help <command>"
|
||||
* @param f The callback function that is called by the commander
|
||||
* The callback function must take a table as an argument
|
||||
* Any arguments included when the command is executed will be passed in
|
||||
*this table
|
||||
*
|
||||
* @b Example:
|
||||
* @code {.lua}
|
||||
* function hello (args)
|
||||
* if args[1] == "there" then
|
||||
* print("General Kenobi")
|
||||
* elseif args[1] == "world" then
|
||||
* print("World says hi")
|
||||
* else
|
||||
* print("with you, the force is not")
|
||||
* end
|
||||
* end
|
||||
* core.command.register("Hello", "Master the arts of the Jedi you
|
||||
*must", hello)
|
||||
* @endcode
|
||||
*/
|
||||
manager->registerFunction(
|
||||
"core.command.register",
|
||||
[](std::string command, std::string help, sol::function f) {
|
||||
CommandBook::get()->add(command, help, "all", f);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
bool Commander::help(const std::vector<std::string>& args, std::ostream& out)
|
||||
|
@ -282,4 +240,3 @@ void Commander::callback(const std::string& input, std::ostringstream& cout)
|
|||
run(command, args, cout);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
// Copyright 2019-20 Genten Studios
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
|
||||
#include <Common/ContentLoader.hpp>
|
||||
|
||||
using namespace phx;
|
||||
|
||||
ContentManager::ContentManager()
|
||||
{
|
||||
currentMod = "";
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
/**
|
||||
* @defgroup luaapi Lua API
|
||||
*
|
||||
* The lua API is . . .
|
||||
*
|
||||
* @tableofcontents
|
||||
*
|
||||
*/
|
||||
lua["core"] = lua.create_table();
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* ---
|
||||
* ---
|
||||
* @section core core
|
||||
* @brief The core API for interacting with Quartz
|
||||
*/
|
||||
}
|
||||
|
||||
Mod::Mod(std::string modName) : name(std::move(modName))
|
||||
{
|
||||
std::fstream fileStream;
|
||||
fileStream.open("Modules/" + name + "/Dependencies.txt");
|
||||
if (!fileStream.is_open())
|
||||
{
|
||||
std::cout << "Couldn't find dependencies file for mod: " << name
|
||||
<< "\n";
|
||||
return;
|
||||
}
|
||||
while (fileStream.peek() != EOF)
|
||||
{
|
||||
std::string input;
|
||||
std::getline(fileStream, input);
|
||||
dependencies.push_back(input);
|
||||
}
|
||||
fileStream.close();
|
||||
}
|
||||
|
||||
bool ContentManager::loadModules(const std::string& save)
|
||||
{
|
||||
std::fstream fileStream;
|
||||
std::queue<Mod> toLoad; // A queue of mods that need loaded
|
||||
|
||||
fileStream.open("Saves/" + save + "/Mods.txt");
|
||||
if (!fileStream.is_open())
|
||||
{
|
||||
std::cout << "Error opening save file";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; fileStream.peek() != EOF && i <= 10; i++)
|
||||
{
|
||||
std::string input;
|
||||
std::getline(fileStream, input);
|
||||
Mod mod = Mod(input);
|
||||
toLoad.push(mod);
|
||||
}
|
||||
fileStream.close();
|
||||
|
||||
// Sort and load the mods
|
||||
std::vector<std::string> loadedMods;
|
||||
while (!toLoad.empty())
|
||||
{
|
||||
int lastPass = toLoad.size();
|
||||
|
||||
// For each mod that needs loaded
|
||||
for (int i = 0; i < toLoad.size(); i++)
|
||||
{
|
||||
Mod mod = toLoad.front();
|
||||
bool satisfied = true;
|
||||
|
||||
// For each dependency the mod has
|
||||
for (const auto& dependency : mod.dependencies)
|
||||
{
|
||||
// If dependency is not satisfied, mark satisfied as false.
|
||||
if (std::find(loadedMods.begin(), loadedMods.end(),
|
||||
dependency) == loadedMods.end())
|
||||
{
|
||||
satisfied = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If all dependencies were met, run lua and add mod to satisfied
|
||||
// list Otherwise, move mod to back of load queue
|
||||
if (satisfied)
|
||||
{
|
||||
currentMod = mod.name;
|
||||
lua.script_file("Modules/" + mod.name + "/Init.lua");
|
||||
loadedMods.push_back(mod.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
toLoad.push(toLoad.front());
|
||||
}
|
||||
toLoad.pop();
|
||||
}
|
||||
|
||||
// If we haven't loaded any new mods, throw error
|
||||
if (lastPass == toLoad.size())
|
||||
{
|
||||
// TODO: Replace this with actuall error handling/ logging
|
||||
std::cout
|
||||
<< "One or more mods are missing required dependencies. \n";
|
||||
std::cout << "Failed Mods:\n";
|
||||
for (int i = 0; i < toLoad.size(); i++)
|
||||
{
|
||||
std::cout << "- " + toLoad.front().name + "\n";
|
||||
toLoad.pop();
|
||||
}
|
||||
std::cout << "Loaded Mods:\n";
|
||||
for (const auto& loadedMod : loadedMods)
|
||||
{
|
||||
std::cout << "- " + loadedMod + "\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -26,17 +26,17 @@
|
|||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <Common/ContentLoader.hpp>
|
||||
#include <Common/Settings.hpp>
|
||||
|
||||
#include <climits>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
using namespace phx;
|
||||
|
||||
Setting::Setting(std::string name, std::string key, int defaultValue, json* json_)
|
||||
Setting::Setting(std::string name, std::string key, int defaultValue,
|
||||
json* json_)
|
||||
: m_name(std::move(name)), m_key(std::move(key)), m_value(defaultValue),
|
||||
m_maxValue(SHRT_MAX), m_minValue(SHRT_MIN), m_default(defaultValue),
|
||||
m_json(json_)
|
||||
|
@ -47,7 +47,7 @@ bool Setting::set(int value)
|
|||
{
|
||||
if (value >= m_minValue && value <= m_maxValue)
|
||||
{
|
||||
m_value = value;
|
||||
m_value = value;
|
||||
(*m_json)[m_key] = value;
|
||||
return true;
|
||||
}
|
||||
|
@ -66,68 +66,24 @@ int Setting::value() const { return m_value; }
|
|||
|
||||
int Setting::getDefault() const { return m_default; }
|
||||
|
||||
Settings::Settings() :
|
||||
m_data(json::object())
|
||||
Settings::Settings() : m_data(json::object()) {}
|
||||
|
||||
void Settings::registerAPI(cms::ModManager* manager)
|
||||
{
|
||||
ContentManager::get()->lua["core"]["setting"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* ---
|
||||
* @subsection coreset core.setting
|
||||
* @brief Interfaces with the settings system
|
||||
*/
|
||||
ContentManager::get()->lua.create_table();
|
||||
ContentManager::get()->lua["core"]["setting"]["register"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection coresetreg core.setting.register(displayName, key,
|
||||
* defaultValue)
|
||||
* @brief Registers a setting that the player can adjust via the
|
||||
* settings menu
|
||||
*
|
||||
* @param displayName The Display name for the setting seen in the
|
||||
* settings menu
|
||||
* @param key The unique key for the setting, usually in the form
|
||||
* module:setting
|
||||
* @param defaultValue The default value for the setting if not already
|
||||
* set
|
||||
*
|
||||
*/
|
||||
manager->registerFunction(
|
||||
"core.setting.register",
|
||||
[](std::string displayName, std::string key, int defaultValue) {
|
||||
Settings::get()->add(displayName, key, defaultValue);
|
||||
};
|
||||
ContentManager::get()->lua["core"]["setting"]["get"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection coresetget core.setting.get(key)
|
||||
* @brief Gets the value of a setting based on its unique key
|
||||
*
|
||||
* @param key The unique key for the setting, usually in the form
|
||||
* module:setting
|
||||
* @return The integer value of the setting
|
||||
*
|
||||
*/
|
||||
[](std::string key) {
|
||||
return Settings::get()->getSetting(key)->value();
|
||||
};
|
||||
ContentManager::get()->lua["core"]["setting"]["set"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection coresetset core.setting.set(key)
|
||||
* @brief Sets the value of a setting based on its unique key
|
||||
*
|
||||
* @param key The unique key for the setting, usually in the form
|
||||
* module:setting
|
||||
* @param value The value the setting should be set to
|
||||
*
|
||||
*/
|
||||
[](std::string key, int value) {
|
||||
Settings::get()->getSetting(key)->set(value);
|
||||
};
|
||||
});
|
||||
|
||||
manager->registerFunction("core.setting.get", [](std::string key) {
|
||||
return Settings::get()->getSetting(key)->value();
|
||||
});
|
||||
|
||||
manager->registerFunction("core.setting.set",
|
||||
[](std::string key, int value) {
|
||||
Settings::get()->getSetting(key)->set(value);
|
||||
});
|
||||
}
|
||||
|
||||
Setting* Settings::add(const std::string& name, const std::string& key,
|
||||
|
@ -172,4 +128,3 @@ void Settings::save(const std::string& saveFile)
|
|||
file << std::setw(4) << m_data << std::endl;
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,77 +26,34 @@
|
|||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <Common/ContentLoader.hpp>
|
||||
#include <Common/Voxels/BlockRegistry.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
using namespace phx::voxels;
|
||||
using namespace phx;
|
||||
|
||||
BlockRegistry::BlockRegistry()
|
||||
{
|
||||
ContentManager::get()->lua["voxel"] =
|
||||
ContentManager::get()->lua.create_table();
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* ---
|
||||
* ---
|
||||
* @section voxel voxel
|
||||
* @brief The voxel API for interacting voxels
|
||||
*/
|
||||
ContentManager::get()->lua["voxel"]["block"] =
|
||||
ContentManager::get()->lua.create_table();
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* ---
|
||||
* @subsection voxelblock voxel.block
|
||||
* @brief Interfaces with blocks
|
||||
*/
|
||||
ContentManager::get()->lua["voxel"]["block"]["register"] =
|
||||
/**
|
||||
* @addtogroup luaapi
|
||||
*
|
||||
* @subsubsection voxelblockreg voxel.block.register(luaBlock)
|
||||
* @brief Sets the value of a setting based on its unique key
|
||||
*
|
||||
* @param luaBlock a table storing the data used to create a block
|
||||
*
|
||||
* @details The luaBlock table stores the following values: \n
|
||||
* Required:
|
||||
* - @b name: The display name for the block
|
||||
* - @b id: The unique id for the block usually in the form module:block
|
||||
*
|
||||
* Optional:
|
||||
* - @b category: The category of the block chosen from "Air", "Liquid",
|
||||
* or "Solid" \n If not specified, the default is "Solid"
|
||||
* - @b onPlace: A function that is run when the block is placed
|
||||
* - @b onBreak: A function that is run when the block is broken
|
||||
* - @b onInteract: A function that is run when the block is interacted
|
||||
* with
|
||||
* - @b textures: A table of filepaths where textures are located \n
|
||||
* Filepaths are relative to to the module directory \n
|
||||
* If only one filepath is specified, that will be used for
|
||||
* all textures
|
||||
*
|
||||
* @b Example:
|
||||
*
|
||||
* @code {.lua}
|
||||
* block = {}
|
||||
* block.name = "Grass"
|
||||
* block.id = "core.grass"
|
||||
* block.textures = {"Assets/grass_side.png", "Assets/grass_side.png",
|
||||
* "Assets/grass_side.png", "Assets/grass_side.png",
|
||||
* "Assets/grass_top.png", "Assets/dirt.png"}
|
||||
* block.onBreak = function (position)
|
||||
* print("grass broken at" + position)
|
||||
* end
|
||||
* voxel.block.register(block)
|
||||
* @endcode
|
||||
*/
|
||||
[](sol::table luaBlock) {
|
||||
BlockType unknownBlock;
|
||||
unknownBlock.displayName = "Unknown Block";
|
||||
unknownBlock.id = "core.unknown";
|
||||
unknownBlock.category = BlockCategory::SOLID;
|
||||
unknownBlock.setAllTextures("Assets/unknown.png");
|
||||
registerBlock(unknownBlock);
|
||||
|
||||
BlockType outOfBoundsBlock;
|
||||
outOfBoundsBlock.displayName = "Out Of Bounds";
|
||||
outOfBoundsBlock.id = "core.out_of_bounds";
|
||||
outOfBoundsBlock.category = BlockCategory::AIR;
|
||||
registerBlock(outOfBoundsBlock);
|
||||
}
|
||||
|
||||
void BlockRegistry::registerAPI(cms::ModManager* manager)
|
||||
{
|
||||
manager->registerFunction(
|
||||
"voxel.block.register", [manager](sol::table luaBlock) {
|
||||
BlockType block;
|
||||
{
|
||||
block.displayName = luaBlock["name"];
|
||||
|
@ -143,31 +100,14 @@ BlockRegistry::BlockRegistry()
|
|||
// texture in its place
|
||||
texture = luaBlock["textures"][1];
|
||||
}
|
||||
textures[i] = "Modules/" +
|
||||
ContentManager::get()->currentMod + "/" +
|
||||
texture;
|
||||
textures[i] = manager->getCurrentModPath() + texture;
|
||||
}
|
||||
block.textures = textures;
|
||||
|
||||
block.textures = textures;
|
||||
}
|
||||
}
|
||||
BlockRegistry::get()->registerBlock(block);
|
||||
};
|
||||
}
|
||||
|
||||
void BlockRegistry::initialise()
|
||||
{
|
||||
BlockType unknownBlock;
|
||||
unknownBlock.displayName = "Unknown Block";
|
||||
unknownBlock.id = "core.unknown";
|
||||
unknownBlock.category = BlockCategory::SOLID;
|
||||
unknownBlock.setAllTextures("Assets/unknown.png");
|
||||
registerBlock(unknownBlock);
|
||||
|
||||
BlockType outOfBoundsBlock;
|
||||
outOfBoundsBlock.displayName = "Out Of Bounds";
|
||||
outOfBoundsBlock.id = "core.out_of_bounds";
|
||||
outOfBoundsBlock.category = BlockCategory::AIR;
|
||||
registerBlock(outOfBoundsBlock);
|
||||
});
|
||||
}
|
||||
|
||||
void BlockRegistry::registerBlock(BlockType blockInfo)
|
||||
|
@ -210,4 +150,3 @@ BlockType* BlockRegistry::getFromRegistryID(std::size_t registryID)
|
|||
}
|
||||
|
||||
TextureRegistry* BlockRegistry::getTextures() { return &m_textures; }
|
||||
|
||||
|
|
Loading…
Reference in New Issue