mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-12 19:28:21 +00:00
Merge pull request #3 from jgkawell/pr-improvements
Dockerized improvements
This commit is contained in:
commit
ef7dd0f069
@ -5,4 +5,12 @@ BUILD_THREADS=1
|
|||||||
# Updates NET_VERSION in CMakeVariables.txt
|
# Updates NET_VERSION in CMakeVariables.txt
|
||||||
BUILD_VERSION=171022
|
BUILD_VERSION=171022
|
||||||
# make sure this is a long random string
|
# make sure this is a long random string
|
||||||
|
# grab a "SHA 256-bit Key" from here: https://keygen.io/
|
||||||
ACCOUNT_MANAGER_SECRET=
|
ACCOUNT_MANAGER_SECRET=
|
||||||
|
# Should be the externally facing IP of your server host
|
||||||
|
EXTERNAL_IP=localhost
|
||||||
|
# Database values
|
||||||
|
MARIADB_USER=darkflame
|
||||||
|
MARIADB_PASSWORD=SECRET_VALUE_CHANGE_ME
|
||||||
|
MARIADB_ROOT_PASSWORD=SECRET_VALUE_CHANGE_ME
|
||||||
|
MARIADB_DATABASE=darkflame
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
temp/
|
temp/
|
||||||
cmake-build-debug/
|
cmake-build-debug/
|
||||||
RelWithDebInfo/
|
RelWithDebInfo/
|
||||||
|
docker/configs
|
||||||
|
|
||||||
# Third party libraries
|
# Third party libraries
|
||||||
thirdparty/mysql/
|
thirdparty/mysql/
|
||||||
|
@ -95,7 +95,7 @@ if (__include_backtrace__ AND __compile_backtrace__)
|
|||||||
|
|
||||||
link_directories(${backtrace_SOURCE_DIR}/.libs/)
|
link_directories(${backtrace_SOURCE_DIR}/.libs/)
|
||||||
include_directories(${backtrace_SOURCE_DIR})
|
include_directories(${backtrace_SOURCE_DIR})
|
||||||
endif(__include_backtrace__ AND __compile_backtrace__)
|
endif(__include_backtrace__)
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
endif(UNIX)
|
endif(UNIX)
|
||||||
|
22
Docker.md
22
Docker.md
@ -1,22 +1,26 @@
|
|||||||
# Run the Darkflame Server inside Docker
|
# Run the Darkflame Server inside Docker
|
||||||
|
|
||||||
### What you need
|
## What you need
|
||||||
|
|
||||||
- Docker (Docker Desktop or on Linux normal Docker)
|
- Docker (Docker Desktop or on Linux normal Docker)
|
||||||
- Docker-Compose (Included in Docker Desktop)
|
- Docker-Compose (Included in Docker Desktop)
|
||||||
- LEGO® Universe Client
|
- LEGO® Universe Client
|
||||||
|
|
||||||
### Run server inside Docker
|
## Run server inside Docker
|
||||||
|
|
||||||
1. Copy `.env.example` and save it as `.env` inside the root directory of this repository
|
1. Copy `.env.example` and save it as `.env` inside the root directory of this repository
|
||||||
2. Edit the `.env` file and add your path to your LEGO® Universe Client after `CLIENT_PATH=`
|
2. Edit the `.env` file and add your path to your LEGO® Universe Client after `CLIENT_PATH=`
|
||||||
3. Add some random long string after `ACCOUNT_MANAGER_SECRET=` in the `.env` file
|
3. Update other values in the `.env` file as need (be sure to update passwords!)
|
||||||
4. (Optional) You can decrease the build time if you change number behind `BUILD_THREADS=` in the `.env` file. You should change it to the number of threads your system have.
|
4. Run `docker-compose up --build setup`
|
||||||
5. Run `docker compose up -d --build` or `docker-compose up -d --build` and wait for it to complete
|
5. Run `docker-compose up -d database`
|
||||||
6. Now you can see the output of the server with `docker compose logs -f --tail 100` or `docker-compose logs -f --tail 100`. This can help you understand issues and there you can also see when the server finishes it's startup.
|
6. Run `docker-compose up --build -d account-manager brickbuildfix`
|
||||||
|
7. Run `docker-compose build darkflame`
|
||||||
|
8. Run `docker-compose exec darkflame /app/MasterServer -a` and setup your admin account
|
||||||
|
9. Run `docker-compose up -d darkflame`
|
||||||
|
10. Now you can see the output of the server with `docker compose logs -f --tail 100` or `docker-compose logs -f --tail 100`. This can help you understand issues and there you can also see when the server finishes it's startup.
|
||||||
|
11. You're ready to connect your client!
|
||||||
|
|
||||||
|
## Disable brickbuildfix
|
||||||
### Disable brickbuildfix
|
|
||||||
|
|
||||||
If you don't need the http server running on port 80 do this:
|
If you don't need the http server running on port 80 do this:
|
||||||
|
|
||||||
@ -30,4 +34,4 @@ services:
|
|||||||
- donotstart
|
- donotstart
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Now run `docker compose up -d --build` or `docker-compose up -d --build`
|
3. Now run `docker compose up -d --build` or `docker-compose up -d --build`
|
@ -1222,19 +1222,13 @@ void Entity::UpdateXMLDoc(tinyxml2::XMLDocument* doc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Entity::Update(const float deltaTime) {
|
void Entity::Update(const float deltaTime) {
|
||||||
int timerSize = m_Timers.size();
|
for (int i = 0; i < m_Timers.size(); i++) {
|
||||||
for (int i = 0; i < timerSize; i++) {
|
|
||||||
m_Timers[i]->Update(deltaTime);
|
m_Timers[i]->Update(deltaTime);
|
||||||
if (m_Timers[i]->GetTime() <= 0) {
|
if (m_Timers[i]->GetTime() <= 0) {
|
||||||
const auto timerName = m_Timers[i]->GetName();
|
const auto timerName = m_Timers[i]->GetName();
|
||||||
|
|
||||||
do { //sometimes, due to a race condition, m_Timers.erase doesn't actually erase, repeat until it does
|
|
||||||
if (m_Timers[i]->GetName() != timerName) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
delete m_Timers[i];
|
delete m_Timers[i];
|
||||||
m_Timers.erase(m_Timers.begin() + i);
|
m_Timers.erase(m_Timers.begin() + i);
|
||||||
} while (m_Timers.size() == timerSize); //timer size indicates whether it's actually successfully been erased or not
|
|
||||||
|
|
||||||
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
|
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
|
||||||
script->OnTimerDone(this, timerName);
|
script->OnTimerDone(this, timerName);
|
||||||
|
@ -157,10 +157,16 @@ int main(int argc, char** argv) {
|
|||||||
auto* masterLookupStatement = Database::CreatePreppedStmt("SELECT id FROM `servers` WHERE `name` = 'master'");
|
auto* masterLookupStatement = Database::CreatePreppedStmt("SELECT id FROM `servers` WHERE `name` = 'master'");
|
||||||
auto* result = masterLookupStatement->executeQuery();
|
auto* result = masterLookupStatement->executeQuery();
|
||||||
|
|
||||||
|
auto master_server_ip = config.GetValue("master_ip");
|
||||||
|
|
||||||
|
if (master_server_ip == "") {
|
||||||
|
master_server_ip = Game::server->GetIP();
|
||||||
|
}
|
||||||
|
|
||||||
//If we found a server, update it's IP and port to the current one.
|
//If we found a server, update it's IP and port to the current one.
|
||||||
if (result->next()) {
|
if (result->next()) {
|
||||||
auto* updateStatement = Database::CreatePreppedStmt("UPDATE `servers` SET `ip` = ?, `port` = ? WHERE `id` = ?");
|
auto* updateStatement = Database::CreatePreppedStmt("UPDATE `servers` SET `ip` = ?, `port` = ? WHERE `id` = ?");
|
||||||
updateStatement->setString(1, Game::server->GetIP());
|
updateStatement->setString(1, master_server_ip);
|
||||||
updateStatement->setInt(2, Game::server->GetPort());
|
updateStatement->setInt(2, Game::server->GetPort());
|
||||||
updateStatement->setInt(3, result->getInt("id"));
|
updateStatement->setInt(3, result->getInt("id"));
|
||||||
updateStatement->execute();
|
updateStatement->execute();
|
||||||
@ -169,7 +175,7 @@ int main(int argc, char** argv) {
|
|||||||
else {
|
else {
|
||||||
//If we didn't find a server, create one.
|
//If we didn't find a server, create one.
|
||||||
auto* insertStatement = Database::CreatePreppedStmt("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`) VALUES ('master', ?, ?, 0, 171023)");
|
auto* insertStatement = Database::CreatePreppedStmt("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`) VALUES ('master', ?, ?, 0, 171023)");
|
||||||
insertStatement->setString(1, Game::server->GetIP());
|
insertStatement->setString(1, master_server_ip);
|
||||||
insertStatement->setInt(2, Game::server->GetPort());
|
insertStatement->setInt(2, Game::server->GetPort());
|
||||||
insertStatement->execute();
|
insertStatement->execute();
|
||||||
delete insertStatement;
|
delete insertStatement;
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
#include "AgShipShake.h"
|
|
||||||
#include "GeneralUtils.h"
|
|
||||||
#include "GameMessages.h"
|
|
||||||
#include "dZoneManager.h"
|
|
||||||
#include "EntityManager.h"
|
|
||||||
#include "Game.h"
|
|
||||||
|
|
||||||
void AgShipShake::OnStartup(Entity* self) {
|
|
||||||
EntityInfo info{};
|
|
||||||
|
|
||||||
info.pos = { -418, 585, -30 };
|
|
||||||
info.lot = 33;
|
|
||||||
info.spawnerID = self->GetObjectID();
|
|
||||||
|
|
||||||
auto* ref = EntityManager::Instance()->CreateEntity(info);
|
|
||||||
|
|
||||||
EntityManager::Instance()->ConstructEntity(ref);
|
|
||||||
|
|
||||||
self->SetVar(u"ShakeObject", ref->GetObjectID());
|
|
||||||
|
|
||||||
self->AddTimer("ShipShakeIdle", 1.0f);
|
|
||||||
self->SetVar(u"RandomTime", 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AgShipShake::OnTimerDone(Entity* self, std::string timerName) {
|
|
||||||
if (timerName == "ShipShakeExplode") {
|
|
||||||
DoShake(self, true);
|
|
||||||
}
|
|
||||||
else if (timerName == "ShipShakeIdle") {
|
|
||||||
DoShake(self, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AgShipShake::DoShake(Entity* self, bool explodeIdle) {
|
|
||||||
if (!explodeIdle) {
|
|
||||||
auto* ref = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"ShakeObject"));
|
|
||||||
|
|
||||||
const auto randomTime = self->GetVar<int>(u"RandomTime");
|
|
||||||
auto time = GeneralUtils::GenerateRandomNumber<int>(0, randomTime + 1);
|
|
||||||
|
|
||||||
if (time < randomTime / 2) {
|
|
||||||
time += randomTime / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->AddTimer("ShipShakeIdle", static_cast<float>(time));
|
|
||||||
|
|
||||||
if (ref)
|
|
||||||
GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(ref, FXName, ref->GetObjectID(), 500.0f);
|
|
||||||
|
|
||||||
auto* debrisObject = GetEntityInGroup(DebrisFX);
|
|
||||||
|
|
||||||
if (debrisObject)
|
|
||||||
GameMessages::SendPlayFXEffect(debrisObject, -1, u"DebrisFall", "Debris", LWOOBJID_EMPTY, 1.0f, 1.0f, true);
|
|
||||||
|
|
||||||
const auto randomFx = GeneralUtils::GenerateRandomNumber<int>(0, 3);
|
|
||||||
|
|
||||||
auto* shipFxObject = GetEntityInGroup(ShipFX);
|
|
||||||
if (shipFxObject) {
|
|
||||||
std::string effectType = "shipboom" + std::to_string(randomFx);
|
|
||||||
GameMessages::SendPlayFXEffect(shipFxObject, 559, GeneralUtils::ASCIIToUTF16(effectType), "FX", LWOOBJID_EMPTY, 1.0f, 1.0f, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
self->AddTimer("ShipShakeExplode", 5.0f);
|
|
||||||
|
|
||||||
auto* shipFxObject2 = GetEntityInGroup(ShipFX2);
|
|
||||||
if (shipFxObject2)
|
|
||||||
GameMessages::SendPlayAnimation(shipFxObject2, u"explosion");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto* shipFxObject = GetEntityInGroup(ShipFX);
|
|
||||||
auto* shipFxObject2 = GetEntityInGroup(ShipFX2);
|
|
||||||
|
|
||||||
if (shipFxObject)
|
|
||||||
GameMessages::SendPlayAnimation(shipFxObject, u"idle");
|
|
||||||
|
|
||||||
if (shipFxObject2)
|
|
||||||
GameMessages::SendPlayAnimation(shipFxObject2, u"idle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity* AgShipShake::GetEntityInGroup(const std::string& group) {
|
|
||||||
auto entities = EntityManager::Instance()->GetEntitiesInGroup(group);
|
|
||||||
Entity* en = nullptr;
|
|
||||||
|
|
||||||
for (auto entity : entities) {
|
|
||||||
if (entity) {
|
|
||||||
en = entity;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return en;
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "CppScripts.h"
|
|
||||||
|
|
||||||
class AgShipShake : public CppScripts::Script {
|
|
||||||
public:
|
|
||||||
void OnStartup(Entity* self);
|
|
||||||
void OnTimerDone(Entity* self, std::string timerName);
|
|
||||||
void DoShake(Entity* self, bool explodeIdle);
|
|
||||||
|
|
||||||
std::string DebrisFX = "DebrisFX";
|
|
||||||
std::string ShipFX = "ShipFX";
|
|
||||||
std::string ShipFX2 = "ShipFX2";
|
|
||||||
std::u16string FXName = u"camshake-bridge";
|
|
||||||
|
|
||||||
private:
|
|
||||||
Entity* GetEntityInGroup(const std::string& group);
|
|
||||||
};
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
#include "AgSpaceStuff.h"
|
#include "AgSpaceStuff.h"
|
||||||
#include "GeneralUtils.h"
|
#include "GeneralUtils.h"
|
||||||
#include "GameMessages.h"
|
#include "GameMessages.h"
|
||||||
|
#include "dZoneManager.h"
|
||||||
#include "EntityManager.h"
|
#include "EntityManager.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
|
|
||||||
@ -16,6 +17,11 @@ void AgSpaceStuff::OnStartup(Entity* self) {
|
|||||||
auto* ref = EntityManager::Instance()->CreateEntity(info);
|
auto* ref = EntityManager::Instance()->CreateEntity(info);
|
||||||
|
|
||||||
EntityManager::Instance()->ConstructEntity(ref);
|
EntityManager::Instance()->ConstructEntity(ref);
|
||||||
|
|
||||||
|
self->SetVar(u"ShakeObject", ref->GetObjectID());
|
||||||
|
|
||||||
|
self->AddTimer("ShipShakeIdle", 1.0f);
|
||||||
|
self->SetVar(u"RandomTime", 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AgSpaceStuff::OnTimerDone(Entity* self, std::string timerName) {
|
void AgSpaceStuff::OnTimerDone(Entity* self, std::string timerName) {
|
||||||
@ -32,4 +38,72 @@ void AgSpaceStuff::OnTimerDone(Entity* self, std::string timerName) {
|
|||||||
GameMessages::SendPlayAnimation(self, u"path_0" + (GeneralUtils::to_u16string(pathType)));
|
GameMessages::SendPlayAnimation(self, u"path_0" + (GeneralUtils::to_u16string(pathType)));
|
||||||
self->AddTimer("FloaterScale", randTime);
|
self->AddTimer("FloaterScale", randTime);
|
||||||
}
|
}
|
||||||
|
else if (timerName == "ShipShakeExplode") {
|
||||||
|
DoShake(self, true);
|
||||||
|
}
|
||||||
|
else if (timerName == "ShipShakeIdle") {
|
||||||
|
DoShake(self, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgSpaceStuff::DoShake(Entity* self, bool explodeIdle) {
|
||||||
|
|
||||||
|
if (!explodeIdle) {
|
||||||
|
auto* ref = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"ShakeObject"));
|
||||||
|
|
||||||
|
const auto randomTime = self->GetVar<int>(u"RandomTime");
|
||||||
|
auto time = GeneralUtils::GenerateRandomNumber<int>(0, randomTime + 1);
|
||||||
|
|
||||||
|
if (time < randomTime / 2) {
|
||||||
|
time += randomTime / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->AddTimer("ShipShakeIdle", static_cast<float>(time));
|
||||||
|
|
||||||
|
if (ref)
|
||||||
|
GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(ref, FXName, ref->GetObjectID(), 500.0f);
|
||||||
|
|
||||||
|
auto* debrisObject = GetEntityInGroup(DebrisFX);
|
||||||
|
|
||||||
|
if (debrisObject)
|
||||||
|
GameMessages::SendPlayFXEffect(debrisObject, -1, u"DebrisFall", "Debris", LWOOBJID_EMPTY, 1.0f, 1.0f, true);
|
||||||
|
|
||||||
|
const auto randomFx = GeneralUtils::GenerateRandomNumber<int>(0, 3);
|
||||||
|
|
||||||
|
auto* shipFxObject = GetEntityInGroup(ShipFX);
|
||||||
|
if (shipFxObject) {
|
||||||
|
std::string effectType = "shipboom" + std::to_string(randomFx);
|
||||||
|
GameMessages::SendPlayFXEffect(shipFxObject, 559, GeneralUtils::ASCIIToUTF16(effectType), "FX", LWOOBJID_EMPTY, 1.0f, 1.0f, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
self->AddTimer("ShipShakeExplode", 5.0f);
|
||||||
|
|
||||||
|
auto* shipFxObject2 = GetEntityInGroup(ShipFX2);
|
||||||
|
if (shipFxObject2)
|
||||||
|
GameMessages::SendPlayAnimation(shipFxObject2, u"explosion");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto* shipFxObject = GetEntityInGroup(ShipFX);
|
||||||
|
auto* shipFxObject2 = GetEntityInGroup(ShipFX2);
|
||||||
|
|
||||||
|
if (shipFxObject)
|
||||||
|
GameMessages::SendPlayAnimation(shipFxObject, u"idle");
|
||||||
|
|
||||||
|
if (shipFxObject2)
|
||||||
|
GameMessages::SendPlayAnimation(shipFxObject2, u"idle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity* AgSpaceStuff::GetEntityInGroup(const std::string& group) {
|
||||||
|
auto entities = EntityManager::Instance()->GetEntitiesInGroup(group);
|
||||||
|
Entity* en = nullptr;
|
||||||
|
|
||||||
|
for (auto entity : entities) {
|
||||||
|
if (entity) {
|
||||||
|
en = entity;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return en;
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,14 @@ class AgSpaceStuff : public CppScripts::Script {
|
|||||||
public:
|
public:
|
||||||
void OnStartup(Entity* self);
|
void OnStartup(Entity* self);
|
||||||
void OnTimerDone(Entity* self, std::string timerName);
|
void OnTimerDone(Entity* self, std::string timerName);
|
||||||
|
void DoShake(Entity* self, bool explodeIdle);
|
||||||
|
|
||||||
|
std::string DebrisFX = "DebrisFX";
|
||||||
|
std::string ShipFX = "ShipFX";
|
||||||
|
std::string ShipFX2 = "ShipFX2";
|
||||||
|
std::u16string FXName = u"camshake-bridge";
|
||||||
|
|
||||||
|
private:
|
||||||
|
Entity* GetEntityInGroup(const std::string& group);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
//VE / AG scripts:
|
//VE / AG scripts:
|
||||||
#include "AgShipPlayerDeathTrigger.h"
|
#include "AgShipPlayerDeathTrigger.h"
|
||||||
#include "AgShipPlayerShockServer.h"
|
#include "AgShipPlayerShockServer.h"
|
||||||
#include "AgShipShake.h"
|
|
||||||
#include "AgSpaceStuff.h"
|
#include "AgSpaceStuff.h"
|
||||||
#include "AgImagSmashable.h"
|
#include "AgImagSmashable.h"
|
||||||
#include "NpcNpSpacemanBob.h"
|
#include "NpcNpSpacemanBob.h"
|
||||||
@ -291,9 +290,7 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr
|
|||||||
script = new AgShipPlayerDeathTrigger();
|
script = new AgShipPlayerDeathTrigger();
|
||||||
else if (scriptName == "scripts\\ai\\NP\\L_NPC_NP_SPACEMAN_BOB.lua")
|
else if (scriptName == "scripts\\ai\\NP\\L_NPC_NP_SPACEMAN_BOB.lua")
|
||||||
script = new NpcNpSpacemanBob();
|
script = new NpcNpSpacemanBob();
|
||||||
else if (scriptName == "scripts\\ai\\AG\\L_AG_SHIP_SHAKE.lua")
|
else if (scriptName == "scripts\\ai\\AG\\L_AG_SPACE_STUFF.lua") // Broken, will (sometimes) display all animations at once on initial login
|
||||||
script = new AgShipShake();
|
|
||||||
else if (scriptName == "scripts\\ai\\AG\\L_AG_SPACE_STUFF.lua")
|
|
||||||
script = new AgSpaceStuff();
|
script = new AgSpaceStuff();
|
||||||
else if (scriptName == "scripts\\ai\\AG\\L_AG_SHIP_PLAYER_SHOCK_SERVER.lua")
|
else if (scriptName == "scripts\\ai\\AG\\L_AG_SHIP_PLAYER_SHOCK_SERVER.lua")
|
||||||
script = new AgShipPlayerShockServer();
|
script = new AgShipPlayerShockServer();
|
||||||
|
@ -1,9 +1,26 @@
|
|||||||
version: "3"
|
version: "3"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
setup:
|
||||||
|
container_name: DarkflameSetup
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./docker/setup.Dockerfile
|
||||||
|
environment:
|
||||||
|
- DATABASE=${MARIADB_DATABASE:-darkflame}
|
||||||
|
- DATABASE_HOST=database
|
||||||
|
- DATABASE_USER=${MARIADB_USER:-darkflame}
|
||||||
|
- DATABASE_PASSWORD=${MARIADB_PASSWORD:-darkflame}
|
||||||
|
- EXTERNAL_IP=${EXTERNAL_IP:-darkflame}
|
||||||
|
volumes:
|
||||||
|
- ${CLIENT_PATH:?err}:/client
|
||||||
|
- shared_configs:/docker/
|
||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: DarkflameDatabase
|
container_name: DarkflameDatabase
|
||||||
image: mariadb:10.6
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./docker/database.Dockerfile
|
||||||
environment:
|
environment:
|
||||||
- MARIADB_USER=${MARIADB_USER:-darkflame}
|
- MARIADB_USER=${MARIADB_USER:-darkflame}
|
||||||
- MARIADB_PASSWORD=${MARIADB_PASSWORD:-darkflame}
|
- MARIADB_PASSWORD=${MARIADB_PASSWORD:-darkflame}
|
||||||
@ -11,12 +28,14 @@ services:
|
|||||||
- MARIADB_DATABASE=${MARIADB_DATABASE:-darkflame}
|
- MARIADB_DATABASE=${MARIADB_DATABASE:-darkflame}
|
||||||
volumes:
|
volumes:
|
||||||
- database:/var/lib/mysql
|
- database:/var/lib/mysql
|
||||||
- ./migrations/dlu:/docker-entrypoint-initdb.d
|
|
||||||
networks:
|
networks:
|
||||||
- darkflame
|
- darkflame
|
||||||
|
# You can expose these so that DB management tools can connect (WARNING: INSECURE)
|
||||||
|
# ports:
|
||||||
|
# - 3306:3306
|
||||||
|
|
||||||
darkflame:
|
darkflame:
|
||||||
container_name: DarkFlameServer
|
container_name: DarkflameServer
|
||||||
networks:
|
networks:
|
||||||
- darkflame
|
- darkflame
|
||||||
build:
|
build:
|
||||||
@ -25,13 +44,9 @@ services:
|
|||||||
args:
|
args:
|
||||||
- BUILD_THREADS=${BUILD_THREADS:-1}
|
- BUILD_THREADS=${BUILD_THREADS:-1}
|
||||||
- BUILD_VERSION=${BUILD_VERSION:-171022}
|
- BUILD_VERSION=${BUILD_VERSION:-171022}
|
||||||
environment:
|
|
||||||
- DATABASE=${MARIADB_DATABASE:-darkflame}
|
|
||||||
- DATABASE_HOST=database
|
|
||||||
- DATABASE_USER=${MARIADB_USER:-darkflame}
|
|
||||||
- DATABASE_PASSWORD=${MARIADB_PASSWORD:-darkflame}
|
|
||||||
volumes:
|
volumes:
|
||||||
- ${CLIENT_PATH:?err}:/client
|
- ${CLIENT_PATH:?err}:/client
|
||||||
|
- shared_configs:/shared_configs
|
||||||
depends_on:
|
depends_on:
|
||||||
- database
|
- database
|
||||||
ports:
|
ports:
|
||||||
@ -41,7 +56,7 @@ services:
|
|||||||
- "3000-3300:3000-3300/udp"
|
- "3000-3300:3000-3300/udp"
|
||||||
|
|
||||||
brickbuildfix:
|
brickbuildfix:
|
||||||
container_name: DarkFlameBrickBuildFix
|
container_name: DarkflameBrickBuildFix
|
||||||
networks:
|
networks:
|
||||||
- darkflame
|
- darkflame
|
||||||
build:
|
build:
|
||||||
@ -57,7 +72,7 @@ services:
|
|||||||
start_period: 40s
|
start_period: 40s
|
||||||
|
|
||||||
account-manager:
|
account-manager:
|
||||||
container_name: DarkFlameAccountManager
|
container_name: DarkflameAccountManager
|
||||||
networks:
|
networks:
|
||||||
- darkflame
|
- darkflame
|
||||||
build:
|
build:
|
||||||
@ -85,3 +100,4 @@ networks:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
database:
|
database:
|
||||||
|
shared_configs:
|
||||||
|
@ -43,7 +43,7 @@ FROM gcc:11 as runtime
|
|||||||
|
|
||||||
RUN --mount=type=cache,id=runtime-apt-cache,target=/var/cache/apt \
|
RUN --mount=type=cache,id=runtime-apt-cache,target=/var/cache/apt \
|
||||||
apt update && \
|
apt update && \
|
||||||
apt install mariadb-client python3 sudo sqlite3 -yqq --no-install-recommends && \
|
apt install sudo -yqq --no-install-recommends && \
|
||||||
apt remove -y libmysqlcppconn7v5 libmysqlcppconn-dev && \
|
apt remove -y libmysqlcppconn7v5 libmysqlcppconn-dev && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
@ -51,14 +51,9 @@ WORKDIR /app
|
|||||||
|
|
||||||
COPY --from=build /build/build /app
|
COPY --from=build /build/build /app
|
||||||
|
|
||||||
COPY --from=build /build/migrations /app/migrations
|
RUN mkdir /app/logs
|
||||||
|
|
||||||
RUN mkdir -p /build/build && ln -s /app/_deps /build/build/_deps
|
RUN mkdir -p /build/build && ln -s /app/_deps /build/build/_deps
|
||||||
|
|
||||||
ADD docker/*.py /app/utils/
|
|
||||||
|
|
||||||
COPY docker/start_server.sh /start_server.sh
|
COPY docker/start_server.sh /start_server.sh
|
||||||
|
|
||||||
RUN chmod +x /start_server.sh
|
|
||||||
|
|
||||||
CMD [ "/start_server.sh" ]
|
CMD [ "/start_server.sh" ]
|
3
docker/database.Dockerfile
Normal file
3
docker/database.Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
FROM mariadb:10.6
|
||||||
|
|
||||||
|
COPY ./migrations/dlu /docker-entrypoint-initdb.d
|
14
docker/setup.Dockerfile
Normal file
14
docker/setup.Dockerfile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM python:3.10.0-slim-buster as prep
|
||||||
|
|
||||||
|
RUN apt update && apt install unzip sqlite3
|
||||||
|
|
||||||
|
WORKDIR /setup
|
||||||
|
|
||||||
|
# copy needed files from repo
|
||||||
|
COPY resources/ resources/
|
||||||
|
COPY migrations/cdserver/ migrations/cdserver
|
||||||
|
ADD docker/*.py utils/
|
||||||
|
|
||||||
|
COPY docker/setup.sh /setup.sh
|
||||||
|
|
||||||
|
CMD [ "/setup.sh" ]
|
85
docker/setup.sh
Executable file
85
docker/setup.sh
Executable file
@ -0,0 +1,85 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
function update_ini() {
|
||||||
|
FILE="/docker/configs/$1"
|
||||||
|
KEY=$2
|
||||||
|
NEW_VALUE=$3
|
||||||
|
sed -i "/^$KEY=/s/=.*/=$NEW_VALUE/" $FILE
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_database_ini_values_for() {
|
||||||
|
INI_FILE=$1
|
||||||
|
|
||||||
|
update_ini $INI_FILE mysql_host $DATABASE_HOST
|
||||||
|
update_ini $INI_FILE mysql_database $DATABASE
|
||||||
|
update_ini $INI_FILE mysql_username $DATABASE_USER
|
||||||
|
update_ini $INI_FILE mysql_password $DATABASE_PASSWORD
|
||||||
|
if [[ "$INI_FILE" != "worldconfig.ini" ]]; then
|
||||||
|
update_ini $INI_FILE external_ip $EXTERNAL_IP
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_ini_values() {
|
||||||
|
echo "Copying and updating config files"
|
||||||
|
|
||||||
|
mkdir -p /docker/configs
|
||||||
|
cp resources/masterconfig.ini /docker/configs/
|
||||||
|
cp resources/authconfig.ini /docker/configs/
|
||||||
|
cp resources/chatconfig.ini /docker/configs/
|
||||||
|
cp resources/worldconfig.ini /docker/configs/
|
||||||
|
|
||||||
|
update_ini worldconfig.ini chat_server_port $CHAT_SERVER_PORT
|
||||||
|
update_ini worldconfig.ini max_clients $MAX_CLIENTS
|
||||||
|
|
||||||
|
# always use the internal docker hostname
|
||||||
|
update_ini masterconfig.ini master_ip "darkflame"
|
||||||
|
|
||||||
|
update_database_ini_values_for masterconfig.ini
|
||||||
|
update_database_ini_values_for authconfig.ini
|
||||||
|
update_database_ini_values_for chatconfig.ini
|
||||||
|
update_database_ini_values_for worldconfig.ini
|
||||||
|
}
|
||||||
|
|
||||||
|
function fdb_to_sqlite() {
|
||||||
|
echo "Run fdb_to_sqlite"
|
||||||
|
python3 utils/fdb_to_sqlite.py /client/client/res/cdclient.fdb --sqlite_path /client/client/res/CDServer.sqlite
|
||||||
|
|
||||||
|
(
|
||||||
|
cd migrations/cdserver
|
||||||
|
readarray -d '' entries < <(printf '%s\0' *.sql | sort -zV)
|
||||||
|
for entry in "${entries[@]}"; do
|
||||||
|
echo "Execute $entry"
|
||||||
|
sqlite3 /client/client/res/CDServer.sqlite < $entry
|
||||||
|
done
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
update_ini_values
|
||||||
|
|
||||||
|
if [[ ! -d "/client" ]]; then
|
||||||
|
echo "Client not found."
|
||||||
|
echo "Did you forget to mount the client into the \"/client\" directory?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "/client/extracted" ]]; then
|
||||||
|
echo "Start client resource extraction"
|
||||||
|
|
||||||
|
python3 utils/pkextractor.py /client/ /client/
|
||||||
|
|
||||||
|
touch /client/extracted
|
||||||
|
else
|
||||||
|
echo "Client already extracted. Skip this step..."
|
||||||
|
echo "If you want to force a re-extract, just delete the file called \"extracted\" in the client directory"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "/client/migrated" ]]; then
|
||||||
|
echo "Start client db migration"
|
||||||
|
|
||||||
|
fdb_to_sqlite
|
||||||
|
|
||||||
|
touch /client/migrated
|
||||||
|
else
|
||||||
|
echo "Client db already migrated. Skip this step..."
|
||||||
|
echo "If you want to force a re-migrate, just delete the file called \"migrated\" in the client directory"
|
||||||
|
fi
|
124
docker/start_server.sh
Normal file → Executable file
124
docker/start_server.sh
Normal file → Executable file
@ -1,71 +1,14 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
function set_defaults() {
|
|
||||||
DATABASE_PORT=${DATABASE_PORT:-3306}
|
|
||||||
DATABASE=${DATABASE:-darkflame}
|
|
||||||
|
|
||||||
if [[ -z $DATABASE_PASSWORD ]]; then
|
|
||||||
USE_DATABASE_PASSWORD="No"
|
|
||||||
else
|
|
||||||
USE_DATABASE_PASSWORD="Yes"
|
|
||||||
fi
|
|
||||||
|
|
||||||
CHAT_SERVER_PORT=${CHAT_SERVER_PORT:-2005}
|
|
||||||
MAX_CLIENTS=${MAX_CLIENTS:-999}
|
|
||||||
|
|
||||||
echo "Start server with configuration:"
|
|
||||||
echo "===== Database Config ========="
|
|
||||||
echo "Database: $DATABASE"
|
|
||||||
echo "Database host: $DATABASE_HOST"
|
|
||||||
echo "Database port: $DATABASE_PORT"
|
|
||||||
echo "Database user: $DATABASE_USER"
|
|
||||||
echo "Database password set: $USE_DATABASE_PASSWORD"
|
|
||||||
echo "===== Other settings =========="
|
|
||||||
echo "Chat server port: $CHAT_SERVER_PORT"
|
|
||||||
echo "Max clients: $MAX_CLIENTS"
|
|
||||||
}
|
|
||||||
|
|
||||||
function check_sql_connection() {
|
|
||||||
until echo '\q' | mysql -h"$DATABASE_HOST" -P"$DATABASE_PORT" -u"$DATABASE_USER" -p"$DATABASE_PASSWORD" $DATABASE; do
|
|
||||||
>&2 echo "MySQL/MariaDB is unavailable - sleeping"
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
function update_ini() {
|
|
||||||
INI_FILE=$1
|
|
||||||
KEY=$2
|
|
||||||
NEW_VALUE=$3
|
|
||||||
sed -i "/^$KEY=/s/=.*/=$NEW_VALUE/" $INI_FILE
|
|
||||||
}
|
|
||||||
|
|
||||||
function update_database_ini_values_for() {
|
|
||||||
INI_FILE=$1
|
|
||||||
update_ini $INI_FILE mysql_host $DATABASE_HOST
|
|
||||||
update_ini $INI_FILE mysql_database $DATABASE
|
|
||||||
update_ini $INI_FILE mysql_username $DATABASE_USER
|
|
||||||
update_ini $INI_FILE mysql_password $DATABASE_PASSWORD
|
|
||||||
if [[ "$INI_FILE" != "worldconfig.ini" ]]; then
|
|
||||||
update_ini $INI_FILE external_ip "darkflame"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function update_ini_values() {
|
|
||||||
update_ini worldconfig.ini chat_server_port $CHAT_SERVER_PORT
|
|
||||||
update_ini worldconfig.ini max_clients $MAX_CLIENTS
|
|
||||||
|
|
||||||
update_database_ini_values_for masterconfig.ini
|
|
||||||
update_database_ini_values_for authconfig.ini
|
|
||||||
update_database_ini_values_for chatconfig.ini
|
|
||||||
update_database_ini_values_for worldconfig.ini
|
|
||||||
}
|
|
||||||
|
|
||||||
function symlink_client_files() {
|
function symlink_client_files() {
|
||||||
|
echo "Creating symlinks for client files"
|
||||||
ln -s /client/client/res/macros/ /app/res/macros
|
ln -s /client/client/res/macros/ /app/res/macros
|
||||||
ln -s /client/client/res/BrickModels/ /app/res/BrickModels
|
ln -s /client/client/res/BrickModels/ /app/res/BrickModels
|
||||||
ln -s /client/client/res/chatplus_en_us.txt /app/res/chatplus_en_us.txt
|
ln -s /client/client/res/chatplus_en_us.txt /app/res/chatplus_en_us.txt
|
||||||
ln -s /client/client/res/names/ /app/res/names
|
ln -s /client/client/res/names/ /app/res/names
|
||||||
|
ln -s /client/client/res/CDServer.sqlite /app/res/CDServer.sqlite
|
||||||
ln -s /client/client/locale/locale.xml /app/locale/locale.xml
|
ln -s /client/client/locale/locale.xml /app/locale/locale.xml
|
||||||
|
# need to iterate over entries in maps due to maps already being a directory with navmeshes/ in it
|
||||||
(
|
(
|
||||||
cd /client/client/res/maps
|
cd /client/client/res/maps
|
||||||
readarray -d '' entries < <(printf '%s\0' * | sort -zV)
|
readarray -d '' entries < <(printf '%s\0' * | sort -zV)
|
||||||
@ -75,49 +18,32 @@ function symlink_client_files() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function fdb_to_sqlite() {
|
function symlink_config_files() {
|
||||||
echo "Run fdb_to_sqlite"
|
echo "Creating symlinks for config files"
|
||||||
python3 /app/utils/fdb_to_sqlite.py /client/client/res/CDClient.fdb --sqlite_path /app/res/CDServer.sqlite
|
rm /app/*.ini
|
||||||
|
ln -s /shared_configs/configs/authconfig.ini /app/authconfig.ini
|
||||||
(
|
ln -s /shared_configs/configs/chatconfig.ini /app/chatconfig.ini
|
||||||
cd /app/migrations/cdserver
|
ln -s /shared_configs/configs/masterconfig.ini /app/masterconfig.ini
|
||||||
readarray -d '' entries < <(printf '%s\0' *.sql | sort -zV)
|
ln -s /shared_configs/configs/worldconfig.ini /app/worldconfig.ini
|
||||||
for entry in "${entries[@]}"; do
|
|
||||||
echo "Execute $entry"
|
|
||||||
sqlite3 /app/res/CDServer.sqlite < $entry
|
|
||||||
done
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set_defaults
|
if [[ ! -f "/app/initialized" ]]; then
|
||||||
|
# setup symlinks for volume files
|
||||||
check_sql_connection
|
|
||||||
|
|
||||||
update_ini_values
|
|
||||||
|
|
||||||
if [[ ! -d "/client" ]]; then
|
|
||||||
echo "Client not found."
|
|
||||||
echo "Did you forgot to mount the client into the \"/client\" directory?"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f "/client/extracted" ]]; then
|
|
||||||
echo "Start client resource extraction"
|
|
||||||
|
|
||||||
python3 /app/utils/pkextractor.py /client/ /client/
|
|
||||||
|
|
||||||
touch /client/extracted
|
|
||||||
else
|
|
||||||
echo "Client already extracted. Skip this step"
|
|
||||||
echo "If you want to force re-extract, just delete the file called \"extracted\" in the client directory"
|
|
||||||
fi
|
|
||||||
|
|
||||||
symlink_client_files
|
symlink_client_files
|
||||||
|
symlink_config_files
|
||||||
|
# do not run symlinks more than once
|
||||||
|
touch /app/initialized
|
||||||
|
else
|
||||||
|
echo "Server already initialized"
|
||||||
|
fi
|
||||||
|
|
||||||
fdb_to_sqlite
|
# check to make sure the setup has completed
|
||||||
|
while [ ! -f "/client/extracted" ] || [ ! -f "/client/migrated" ]; do
|
||||||
echo "Start MasterServer"
|
echo "Client setup not finished. Waiting for setup container to complete..."
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
# start the server
|
||||||
|
echo "Starting MasterServer"
|
||||||
./MasterServer
|
./MasterServer
|
||||||
|
|
||||||
tail -f /dev/null
|
tail -f /dev/null
|
@ -7,6 +7,9 @@ mysql_password=
|
|||||||
# The public facing IP address. Can be 'localhost' for locally hosted servers
|
# The public facing IP address. Can be 'localhost' for locally hosted servers
|
||||||
external_ip=localhost
|
external_ip=localhost
|
||||||
|
|
||||||
|
# The internal ip of the master server
|
||||||
|
master_ip=localhost
|
||||||
|
|
||||||
# Port number
|
# Port number
|
||||||
port=2000
|
port=2000
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user