Initial commit

This commit is contained in:
NOTPIES committed 2026-03-15 22:25:51 -03:00
commit c356c7b911
100 files changed
+8788

No files matched your search

+559
View File
@@ -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;
}
+30
View File
@@ -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;
};
+140
View File
@@ -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__
+73
View File
@@ -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);
}
+20
View File
@@ -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);
+312
View File
@@ -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
+12
View File
@@ -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();
+184
View File
@@ -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;
}
+46
View File
@@ -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();
};