mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/LCEMP-Server.git
synced 2026-06-08 18:44:45 +00:00
LCEMP v1.1.0 Dedicated Server
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#include "MeCommand.h"
|
||||
#include "../../Minecraft.Client/MinecraftServer.h"
|
||||
#include "../../Minecraft.Client/ConsoleInputSource.h"
|
||||
#include "../../Minecraft.Client/PlayerConnection.h"
|
||||
#include "../../Minecraft.Client/PlayerList.h"
|
||||
#include "../../Minecraft.World/ChatPacket.h"
|
||||
|
||||
@@ -12,7 +13,22 @@ void MeCommand::execute(const wstring& args, ConsoleInputSource *src, MinecraftS
|
||||
src->warn(L"Usage: /me <action ...>");
|
||||
return;
|
||||
}
|
||||
wstring msg = L"* Server " + args;
|
||||
wstring senderName = L"Server";
|
||||
if (src != NULL)
|
||||
{
|
||||
senderName = src->getConsoleName();
|
||||
if (senderName.empty())
|
||||
{
|
||||
senderName = L"Server";
|
||||
}
|
||||
}
|
||||
|
||||
wstring msg = L"* " + senderName + L" " + args;
|
||||
server->getPlayers()->broadcastAll(shared_ptr<Packet>(new ChatPacket(msg)));
|
||||
src->info(msg);
|
||||
|
||||
// player sources already receive the broadcast chat line above
|
||||
if (dynamic_cast<PlayerConnection *>(src) == NULL)
|
||||
{
|
||||
src->info(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "../../Minecraft.World/ChunkSource.h"
|
||||
#include "ServerLogger.h"
|
||||
#include "ServerLists.h"
|
||||
#include "ServerThreadPool.h"
|
||||
#include "../Commands/ServerCommands.h"
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -55,6 +56,7 @@ bool DedicatedServer::init()
|
||||
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());
|
||||
ServerLog(L"Chat: %s\n", m_properties.chatEnabled ? L"ENABLED" : L"DISABLED");
|
||||
|
||||
ServerLists_Init(m_properties.whiteList, &m_properties);
|
||||
|
||||
@@ -66,6 +68,12 @@ bool DedicatedServer::init()
|
||||
|
||||
extern int g_ServerMaxPlayers;
|
||||
g_ServerMaxPlayers = m_properties.maxPlayers;
|
||||
if (g_ServerMaxPlayers < 1)
|
||||
g_ServerMaxPlayers = 1;
|
||||
IQNet::SetPlayerCapacity((DWORD)g_ServerMaxPlayers);
|
||||
|
||||
extern int g_Win64MultiplayerPort;
|
||||
g_Win64MultiplayerPort = m_properties.serverPort;
|
||||
|
||||
extern char g_ServerBindAddress[256];
|
||||
if (!m_properties.serverIp.empty())
|
||||
@@ -134,6 +142,9 @@ bool DedicatedServer::init()
|
||||
|
||||
WinsockNetLayer::Initialize();
|
||||
|
||||
ServerThreadPool::Initialize();
|
||||
ServerLog(L"Thread pool initialized with %d worker threads\n", ServerThreadPool::GetThreadCount());
|
||||
|
||||
app.SetGameHostOption(eGameHostOption_Difficulty, m_properties.difficulty);
|
||||
app.SetGameHostOption(eGameHostOption_GameType, m_properties.gamemode);
|
||||
app.SetGameHostOption(eGameHostOption_PvP, m_properties.pvp ? 1 : 0);
|
||||
@@ -142,6 +153,7 @@ bool DedicatedServer::init()
|
||||
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);
|
||||
app.SetGameHostOption(eGameHostOption_LevelType, m_properties.levelSize == L"flat" ? 1 : 0);
|
||||
|
||||
Minecraft *pMinecraft = new Minecraft(NULL, NULL, NULL, 1, 1, false);
|
||||
pMinecraft->options = new Options(pMinecraft, File(L"."));
|
||||
@@ -163,6 +175,7 @@ bool DedicatedServer::init()
|
||||
}
|
||||
|
||||
app.InitGameSettings();
|
||||
app.SetGameHostOption(eGameHostOption_ChatDisabled, m_properties.chatEnabled ? 0 : 1);
|
||||
|
||||
if (!m_properties.serverIp.empty())
|
||||
ServerLog(L"Starting Minecraft server on %s:%d\n", m_properties.serverIp.c_str(), m_properties.serverPort);
|
||||
@@ -267,13 +280,19 @@ void DedicatedServer::shutdown()
|
||||
m_running = false;
|
||||
MinecraftServer::HaltServer();
|
||||
|
||||
//ServerLog(L"Stopping server: shutting down thread pool\n");
|
||||
ServerThreadPool::Shutdown();
|
||||
//ServerLog(L"Stopping server: thread pool stopped\n");
|
||||
|
||||
Tile::ReleaseThreadStorage();
|
||||
IntCache::ReleaseThreadStorage();
|
||||
AABB::ReleaseThreadStorage();
|
||||
Vec3::ReleaseThreadStorage();
|
||||
Level::destroyLightingCache();
|
||||
|
||||
//ServerLog(L"Stopping server: terminating network manager\n");
|
||||
g_NetworkManager.Terminate();
|
||||
//ServerLog(L"Stopping server: network manager terminated\n");
|
||||
ServerLog(L"Shutdown complete\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,20 @@ int wmain(int argc, wchar_t *argv[])
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
SetConsoleCP(CP_UTF8);
|
||||
SetConsoleTitleW(L"LCEMP Server");
|
||||
|
||||
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (hInput != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD mode = 0;
|
||||
if (GetConsoleMode(hInput, &mode))
|
||||
{
|
||||
mode |= ENABLE_EXTENDED_FLAGS;
|
||||
mode &= ~ENABLE_QUICK_EDIT_MODE;
|
||||
mode &= ~ENABLE_MOUSE_INPUT;
|
||||
SetConsoleMode(hInput, mode);
|
||||
}
|
||||
}
|
||||
|
||||
ServerLog_Init();
|
||||
|
||||
ServerLog(L"Starting Minecraft LCE server version %s (protocol %d)\n", VER_FILEVERSION_STR_W, SharedConstants::NETWORK_PROTOCOL_VERSION);
|
||||
|
||||
@@ -29,6 +29,7 @@ void ServerProperties::loadDefaults()
|
||||
motd = L"A Minecraft LCE Server";
|
||||
whiteList = false;
|
||||
voiceChat = false;
|
||||
chatEnabled = false;
|
||||
levelSize = L"large";
|
||||
advertiseLan = true;
|
||||
serverIp = L"";
|
||||
@@ -79,7 +80,7 @@ bool ServerProperties::load(const wstring& path)
|
||||
difficulty = getInt(L"difficulty", 2);
|
||||
maxPlayers = getInt(L"max-players", 8);
|
||||
if (maxPlayers < 1) maxPlayers = 1;
|
||||
if (maxPlayers > 32) maxPlayers = 32;
|
||||
if (maxPlayers > 255) maxPlayers = 255;
|
||||
pvp = getBool(L"pvp", true);
|
||||
trustPlayers = getBool(L"trust-players", true);
|
||||
fireSpreads = getBool(L"fire-spreads", true);
|
||||
@@ -92,6 +93,7 @@ bool ServerProperties::load(const wstring& path)
|
||||
motd = getString(L"motd", L"A Minecraft LCE Server");
|
||||
whiteList = getBool(L"white-list", false);
|
||||
voiceChat = getBool(L"voice-chat", false);
|
||||
chatEnabled = getBool(L"enable-chat", false);
|
||||
levelSize = getString(L"level-size", L"large");
|
||||
advertiseLan = getBool(L"advertise-lan", true);
|
||||
serverIp = getString(L"server-ip", L"");
|
||||
@@ -137,6 +139,7 @@ void ServerProperties::save(const wstring& path)
|
||||
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"enable-chat=%ls\n", chatEnabled ? 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())
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
wstring motd;
|
||||
bool whiteList;
|
||||
bool voiceChat;
|
||||
bool chatEnabled;
|
||||
wstring levelSize;
|
||||
bool advertiseLan;
|
||||
wstring serverIp;
|
||||
|
||||
375
Core/ServerThreadPool.cpp
Normal file
375
Core/ServerThreadPool.cpp
Normal file
@@ -0,0 +1,375 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#if defined(__linux__) || defined(_WIN32)
|
||||
|
||||
#include "ServerThreadPool.h"
|
||||
#include "../../Minecraft.World/AABB.h"
|
||||
#include "../../Minecraft.World/Vec3.h"
|
||||
#include "../../Minecraft.World/IntCache.h"
|
||||
#include "../../Minecraft.World/compression.h"
|
||||
#include "../../Minecraft.World/Tile.h"
|
||||
#include "../../Minecraft.World/Level.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
#include <cstring>
|
||||
|
||||
#ifdef __linux__
|
||||
std::vector<pthread_t> ServerThreadPool::s_workers;
|
||||
pthread_mutex_t ServerThreadPool::s_queueLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t ServerThreadPool::s_queueCond = PTHREAD_COND_INITIALIZER;
|
||||
pthread_cond_t ServerThreadPool::s_doneCond = PTHREAD_COND_INITIALIZER;
|
||||
#else
|
||||
std::vector<HANDLE> ServerThreadPool::s_workers;
|
||||
CRITICAL_SECTION ServerThreadPool::s_queueLock;
|
||||
CONDITION_VARIABLE ServerThreadPool::s_queueCond;
|
||||
CONDITION_VARIABLE ServerThreadPool::s_doneCond;
|
||||
#endif
|
||||
|
||||
std::queue<ServerThreadPool::Task> ServerThreadPool::s_taskQueue;
|
||||
std::atomic<int> ServerThreadPool::s_pendingTasks(0);
|
||||
volatile bool ServerThreadPool::s_running = false;
|
||||
int ServerThreadPool::s_threadCount = 0;
|
||||
bool ServerThreadPool::s_initialized = false;
|
||||
|
||||
#ifdef __linux__
|
||||
static bool JoinWorkerWithTimeout(pthread_t worker, int timeoutMs)
|
||||
{
|
||||
#if defined(__GLIBC__)
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_sec += timeoutMs / 1000;
|
||||
ts.tv_nsec += (timeoutMs % 1000) * 1000000;
|
||||
if (ts.tv_nsec >= 1000000000)
|
||||
{
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec -= 1000000000;
|
||||
}
|
||||
|
||||
int rc = pthread_timedjoin_np(worker, NULL, &ts);
|
||||
if (rc == 0)
|
||||
return true;
|
||||
|
||||
pthread_detach(worker);
|
||||
return false;
|
||||
#else
|
||||
int waitedMs = 0;
|
||||
while (waitedMs < timeoutMs)
|
||||
{
|
||||
if (pthread_tryjoin_np(worker, NULL) == 0)
|
||||
return true;
|
||||
|
||||
usleep(10 * 1000);
|
||||
waitedMs += 10;
|
||||
}
|
||||
|
||||
pthread_detach(worker);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void ServerThreadPool::WorkerInit()
|
||||
{
|
||||
AABB::CreateNewThreadStorage();
|
||||
Vec3::CreateNewThreadStorage();
|
||||
IntCache::CreateNewThreadStorage();
|
||||
Compression::CreateNewThreadStorage();
|
||||
Level::enableLightingCache();
|
||||
Tile::CreateNewThreadStorage();
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
void *ServerThreadPool::WorkerProc(void *param)
|
||||
#else
|
||||
DWORD WINAPI ServerThreadPool::WorkerProc(LPVOID param)
|
||||
#endif
|
||||
{
|
||||
WorkerInit();
|
||||
|
||||
while (s_running)
|
||||
{
|
||||
Task task;
|
||||
bool gotTask = false;
|
||||
|
||||
#ifdef __linux__
|
||||
pthread_mutex_lock(&s_queueLock);
|
||||
while (s_running && s_taskQueue.empty())
|
||||
pthread_cond_wait(&s_queueCond, &s_queueLock);
|
||||
|
||||
if (!s_running && s_taskQueue.empty())
|
||||
{
|
||||
pthread_mutex_unlock(&s_queueLock);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!s_taskQueue.empty())
|
||||
{
|
||||
task = s_taskQueue.front();
|
||||
s_taskQueue.pop();
|
||||
gotTask = true;
|
||||
}
|
||||
pthread_mutex_unlock(&s_queueLock);
|
||||
#else
|
||||
EnterCriticalSection(&s_queueLock);
|
||||
while (s_running && s_taskQueue.empty())
|
||||
SleepConditionVariableCS(&s_queueCond, &s_queueLock, INFINITE);
|
||||
|
||||
if (!s_running && s_taskQueue.empty())
|
||||
{
|
||||
LeaveCriticalSection(&s_queueLock);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!s_taskQueue.empty())
|
||||
{
|
||||
task = s_taskQueue.front();
|
||||
s_taskQueue.pop();
|
||||
gotTask = true;
|
||||
}
|
||||
LeaveCriticalSection(&s_queueLock);
|
||||
#endif
|
||||
|
||||
if (gotTask && task.func != NULL)
|
||||
{
|
||||
try
|
||||
{
|
||||
task.func(task.param);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
if (s_pendingTasks.fetch_sub(1) == 1)
|
||||
{
|
||||
#ifdef __linux__
|
||||
pthread_mutex_lock(&s_queueLock);
|
||||
pthread_cond_broadcast(&s_doneCond);
|
||||
pthread_mutex_unlock(&s_queueLock);
|
||||
#else
|
||||
EnterCriticalSection(&s_queueLock);
|
||||
WakeAllConditionVariable(&s_doneCond);
|
||||
LeaveCriticalSection(&s_queueLock);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AABB::ReleaseThreadStorage();
|
||||
Vec3::ReleaseThreadStorage();
|
||||
IntCache::ReleaseThreadStorage();
|
||||
Tile::ReleaseThreadStorage();
|
||||
Level::destroyLightingCache();
|
||||
|
||||
#ifdef __linux__
|
||||
return NULL;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ServerThreadPool::Initialize(int threadCount)
|
||||
{
|
||||
if (s_initialized) return true;
|
||||
|
||||
if (threadCount <= 0)
|
||||
{
|
||||
#ifdef __linux__
|
||||
long cores = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#else
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo(&sysInfo);
|
||||
long cores = (long)sysInfo.dwNumberOfProcessors;
|
||||
#endif
|
||||
if (cores < 2) cores = 2;
|
||||
threadCount = (int)(cores - 1);
|
||||
if (threadCount > 16) threadCount = 16;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&s_queueLock, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
pthread_cond_init(&s_queueCond, NULL);
|
||||
pthread_cond_init(&s_doneCond, NULL);
|
||||
#else
|
||||
InitializeCriticalSection(&s_queueLock);
|
||||
InitializeConditionVariable(&s_queueCond);
|
||||
InitializeConditionVariable(&s_doneCond);
|
||||
#endif
|
||||
|
||||
s_running = true;
|
||||
s_threadCount = threadCount;
|
||||
|
||||
s_workers.resize(threadCount);
|
||||
for (int i = 0; i < threadCount; i++)
|
||||
{
|
||||
#ifdef __linux__
|
||||
pthread_create(&s_workers[i], NULL, WorkerProc, NULL);
|
||||
#else
|
||||
s_workers[i] = CreateThread(NULL, 0, WorkerProc, NULL, 0, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
s_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ServerThreadPool::Shutdown()
|
||||
{
|
||||
if (!s_initialized) return;
|
||||
|
||||
s_running = false;
|
||||
s_initialized = false;
|
||||
|
||||
#ifdef __linux__
|
||||
pthread_mutex_lock(&s_queueLock);
|
||||
while (!s_taskQueue.empty())
|
||||
s_taskQueue.pop();
|
||||
pthread_cond_broadcast(&s_queueCond);
|
||||
pthread_mutex_unlock(&s_queueLock);
|
||||
|
||||
bool allWorkersJoined = true;
|
||||
for (int i = 0; i < (int)s_workers.size(); i++)
|
||||
{
|
||||
if (!JoinWorkerWithTimeout(s_workers[i], 5000))
|
||||
allWorkersJoined = false;
|
||||
}
|
||||
#else
|
||||
EnterCriticalSection(&s_queueLock);
|
||||
while (!s_taskQueue.empty())
|
||||
s_taskQueue.pop();
|
||||
WakeAllConditionVariable(&s_queueCond);
|
||||
LeaveCriticalSection(&s_queueLock);
|
||||
|
||||
for (int i = 0; i < (int)s_workers.size(); i++)
|
||||
{
|
||||
WaitForSingleObject(s_workers[i], 5000);
|
||||
CloseHandle(s_workers[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
s_workers.clear();
|
||||
s_pendingTasks.store(0);
|
||||
|
||||
#ifdef __linux__
|
||||
if (allWorkersJoined)
|
||||
{
|
||||
pthread_mutex_destroy(&s_queueLock);
|
||||
pthread_cond_destroy(&s_queueCond);
|
||||
pthread_cond_destroy(&s_doneCond);
|
||||
}
|
||||
#else
|
||||
DeleteCriticalSection(&s_queueLock);
|
||||
#endif
|
||||
|
||||
s_threadCount = 0;
|
||||
}
|
||||
|
||||
int ServerThreadPool::GetThreadCount()
|
||||
{
|
||||
return s_threadCount;
|
||||
}
|
||||
|
||||
void ServerThreadPool::Submit(TaskFunc func, void *param)
|
||||
{
|
||||
if (!s_initialized || func == NULL) return;
|
||||
|
||||
Task task;
|
||||
task.func = func;
|
||||
task.param = param;
|
||||
|
||||
s_pendingTasks.fetch_add(1);
|
||||
|
||||
#ifdef __linux__
|
||||
pthread_mutex_lock(&s_queueLock);
|
||||
s_taskQueue.push(task);
|
||||
pthread_cond_signal(&s_queueCond);
|
||||
pthread_mutex_unlock(&s_queueLock);
|
||||
#else
|
||||
EnterCriticalSection(&s_queueLock);
|
||||
s_taskQueue.push(task);
|
||||
WakeConditionVariable(&s_queueCond);
|
||||
LeaveCriticalSection(&s_queueLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ServerThreadPool::SubmitBatch(Task *tasks, int count)
|
||||
{
|
||||
if (!s_initialized || tasks == NULL || count <= 0) return;
|
||||
|
||||
s_pendingTasks.fetch_add(count);
|
||||
|
||||
#ifdef __linux__
|
||||
pthread_mutex_lock(&s_queueLock);
|
||||
for (int i = 0; i < count; i++)
|
||||
s_taskQueue.push(tasks[i]);
|
||||
pthread_cond_broadcast(&s_queueCond);
|
||||
pthread_mutex_unlock(&s_queueLock);
|
||||
#else
|
||||
EnterCriticalSection(&s_queueLock);
|
||||
for (int i = 0; i < count; i++)
|
||||
s_taskQueue.push(tasks[i]);
|
||||
WakeAllConditionVariable(&s_queueCond);
|
||||
LeaveCriticalSection(&s_queueLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ServerThreadPool::WaitAll()
|
||||
{
|
||||
if (!s_initialized) return;
|
||||
|
||||
#ifdef __linux__
|
||||
pthread_mutex_lock(&s_queueLock);
|
||||
while (s_pendingTasks.load() > 0)
|
||||
pthread_cond_wait(&s_doneCond, &s_queueLock);
|
||||
pthread_mutex_unlock(&s_queueLock);
|
||||
#else
|
||||
EnterCriticalSection(&s_queueLock);
|
||||
while (s_pendingTasks.load() > 0)
|
||||
SleepConditionVariableCS(&s_doneCond, &s_queueLock, INFINITE);
|
||||
LeaveCriticalSection(&s_queueLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ParallelForTaskFunc(void *param)
|
||||
{
|
||||
ParallelForData *data = (ParallelForData *)param;
|
||||
if (data != NULL && data->func != NULL)
|
||||
data->func(data->index, data->param);
|
||||
}
|
||||
|
||||
void ServerThreadPool::ParallelFor(int start, int end, void (*func)(int index, void *param), void *param)
|
||||
{
|
||||
int count = end - start;
|
||||
if (count <= 0 || func == NULL) return;
|
||||
|
||||
if (count == 1 || !s_initialized)
|
||||
{
|
||||
for (int i = start; i < end; i++)
|
||||
func(i, param);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<ParallelForData> taskData(count);
|
||||
std::vector<Task> tasks(count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
taskData[i].func = func;
|
||||
taskData[i].param = param;
|
||||
taskData[i].index = start + i;
|
||||
tasks[i].func = ParallelForTaskFunc;
|
||||
tasks[i].param = &taskData[i];
|
||||
}
|
||||
|
||||
SubmitBatch(&tasks[0], count);
|
||||
WaitAll();
|
||||
}
|
||||
|
||||
#endif
|
||||
73
Core/ServerThreadPool.h
Normal file
73
Core/ServerThreadPool.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__linux__) || defined(_WIN32)
|
||||
|
||||
#ifdef __linux__
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <functional>
|
||||
#include <atomic>
|
||||
|
||||
#define SERVER_THREAD_POOL_DEFAULT_SIZE 0
|
||||
|
||||
class ServerThreadPool
|
||||
{
|
||||
public:
|
||||
typedef void (*TaskFunc)(void *param);
|
||||
|
||||
struct Task
|
||||
{
|
||||
TaskFunc func;
|
||||
void *param;
|
||||
};
|
||||
|
||||
static bool Initialize(int threadCount = SERVER_THREAD_POOL_DEFAULT_SIZE);
|
||||
static void Shutdown();
|
||||
static int GetThreadCount();
|
||||
static bool IsInitialized() { return s_initialized; }
|
||||
|
||||
static void Submit(TaskFunc func, void *param);
|
||||
static void SubmitBatch(Task *tasks, int count);
|
||||
static void WaitAll();
|
||||
|
||||
static void ParallelFor(int start, int end, void (*func)(int index, void *param), void *param);
|
||||
|
||||
private:
|
||||
#ifdef __linux__
|
||||
static void *WorkerProc(void *param);
|
||||
#else
|
||||
static DWORD WINAPI WorkerProc(LPVOID param);
|
||||
#endif
|
||||
static void WorkerInit();
|
||||
|
||||
#ifdef __linux__
|
||||
static std::vector<pthread_t> s_workers;
|
||||
static pthread_mutex_t s_queueLock;
|
||||
static pthread_cond_t s_queueCond;
|
||||
static pthread_cond_t s_doneCond;
|
||||
#else
|
||||
static std::vector<HANDLE> s_workers;
|
||||
static CRITICAL_SECTION s_queueLock;
|
||||
static CONDITION_VARIABLE s_queueCond;
|
||||
static CONDITION_VARIABLE s_doneCond;
|
||||
#endif
|
||||
static std::queue<Task> s_taskQueue;
|
||||
static std::atomic<int> s_pendingTasks;
|
||||
static volatile bool s_running;
|
||||
static int s_threadCount;
|
||||
static bool s_initialized;
|
||||
};
|
||||
|
||||
struct ParallelForData
|
||||
{
|
||||
void (*func)(int index, void *param);
|
||||
void *param;
|
||||
int index;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -197,6 +197,9 @@ typedef union _LARGE_INTEGER {
|
||||
#define VK_F5 0x74
|
||||
#define VK_LSHIFT 0xA0
|
||||
#define VK_LCONTROL 0xA2
|
||||
#ifndef WHEEL_DELTA
|
||||
#define WHEEL_DELTA 120
|
||||
#endif
|
||||
|
||||
#define VK_PAD_A 0x5800
|
||||
#define VK_PAD_B 0x5801
|
||||
@@ -716,6 +719,21 @@ inline LONGLONG InterlockedCompareExchangeRelease64(volatile LONGLONG* destinati
|
||||
return __sync_val_compare_and_swap(destination, comparand, exchange);
|
||||
}
|
||||
|
||||
inline LONG InterlockedCompareExchange(volatile LONG* destination, LONG exchange, LONG comparand)
|
||||
{
|
||||
return __sync_val_compare_and_swap(destination, comparand, exchange);
|
||||
}
|
||||
|
||||
inline LONG InterlockedCompareExchangeRelease(volatile LONG* destination, LONG exchange, LONG comparand)
|
||||
{
|
||||
return __sync_val_compare_and_swap(destination, comparand, exchange);
|
||||
}
|
||||
|
||||
inline LONG InterlockedExchange(volatile LONG* target, LONG value)
|
||||
{
|
||||
return __sync_lock_test_and_set(target, value);
|
||||
}
|
||||
|
||||
typedef DWORD (*LPTHREAD_START_ROUTINE)(LPVOID);
|
||||
|
||||
struct LinuxThreadData {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,9 +12,11 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <vector>
|
||||
#include <pthread.h>
|
||||
#include <cstring>
|
||||
#include <atomic>
|
||||
|
||||
#include "../../Minecraft.Client/Common/Network/NetworkPlayerInterface.h"
|
||||
|
||||
@@ -25,12 +27,14 @@ typedef int SOCKET;
|
||||
inline int closesocket(SOCKET s) { return close(s); }
|
||||
|
||||
#define WIN64_NET_DEFAULT_PORT 25565
|
||||
#define WIN64_NET_MAX_CLIENTS 31
|
||||
#define WIN64_NET_RECV_BUFFER_SIZE 65536
|
||||
#define WIN64_NET_RECV_BUFFER_SIZE 131072
|
||||
#define WIN64_NET_MAX_PACKET_SIZE (3 * 1024 * 1024)
|
||||
#define WIN64_LAN_DISCOVERY_PORT 25566
|
||||
#define WIN64_LAN_BROADCAST_MAGIC 0x4D434C4E
|
||||
#define WIN64_LAN_BROADCAST_PLAYERS 8
|
||||
#define WIN64_NET_IO_THREADS 2
|
||||
#define WIN64_NET_EPOLL_MAX_EVENTS 64
|
||||
#define WIN64_NET_SEND_BUFFER_SIZE 262144
|
||||
|
||||
class Socket;
|
||||
|
||||
@@ -73,10 +77,19 @@ struct Win64RemoteConnection
|
||||
{
|
||||
SOCKET tcpSocket;
|
||||
uint8_t smallId;
|
||||
pthread_t recvThread;
|
||||
bool recvThreadActive;
|
||||
volatile bool active;
|
||||
pthread_mutex_t sendLock;
|
||||
|
||||
uint8_t *recvBuffer;
|
||||
int recvBufferUsed;
|
||||
int recvBufferSize;
|
||||
int currentPacketSize;
|
||||
bool readingHeader;
|
||||
|
||||
uint8_t *sendBuffer;
|
||||
int sendBufferUsed;
|
||||
int sendBufferSize;
|
||||
pthread_mutex_t sendBufLock;
|
||||
};
|
||||
|
||||
class WinsockNetLayer
|
||||
@@ -88,6 +101,11 @@ public:
|
||||
static bool HostGame(int port);
|
||||
static bool JoinGame(const char *ip, int port);
|
||||
|
||||
enum JoinResult { JOIN_IN_PROGRESS, JOIN_SUCCESS, JOIN_FAILED };
|
||||
static bool BeginJoinGame(const char *ip, int port);
|
||||
static JoinResult PollJoinResult();
|
||||
static void CancelJoinGame();
|
||||
|
||||
static bool SendToSmallId(uint8_t targetSmallId, const void *data, int dataSize);
|
||||
static bool SendOnSocket(SOCKET sock, const void *data, int dataSize);
|
||||
|
||||
@@ -117,6 +135,7 @@ public:
|
||||
static void UpdateAdvertisePlayerCount(uint8_t count);
|
||||
static void UpdateAdvertiseJoinable(bool joinable);
|
||||
static void UpdateAdvertisePlayerNames(uint8_t count, const char playerNames[][32]);
|
||||
static void UpdateAdvertiseGameHostSettings(unsigned int settings);
|
||||
|
||||
static bool StartDiscovery();
|
||||
static void StopDiscovery();
|
||||
@@ -124,12 +143,17 @@ public:
|
||||
|
||||
static int GetHostPort() { return s_hostGamePort; }
|
||||
|
||||
static void FlushSendBuffers();
|
||||
|
||||
private:
|
||||
static size_t GetConnectionSlotCount();
|
||||
static void* AcceptThreadProc(void* param);
|
||||
static void* RecvThreadProc(void* param);
|
||||
static void* EpollThreadProc(void* param);
|
||||
static void* ClientRecvThreadProc(void* param);
|
||||
static void* AdvertiseThreadProc(void* param);
|
||||
static void* DiscoveryThreadProc(void* param);
|
||||
static void* AsyncJoinThreadProc(void* param);
|
||||
static bool ProcessRecvData(Win64RemoteConnection &conn);
|
||||
|
||||
static SOCKET s_listenSocket;
|
||||
static SOCKET s_hostConnectionSocket;
|
||||
@@ -138,6 +162,10 @@ private:
|
||||
static pthread_t s_clientRecvThread;
|
||||
static bool s_clientRecvThreadActive;
|
||||
|
||||
static int s_epollFd;
|
||||
static pthread_t s_epollThreads[WIN64_NET_IO_THREADS];
|
||||
static bool s_epollThreadsActive;
|
||||
|
||||
static bool s_isHost;
|
||||
static bool s_connected;
|
||||
static bool s_active;
|
||||
@@ -145,12 +173,12 @@ private:
|
||||
|
||||
static uint8_t s_localSmallId;
|
||||
static uint8_t s_hostSmallId;
|
||||
static uint8_t s_nextSmallId;
|
||||
static std::atomic<uint8_t> s_nextSmallId;
|
||||
|
||||
static pthread_mutex_t s_sendLock;
|
||||
static pthread_mutex_t s_connectionsLock;
|
||||
|
||||
static Win64RemoteConnection s_connections[WIN64_NET_MAX_CLIENTS + 1];
|
||||
static std::vector<Win64RemoteConnection> s_connections;
|
||||
|
||||
static SOCKET s_advertiseSock;
|
||||
static pthread_t s_advertiseThread;
|
||||
@@ -161,6 +189,7 @@ private:
|
||||
static int s_hostGamePort;
|
||||
|
||||
static SOCKET s_discoverySock;
|
||||
static SOCKET s_discoveryLegacySock;
|
||||
static pthread_t s_discoveryThread;
|
||||
static bool s_discoveryThreadActive;
|
||||
static volatile bool s_discovering;
|
||||
@@ -177,7 +206,14 @@ private:
|
||||
static std::vector<uint8_t> s_freeSmallIds;
|
||||
|
||||
static pthread_mutex_t s_earlyDataLock;
|
||||
static std::vector<uint8_t> s_earlyDataBuffers[WIN64_NET_MAX_CLIENTS + 1];
|
||||
static std::vector<std::vector<uint8_t> > s_earlyDataBuffers;
|
||||
|
||||
static pthread_t s_asyncJoinThread;
|
||||
static bool s_asyncJoinThreadActive;
|
||||
static volatile JoinResult s_asyncJoinResult;
|
||||
static volatile bool s_asyncJoinActive;
|
||||
static char s_asyncJoinIP[256];
|
||||
static int s_asyncJoinPort;
|
||||
};
|
||||
|
||||
extern bool g_Win64MultiplayerHost;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>MinecraftServer</RootNamespace>
|
||||
<ProjectName>Minecraft.Server</ProjectName>
|
||||
<WindowsTargetPlatformVersion Condition="'$(Platform)'=='x64'">10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
@@ -124,8 +125,8 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<Optimization>Full</Optimization>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)$(ProjectName).pch</PrecompiledHeaderOutputFile>
|
||||
@@ -136,14 +137,19 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<ShowIncludes>false</ShowIncludes>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<StringPooling>true</StringPooling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>ws2_32.lib;..\Minecraft.World\x64_Release\Minecraft.World.lib;..\Minecraft.Client\Windows64\4JLibs\libs\4J_Storage.lib;..\Minecraft.Client\Windows64\4JLibs\libs\4J_Profile_r.lib;..\Minecraft.Client\Windows64\4JLibs\libs\4J_Render_PC.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ShowProgress>NotSet</ShowProgress>
|
||||
<SuppressStartupBanner>false</SuppressStartupBanner>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
@@ -212,6 +218,7 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-Linux|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Core\DedicatedServer.cpp" />
|
||||
<ClCompile Include="Core\ServerThreadPool.cpp" />
|
||||
<ClCompile Include="Core\ServerProperties.cpp" />
|
||||
<ClCompile Include="Stubs\ServerStubs.cpp" />
|
||||
<ClCompile Include="Stubs\ServerStubs2.cpp" />
|
||||
|
||||
@@ -226,6 +226,9 @@
|
||||
<ClCompile Include="Core\DedicatedServer.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Core\ServerThreadPool.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Core\ServerProperties.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "../../Minecraft.World/Dimension.h"
|
||||
#include "../../Minecraft.World/ChunkSource.h"
|
||||
#include "../../Minecraft.Client/Windows64/4JLibs/inc/4J_Input.h"
|
||||
#include "../../Minecraft.Client/Windows64/4JLibs/inc/4J_Storage.h"
|
||||
#include "../../Minecraft.Client/TexturePackRepository.h"
|
||||
|
||||
Reference in New Issue
Block a user