Finalize properties parsing system and load/save

This commit is contained in:
DankParrot 2020-07-23 19:46:37 -07:00
parent 4488d8bcf2
commit ac693ed4e5
6 changed files with 335 additions and 44 deletions

View File

@ -6,7 +6,8 @@ using namespace Feather;
int main()
{
ServerProperties properties("server.properties");
printf("Starting server on port %d\n", properties.Get<int>("server-port"));
properties.Save();
printf("Starting server on port %d\n", properties.serverPort.GetValue());
return 1;
}

47
src/config/Properties.cpp Normal file
View File

@ -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>(string_view key)
{
return properties.at(string(key));
}
template <>
bool Properties::Get<bool>(string_view key)
{
string value = Get<string>(key);
if (StringUtil::iequal(value, STRING_TRUE))
{
return true;
}
else
{
// TODO: complain about non-bool
return false;
}
}
template <>
int Properties::Get<int>(string_view key)
{
return std::stoi(Get<string>(key));
}
template <>
long Properties::Get<long>(string_view key)
{
return std::stol(Get<string>(key));
}
template <>
long long Properties::Get<long long>(string_view key)
{
return std::stoll(Get<string>(key));
}
}

21
src/config/Properties.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <iostream>
#include <string>
#include <string_view>
#include <unordered_map>
using std::string;
using std::string_view;
using std::unordered_map;
namespace Feather
{
class Properties
{
public:
template <typename T> T Get(string_view key);
protected:
unordered_map<string, string> properties;
};
}

68
src/config/Property.h Normal file
View File

@ -0,0 +1,68 @@
#pragma once
#include "Properties.h"
#include "ServerProperties.h"
#include <string>
#include <string_view>
#include <unordered_map>
#include <functional>
using std::string;
using std::string_view;
using std::unordered_map;
namespace Feather
{
template <typename T>
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<T(T)> op, T defaultValue) : key(key), op(op), value(defaultValue) {}
void Init(Properties *properties)
{
try
{
SetValue(properties->Get<T>(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<T(T)> op;
};
template <>
inline string Property<string>::ToString()
{
return value;
}
template <>
inline string Property<bool>::ToString()
{
return value ? "true" : "false";
}
}

View File

@ -3,15 +3,15 @@
#include <fstream>
#include <string_view>
#include <algorithm>
#include <ctime>
#include <cstring>
#include <iomanip>
#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>(string_view key)
{
return properties[string(key)];
}
template <>
bool ServerProperties::Get<bool>(string_view key)
{
string value = Get<string>(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<int>(string_view key)
void ServerProperties::Save()
{
return std::stoi(Get<string>(key));
}
std::ofstream file;
file.open(path);
template <>
long ServerProperties::Get<long>(string_view key)
{
return std::stol(Get<string>(key));
}
file << "#Minecraft server properties" << std::endl;
template <>
long long ServerProperties::Get<long long>(string_view key)
{
return std::stoll(Get<string>(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();
}
}

View File

@ -1,21 +1,127 @@
#pragma once
#include "Properties.h"
#include "Property.h"
#include <iostream>
#include <string>
#include <string_view>
#include <unordered_map>
#include <algorithm>
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 <typename T>
T Get(string_view key);
Property<bool> onlineMode = Property<bool>("online-mode", true);
Property<bool> preventProxyConnections = Property<bool>("prevent-proxy-connections", false);
Property<string> serverIp = Property<string>("server-ip", "");
Property<bool> spawnAnimals = Property<bool>("spawn-animals", true);
Property<bool> spawnNpcs = Property<bool>("spawn-npcs", true);
Property<bool> pvp = Property<bool>("pvp", true);
Property<bool> allowFlight = Property<bool>("allow-flight", false);
Property<string> resourcePack = Property<string>("resource-pack", "");
Property<string> motd = Property<string>("motd", "A Minecraft Server");
Property<bool> forceGameMode = Property<bool>("force-gamemode", false);
Property<bool> enforceWhitelist = Property<bool>("enforce-whitelist", false);
//Property<Difficulty> difficulty = Property<Difficulty>("difficulty", DedicatedServerProperties.dispatchNumberOrString(Difficulty::byId, Difficulty::byName), Difficulty::getKey, Difficulty.EASY);
//Property<GameType> gamemode = Property<GameType>("gamemode", DedicatedServerProperties.dispatchNumberOrString(GameType::byId, GameType::byName), GameType::getName, GameType.SURVIVAL);
Property<string> levelName = Property<string>("level-name", "world");
Property<int> serverPort = Property<int>("server-port", 25565);
Property<int> maxBuildHeight = Property<int>("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<bool> announcePlayerAchievements = Property<bool>("announce-player-achievements");
Property<bool> enableQuery = Property<bool>("enable-query", false);
Property<int> queryPort = Property<int>("query.port", 25565);
Property<bool> enableRcon = Property<bool>("enable-rcon", false);
Property<int> rconPort = Property<int>("rcon.port", 25575);
Property<string> rconPassword = Property<string>("rcon.password", "");
// (REMOVED) Property<string> resourcePackHash = Property<string>("resource-pack-hash");
Property<string> resourcePackSha1 = Property<string>("resource-pack-sha1", "");
Property<bool> hardcore = Property<bool>("hardcore", false);
Property<bool> allowNether = Property<bool>("allow-nether", true);
Property<bool> spawnMonsters = Property<bool>("spawn-monsters", true);
Property<bool> snooperEnabled = Property<bool>("snooper-enabled", true);
Property<bool> useNativeTransport = Property<bool>("use-native-transport", true);
Property<bool> enableCommandBlock = Property<bool>("enable-command-block", false);
Property<int> spawnProtection = Property<int>("spawn-protection", 16);
Property<int> opPermissionLevel = Property<int>("op-permission-level", 4);
Property<int> functionPermissionLevel = Property<int>("function-permission-level", 2);
Property<long> maxTickTime = Property<long>("max-tick-time");//, TimeUnit.MINUTES.toMillis(1L));
Property<int> viewDistance = Property<int>("view-distance", 10);
Property<int> maxPlayers = Property<int>("max-players", 20);
Property<int> networkCompressionThreshold = Property<int>("network-compression-threshold", 256);
Property<bool> broadcastRconToOps = Property<bool>("broadcast-rcon-to-ops", true);
Property<bool> broadcastConsoleToOps = Property<bool>("broadcast-console-to-ops", true);
Property<int> maxWorldSize = Property<int>("max-world-size", [](int n) { return std::clamp(n, 1, 29999984); }, 29999984);
Property<bool> syncChunkWrites = Property<bool>("sync-chunk-writes", true);
Property<bool> enableJmxMonitoring = Property<bool>("enable-jmx-monitoring", false);
Property<bool> enableStatus = Property<bool>("enable-status", true);
Property<int> entityBroadcastRangePercentage = Property<int>("entity-broadcast-range-percentage", [](int n) { return std::clamp(n, 10, 1000); }, 100);
/*mutable*/ Property<int> playerIdleTimeout = Property<int>("player-idle-timeout", 0);
/*mutable*/ Property<bool> whiteList = Property<bool>("white-list", false);
//Property<WorldGenSettings> 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<string, string> properties;
const char* path;
};
}