From ac693ed4e5c5ab3dbe639e9d287e02ab33cec319 Mon Sep 17 00:00:00 2001 From: DankParrot Date: Thu, 23 Jul 2020 19:46:37 -0700 Subject: [PATCH] Finalize properties parsing system and load/save --- src/Main.cpp | 3 +- src/config/Properties.cpp | 47 ++++++++++++ src/config/Properties.h | 21 ++++++ src/config/Property.h | 68 ++++++++++++++++++ src/config/ServerProperties.cpp | 124 ++++++++++++++++++++++---------- src/config/ServerProperties.h | 116 ++++++++++++++++++++++++++++-- 6 files changed, 335 insertions(+), 44 deletions(-) create mode 100644 src/config/Properties.cpp create mode 100644 src/config/Properties.h create mode 100644 src/config/Property.h diff --git a/src/Main.cpp b/src/Main.cpp index 55a3442..14e81e4 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -6,7 +6,8 @@ using namespace Feather; int main() { ServerProperties properties("server.properties"); - printf("Starting server on port %d\n", properties.Get("server-port")); + properties.Save(); + printf("Starting server on port %d\n", properties.serverPort.GetValue()); return 1; } diff --git a/src/config/Properties.cpp b/src/config/Properties.cpp new file mode 100644 index 0000000..1f4700a --- /dev/null +++ b/src/config/Properties.cpp @@ -0,0 +1,47 @@ +#include "Properties.h" +#include "../util/StringUtil.h" + +static const string STRING_TRUE("true"); +static const string STRING_FALSE("false"); + +namespace Feather +{ + template <> + string Properties::Get(string_view key) + { + return properties.at(string(key)); + } + + template <> + bool Properties::Get(string_view key) + { + string value = Get(key); + if (StringUtil::iequal(value, STRING_TRUE)) + { + return true; + } + else + { + // TODO: complain about non-bool + return false; + } + } + + template <> + int Properties::Get(string_view key) + { + return std::stoi(Get(key)); + } + + template <> + long Properties::Get(string_view key) + { + return std::stol(Get(key)); + } + + template <> + long long Properties::Get(string_view key) + { + return std::stoll(Get(key)); + } +} \ No newline at end of file diff --git a/src/config/Properties.h b/src/config/Properties.h new file mode 100644 index 0000000..9e6680b --- /dev/null +++ b/src/config/Properties.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include +#include + +using std::string; +using std::string_view; +using std::unordered_map; + +namespace Feather +{ + class Properties + { + public: + template T Get(string_view key); + protected: + unordered_map properties; + }; +} \ No newline at end of file diff --git a/src/config/Property.h b/src/config/Property.h new file mode 100644 index 0000000..15bd744 --- /dev/null +++ b/src/config/Property.h @@ -0,0 +1,68 @@ +#pragma once + +#include "Properties.h" +#include "ServerProperties.h" + +#include +#include +#include +#include + +using std::string; +using std::string_view; +using std::unordered_map; + +namespace Feather +{ + + template + class Property + { + public: + Property(string_view key) : key(key) {} + Property(string_view key, T defaultValue) : key(key), value(defaultValue) {} + Property(string_view key, std::function op, T defaultValue) : key(key), op(op), value(defaultValue) {} + + void Init(Properties *properties) + { + try + { + SetValue(properties->Get(key)); + } + catch (std::out_of_range err) + { + // process default value from constructor + SetValue(value); + } + } + + virtual void SetValue(T value) + { + if (op) { + this->value = op(value); + } else { + this->value = value; + } + } + virtual T GetValue() { return value; } + + inline string ToString() { return std::to_string(value); } + + string_view key; + private: + T value = T(); + std::function op; + }; + + template <> + inline string Property::ToString() + { + return value; + } + + template <> + inline string Property::ToString() + { + return value ? "true" : "false"; + } +} \ No newline at end of file diff --git a/src/config/ServerProperties.cpp b/src/config/ServerProperties.cpp index 754b58b..50d2cc8 100644 --- a/src/config/ServerProperties.cpp +++ b/src/config/ServerProperties.cpp @@ -3,15 +3,15 @@ #include #include #include +#include +#include +#include #include "../util/StringUtil.h" -static const string STRING_TRUE("true"); -static const string STRING_FALSE("false"); - namespace Feather { - ServerProperties::ServerProperties(const char* path) + void ServerProperties::Load() { std::ifstream file; file.open(path); @@ -47,45 +47,93 @@ namespace Feather } file.close(); } - - //for ( auto const& pair : properties ) - // std::cout << "[" << pair.first << "] = [" << pair.second << "]\n"; - - } - - template <> - string ServerProperties::Get(string_view key) - { - return properties[string(key)]; - } - - template <> - bool ServerProperties::Get(string_view key) - { - string value = Get(key); - if (StringUtil::iequal(value, STRING_TRUE)) { - return true; - } else { - // TODO: complain about non-bool - return false; + else + { + printf("Could not find %s\n"); } } - template <> - int ServerProperties::Get(string_view key) + void ServerProperties::Save() { - return std::stoi(Get(key)); - } + std::ofstream file; + file.open(path); - template <> - long ServerProperties::Get(string_view key) - { - return std::stol(Get(key)); - } + file << "#Minecraft server properties" << std::endl; - template <> - long long ServerProperties::Get(string_view key) - { - return std::stoll(Get(key)); + auto time = std::time(nullptr); + auto localTime = *std::localtime(&time); + + // The following code abbreviates a time zone like "Pacifc Daylight Time" + // to a short form like "PDT". If the time zone is already abbreviated + // then it won't change the abbreviation + + char timeZone[256]; + strftime(timeZone, 256, "%Z", &localTime); + + char timeZoneAbbr[5]; + int counter = 0; + for (int i = 0; i < strlen(timeZone); i++) + { + char c = timeZone[i]; + if (std::isupper(c)) { + timeZoneAbbr[counter++] = c; + // stop before last char to insert 0 + if (counter >= 4) { + timeZoneAbbr[counter] = 0; + break; + } + } + } + + // Ex: Thu Jul 23 01:43:47 PDT 2020 + file << "#" << std::put_time(&localTime, "%a %b %d %H:%M:%S ") << timeZoneAbbr << std::put_time(&localTime, " %Y") << std::endl; + + file << onlineMode.key << "=" << onlineMode.ToString() << std::endl; + file << preventProxyConnections.key << "=" << preventProxyConnections.ToString() << std::endl; + file << serverIp.key << "=" << serverIp.ToString() << std::endl; + file << spawnAnimals.key << "=" << spawnAnimals.ToString() << std::endl; + file << spawnNpcs.key << "=" << spawnNpcs.ToString() << std::endl; + file << pvp.key << "=" << pvp.ToString() << std::endl; + file << allowFlight.key << "=" << allowFlight.ToString() << std::endl; + file << resourcePack.key << "=" << resourcePack.ToString() << std::endl; + file << motd.key << "=" << motd.ToString() << std::endl; + file << forceGameMode.key << "=" << forceGameMode.ToString() << std::endl; + file << enforceWhitelist.key << "=" << enforceWhitelist.ToString() << std::endl; + file << levelName.key << "=" << levelName.ToString() << std::endl; + file << serverPort.key << "=" << serverPort.ToString() << std::endl; + file << maxBuildHeight.key << "=" << maxBuildHeight.ToString() << std::endl; + //file << announcePlayerAchievements.key << "=" << announcePlayerAchievements.ToString() << std::endl; + file << enableQuery.key << "=" << enableQuery.ToString() << std::endl; + file << queryPort.key << "=" << queryPort.ToString() << std::endl; + file << enableRcon.key << "=" << enableRcon.ToString() << std::endl; + file << rconPort.key << "=" << rconPort.ToString() << std::endl; + file << rconPassword.key << "=" << rconPassword.ToString() << std::endl; + //file << resourcePackHash.key << "=" << resourcePackHash.ToString() << std::endl; + file << resourcePackSha1.key << "=" << resourcePackSha1.ToString() << std::endl; + file << hardcore.key << "=" << hardcore.ToString() << std::endl; + file << allowNether.key << "=" << allowNether.ToString() << std::endl; + file << spawnMonsters.key << "=" << spawnMonsters.ToString() << std::endl; + file << snooperEnabled.key << "=" << snooperEnabled.ToString() << std::endl; + file << useNativeTransport.key << "=" << useNativeTransport.ToString() << std::endl; + file << enableCommandBlock.key << "=" << enableCommandBlock.ToString() << std::endl; + file << spawnProtection.key << "=" << spawnProtection.ToString() << std::endl; + file << opPermissionLevel.key << "=" << opPermissionLevel.ToString() << std::endl; + file << functionPermissionLevel.key << "=" << functionPermissionLevel.ToString() << std::endl; + file << maxTickTime.key << "=" << maxTickTime.ToString() << std::endl; + file << viewDistance.key << "=" << viewDistance.ToString() << std::endl; + file << maxPlayers.key << "=" << maxPlayers.ToString() << std::endl; + file << networkCompressionThreshold.key << "=" << networkCompressionThreshold.ToString() << std::endl; + file << broadcastRconToOps.key << "=" << broadcastRconToOps.ToString() << std::endl; + file << broadcastConsoleToOps.key << "=" << broadcastConsoleToOps.ToString() << std::endl; + file << maxWorldSize.key << "=" << maxWorldSize.ToString() << std::endl; + file << syncChunkWrites.key << "=" << syncChunkWrites.ToString() << std::endl; + file << enableJmxMonitoring.key << "=" << enableJmxMonitoring.ToString() << std::endl; + file << enableStatus.key << "=" << enableStatus.ToString() << std::endl; + file << entityBroadcastRangePercentage.key << "=" << entityBroadcastRangePercentage.ToString() << std::endl; + file << playerIdleTimeout.key << "=" << playerIdleTimeout.ToString() << std::endl; + file << whiteList.key << "=" << whiteList.ToString() << std::endl; + + file << std::endl; + file.close(); } } \ No newline at end of file diff --git a/src/config/ServerProperties.h b/src/config/ServerProperties.h index 67c8e47..5113ee5 100644 --- a/src/config/ServerProperties.h +++ b/src/config/ServerProperties.h @@ -1,21 +1,127 @@ #pragma once +#include "Properties.h" +#include "Property.h" + +#include #include +#include #include +#include using std::string; using std::string_view; +using std::unordered_map; namespace Feather { - class ServerProperties + class ServerProperties : public Properties { public: - ServerProperties(const char* path); - template - T Get(string_view key); + Property onlineMode = Property("online-mode", true); + Property preventProxyConnections = Property("prevent-proxy-connections", false); + Property serverIp = Property("server-ip", ""); + Property spawnAnimals = Property("spawn-animals", true); + Property spawnNpcs = Property("spawn-npcs", true); + Property pvp = Property("pvp", true); + Property allowFlight = Property("allow-flight", false); + Property resourcePack = Property("resource-pack", ""); + Property motd = Property("motd", "A Minecraft Server"); + Property forceGameMode = Property("force-gamemode", false); + Property enforceWhitelist = Property("enforce-whitelist", false); + //Property difficulty = Property("difficulty", DedicatedServerProperties.dispatchNumberOrString(Difficulty::byId, Difficulty::byName), Difficulty::getKey, Difficulty.EASY); + //Property gamemode = Property("gamemode", DedicatedServerProperties.dispatchNumberOrString(GameType::byId, GameType::byName), GameType::getName, GameType.SURVIVAL); + Property levelName = Property("level-name", "world"); + Property serverPort = Property("server-port", 25565); + Property maxBuildHeight = Property("max-build-height", [](int n) { return std::clamp((n + 8) / 16 * 16, 64, 256); }, 256); // round to nearest 16, clamp to range [64, 256] + // (REMOVED) Property announcePlayerAchievements = Property("announce-player-achievements"); + Property enableQuery = Property("enable-query", false); + Property queryPort = Property("query.port", 25565); + Property enableRcon = Property("enable-rcon", false); + Property rconPort = Property("rcon.port", 25575); + Property rconPassword = Property("rcon.password", ""); + // (REMOVED) Property resourcePackHash = Property("resource-pack-hash"); + Property resourcePackSha1 = Property("resource-pack-sha1", ""); + Property hardcore = Property("hardcore", false); + Property allowNether = Property("allow-nether", true); + Property spawnMonsters = Property("spawn-monsters", true); + + Property snooperEnabled = Property("snooper-enabled", true); + Property useNativeTransport = Property("use-native-transport", true); + Property enableCommandBlock = Property("enable-command-block", false); + Property spawnProtection = Property("spawn-protection", 16); + Property opPermissionLevel = Property("op-permission-level", 4); + Property functionPermissionLevel = Property("function-permission-level", 2); + Property maxTickTime = Property("max-tick-time");//, TimeUnit.MINUTES.toMillis(1L)); + Property viewDistance = Property("view-distance", 10); + Property maxPlayers = Property("max-players", 20); + Property networkCompressionThreshold = Property("network-compression-threshold", 256); + Property broadcastRconToOps = Property("broadcast-rcon-to-ops", true); + Property broadcastConsoleToOps = Property("broadcast-console-to-ops", true); + Property maxWorldSize = Property("max-world-size", [](int n) { return std::clamp(n, 1, 29999984); }, 29999984); + Property syncChunkWrites = Property("sync-chunk-writes", true); + Property enableJmxMonitoring = Property("enable-jmx-monitoring", false); + Property enableStatus = Property("enable-status", true); + Property entityBroadcastRangePercentage = Property("entity-broadcast-range-percentage", [](int n) { return std::clamp(n, 10, 1000); }, 100); + /*mutable*/ Property playerIdleTimeout = Property("player-idle-timeout", 0); + /*mutable*/ Property whiteList = Property("white-list", false); + //Property worldGenSettings = WorldGenSettings.create(properties); + + ServerProperties(const char* path) : path(path) + { + Load(); + + onlineMode.Init(this); + preventProxyConnections.Init(this); + serverIp.Init(this); + spawnAnimals.Init(this); + spawnNpcs.Init(this); + pvp.Init(this); + allowFlight.Init(this); + resourcePack.Init(this); + motd.Init(this); + forceGameMode.Init(this); + enforceWhitelist.Init(this); + levelName.Init(this); + serverPort.Init(this); + maxBuildHeight.Init(this); + //announcePlayerAchievements.Init(this); + enableQuery.Init(this); + queryPort.Init(this); + enableRcon.Init(this); + rconPort.Init(this); + rconPassword.Init(this); + //resourcePackHash.Init(this); + resourcePackSha1.Init(this); + hardcore.Init(this); + allowNether.Init(this); + spawnMonsters.Init(this); + snooperEnabled.Init(this); + useNativeTransport.Init(this); + enableCommandBlock.Init(this); + spawnProtection.Init(this); + opPermissionLevel.Init(this); + functionPermissionLevel.Init(this); + maxTickTime.Init(this); + viewDistance.Init(this); + maxPlayers.Init(this); + networkCompressionThreshold.Init(this); + broadcastRconToOps.Init(this); + broadcastConsoleToOps.Init(this); + maxWorldSize.Init(this); + syncChunkWrites.Init(this); + enableJmxMonitoring.Init(this); + enableStatus.Init(this); + entityBroadcastRangePercentage.Init(this); + playerIdleTimeout.Init(this); + whiteList.Init(this); + + } + + void Load(); + void Save(); private: - std::unordered_map properties; + const char* path; }; } \ No newline at end of file