Skip to content

Commit

Permalink
Mod-defined server config options. Fixes #105.
Browse files Browse the repository at this point in the history
[Chat] History system with up/down arrow keys.
[ChatCommandHandler] '/option' command added.
  • Loading branch information
Unarelith committed Jun 19, 2020
1 parent cc85f5f commit 00d1cb8
Show file tree
Hide file tree
Showing 13 changed files with 194 additions and 22 deletions.
11 changes: 11 additions & 0 deletions docs/lua-api-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,14 @@ Possible events:
- `BlockActivated`: `function(pos, block, player, world, client, server)`
- `PlayerConnected`: `function(pos, player, client, server)`

### `openminer:get_config(name)`

Get value for config option.

Example:
```lua
use_item_drop = openminer:get_config("default:use_item_drop")
```

See [this page](lua-api-mod.md#config) for more details about config options.

11 changes: 11 additions & 0 deletions docs/lua-api-mod.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@ Defines a block from a table, see [this page](lua-api-block.md) for more informa

Defines a biome from a table, see [this page](lua-api-biome.md) for more information.

### `config`

Defines a config option.

Example:
```lua
mod:option("use_item_drops", false);
```

See [this page](lua-api-core.md#openminerget_configname) for more details.

### `dimension`

Defines a dimension from a table, see [this page](lua-api-dimension.md) for more information.
Expand Down
4 changes: 3 additions & 1 deletion mods/default/item_drop.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ mod:entity {
end,
}

mod:option("use_item_drops", false)

openminer:add_listener(Event.BlockDigged, function(pos, block, player, world, client, server)
if ServerConfig.useItemDrops then
if openminer.get_config("default:use_item_drops")then
mods["default"]:spawn_entity("default:item_drop", {
position = {pos.x + 0.5, pos.y + 0.5, pos.z + 0.5},
dimension = world:dimension():id(),
Expand Down
5 changes: 5 additions & 0 deletions source/client/hud/Chat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,15 @@ class Chat : public gk::Drawable, public gk::Transformable {

void setMessageVisibility(bool areMessagesVisible);

const std::string &getHistoryEntry(u32 id) const { return m_history.at(m_history.size() - id - 1); }
void addHistoryEntry(const std::string &entry) { m_history.emplace_back(entry); }
u32 historySize() const { return m_history.size(); }

private:
void draw(gk::RenderTarget &target, gk::RenderStates states) const override;

std::deque<ChatMessage> m_chatMessages;
std::deque<std::string> m_history;

u32 m_posY = 0;
};
Expand Down
19 changes: 18 additions & 1 deletion source/client/states/ChatState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ void ChatState::onEvent(const sf::Event &event) {
}

if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Return) {
if (!m_textInput.text().empty())
if (!m_textInput.text().empty()) {
m_clientCommandHandler.sendChatMessage(m_textInput.text());
m_chat.addHistoryEntry(m_textInput.text());
}

gk::Mouse::setCursorGrabbed(true);
gk::Mouse::setCursorVisible(false);
Expand All @@ -91,6 +93,21 @@ void ChatState::onEvent(const sf::Event &event) {
if (!m_stateStack->empty())
m_stateStack->pop();
}

if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::Up && m_currentHistoryEntry < (int)m_chat.historySize() - 1) {
if (m_currentHistoryEntry == -1)
m_oldEntry = m_textInput.text();
m_textInput.setText(m_chat.getHistoryEntry(++m_currentHistoryEntry));
}
else if (event.key.code == sf::Keyboard::Down && m_currentHistoryEntry >= 0) {
--m_currentHistoryEntry;
if (m_currentHistoryEntry == -1)
m_textInput.setText(m_oldEntry);
else
m_textInput.setText(m_chat.getHistoryEntry(m_currentHistoryEntry));
}
}
}

void ChatState::draw(gk::RenderTarget &target, gk::RenderStates states) const {
Expand Down
3 changes: 3 additions & 0 deletions source/client/states/ChatState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ class ChatState : public InterfaceState {
ClientCommandHandler &m_clientCommandHandler;

Chat &m_chat;

s32 m_currentHistoryEntry = -1;
std::string m_oldEntry;
};

#endif // CHATSTATE_HPP_
6 changes: 6 additions & 0 deletions source/server/core/ServerApplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ int ServerApplication::run(bool isProtected) {

gkError() << "Fatal error" << e.what();

ServerConfig::saveConfigToFile("config/server.lua");
ServerConfig::options.clear();

m_serverCommandHandler.sendServerClosed(std::string("Server error ") + e.what());

m_registry.clear();
Expand All @@ -132,6 +135,9 @@ int ServerApplication::run(bool isProtected) {

gkInfo() << "Stopping server...";

ServerConfig::saveConfigToFile("config/server.lua");
ServerConfig::options.clear();

m_serverCommandHandler.sendServerClosed("Server closed.");

m_registry.clear();
Expand Down
76 changes: 66 additions & 10 deletions source/server/core/ServerConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,33 @@
*
* =====================================================================================
*/
#include "ServerConfig.hpp"
#include <fstream>

// Gameplay
bool ServerConfig::useItemDrops = false;
#include <gk/core/Debug.hpp>
#include <gk/core/Filesystem.hpp>

#include "ServerConfig.hpp"

// Server
u8 ServerConfig::maxPlayers = 5;

#include <gk/core/Debug.hpp>
#include <gk/core/Filesystem.hpp>
// Mod-defined options
std::unordered_map<std::string, sol::object> ServerConfig::options;

#include <sol/sol.hpp>
static sol::state lua;

void ServerConfig::loadConfigFromFile(const char *file) {
if (gk::Filesystem::fileExists(file)) {
sol::state lua;

try {
lua.safe_script_file(file);

useItemDrops = lua["useItemDrops"].get_or(useItemDrops);
maxPlayers = lua["max_players"].get_or(maxPlayers);

maxPlayers = lua["maxPlayers"].get_or(maxPlayers);
if (lua["mod_options"].valid() && lua["mod_options"].get_type() == sol::type::table) {
for (auto &it : lua["mod_options"].get<sol::table>()) {
options.emplace(it.first.as<std::string>(), it.second);
}
}

gkInfo() << "Config file loaded successfully";
}
Expand All @@ -56,3 +60,55 @@ void ServerConfig::loadConfigFromFile(const char *file) {
}
}

void ServerConfig::saveConfigToFile(const char *filename) {
std::ofstream file{filename, std::ofstream::out | std::ofstream::trunc};
file << "max_players = " << (u16)maxPlayers << std::endl;
file << "mod_options = {" << std::endl;

for (auto &it : options) {
file << "\t[\"" << it.first << "\"] = ";

if (it.second.get_type() == sol::type::boolean) {
bool value = it.second.as<bool>();
file << (value ? "true" : "false");
}
else if (it.second.get_type() == sol::type::number) {
file << it.second.as<double>();
}
else if (it.second.get_type() == sol::type::string) {
file << it.second.as<std::string>();
}
else {
file << "nil";
}

file << "," << std::endl;
}

file << "}" << std::endl;
}

bool ServerConfig::assignOption(const std::string &name, const std::string &value) {
auto it = options.find(name);
if (it != options.end()) {
try {
sol::object object = lua.load("return " + value)();
if (object.valid()
&& (object.get_type() == sol::type::boolean
|| object.get_type() == sol::type::number
|| object.get_type() == sol::type::string)) {
it->second = object;
return true;
}
}
catch (sol::error &e) {
gkWarning() << e.what();
}
}
else {
gkWarning() << "Can't assign option: '" + name + "' doesn't exist";
}

return false;
}

14 changes: 11 additions & 3 deletions source/server/core/ServerConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,24 @@
#ifndef SERVERCONFIG_HPP_
#define SERVERCONFIG_HPP_

#include <string>
#include <unordered_map>

#include <gk/core/IntTypes.hpp>

namespace ServerConfig {
// Gameplay
extern bool useItemDrops;
#include <sol/sol.hpp>

namespace ServerConfig {
// Server
extern u8 maxPlayers;

// Mod-defined options
extern std::unordered_map<std::string, sol::object> options;

void loadConfigFromFile(const char *file);
void saveConfigToFile(const char *file);

bool assignOption(const std::string &name, const std::string &value);
}

#endif // SERVERCONFIG_HPP_
17 changes: 11 additions & 6 deletions source/server/lua/LuaCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,20 @@ void LuaCore::initUsertype(sol::state &lua) {
"PlayerConnected", LuaEventType::PlayerConnected
);

lua["ServerConfig"] = lua.create_table_with(
"useItemDrops", ServerConfig::useItemDrops
);

lua.new_usertype<LuaCore>("LuaCore",
"registry", &LuaCore::m_registry,
"mod_loader", &LuaCore::m_modLoader,

"add_listener", &LuaCore::addListener,
"get_config", [&](const std::string &option) {
auto it = ServerConfig::options.find(option);
if (it == ServerConfig::options.end()) {
gkWarning() << "Option" << option << "doesn't exist";
return sol::object{};
}

"registry", &LuaCore::m_registry,
"mod_loader", &LuaCore::m_modLoader
return it->second;
}
);
}

9 changes: 8 additions & 1 deletion source/server/lua/LuaMod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "PlacementEntry.hpp"
#include "Registry.hpp"
#include "ServerCommandHandler.hpp"
#include "ServerConfig.hpp"
#include "ServerPlayer.hpp"
#include "Tree.hpp"
#include "WorldController.hpp"
Expand Down Expand Up @@ -79,7 +80,13 @@ void LuaMod::initUsertype(sol::state &lua) {
"biome", DEF_FUNC(DefinitionType::Biome),
"dimension", DEF_FUNC(DefinitionType::Dimension),
"key", DEF_FUNC(DefinitionType::Key),
"entity", DEF_FUNC(DefinitionType::Entity)
"entity", DEF_FUNC(DefinitionType::Entity),

"option", [&] (LuaMod &self, const std::string &name, sol::object defaultValue) {
auto it = ServerConfig::options.find(name);
if (it == ServerConfig::options.end())
ServerConfig::options.emplace(self.m_id + ":" + name, defaultValue);
}
);
}

Expand Down
40 changes: 40 additions & 0 deletions source/server/network/ChatCommandHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ void ChatCommandHandler::parseCommand(const std::string &str, ClientInfo &client
{"save", &ChatCommandHandler::saveCommand},
{"load", &ChatCommandHandler::loadCommand},
{"stop", &ChatCommandHandler::stopCommand},
{"option", &ChatCommandHandler::optionCommand},
};

if (!command.empty()) {
Expand Down Expand Up @@ -117,3 +118,42 @@ void ChatCommandHandler::stopCommand(const std::vector<std::string> &, ClientInf
m_server.stopServer();
}

#include "ServerConfig.hpp"

void ChatCommandHandler::optionCommand(const std::vector<std::string> &command, ClientInfo &client) const {
if (command.size() < 2 || command.size() > 3) {
m_server.sendChatMessage(0, "Usage: /option <name> [<value>]", &client);
}
else {
std::string name = command.at(1);

auto it = ServerConfig::options.find(name);
if (it != ServerConfig::options.end()) {
if (command.size() < 3) {
if (it->second.get_type() == sol::type::boolean) {
bool value = it->second.as<bool>();
m_server.sendChatMessage(0, std::string("Value: ") + (value ? "true" : "false"));
}
else if (it->second.get_type() == sol::type::number) {
m_server.sendChatMessage(0, "Value: " + std::to_string(it->second.as<double>()));
}
else if (it->second.get_type() == sol::type::string) {
m_server.sendChatMessage(0, "Value: " + it->second.as<std::string>());
}
else {
m_server.sendChatMessage(0, "Value: nil");
}
}
else {
std::string value = command.at(2);
if (ServerConfig::assignOption(name, value))
m_server.sendChatMessage(0, "Value: " + value);
else
m_server.sendChatMessage(0, "Invalid option value");
}
}
else {
m_server.sendChatMessage(0, "Option '" + name + "' doesn't exist");
}
}
}
1 change: 1 addition & 0 deletions source/server/network/ChatCommandHandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class ChatCommandHandler {
void saveCommand(const std::vector<std::string> &command, ClientInfo &client) const;
void loadCommand(const std::vector<std::string> &command, ClientInfo &client) const;
void stopCommand(const std::vector<std::string> &command, ClientInfo &client) const;
void optionCommand(const std::vector<std::string> &command, ClientInfo &client) const;

ServerCommandHandler &m_server;
WorldController &m_worldController;
Expand Down

0 comments on commit 00d1cb8

Please sign in to comment.