Initial commit
This commit is contained in:
commit
c356c7b911
100 files changed
+8788
No files matched your search
@@ -0,0 +1,559 @@
|
||||
#include "stdafx.h"
|
||||
#include "DedicatedServer.h"
|
||||
|
||||
#include "../../Minecraft.Client/MinecraftServer.h"
|
||||
#include "../../Minecraft.Client/Minecraft.h"
|
||||
#include "../../Minecraft.Client/ProgressRenderer.h"
|
||||
#include "../../Minecraft.Client/GameRenderer.h"
|
||||
#include "../../Minecraft.Client/Options.h"
|
||||
#include "../../Minecraft.Client/User.h"
|
||||
#include "../../Minecraft.Client/StatsCounter.h"
|
||||
#include "../../Minecraft.Client/Windows64/Network/WinsockNetLayer.h"
|
||||
#include "../../Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h"
|
||||
#include "../../Minecraft.World/Minecraft.World.h"
|
||||
#include "../../Minecraft.World/System.h"
|
||||
#include "../../Minecraft.World/AABB.h"
|
||||
#include "../../Minecraft.World/Vec3.h"
|
||||
#include "../../Minecraft.World/IntCache.h"
|
||||
#include "../../Minecraft.World/compression.h"
|
||||
#include "../../Minecraft.World/OldChunkStorage.h"
|
||||
#include "../../Minecraft.World/Level.h"
|
||||
#include "../../Minecraft.World/Tile.h"
|
||||
#include "../../Minecraft.World/Entity.h"
|
||||
#include "../../Minecraft.World/SharedConstants.h"
|
||||
#include "../../Minecraft.World/ChunkSource.h"
|
||||
#include "ServerLogger.h"
|
||||
#include "ServerLists.h"
|
||||
#include "../Commands/ServerCommands.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <conio.h>
|
||||
#endif
|
||||
|
||||
DedicatedServer::DedicatedServer()
|
||||
: m_running(false)
|
||||
{
|
||||
}
|
||||
|
||||
DedicatedServer::~DedicatedServer()
|
||||
{
|
||||
}
|
||||
|
||||
bool DedicatedServer::init()
|
||||
{
|
||||
if (!m_properties.load(L"server.properties"))
|
||||
{
|
||||
ServerLog(L"server.properties not found, generating defaults\n");
|
||||
m_properties.save(L"server.properties");
|
||||
}
|
||||
|
||||
ServerLog(L"Loading properties\n");
|
||||
ServerLog(L"Default game type: %s\n", m_properties.gamemode == 0 ? L"SURVIVAL" : L"CREATIVE");
|
||||
ServerLog(L"Max players: %d\n", m_properties.maxPlayers);
|
||||
ServerLog(L"Difficulty: %d\n", m_properties.difficulty);
|
||||
ServerLog(L"Level size: %s\n", m_properties.levelSize.c_str());
|
||||
|
||||
ServerLists_Init(m_properties.whiteList, &m_properties);
|
||||
|
||||
extern bool g_voiceChatEnabled;
|
||||
g_voiceChatEnabled = m_properties.voiceChat;
|
||||
|
||||
extern bool g_ServerAdvertiseLAN;
|
||||
g_ServerAdvertiseLAN = m_properties.advertiseLan;
|
||||
|
||||
extern char g_ServerBindAddress[256];
|
||||
if (!m_properties.serverIp.empty())
|
||||
{
|
||||
wcstombs(g_ServerBindAddress, m_properties.serverIp.c_str(), sizeof(g_ServerBindAddress) - 1);
|
||||
g_ServerBindAddress[sizeof(g_ServerBindAddress) - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ServerBindAddress[0] = '\0';
|
||||
}
|
||||
if (g_voiceChatEnabled && m_properties.maxPlayers > 8)
|
||||
{
|
||||
ServerLog(L"Voice chat has been disabled: max-players (%d) exceeds the maximum supported for voice chat (8)\n", m_properties.maxPlayers);
|
||||
g_voiceChatEnabled = false;
|
||||
}
|
||||
else if (g_voiceChatEnabled)
|
||||
{
|
||||
ServerLog(L"Voice chat is enabled\n");
|
||||
}
|
||||
|
||||
AABB::CreateNewThreadStorage();
|
||||
Vec3::CreateNewThreadStorage();
|
||||
IntCache::CreateNewThreadStorage();
|
||||
Compression::CreateNewThreadStorage();
|
||||
OldChunkStorage::CreateNewThreadStorage();
|
||||
Level::enableLightingCache();
|
||||
Tile::CreateNewThreadStorage();
|
||||
|
||||
MinecraftWorld_RunStaticCtors();
|
||||
|
||||
{
|
||||
wchar_t exePath[MAX_PATH];
|
||||
if (GetModuleFileNameW(NULL, exePath, MAX_PATH))
|
||||
{
|
||||
wstring exeDir(exePath);
|
||||
size_t lastSlash = exeDir.find_last_of(L"\\/");
|
||||
if (lastSlash != wstring::npos)
|
||||
exeDir = exeDir.substr(0, lastSlash);
|
||||
SetCurrentDirectoryW(exeDir.c_str());
|
||||
#ifdef __linux__
|
||||
wstring gameHDDPath = exeDir + L"/Linux/GameHDD";
|
||||
CreateDirectoryW((exeDir + L"/Linux").c_str(), NULL);
|
||||
#else
|
||||
wstring gameHDDPath = exeDir + L"\\Windows64\\GameHDD";
|
||||
CreateDirectoryW((exeDir + L"\\Windows64").c_str(), NULL);
|
||||
#endif
|
||||
CreateDirectoryW(gameHDDPath.c_str(), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
StorageManager.Init(1, app.GetString(IDS_DEFAULT_SAVENAME), "savegame.dat", FIFTY_ONE_MB, NULL, NULL, "MinecraftDedicatedServer");
|
||||
StorageManager.SetMaxSaves(99);
|
||||
StorageManager.StoreTMSPathName();
|
||||
|
||||
g_NetworkManager.Initialise();
|
||||
|
||||
for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
||||
{
|
||||
IQNet::m_player[i].m_smallId = (BYTE)i;
|
||||
IQNet::m_player[i].m_isRemote = false;
|
||||
IQNet::m_player[i].m_isHostPlayer = (i == 0);
|
||||
swprintf_s(IQNet::m_player[i].m_gamertag, 32, L"Server%d", i);
|
||||
}
|
||||
wcscpy_s(IQNet::m_player[0].m_gamertag, 32, m_properties.motd.c_str());
|
||||
|
||||
WinsockNetLayer::Initialize();
|
||||
|
||||
app.SetGameHostOption(eGameHostOption_Difficulty, m_properties.difficulty);
|
||||
app.SetGameHostOption(eGameHostOption_GameType, m_properties.gamemode);
|
||||
app.SetGameHostOption(eGameHostOption_PvP, m_properties.pvp ? 1 : 0);
|
||||
app.SetGameHostOption(eGameHostOption_TrustPlayers, m_properties.trustPlayers ? 1 : 0);
|
||||
app.SetGameHostOption(eGameHostOption_FireSpreads, m_properties.fireSpreads ? 1 : 0);
|
||||
app.SetGameHostOption(eGameHostOption_TNT, m_properties.tntExplodes ? 1 : 0);
|
||||
app.SetGameHostOption(eGameHostOption_Structures, m_properties.structures ? 1 : 0);
|
||||
app.SetGameHostOption(eGameHostOption_Gamertags, m_properties.showGamertags ? 1 : 0);
|
||||
|
||||
Minecraft *pMinecraft = new Minecraft(NULL, NULL, NULL, 1, 1, false);
|
||||
pMinecraft->options = new Options(pMinecraft, File(L"."));
|
||||
pMinecraft->progressRenderer = new ProgressRenderer(pMinecraft);
|
||||
pMinecraft->gameRenderer = new GameRenderer(pMinecraft);
|
||||
for (int i = 0; i < 4; i++)
|
||||
pMinecraft->stats[i] = new StatsCounter();
|
||||
|
||||
{
|
||||
static DWORD dwProfileSettingsA[5] = {0, 0, 0, 0, 0};
|
||||
ProfileManager.Initialise(TITLEID_MINECRAFT,
|
||||
app.m_dwOfferID,
|
||||
PROFILE_VERSION_10,
|
||||
5,
|
||||
4,
|
||||
dwProfileSettingsA,
|
||||
app.GAME_DEFINED_PROFILE_DATA_BYTES * XUSER_MAX_COUNT,
|
||||
&app.uiGameDefinedDataChangedBitmask);
|
||||
}
|
||||
|
||||
app.InitGameSettings();
|
||||
|
||||
if (!m_properties.serverIp.empty())
|
||||
ServerLog(L"Starting Minecraft server on %s:%d\n", m_properties.serverIp.c_str(), m_properties.serverPort);
|
||||
else
|
||||
ServerLog(L"Starting Minecraft server on *:%d\n", m_properties.serverPort);
|
||||
m_running = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
int DedicatedServer::run()
|
||||
{
|
||||
if (!m_running)
|
||||
{
|
||||
ServerWarn(L"Server not initialized!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ServerLog(L"Preparing level \"%s\"\n", m_properties.levelName.c_str());
|
||||
|
||||
StorageManager.GetSavesInfo(0, NULL, NULL, NULL);
|
||||
PSAVE_DETAILS pSaveDetails = StorageManager.ReturnSavesInfo();
|
||||
if (pSaveDetails && pSaveDetails->iSaveC > 0)
|
||||
{
|
||||
int bestIdx = 0;
|
||||
time_t bestTime = pSaveDetails->SaveInfoA[0].metaData.modifiedTime;
|
||||
for (int i = 1; i < pSaveDetails->iSaveC; i++)
|
||||
{
|
||||
if (pSaveDetails->SaveInfoA[i].metaData.modifiedTime > bestTime)
|
||||
{
|
||||
bestTime = pSaveDetails->SaveInfoA[i].metaData.modifiedTime;
|
||||
bestIdx = i;
|
||||
}
|
||||
}
|
||||
ServerLog(L"Loading existing world from save \"%S\"\n", pSaveDetails->SaveInfoA[bestIdx].UTF8SaveFilename);
|
||||
StorageManager.LoadSaveData(&pSaveDetails->SaveInfoA[bestIdx], NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerLog(L"No existing save found, creating new world\n");
|
||||
wstring title = m_properties.levelName;
|
||||
StorageManager.SetSaveTitle(title.c_str());
|
||||
}
|
||||
|
||||
g_NetworkManager.HostGame(1, true, false, (unsigned char)m_properties.maxPlayers, 0);
|
||||
|
||||
extern CPlatformNetworkManagerStub *g_pPlatformNetworkManager;
|
||||
g_pPlatformNetworkManager->NotifyPlayerJoined(&IQNet::m_player[0]);
|
||||
|
||||
g_NetworkManager.ServerReadyCreate(true);
|
||||
g_NetworkManager.ServerStoppedCreate(true);
|
||||
|
||||
NetworkGameInitData initData;
|
||||
initData.seed = m_properties.levelSeed;
|
||||
initData.saveData = NULL;
|
||||
initData.settings = 0;
|
||||
initData.levelGen = NULL;
|
||||
initData.texturePackId = 0;
|
||||
initData.findSeed = (m_properties.levelSeed == 0);
|
||||
|
||||
if (m_properties.levelSize == L"classic")
|
||||
{
|
||||
initData.xzSize = 1 * 54;
|
||||
initData.hellScale = 3;
|
||||
}
|
||||
else if (m_properties.levelSize == L"small")
|
||||
{
|
||||
initData.xzSize = 1 * 64;
|
||||
initData.hellScale = 3;
|
||||
}
|
||||
else if (m_properties.levelSize == L"medium")
|
||||
{
|
||||
initData.xzSize = 3 * 64;
|
||||
initData.hellScale = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
initData.xzSize = LEVEL_MAX_WIDTH;
|
||||
initData.hellScale = HELL_LEVEL_MAX_SCALE;
|
||||
}
|
||||
|
||||
AABB::CreateNewThreadStorage();
|
||||
Vec3::CreateNewThreadStorage();
|
||||
IntCache::CreateNewThreadStorage();
|
||||
Compression::UseDefaultThreadStorage();
|
||||
Entity::useSmallIds();
|
||||
Level::enableLightingCache();
|
||||
Tile::CreateNewThreadStorage();
|
||||
|
||||
ServerLog(L"Preparing start region for level 0\n");
|
||||
MinecraftServer::main(m_properties.levelSeed, &initData);
|
||||
|
||||
g_NetworkManager.ServerReadyDestroy();
|
||||
g_NetworkManager.ServerStoppedDestroy();
|
||||
|
||||
ServerLog(L"Server stopped\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DedicatedServer::shutdown()
|
||||
{
|
||||
ServerLog(L"Stopping server\n");
|
||||
m_running = false;
|
||||
MinecraftServer::HaltServer();
|
||||
|
||||
Tile::ReleaseThreadStorage();
|
||||
IntCache::ReleaseThreadStorage();
|
||||
AABB::ReleaseThreadStorage();
|
||||
Vec3::ReleaseThreadStorage();
|
||||
Level::destroyLightingCache();
|
||||
|
||||
g_NetworkManager.Terminate();
|
||||
ServerLog(L"Shutdown complete\n");
|
||||
}
|
||||
|
||||
void DedicatedServer::info(const wstring& string)
|
||||
{
|
||||
ServerLog(L"%s\n", string.c_str());
|
||||
}
|
||||
|
||||
void DedicatedServer::warn(const wstring& string)
|
||||
{
|
||||
ServerWarn(L"%s\n", string.c_str());
|
||||
}
|
||||
|
||||
wstring DedicatedServer::getConsoleName()
|
||||
{
|
||||
return L"Server";
|
||||
}
|
||||
|
||||
int DedicatedServer::consoleInputThread(void *param)
|
||||
{
|
||||
DedicatedServer *server = (DedicatedServer *)param;
|
||||
|
||||
#ifdef __linux__
|
||||
struct termios origTermios;
|
||||
tcgetattr(STDIN_FILENO, &origTermios);
|
||||
{
|
||||
struct termios raw = origTermios;
|
||||
raw.c_lflag &= ~(ICANON | ECHO);
|
||||
raw.c_cc[VMIN] = 1;
|
||||
raw.c_cc[VTIME] = 0;
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
|
||||
}
|
||||
#endif
|
||||
|
||||
wstring buffer;
|
||||
vector<wstring> history;
|
||||
int historyPos = -1;
|
||||
wstring savedBuffer;
|
||||
ServerLog_RegisterInput(&buffer);
|
||||
|
||||
auto clearLine = [&]() {
|
||||
if (buffer.empty()) return;
|
||||
#ifdef __linux__
|
||||
for (size_t i = 0; i < buffer.size(); i++)
|
||||
printf("\b \b");
|
||||
fflush(stdout);
|
||||
#else
|
||||
for (size_t i = 0; i < buffer.size(); i++)
|
||||
wprintf(L"\b \b");
|
||||
#endif
|
||||
};
|
||||
|
||||
auto redrawLine = [&]() {
|
||||
#ifdef __linux__
|
||||
printf("%ls", buffer.c_str());
|
||||
fflush(stdout);
|
||||
#else
|
||||
wprintf(L"%s", buffer.c_str());
|
||||
#endif
|
||||
};
|
||||
|
||||
while (server->m_running)
|
||||
{
|
||||
#ifdef __linux__
|
||||
char c;
|
||||
if (read(STDIN_FILENO, &c, 1) <= 0) break;
|
||||
wchar_t wc = (wchar_t)(unsigned char)c;
|
||||
#else
|
||||
wchar_t wc = _getwch();
|
||||
#endif
|
||||
|
||||
if (wc == L'\t')
|
||||
{
|
||||
ServerLog_LockOutput();
|
||||
MinecraftServer *mcServer = MinecraftServer::getInstance();
|
||||
vector<wstring> completions = GetServerCommandCompletions(buffer, mcServer);
|
||||
|
||||
if (completions.size() == 1)
|
||||
{
|
||||
size_t lastSpace = buffer.find_last_of(L' ');
|
||||
wstring currentWord = (lastSpace == wstring::npos) ? buffer : buffer.substr(lastSpace + 1);
|
||||
wstring toAppend = completions[0].substr(currentWord.size()) + L" ";
|
||||
buffer += toAppend;
|
||||
#ifdef __linux__
|
||||
printf("%ls", toAppend.c_str());
|
||||
fflush(stdout);
|
||||
#else
|
||||
wprintf(L"%s", toAppend.c_str());
|
||||
#endif
|
||||
}
|
||||
else if (completions.size() > 1)
|
||||
{
|
||||
wstring common = completions[0];
|
||||
for (size_t i = 1; i < completions.size(); i++)
|
||||
{
|
||||
size_t j = 0;
|
||||
while (j < common.size() && j < completions[i].size() &&
|
||||
towlower(common[j]) == towlower(completions[i][j]))
|
||||
j++;
|
||||
common = common.substr(0, j);
|
||||
}
|
||||
|
||||
size_t lastSpace = buffer.find_last_of(L' ');
|
||||
wstring currentWord = (lastSpace == wstring::npos) ? buffer : buffer.substr(lastSpace + 1);
|
||||
|
||||
if (common.size() > currentWord.size())
|
||||
{
|
||||
wstring toAppend = common.substr(currentWord.size());
|
||||
buffer += toAppend;
|
||||
#ifdef __linux__
|
||||
printf("%ls", toAppend.c_str());
|
||||
fflush(stdout);
|
||||
#else
|
||||
wprintf(L"%s", toAppend.c_str());
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __linux__
|
||||
printf("\n");
|
||||
for (size_t i = 0; i < completions.size(); i++)
|
||||
printf("%ls ", completions[i].c_str());
|
||||
printf("\n%ls", buffer.c_str());
|
||||
fflush(stdout);
|
||||
#else
|
||||
wprintf(L"\n");
|
||||
for (size_t i = 0; i < completions.size(); i++)
|
||||
wprintf(L"%s ", completions[i].c_str());
|
||||
wprintf(L"\n%s", buffer.c_str());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
ServerLog_UnlockOutput();
|
||||
}
|
||||
else if (wc == L'\r' || wc == L'\n')
|
||||
{
|
||||
ServerLog_LockOutput();
|
||||
#ifdef __linux__
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
#else
|
||||
wprintf(L"\n");
|
||||
#endif
|
||||
wstring cmd = buffer;
|
||||
buffer.clear();
|
||||
ServerLog_UnlockOutput();
|
||||
if (!cmd.empty())
|
||||
{
|
||||
if (history.empty() || history.back() != cmd)
|
||||
history.push_back(cmd);
|
||||
historyPos = -1;
|
||||
|
||||
if (cmd == L"stop" || cmd == L"quit" || cmd == L"exit")
|
||||
{
|
||||
ServerLog(L"Stopping the server\n");
|
||||
MinecraftServer::HaltServer();
|
||||
server->m_running = false;
|
||||
break;
|
||||
}
|
||||
MinecraftServer *mcServer = MinecraftServer::getInstance();
|
||||
if (mcServer)
|
||||
mcServer->handleConsoleInput(cmd, server);
|
||||
}
|
||||
}
|
||||
else if (wc == 127 || wc == 8)
|
||||
{
|
||||
if (!buffer.empty())
|
||||
{
|
||||
ServerLog_LockOutput();
|
||||
buffer.pop_back();
|
||||
#ifdef __linux__
|
||||
printf("\b \b");
|
||||
fflush(stdout);
|
||||
#else
|
||||
wprintf(L"\b \b");
|
||||
#endif
|
||||
ServerLog_UnlockOutput();
|
||||
}
|
||||
}
|
||||
#ifdef __linux__
|
||||
else if (c == 27)
|
||||
{
|
||||
char seq[2];
|
||||
if (read(STDIN_FILENO, &seq[0], 1) != 1) continue;
|
||||
if (seq[0] != '[') continue;
|
||||
if (read(STDIN_FILENO, &seq[1], 1) != 1) continue;
|
||||
|
||||
if (seq[1] == 'A')
|
||||
{
|
||||
if (history.empty()) continue;
|
||||
if (historyPos == -1)
|
||||
{
|
||||
savedBuffer = buffer;
|
||||
historyPos = (int)history.size() - 1;
|
||||
}
|
||||
else if (historyPos > 0)
|
||||
{
|
||||
historyPos--;
|
||||
}
|
||||
ServerLog_LockOutput();
|
||||
clearLine();
|
||||
buffer = history[historyPos];
|
||||
redrawLine();
|
||||
ServerLog_UnlockOutput();
|
||||
}
|
||||
else if (seq[1] == 'B')
|
||||
{
|
||||
if (historyPos == -1) continue;
|
||||
ServerLog_LockOutput();
|
||||
clearLine();
|
||||
if (historyPos < (int)history.size() - 1)
|
||||
{
|
||||
historyPos++;
|
||||
buffer = history[historyPos];
|
||||
}
|
||||
else
|
||||
{
|
||||
historyPos = -1;
|
||||
buffer = savedBuffer;
|
||||
}
|
||||
redrawLine();
|
||||
ServerLog_UnlockOutput();
|
||||
}
|
||||
}
|
||||
#else
|
||||
else if (wc == 0 || wc == 0xE0)
|
||||
{
|
||||
wchar_t ext = _getwch();
|
||||
if (ext == 72)
|
||||
{
|
||||
if (history.empty()) continue;
|
||||
if (historyPos == -1)
|
||||
{
|
||||
savedBuffer = buffer;
|
||||
historyPos = (int)history.size() - 1;
|
||||
}
|
||||
else if (historyPos > 0)
|
||||
{
|
||||
historyPos--;
|
||||
}
|
||||
ServerLog_LockOutput();
|
||||
clearLine();
|
||||
buffer = history[historyPos];
|
||||
redrawLine();
|
||||
ServerLog_UnlockOutput();
|
||||
}
|
||||
else if (ext == 80)
|
||||
{
|
||||
if (historyPos == -1) continue;
|
||||
ServerLog_LockOutput();
|
||||
clearLine();
|
||||
if (historyPos < (int)history.size() - 1)
|
||||
{
|
||||
historyPos++;
|
||||
buffer = history[historyPos];
|
||||
}
|
||||
else
|
||||
{
|
||||
historyPos = -1;
|
||||
buffer = savedBuffer;
|
||||
}
|
||||
redrawLine();
|
||||
ServerLog_UnlockOutput();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (wc >= 32)
|
||||
{
|
||||
ServerLog_LockOutput();
|
||||
buffer += wc;
|
||||
#ifdef __linux__
|
||||
printf("%lc", wc);
|
||||
fflush(stdout);
|
||||
#else
|
||||
wprintf(L"%c", wc);
|
||||
#endif
|
||||
ServerLog_UnlockOutput();
|
||||
}
|
||||
}
|
||||
|
||||
ServerLog_UnregisterInput();
|
||||
#ifdef __linux__
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &origTermios);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Minecraft.Client/ConsoleInputSource.h"
|
||||
#include "../../Minecraft.Client/MinecraftServer.h"
|
||||
#include "ServerProperties.h"
|
||||
|
||||
class DedicatedServer : public ConsoleInputSource
|
||||
{
|
||||
public:
|
||||
DedicatedServer();
|
||||
~DedicatedServer();
|
||||
|
||||
bool init();
|
||||
|
||||
int run();
|
||||
|
||||
void shutdown();
|
||||
|
||||
virtual void info(const wstring& string);
|
||||
virtual void warn(const wstring& string);
|
||||
virtual wstring getConsoleName();
|
||||
|
||||
static int consoleInputThread(void *param);
|
||||
|
||||
private:
|
||||
void processConsoleInput();
|
||||
|
||||
bool m_running;
|
||||
ServerProperties m_properties;
|
||||
};
|
||||
@@ -0,0 +1,140 @@
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "DedicatedServer.h"
|
||||
#include "ServerLogger.h"
|
||||
#include "../../Minecraft.World/C4JThread.h"
|
||||
#include "../../Minecraft.Client/Common/BuildVer.h"
|
||||
#include "../../Minecraft.World/SharedConstants.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <signal.h>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <locale.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
static DedicatedServer g_dedicatedServer;
|
||||
static volatile bool g_shutdownRequested = false;
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
static void SignalHandler(int sig)
|
||||
{
|
||||
if (sig == SIGINT || sig == SIGTERM)
|
||||
{
|
||||
printf("\n");
|
||||
ServerLog(L"Received shutdown signal, saving and stopping...\n");
|
||||
g_shutdownRequested = true;
|
||||
MinecraftServer::HaltServer();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
setlocale(LC_ALL, "");
|
||||
ServerLog_Init();
|
||||
|
||||
ServerLog(L"Starting Minecraft LCE server version %s (protocol %d)\n", VER_FILEVERSION_STR_W, SharedConstants::NETWORK_PROTOCOL_VERSION);
|
||||
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = SignalHandler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGTTIN, SIG_IGN);
|
||||
|
||||
if (!g_dedicatedServer.init())
|
||||
{
|
||||
ServerLog(L"Failed to initialize. Exiting.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
C4JThread *inputThread = new C4JThread(DedicatedServer::consoleInputThread, &g_dedicatedServer, "ConsoleInput");
|
||||
inputThread->Run();
|
||||
|
||||
int result = g_dedicatedServer.run();
|
||||
|
||||
g_dedicatedServer.shutdown();
|
||||
delete inputThread;
|
||||
|
||||
ServerLog(L"Goodbye.\n");
|
||||
ServerLog_Close();
|
||||
return result;
|
||||
}
|
||||
|
||||
#else // Windows
|
||||
|
||||
static HANDLE g_shutdownCompleteEvent = NULL;
|
||||
|
||||
BOOL WINAPI ConsoleCtrlHandler(DWORD ctrlType)
|
||||
{
|
||||
switch (ctrlType)
|
||||
{
|
||||
case CTRL_C_EVENT:
|
||||
case CTRL_BREAK_EVENT:
|
||||
wprintf(L"\n");
|
||||
ServerLog(L"Received shutdown signal, saving and stopping...\n");
|
||||
g_shutdownRequested = true;
|
||||
MinecraftServer::HaltServer();
|
||||
if (g_shutdownCompleteEvent)
|
||||
WaitForSingleObject(g_shutdownCompleteEvent, 30000);
|
||||
return TRUE;
|
||||
case CTRL_CLOSE_EVENT:
|
||||
FreeConsole();
|
||||
g_shutdownRequested = true;
|
||||
MinecraftServer::HaltServer();
|
||||
if (g_shutdownCompleteEvent)
|
||||
WaitForSingleObject(g_shutdownCompleteEvent, 30000);
|
||||
ExitProcess(0);
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t *argv[])
|
||||
{
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
SetConsoleCP(CP_UTF8);
|
||||
SetConsoleTitleW(L"LCEMP Server");
|
||||
ServerLog_Init();
|
||||
|
||||
ServerLog(L"Starting Minecraft LCE server version %s (protocol %d)\n", VER_FILEVERSION_STR_W, SharedConstants::NETWORK_PROTOCOL_VERSION);
|
||||
|
||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
||||
|
||||
g_shutdownCompleteEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (!g_dedicatedServer.init())
|
||||
{
|
||||
ServerLog(L"Failed to initialize. Exiting.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
C4JThread *inputThread = new C4JThread(DedicatedServer::consoleInputThread, &g_dedicatedServer, "ConsoleInput");
|
||||
inputThread->Run();
|
||||
|
||||
int result = g_dedicatedServer.run();
|
||||
|
||||
g_dedicatedServer.shutdown();
|
||||
if (g_shutdownCompleteEvent)
|
||||
{
|
||||
SetEvent(g_shutdownCompleteEvent);
|
||||
CloseHandle(g_shutdownCompleteEvent);
|
||||
}
|
||||
delete inputThread;
|
||||
|
||||
ServerLog(L"Goodbye.\n");
|
||||
ServerLog_Close();
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // __linux__
|
||||
@@ -0,0 +1,73 @@
|
||||
#include "stdafx.h"
|
||||
#include "ServerLists.h"
|
||||
#include "ServerProperties.h"
|
||||
#include "../Commands/ServerTextList.h"
|
||||
#include <cwctype>
|
||||
|
||||
static ServerTextList* s_bannedPlayers = NULL;
|
||||
static ServerTextList* s_bannedIPs = NULL;
|
||||
static ServerTextList* s_whitelist = NULL;
|
||||
static ServerTextList* s_ops = NULL;
|
||||
static bool s_whitelistEnabled = false;
|
||||
static ServerProperties* s_properties = NULL;
|
||||
|
||||
void ServerLists_Init(bool whitelistEnabled, ServerProperties* props)
|
||||
{
|
||||
static ServerTextList bannedPlayers(L"banned-players.txt");
|
||||
static ServerTextList bannedIPs(L"banned-ips.txt");
|
||||
static ServerTextList whitelist(L"white-list.txt");
|
||||
static ServerTextList ops(L"ops.txt");
|
||||
|
||||
s_bannedPlayers = &bannedPlayers;
|
||||
s_bannedIPs = &bannedIPs;
|
||||
s_whitelist = &whitelist;
|
||||
s_ops = &ops;
|
||||
s_whitelistEnabled = whitelistEnabled;
|
||||
s_properties = props;
|
||||
}
|
||||
|
||||
ServerTextList* ServerLists_GetBannedPlayers() { return s_bannedPlayers; }
|
||||
ServerTextList* ServerLists_GetBannedIPs() { return s_bannedIPs; }
|
||||
ServerTextList* ServerLists_GetWhitelist() { return s_whitelist; }
|
||||
ServerTextList* ServerLists_GetOps() { return s_ops; }
|
||||
|
||||
bool ServerLists_IsWhitelistEnabled() { return s_whitelistEnabled; }
|
||||
void ServerLists_SetWhitelistEnabled(bool enabled)
|
||||
{
|
||||
s_whitelistEnabled = enabled;
|
||||
if (s_properties)
|
||||
{
|
||||
s_properties->whiteList = enabled;
|
||||
s_properties->save(L"server.properties");
|
||||
}
|
||||
}
|
||||
|
||||
bool ServerLists_IsPlayerBanned(const std::wstring& name)
|
||||
{
|
||||
if (!s_bannedPlayers) return false;
|
||||
return s_bannedPlayers->contains(name);
|
||||
}
|
||||
|
||||
bool ServerLists_IsIPBanned(const std::wstring& ip)
|
||||
{
|
||||
if (!s_bannedIPs) return false;
|
||||
return s_bannedIPs->contains(ip);
|
||||
}
|
||||
|
||||
bool ServerLists_IsPlayerOp(const std::wstring& name)
|
||||
{
|
||||
if (!s_ops) return false;
|
||||
return s_ops->contains(name);
|
||||
}
|
||||
|
||||
bool ServerLists_IsPlayerWhitelisted(const std::wstring& name)
|
||||
{
|
||||
if (!s_whitelistEnabled) return true;
|
||||
if (ServerLists_IsPlayerOp(name)) return true;
|
||||
if (!s_whitelist) return true;
|
||||
|
||||
std::wstring lower = name;
|
||||
for (size_t i = 0; i < lower.size(); i++)
|
||||
lower[i] = towlower(lower[i]);
|
||||
return s_whitelist->contains(lower);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
class ServerTextList;
|
||||
class ServerProperties;
|
||||
|
||||
void ServerLists_Init(bool whitelistEnabled, ServerProperties* props = 0);
|
||||
|
||||
ServerTextList* ServerLists_GetBannedPlayers();
|
||||
ServerTextList* ServerLists_GetBannedIPs();
|
||||
ServerTextList* ServerLists_GetWhitelist();
|
||||
ServerTextList* ServerLists_GetOps();
|
||||
|
||||
bool ServerLists_IsWhitelistEnabled();
|
||||
void ServerLists_SetWhitelistEnabled(bool enabled);
|
||||
|
||||
bool ServerLists_IsPlayerBanned(const std::wstring& name);
|
||||
bool ServerLists_IsPlayerWhitelisted(const std::wstring& name);
|
||||
bool ServerLists_IsPlayerOp(const std::wstring& name);
|
||||
bool ServerLists_IsIPBanned(const std::wstring& ip);
|
||||
@@ -0,0 +1,312 @@
|
||||
#include "stdafx.h"
|
||||
#include "ServerLogger.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <ctime>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
using std::string;
|
||||
using std::wstring;
|
||||
|
||||
#ifdef __linux__
|
||||
#include <pthread.h>
|
||||
static pthread_mutex_t g_logMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#else
|
||||
static CRITICAL_SECTION g_logCS;
|
||||
#endif
|
||||
|
||||
static FILE* g_logFile = NULL;
|
||||
static bool g_initialized = false;
|
||||
static wstring* g_inputBuffer = nullptr;
|
||||
|
||||
void ServerLog_Init()
|
||||
{
|
||||
if (g_initialized) return;
|
||||
|
||||
#ifndef __linux__
|
||||
InitializeCriticalSection(&g_logCS);
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
g_logFile = fopen("server.log", "a");
|
||||
#else
|
||||
g_logFile = _wfopen(L"server.log", L"a");
|
||||
#endif
|
||||
|
||||
if (!g_logFile)
|
||||
{
|
||||
fprintf(stderr, "WARNING: Failed to log to server.log\n");
|
||||
}
|
||||
|
||||
g_initialized = true;
|
||||
}
|
||||
|
||||
void ServerLog_Close()
|
||||
{
|
||||
if (!g_initialized) return;
|
||||
|
||||
if (g_logFile)
|
||||
{
|
||||
fclose(g_logFile);
|
||||
g_logFile = NULL;
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
DeleteCriticalSection(&g_logCS);
|
||||
#endif
|
||||
|
||||
g_initialized = false;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
static string processNarrowFormattingCodes(const char* input)
|
||||
{
|
||||
string result;
|
||||
bool hasColor = false;
|
||||
for (size_t i = 0; input[i]; i++)
|
||||
{
|
||||
if ((unsigned char)input[i] == 0xC2 && (unsigned char)input[i + 1] == 0xA7 && input[i + 2])
|
||||
{
|
||||
char code = tolower((unsigned char)input[i + 2]);
|
||||
i += 2;
|
||||
hasColor = true;
|
||||
switch (code)
|
||||
{
|
||||
case '0': result += "\x1b[30m"; break;
|
||||
case '1': result += "\x1b[34m"; break;
|
||||
case '2': result += "\x1b[32m"; break;
|
||||
case '3': result += "\x1b[36m"; break;
|
||||
case '4': result += "\x1b[31m"; break;
|
||||
case '5': result += "\x1b[35m"; break;
|
||||
case '6': result += "\x1b[33m"; break;
|
||||
case '7': result += "\x1b[37m"; break;
|
||||
case '8': result += "\x1b[90m"; break;
|
||||
case '9': result += "\x1b[94m"; break;
|
||||
case 'a': result += "\x1b[92m"; break;
|
||||
case 'b': result += "\x1b[96m"; break;
|
||||
case 'c': result += "\x1b[91m"; break;
|
||||
case 'd': result += "\x1b[95m"; break;
|
||||
case 'e': result += "\x1b[93m"; break;
|
||||
case 'f': result += "\x1b[97m"; break;
|
||||
case 'l': result += "\x1b[1m"; break;
|
||||
case 'm': result += "\x1b[9m"; break;
|
||||
case 'n': result += "\x1b[4m"; break;
|
||||
case 'o': result += "\x1b[3m"; break;
|
||||
case 'r': result += "\x1b[0m"; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result += input[i];
|
||||
}
|
||||
}
|
||||
if (hasColor) result += "\x1b[0m";
|
||||
return result;
|
||||
}
|
||||
|
||||
static string stripNarrowFormattingCodes(const char* input)
|
||||
{
|
||||
string result;
|
||||
for (size_t i = 0; input[i]; i++)
|
||||
{
|
||||
if ((unsigned char)input[i] == 0xC2 && (unsigned char)input[i + 1] == 0xA7 && input[i + 2])
|
||||
i += 2;
|
||||
else
|
||||
result += input[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void logImpl(const char* level, const wchar_t* fmt, va_list ap)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
struct tm t;
|
||||
localtime_r(&now, &t);
|
||||
|
||||
char narrowFmt[2048];
|
||||
_wfmtToNarrow(fmt, narrowFmt, sizeof(narrowFmt));
|
||||
|
||||
char narrowMsg[4096];
|
||||
vsnprintf(narrowMsg, sizeof(narrowMsg), narrowFmt, ap);
|
||||
|
||||
string consoleMsg = processNarrowFormattingCodes(narrowMsg);
|
||||
|
||||
pthread_mutex_lock(&g_logMutex);
|
||||
|
||||
if (g_inputBuffer && !g_inputBuffer->empty())
|
||||
printf("\r\033[K");
|
||||
|
||||
printf("%04d-%02d-%02d %02d:%02d:%02d [%s] %s",
|
||||
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
|
||||
t.tm_hour, t.tm_min, t.tm_sec, level, consoleMsg.c_str());
|
||||
fflush(stdout);
|
||||
|
||||
if (g_logFile)
|
||||
{
|
||||
string fileMsg = stripNarrowFormattingCodes(narrowMsg);
|
||||
fprintf(g_logFile, "%04d-%02d-%02d %02d:%02d:%02d [%s] %s",
|
||||
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
|
||||
t.tm_hour, t.tm_min, t.tm_sec, level, fileMsg.c_str());
|
||||
fflush(g_logFile);
|
||||
}
|
||||
|
||||
if (g_inputBuffer && !g_inputBuffer->empty())
|
||||
{
|
||||
printf("%ls", g_inputBuffer->c_str());
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&g_logMutex);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static wstring stripWideFormattingCodes(const wchar_t* input)
|
||||
{
|
||||
wstring result;
|
||||
for (size_t i = 0; input[i]; i++)
|
||||
{
|
||||
if (input[i] == L'\u00A7' && input[i + 1])
|
||||
i++;
|
||||
else
|
||||
result += input[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct ColorSpan {
|
||||
size_t start;
|
||||
size_t end;
|
||||
WORD attr;
|
||||
};
|
||||
|
||||
static void printColored(const wchar_t* text)
|
||||
{
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
GetConsoleScreenBufferInfo(hConsole, &csbi);
|
||||
WORD defaultAttr = csbi.wAttributes;
|
||||
WORD currentAttr = defaultAttr;
|
||||
|
||||
const wchar_t* p = text;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == L'\u00A7' && *(p + 1))
|
||||
{
|
||||
wchar_t code = towlower(*(p + 1));
|
||||
p += 2;
|
||||
switch (code)
|
||||
{
|
||||
case L'0': currentAttr = 0; break;
|
||||
case L'1': currentAttr = FOREGROUND_BLUE; break;
|
||||
case L'2': currentAttr = FOREGROUND_GREEN; break;
|
||||
case L'3': currentAttr = FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
case L'4': currentAttr = FOREGROUND_RED; break;
|
||||
case L'5': currentAttr = FOREGROUND_RED | FOREGROUND_BLUE; break;
|
||||
case L'6': currentAttr = FOREGROUND_RED | FOREGROUND_GREEN; break;
|
||||
case L'7': currentAttr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
case L'8': currentAttr = FOREGROUND_INTENSITY; break;
|
||||
case L'9': currentAttr = FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
|
||||
case L'a': currentAttr = FOREGROUND_GREEN | FOREGROUND_INTENSITY; break;
|
||||
case L'b': currentAttr = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
|
||||
case L'c': currentAttr = FOREGROUND_RED | FOREGROUND_INTENSITY; break;
|
||||
case L'd': currentAttr = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
|
||||
case L'e': currentAttr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; break;
|
||||
case L'f': currentAttr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
|
||||
case L'l': currentAttr |= FOREGROUND_INTENSITY; break;
|
||||
case L'r': currentAttr = defaultAttr; break;
|
||||
default: break;
|
||||
}
|
||||
SetConsoleTextAttribute(hConsole, currentAttr);
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t ch[2] = { *p, 0 };
|
||||
wprintf(L"%ls", ch);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
SetConsoleTextAttribute(hConsole, defaultAttr);
|
||||
}
|
||||
|
||||
static void logImpl(const char* level, const wchar_t* fmt, va_list ap)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
struct tm t;
|
||||
localtime_s(&t, &now);
|
||||
|
||||
wchar_t wbuf[4096];
|
||||
vswprintf_s(wbuf, 4096, fmt, ap);
|
||||
|
||||
wstring stripped = stripWideFormattingCodes(wbuf);
|
||||
|
||||
EnterCriticalSection(&g_logCS);
|
||||
|
||||
if (g_inputBuffer && !g_inputBuffer->empty())
|
||||
{
|
||||
wstring spaces(g_inputBuffer->size(), L' ');
|
||||
wprintf(L"\r%ls\r", spaces.c_str());
|
||||
}
|
||||
|
||||
wprintf(L"%04d-%02d-%02d %02d:%02d:%02d [%S] ",
|
||||
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
|
||||
t.tm_hour, t.tm_min, t.tm_sec, level);
|
||||
printColored(wbuf);
|
||||
|
||||
if (g_logFile)
|
||||
{
|
||||
char narrowMsg[4096];
|
||||
size_t converted;
|
||||
wcstombs_s(&converted, narrowMsg, sizeof(narrowMsg), stripped.c_str(), _TRUNCATE);
|
||||
|
||||
fprintf(g_logFile, "%04d-%02d-%02d %02d:%02d:%02d [%s] %s",
|
||||
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
|
||||
t.tm_hour, t.tm_min, t.tm_sec, level, narrowMsg);
|
||||
fflush(g_logFile);
|
||||
}
|
||||
|
||||
if (g_inputBuffer && !g_inputBuffer->empty())
|
||||
wprintf(L"%ls", g_inputBuffer->c_str());
|
||||
|
||||
LeaveCriticalSection(&g_logCS);
|
||||
}
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
void ServerLog(const wchar_t* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logImpl("INFO", fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void ServerWarn(const wchar_t* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logImpl("WARNING", fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void ServerLog_RegisterInput(wstring* buffer)
|
||||
{
|
||||
g_inputBuffer = buffer;
|
||||
}
|
||||
|
||||
void ServerLog_UnregisterInput()
|
||||
{
|
||||
g_inputBuffer = nullptr;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
void ServerLog_LockOutput() { pthread_mutex_lock(&g_logMutex); }
|
||||
void ServerLog_UnlockOutput() { pthread_mutex_unlock(&g_logMutex); }
|
||||
#else
|
||||
void ServerLog_LockOutput() { EnterCriticalSection(&g_logCS); }
|
||||
void ServerLog_UnlockOutput() { LeaveCriticalSection(&g_logCS); }
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
void ServerLog_Init();
|
||||
void ServerLog_Close();
|
||||
void ServerLog(const wchar_t* fmt, ...);
|
||||
void ServerWarn(const wchar_t* fmt, ...);
|
||||
void ServerLog_RegisterInput(std::wstring* buffer);
|
||||
void ServerLog_UnregisterInput();
|
||||
void ServerLog_LockOutput();
|
||||
void ServerLog_UnlockOutput();
|
||||
@@ -0,0 +1,184 @@
|
||||
#include "stdafx.h"
|
||||
#include "ServerProperties.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
|
||||
ServerProperties::ServerProperties()
|
||||
{
|
||||
loadDefaults();
|
||||
}
|
||||
|
||||
void ServerProperties::loadDefaults()
|
||||
{
|
||||
serverPort = 25565;
|
||||
levelName = L"world";
|
||||
levelSeed = 0;
|
||||
gamemode = 0;
|
||||
difficulty = 2;
|
||||
maxPlayers = 8;
|
||||
pvp = true;
|
||||
trustPlayers = true;
|
||||
fireSpreads = true;
|
||||
tntExplodes = true;
|
||||
structures = true;
|
||||
spawnAnimals = true;
|
||||
spawnNpcs = true;
|
||||
onlineMode = false;
|
||||
showGamertags = true;
|
||||
motd = L"A Minecraft LCE Server";
|
||||
whiteList = false;
|
||||
voiceChat = false;
|
||||
levelSize = L"large";
|
||||
advertiseLan = true;
|
||||
serverIp = L"";
|
||||
}
|
||||
|
||||
static wstring trimWs(const wstring& s)
|
||||
{
|
||||
size_t start = s.find_first_not_of(L" \t\r\n");
|
||||
if (start == wstring::npos) return L"";
|
||||
size_t end = s.find_last_not_of(L" \t\r\n");
|
||||
return s.substr(start, end - start + 1);
|
||||
}
|
||||
|
||||
bool ServerProperties::load(const wstring& path)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
_wfopen_s(&f, path.c_str(), L"r, ccs=UTF-8");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
wchar_t line[1024];
|
||||
while (fgetws(line, 1024, f))
|
||||
{
|
||||
wstring ws(line);
|
||||
size_t nl = ws.find_last_not_of(L"\r\n");
|
||||
if (nl != wstring::npos)
|
||||
ws = ws.substr(0, nl + 1);
|
||||
else
|
||||
ws.clear();
|
||||
|
||||
if (ws.empty()) continue;
|
||||
if (ws[0] == L'#') continue;
|
||||
|
||||
size_t eq = ws.find(L'=');
|
||||
if (eq == wstring::npos) continue;
|
||||
|
||||
wstring key = trimWs(ws.substr(0, eq));
|
||||
wstring val = trimWs(ws.substr(eq + 1));
|
||||
m_properties[key] = val;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
serverPort = getInt(L"server-port", 25565);
|
||||
if (serverPort <= 0 || serverPort > 65535) serverPort = 25565;
|
||||
levelName = getString(L"level-name", L"world");
|
||||
levelSeed = getInt64(L"level-seed", 0);
|
||||
gamemode = getInt(L"gamemode", 0);
|
||||
difficulty = getInt(L"difficulty", 2);
|
||||
maxPlayers = getInt(L"max-players", 8);
|
||||
if (maxPlayers < 1) maxPlayers = 1;
|
||||
if (maxPlayers > 8) maxPlayers = 8;
|
||||
pvp = getBool(L"pvp", true);
|
||||
trustPlayers = getBool(L"trust-players", true);
|
||||
fireSpreads = getBool(L"fire-spreads", true);
|
||||
tntExplodes = getBool(L"tnt-explodes", true);
|
||||
structures = getBool(L"structures", true);
|
||||
spawnAnimals = getBool(L"spawn-animals", true);
|
||||
spawnNpcs = getBool(L"spawn-npcs", true);
|
||||
onlineMode = getBool(L"online-mode", false);
|
||||
showGamertags = getBool(L"show-gamertags", true);
|
||||
motd = getString(L"motd", L"A Minecraft LCE Server");
|
||||
whiteList = getBool(L"white-list", false);
|
||||
voiceChat = getBool(L"voice-chat", false);
|
||||
levelSize = getString(L"level-size", L"large");
|
||||
advertiseLan = getBool(L"advertise-lan", true);
|
||||
serverIp = getString(L"server-ip", L"");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ServerProperties::save(const wstring& path)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
_wfopen_s(&f, path.c_str(), L"w, ccs=UTF-8");
|
||||
if (!f) return;
|
||||
|
||||
fwprintf(f, L"#Minecraft server properties\n");
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
struct tm t;
|
||||
localtime_s(&t, &now);
|
||||
static const wchar_t* dayNames[] = { L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat" };
|
||||
static const wchar_t* monNames[] = { L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec" };
|
||||
fwprintf(f, L"#%ls %ls %02d %02d:%02d:%02d %04d\n",
|
||||
dayNames[t.tm_wday], monNames[t.tm_mon], t.tm_mday,
|
||||
t.tm_hour, t.tm_min, t.tm_sec, t.tm_year + 1900);
|
||||
}
|
||||
fwprintf(f, L"server-port=%d\n", serverPort);
|
||||
fwprintf(f, L"level-name=%ls\n", levelName.c_str());
|
||||
if (levelSeed != 0)
|
||||
fwprintf(f, L"level-seed=%lld\n", levelSeed);
|
||||
else
|
||||
fwprintf(f, L"level-seed=\n");
|
||||
fwprintf(f, L"gamemode=%d\n", gamemode);
|
||||
fwprintf(f, L"difficulty=%d\n", difficulty);
|
||||
fwprintf(f, L"max-players=%d\n", maxPlayers);
|
||||
fwprintf(f, L"pvp=%ls\n", pvp ? L"true" : L"false");
|
||||
fwprintf(f, L"trust-players=%ls\n", trustPlayers ? L"true" : L"false");
|
||||
fwprintf(f, L"fire-spreads=%ls\n", fireSpreads ? L"true" : L"false");
|
||||
fwprintf(f, L"tnt-explodes=%ls\n", tntExplodes ? L"true" : L"false");
|
||||
fwprintf(f, L"structures=%ls\n", structures ? L"true" : L"false");
|
||||
fwprintf(f, L"spawn-animals=%ls\n", spawnAnimals ? L"true" : L"false");
|
||||
fwprintf(f, L"spawn-npcs=%ls\n", spawnNpcs ? L"true" : L"false");
|
||||
fwprintf(f, L"online-mode=%ls\n", onlineMode ? L"true" : L"false");
|
||||
fwprintf(f, L"show-gamertags=%ls\n", showGamertags ? L"true" : L"false");
|
||||
fwprintf(f, L"motd=%ls\n", motd.c_str());
|
||||
fwprintf(f, L"white-list=%ls\n", whiteList ? L"true" : L"false");
|
||||
fwprintf(f, L"voice-chat=%ls\n", voiceChat ? L"true" : L"false");
|
||||
fwprintf(f, L"level-size=%ls\n", levelSize.c_str());
|
||||
fwprintf(f, L"advertise-lan=%ls\n", advertiseLan ? L"true" : L"false");
|
||||
if (!serverIp.empty())
|
||||
fwprintf(f, L"server-ip=%ls\n", serverIp.c_str());
|
||||
else
|
||||
fwprintf(f, L"server-ip=\n");
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
wstring ServerProperties::getString(const wstring& key, const wstring& defaultVal)
|
||||
{
|
||||
map<wstring, wstring>::iterator it = m_properties.find(key);
|
||||
if (it != m_properties.end())
|
||||
return it->second;
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
int ServerProperties::getInt(const wstring& key, int defaultVal)
|
||||
{
|
||||
map<wstring, wstring>::iterator it = m_properties.find(key);
|
||||
if (it != m_properties.end() && !it->second.empty())
|
||||
return _wtoi(it->second.c_str());
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
__int64 ServerProperties::getInt64(const wstring& key, __int64 defaultVal)
|
||||
{
|
||||
map<wstring, wstring>::iterator it = m_properties.find(key);
|
||||
if (it != m_properties.end() && !it->second.empty())
|
||||
return _wtoi64(it->second.c_str());
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
bool ServerProperties::getBool(const wstring& key, bool defaultVal)
|
||||
{
|
||||
map<wstring, wstring>::iterator it = m_properties.find(key);
|
||||
if (it != m_properties.end())
|
||||
{
|
||||
wstring val = it->second;
|
||||
if (val == L"true" || val == L"1") return true;
|
||||
if (val == L"false" || val == L"0") return false;
|
||||
}
|
||||
return defaultVal;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class ServerProperties
|
||||
{
|
||||
public:
|
||||
ServerProperties();
|
||||
|
||||
bool load(const wstring& path);
|
||||
void save(const wstring& path);
|
||||
|
||||
wstring getString(const wstring& key, const wstring& defaultVal);
|
||||
int getInt(const wstring& key, int defaultVal);
|
||||
__int64 getInt64(const wstring& key, __int64 defaultVal);
|
||||
bool getBool(const wstring& key, bool defaultVal);
|
||||
|
||||
int serverPort;
|
||||
wstring levelName;
|
||||
__int64 levelSeed;
|
||||
int gamemode;
|
||||
int difficulty;
|
||||
int maxPlayers;
|
||||
bool pvp;
|
||||
bool trustPlayers;
|
||||
bool fireSpreads;
|
||||
bool tntExplodes;
|
||||
bool structures;
|
||||
bool spawnAnimals;
|
||||
bool spawnNpcs;
|
||||
bool onlineMode;
|
||||
bool showGamertags;
|
||||
wstring motd;
|
||||
bool whiteList;
|
||||
bool voiceChat;
|
||||
wstring levelSize;
|
||||
bool advertiseLan;
|
||||
wstring serverIp;
|
||||
|
||||
private:
|
||||
map<wstring, wstring> m_properties;
|
||||
void loadDefaults();
|
||||
};
|
||||
Reference in new issue
Block a user