mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
A new server (dUgcServer, started by master with enable_ugc_server=1) that takes unprocessed ugc and ugc_modular_build rows from the database and makes what the client downloads with UGCUSE3DSERVICES: an optimized NIF (hidden faces removed, ambient occlusion baked into vertex colors) and a 128px DDS icon for player models, rendered by a software rasterizer from the client's LDD brick primitives, and icons for cars and rockets assembled from their modules per ModularBuildComponent/ModuleComponent. It serves them, with the models' LXFML, over HTTP in the client's UGCC<dc>/3DOPTIMIZED and IMAGE128DDS layout with .gz and .checksum files, and keeps its folder under a size cap. Processing state lives in ugc.is_optimized plus new processed_at, process_attempts and process_error columns (and the same on ugc_modular_build). ServiceType::UGC is appended. NifFile moves to dCommon and records named node transforms for the modules' attach points. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
222 lines
6.2 KiB
C++
222 lines
6.2 KiB
C++
#include "Start.h"
|
|
#include "Logger.h"
|
|
#include "dConfig.h"
|
|
#include "Game.h"
|
|
#include "BinaryPathFinder.h"
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <handleapi.h>
|
|
#include <processthreadsapi.h>
|
|
|
|
namespace {
|
|
const auto startup = STARTUPINFOW{
|
|
.cb = sizeof(STARTUPINFOW),
|
|
.lpReserved = nullptr,
|
|
.lpDesktop = nullptr,
|
|
.lpTitle = nullptr,
|
|
.dwX = 0,
|
|
.dwY = 0,
|
|
.dwXSize = 0,
|
|
.dwYSize = 0,
|
|
.dwXCountChars = 0,
|
|
.dwYCountChars = 0,
|
|
.dwFillAttribute = 0,
|
|
.dwFlags = 0,
|
|
.wShowWindow = 0,
|
|
.cbReserved2 = 0,
|
|
.lpReserved2 = nullptr,
|
|
.hStdInput = INVALID_HANDLE_VALUE,
|
|
.hStdOutput = INVALID_HANDLE_VALUE,
|
|
.hStdError = INVALID_HANDLE_VALUE,
|
|
};
|
|
}
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
uint32_t StartChatServer() {
|
|
if (Game::ShouldShutdown()) {
|
|
LOG("Currently shutting down. Chat will not be restarted.");
|
|
return 0;
|
|
}
|
|
auto chat_path = BinaryPathFinder::GetBinaryDir() / "ChatServer";
|
|
#ifdef _WIN32
|
|
chat_path.replace_extension(".exe");
|
|
auto chat_startup = startup;
|
|
auto chat_info = PROCESS_INFORMATION{};
|
|
if (!CreateProcessW(chat_path.wstring().data(), chat_path.wstring().data(),
|
|
nullptr, nullptr, false, 0, nullptr, nullptr,
|
|
&chat_startup, &chat_info))
|
|
{
|
|
LOG("Failed to launch ChatServer");
|
|
return 0;
|
|
}
|
|
|
|
// get pid and close unused handles
|
|
auto chat_pid = chat_info.dwProcessId;
|
|
CloseHandle(chat_info.hProcess);
|
|
CloseHandle(chat_info.hThread);
|
|
#else // *nix systems
|
|
const auto chat_pid = fork();
|
|
if (chat_pid < 0) {
|
|
LOG("Failed to launch ChatServer");
|
|
return 0;
|
|
} else if (chat_pid == 0) {
|
|
// We are the child process
|
|
execl(chat_path.string().c_str(), chat_path.string().c_str(), nullptr);
|
|
}
|
|
#endif
|
|
LOG("ChatServer PID is %d", chat_pid);
|
|
return chat_pid;
|
|
}
|
|
|
|
uint32_t StartAuthServer() {
|
|
if (Game::ShouldShutdown()) {
|
|
LOG("Currently shutting down. Auth will not be restarted.");
|
|
return 0;
|
|
}
|
|
auto auth_path = BinaryPathFinder::GetBinaryDir() / "AuthServer";
|
|
#ifdef _WIN32
|
|
auth_path.replace_extension(".exe");
|
|
auto auth_startup = startup;
|
|
auto auth_info = PROCESS_INFORMATION{};
|
|
if (!CreateProcessW(auth_path.wstring().data(), auth_path.wstring().data(),
|
|
nullptr, nullptr, false, 0, nullptr, nullptr,
|
|
&auth_startup, &auth_info))
|
|
{
|
|
LOG("Failed to launch AuthServer");
|
|
return 0;
|
|
}
|
|
|
|
// get pid and close unused handles
|
|
auto auth_pid = auth_info.dwProcessId;
|
|
CloseHandle(auth_info.hProcess);
|
|
CloseHandle(auth_info.hThread);
|
|
#else // *nix systems
|
|
const auto auth_pid = fork();
|
|
if (auth_pid < 0) {
|
|
LOG("Failed to launch AuthServer");
|
|
return 0;
|
|
} else if (auth_pid == 0) {
|
|
// We are the child process
|
|
execl(auth_path.string().c_str(), auth_path.string().c_str(), nullptr);
|
|
}
|
|
#endif
|
|
LOG("AuthServer PID is %d", auth_pid);
|
|
return auth_pid;
|
|
}
|
|
|
|
uint32_t StartDashboardServer() {
|
|
if (Game::ShouldShutdown()) {
|
|
LOG("Currently shutting down. DashboardServer will not be restarted.");
|
|
return 0;
|
|
}
|
|
auto web_path = BinaryPathFinder::GetBinaryDir() / "DashboardServer";
|
|
#ifdef _WIN32
|
|
web_path.replace_extension(".exe");
|
|
auto web_startup = startup;
|
|
auto web_info = PROCESS_INFORMATION{};
|
|
if (!CreateProcessW(web_path.wstring().data(), web_path.wstring().data(),
|
|
nullptr, nullptr, false, 0, nullptr, nullptr,
|
|
&web_startup, &web_info))
|
|
{
|
|
LOG("Failed to launch DashboardServer");
|
|
return 0;
|
|
}
|
|
|
|
// get pid and close unused handles
|
|
auto web_pid = web_info.dwProcessId;
|
|
CloseHandle(web_info.hProcess);
|
|
CloseHandle(web_info.hThread);
|
|
#else // *nix systems
|
|
const auto web_pid = fork();
|
|
if (web_pid < 0) {
|
|
LOG("Failed to launch DashboardServer");
|
|
return 0;
|
|
} else if (web_pid == 0) {
|
|
// We are the child process
|
|
execl(web_path.string().c_str(), web_path.string().c_str(), nullptr);
|
|
}
|
|
#endif
|
|
LOG("DashboardServer PID is %d", web_pid);
|
|
return web_pid;
|
|
}
|
|
|
|
uint32_t StartUgcServer() {
|
|
if (Game::ShouldShutdown()) {
|
|
LOG("Currently shutting down. UgcServer will not be restarted.");
|
|
return 0;
|
|
}
|
|
auto ugc_path = BinaryPathFinder::GetBinaryDir() / "UgcServer";
|
|
#ifdef _WIN32
|
|
ugc_path.replace_extension(".exe");
|
|
auto ugc_startup = startup;
|
|
auto ugc_info = PROCESS_INFORMATION{};
|
|
if (!CreateProcessW(ugc_path.wstring().data(), ugc_path.wstring().data(),
|
|
nullptr, nullptr, false, 0, nullptr, nullptr,
|
|
&ugc_startup, &ugc_info))
|
|
{
|
|
LOG("Failed to launch UgcServer");
|
|
return 0;
|
|
}
|
|
|
|
// get pid and close unused handles
|
|
auto ugc_pid = ugc_info.dwProcessId;
|
|
CloseHandle(ugc_info.hProcess);
|
|
CloseHandle(ugc_info.hThread);
|
|
#else // *nix systems
|
|
const auto ugc_pid = fork();
|
|
if (ugc_pid < 0) {
|
|
LOG("Failed to launch UgcServer");
|
|
return 0;
|
|
} else if (ugc_pid == 0) {
|
|
// We are the child process
|
|
execl(ugc_path.string().c_str(), ugc_path.string().c_str(), nullptr);
|
|
}
|
|
#endif
|
|
LOG("UgcServer PID is %d", ugc_pid);
|
|
return ugc_pid;
|
|
}
|
|
|
|
uint32_t StartWorldServer(LWOMAPID mapID, uint16_t port, LWOINSTANCEID lastInstanceID, int maxPlayers, LWOCLONEID cloneID) {
|
|
auto world_path = BinaryPathFinder::GetBinaryDir() / "WorldServer";
|
|
#ifdef _WIN32
|
|
world_path.replace_extension(".exe");
|
|
auto cmd = world_path.wstring() + L" -zone " + std::to_wstring(mapID) + L" -port " + std::to_wstring(port) +
|
|
L" -instance " + std::to_wstring(lastInstanceID) + L" -maxclients " + std::to_wstring(maxPlayers) +
|
|
L" -clone " + std::to_wstring(cloneID);
|
|
|
|
auto world_startup = startup;
|
|
auto world_info = PROCESS_INFORMATION{};
|
|
if (!CreateProcessW(world_path.wstring().data(), cmd.data(),
|
|
nullptr, nullptr, false, 0, nullptr, nullptr,
|
|
&world_startup, &world_info))
|
|
{
|
|
LOG("Failed to launch WorldServer");
|
|
return 0;
|
|
}
|
|
|
|
// get pid and close unused handles
|
|
auto world_pid = world_info.dwProcessId;
|
|
CloseHandle(world_info.hProcess);
|
|
CloseHandle(world_info.hThread);
|
|
#else
|
|
const auto world_pid = fork();
|
|
if (world_pid < 0) {
|
|
LOG("Failed to launch WorldServer");
|
|
return 0;
|
|
} else if (world_pid == 0) {
|
|
// We are the child process
|
|
execl(world_path.string().c_str(), world_path.string().c_str(),
|
|
"-zone", std::to_string(mapID).c_str(),
|
|
"-port", std::to_string(port).c_str(),
|
|
"-instance", std::to_string(lastInstanceID).c_str(),
|
|
"-maxclients", std::to_string(maxPlayers).c_str(),
|
|
"-clone", std::to_string(cloneID).c_str(), nullptr);
|
|
}
|
|
#endif
|
|
LOG("WorldServer PID is %d", world_pid);
|
|
return world_pid;
|
|
}
|