diff --git a/.gitignore b/.gitignore index a28f0302..28f8f297 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ temp/ cmake-build-debug/ RelWithDebInfo/ +docker/configs # Third party libraries thirdparty/mysql/ diff --git a/Docker.md b/Docker.md index 9baf2add..06beb87e 100644 --- a/Docker.md +++ b/Docker.md @@ -1,22 +1,23 @@ # Run the Darkflame Server inside Docker -### What you need +## What you need - Docker (Docker Desktop or on Linux normal Docker) - Docker-Compose (Included in Docker Desktop) - 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 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 -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. -5. Run `docker compose up -d --build` or `docker-compose up -d --build` and wait for it to complete -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. +3. Update other values in the `.env` file as need (be sure to update passwords!) +4. Run `docker-compose up setup --build` +5. Run `docker-compose up -d database` +6. Run `docker-compose up -d account-manager brickbuildfix --build` +7. Run `docker-compose up -d darkflame` +8. 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. - -### Disable brickbuildfix +## Disable brickbuildfix If you don't need the http server running on port 80 do this: @@ -30,4 +31,4 @@ services: - donotstart ``` -4. Now run `docker compose up -d --build` or `docker-compose up -d --build` \ No newline at end of file +3. Now run `docker compose up -d --build` or `docker-compose up -d --build` \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 9b60cd51..3974a959 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,21 @@ version: "3" 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 + - ./docker/:/docker/ + database: container_name: DarkflameDatabase image: mariadb:10.6 @@ -27,14 +42,9 @@ services: args: - BUILD_THREADS=${BUILD_THREADS:-1} - BUILD_VERSION=${BUILD_VERSION:-171022} - 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 + - ./docker/configs/:/configs depends_on: - database ports: diff --git a/docker/Dockerfile b/docker/Dockerfile index 8f583b4b..0e5fa06a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -43,7 +43,7 @@ FROM gcc:11 as runtime RUN --mount=type=cache,id=runtime-apt-cache,target=/var/cache/apt \ 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 && \ rm -rf /var/lib/apt/lists/* @@ -51,16 +51,9 @@ WORKDIR /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 -ADD docker/*.py /app/utils/ - COPY docker/start_server.sh /start_server.sh -RUN chmod +x /start_server.sh - -RUN mkdir /app/logs - CMD [ "/start_server.sh" ] \ No newline at end of file diff --git a/docker/setup.Dockerfile b/docker/setup.Dockerfile new file mode 100644 index 00000000..b49f8dbf --- /dev/null +++ b/docker/setup.Dockerfile @@ -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" ] \ No newline at end of file diff --git a/docker/setup.sh b/docker/setup.sh new file mode 100755 index 00000000..98a92515 --- /dev/null +++ b/docker/setup.sh @@ -0,0 +1,82 @@ +#!/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 + + 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 forgot 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 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 re-migrate, just delete the file called \"migrated\" in the client directory" +fi diff --git a/docker/start_server.sh b/docker/start_server.sh old mode 100644 new mode 100755 index 50422c60..ee5de738 --- a/docker/start_server.sh +++ b/docker/start_server.sh @@ -1,72 +1,12 @@ #!/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} - EXTERNAL_IP=${EXTERNAL_IP:-localhost} - - 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" - echo "External IP: $EXTERNAL_IP" -} - -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 $EXTERNAL_IP - 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() { + echo "Creating symlinks for client files" ln -s /client/client/res/macros/ /app/res/macros 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/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 # need to iterate over entries in maps due to maps already being a directory with navmeshes/ in it ( @@ -78,51 +18,20 @@ function symlink_client_files() { ) } -function fdb_to_sqlite() { - echo "Run fdb_to_sqlite" - python3 /app/utils/fdb_to_sqlite.py /client/client/res/cdclient.fdb --sqlite_path /client/client/res/CDServer.sqlite - - ( - cd /app/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 - ) - - ln -s /client/client/res/CDServer.sqlite /app/res/CDServer.sqlite +function symlink_config_files() { + echo "Creating symlinks for config files" + rm /app/*.ini + ln -s /configs/authconfig.ini /app/authconfig.ini + ln -s /configs/chatconfig.ini /app/chatconfig.ini + ln -s /configs/masterconfig.ini /app/masterconfig.ini + ln -s /configs/worldconfig.ini /app/worldconfig.ini } -set_defaults - -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 - +# setup symlinks for volume files symlink_client_files +symlink_config_files -fdb_to_sqlite - +# start the server echo "Start MasterServer" - ./MasterServer - tail -f /dev/null \ No newline at end of file