From fef253d1a2cb2cfb52027415fa5069946772fd63 Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 20 Jun 2021 21:39:40 +0100 Subject: [PATCH 01/15] WIP --- .github/workflows/comment-commands.yml | 29 ++++++++++++++++ .github/workflows/test-server.yaml | 47 ++++++++++++++++++++++++++ .github/workflows/test.yaml | 2 ++ 3 files changed, 78 insertions(+) create mode 100644 .github/workflows/comment-commands.yml create mode 100644 .github/workflows/test-server.yaml diff --git a/.github/workflows/comment-commands.yml b/.github/workflows/comment-commands.yml new file mode 100644 index 0000000000..ede562b7a9 --- /dev/null +++ b/.github/workflows/comment-commands.yml @@ -0,0 +1,29 @@ +name: Slash Command Dispatch +on: + issue_comment: + types: [created] +jobs: + slashCommandDispatch: + runs-on: ubuntu-latest + steps: + - name: Slash Command Dispatch + id: scd + uses: peter-evans/slash-command-dispatch@v2 + with: + token: ${{ secrets.SLASH_COMMANDS_PAT }} + issue-type: pull-request + dispatch-type: workflow + permission: write + commands: | + test-server + static-args: | + repository=${{ github.repository }} + comment-id=${{ github.event.comment.id }} + + - name: Edit comment with error message + if: steps.scd.outputs.error-message + uses: peter-evans/create-or-update-comment@v1 + with: + comment-id: ${{ github.event.comment.id }} + body: | + > ${{ steps.scd.outputs.error-message }} \ No newline at end of file diff --git a/.github/workflows/test-server.yaml b/.github/workflows/test-server.yaml new file mode 100644 index 0000000000..5c00ecabfe --- /dev/null +++ b/.github/workflows/test-server.yaml @@ -0,0 +1,47 @@ +name: Publish PR Docker Image +on: + workflow_dispatch: + inputs: + repository: + description: 'The repository from which the slash command was dispatched' + required: true + comment-id: + description: 'The comment-id of the slash command' + required: true +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Dump the client payload context + env: + PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }} + run: echo "$PAYLOAD_CONTEXT" + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v1 + # - name: Set variables + # id: prep + # run: | + # DOCKER_IMAGE=test-server + # REPOSITORY="$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')" # Repository name must be lowercase in image tags + + # if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then + # GITHUB_SHA=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.head.sha) # GITHUB_SHA is the merge SHA, not the head commit SHA in a PR, replace it. + # fi + + # TAGS="ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:${GITHUB_SHA}" + # if [ "${{ github.ref }}" = "refs/heads/master" ]; then + # TAGS="$TAGS,ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:latest,ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:master" + # fi + + # echo ::set-output name=tags::${TAGS} + # - name: Log in to GitHub Docker Registry + # uses: docker/login-action@v1 + # with: + # registry: ghcr.io + # username: ${{ github.repository_owner }} + # password: ${{ secrets.GITHUB_TOKEN }} + # - name: Build container image + # uses: docker/build-push-action@v2 + # with: + # push: true + # tags: ${{ steps.prep.outputs.tags }} \ No newline at end of file diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index bba53b3c66..6a7cef260f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -1,9 +1,11 @@ name: Test on: push: + paths-ignore: .github\workflows branches: - master pull_request: + paths-ignore: .github\workflows types: [ opened, reopened, synchronize ] jobs: test: From 462692b25a581c0ee14b954ebe2ebf03a2c375c1 Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 20 Jun 2021 21:59:14 +0100 Subject: [PATCH 02/15] WIP --- .../workflows/{test-server.yaml => test-server-command.yaml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{test-server.yaml => test-server-command.yaml} (95%) diff --git a/.github/workflows/test-server.yaml b/.github/workflows/test-server-command.yaml similarity index 95% rename from .github/workflows/test-server.yaml rename to .github/workflows/test-server-command.yaml index 5c00ecabfe..a3f810ea8f 100644 --- a/.github/workflows/test-server.yaml +++ b/.github/workflows/test-server-command.yaml @@ -16,8 +16,8 @@ jobs: env: PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }} run: echo "$PAYLOAD_CONTEXT" - # - name: Set up Docker Buildx - # uses: docker/setup-buildx-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 # - name: Set variables # id: prep # run: | From c79bbdf928ca24dc98e17e89316d0612ae5035bb Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 20 Jun 2021 22:02:34 +0100 Subject: [PATCH 03/15] WIP --- .github/workflows/test-server-command.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-server-command.yaml b/.github/workflows/test-server-command.yaml index a3f810ea8f..5c00ecabfe 100644 --- a/.github/workflows/test-server-command.yaml +++ b/.github/workflows/test-server-command.yaml @@ -16,8 +16,8 @@ jobs: env: PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }} run: echo "$PAYLOAD_CONTEXT" - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v1 # - name: Set variables # id: prep # run: | From 279d477706926ca1571a31799e5e05235e5775de Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 20 Jun 2021 22:11:05 +0100 Subject: [PATCH 04/15] WIP --- .github/workflows/{publish.yaml => publish.yml} | 0 .../{test-server-command.yaml => test-server-command.yml} | 0 .github/workflows/{test.yaml => test.yml} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{publish.yaml => publish.yml} (100%) rename .github/workflows/{test-server-command.yaml => test-server-command.yml} (100%) rename .github/workflows/{test.yaml => test.yml} (100%) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yml similarity index 100% rename from .github/workflows/publish.yaml rename to .github/workflows/publish.yml diff --git a/.github/workflows/test-server-command.yaml b/.github/workflows/test-server-command.yml similarity index 100% rename from .github/workflows/test-server-command.yaml rename to .github/workflows/test-server-command.yml diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yml similarity index 100% rename from .github/workflows/test.yaml rename to .github/workflows/test.yml From 7f381f791b19201104fd652963d26a56624e70fa Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 20 Jun 2021 22:11:32 +0100 Subject: [PATCH 05/15] WIP --- .github/workflows/test-server-command.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-server-command.yml b/.github/workflows/test-server-command.yml index 5c00ecabfe..a73c61805f 100644 --- a/.github/workflows/test-server-command.yml +++ b/.github/workflows/test-server-command.yml @@ -14,10 +14,10 @@ jobs: steps: - name: Dump the client payload context env: - PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }} - run: echo "$PAYLOAD_CONTEXT" - # - name: Set up Docker Buildx - # uses: docker/setup-buildx-action@v1 + GITHUBREF: ${{ toJson(github.event.inputs.ref) }} + run: echo "$GITHUBREF" + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 # - name: Set variables # id: prep # run: | From 9be204a443cd4f7adec0bd0e854f51a49ef2fccf Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 20 Jun 2021 22:25:06 +0100 Subject: [PATCH 06/15] WIP --- .github/workflows/test-server-command.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-server-command.yml b/.github/workflows/test-server-command.yml index a73c61805f..23d98cb0f6 100644 --- a/.github/workflows/test-server-command.yml +++ b/.github/workflows/test-server-command.yml @@ -16,8 +16,8 @@ jobs: env: GITHUBREF: ${{ toJson(github.event.inputs.ref) }} run: echo "$GITHUBREF" - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v1 # - name: Set variables # id: prep # run: | From 5db91a77fa4f0da635f22b6dd7af9e525a29021a Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 20 Jun 2021 22:28:16 +0100 Subject: [PATCH 07/15] WIP --- .github/workflows/test-server-command.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test-server-command.yml b/.github/workflows/test-server-command.yml index 23d98cb0f6..2474e98a39 100644 --- a/.github/workflows/test-server-command.yml +++ b/.github/workflows/test-server-command.yml @@ -2,6 +2,9 @@ name: Publish PR Docker Image on: workflow_dispatch: inputs: + ref: + description: 'Git ref to the triggering action' + required: true repository: description: 'The repository from which the slash command was dispatched' required: true From 85203259e38ac33035b1d33e71db10550c2bb030 Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 20 Jun 2021 22:28:40 +0100 Subject: [PATCH 08/15] WIP --- .github/workflows/test-server-command.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-server-command.yml b/.github/workflows/test-server-command.yml index 2474e98a39..af23b04c91 100644 --- a/.github/workflows/test-server-command.yml +++ b/.github/workflows/test-server-command.yml @@ -19,8 +19,8 @@ jobs: env: GITHUBREF: ${{ toJson(github.event.inputs.ref) }} run: echo "$GITHUBREF" - # - name: Set up Docker Buildx - # uses: docker/setup-buildx-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 # - name: Set variables # id: prep # run: | From 34471ec35b673a45e3c86572b424041c0577b6cd Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 20 Jun 2021 22:29:22 +0100 Subject: [PATCH 09/15] WIP --- .github/workflows/comment-commands.yml | 2 +- .github/workflows/test-server-command.yml | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/comment-commands.yml b/.github/workflows/comment-commands.yml index ede562b7a9..97b2674f58 100644 --- a/.github/workflows/comment-commands.yml +++ b/.github/workflows/comment-commands.yml @@ -12,7 +12,7 @@ jobs: with: token: ${{ secrets.SLASH_COMMANDS_PAT }} issue-type: pull-request - dispatch-type: workflow + dispatch-type: repository permission: write commands: | test-server diff --git a/.github/workflows/test-server-command.yml b/.github/workflows/test-server-command.yml index af23b04c91..a3f810ea8f 100644 --- a/.github/workflows/test-server-command.yml +++ b/.github/workflows/test-server-command.yml @@ -2,9 +2,6 @@ name: Publish PR Docker Image on: workflow_dispatch: inputs: - ref: - description: 'Git ref to the triggering action' - required: true repository: description: 'The repository from which the slash command was dispatched' required: true @@ -17,8 +14,8 @@ jobs: steps: - name: Dump the client payload context env: - GITHUBREF: ${{ toJson(github.event.inputs.ref) }} - run: echo "$GITHUBREF" + PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }} + run: echo "$PAYLOAD_CONTEXT" - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 # - name: Set variables From 77e3fd1e1deeb49b6520c3f544fe4ac1c515acb3 Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 20 Jun 2021 22:34:16 +0100 Subject: [PATCH 10/15] WIP --- .github/workflows/comment-commands.yml | 10 +--------- .github/workflows/test-server-command.yml | 14 ++++---------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/.github/workflows/comment-commands.yml b/.github/workflows/comment-commands.yml index 97b2674f58..9a1bd3a1f0 100644 --- a/.github/workflows/comment-commands.yml +++ b/.github/workflows/comment-commands.yml @@ -18,12 +18,4 @@ jobs: test-server static-args: | repository=${{ github.repository }} - comment-id=${{ github.event.comment.id }} - - - name: Edit comment with error message - if: steps.scd.outputs.error-message - uses: peter-evans/create-or-update-comment@v1 - with: - comment-id: ${{ github.event.comment.id }} - body: | - > ${{ steps.scd.outputs.error-message }} \ No newline at end of file + comment-id=${{ github.event.comment.id }} \ No newline at end of file diff --git a/.github/workflows/test-server-command.yml b/.github/workflows/test-server-command.yml index a3f810ea8f..4329589a23 100644 --- a/.github/workflows/test-server-command.yml +++ b/.github/workflows/test-server-command.yml @@ -1,13 +1,7 @@ name: Publish PR Docker Image on: - workflow_dispatch: - inputs: - repository: - description: 'The repository from which the slash command was dispatched' - required: true - comment-id: - description: 'The comment-id of the slash command' - required: true + repository_dispatch: + types: [test-server-command] jobs: docker: runs-on: ubuntu-latest @@ -16,8 +10,8 @@ jobs: env: PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }} run: echo "$PAYLOAD_CONTEXT" - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v1 # - name: Set variables # id: prep # run: | From 3baf7526517dc937cd6e34fa1be3c8d408bead67 Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 20 Jun 2021 22:39:21 +0100 Subject: [PATCH 11/15] WIP --- .github/workflows/test-server-command.yml | 52 ++-- config/worldserver.ini | 259 ++++++++++++++++++ pslogin/src/main/resources/user.conf | 3 + .../scala/actor/objects/PainboxTest.scala | 202 ++++++++++++++ .../types/LatticeCavernBenefits.scala | 23 ++ .../terminal/CaptureTerminalTest.scala | 89 ++++++ 6 files changed, 602 insertions(+), 26 deletions(-) create mode 100644 config/worldserver.ini create mode 100644 pslogin/src/main/resources/user.conf create mode 100644 server/src/test/scala/actor/objects/PainboxTest.scala create mode 100644 src/main/scala/net/psforever/types/LatticeCavernBenefits.scala create mode 100644 src/test/scala/objects/terminal/CaptureTerminalTest.scala diff --git a/.github/workflows/test-server-command.yml b/.github/workflows/test-server-command.yml index 4329589a23..85b0477521 100644 --- a/.github/workflows/test-server-command.yml +++ b/.github/workflows/test-server-command.yml @@ -10,32 +10,32 @@ jobs: env: PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }} run: echo "$PAYLOAD_CONTEXT" - # - name: Set up Docker Buildx - # uses: docker/setup-buildx-action@v1 - # - name: Set variables - # id: prep - # run: | - # DOCKER_IMAGE=test-server - # REPOSITORY="$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')" # Repository name must be lowercase in image tags + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Set variables + id: prep + run: | + DOCKER_IMAGE=test-server + REPOSITORY="$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')" # Repository name must be lowercase in image tags - # if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then - # GITHUB_SHA=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.head.sha) # GITHUB_SHA is the merge SHA, not the head commit SHA in a PR, replace it. - # fi + if [ "$GITHUB_EVENT_NAME" == "issue_comment" ] && [ $(cat $GITHUB_EVENT_PATH | jq -r .payload.comment.body) == "/test-server" ]; then + GITHUB_SHA=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.head.sha) # GITHUB_SHA is the merge SHA, not the head commit SHA in a PR; replace it. + fi - # TAGS="ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:${GITHUB_SHA}" - # if [ "${{ github.ref }}" = "refs/heads/master" ]; then - # TAGS="$TAGS,ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:latest,ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:master" - # fi + TAGS="ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:${GITHUB_SHA}" + if [ "${{ github.ref }}" = "refs/heads/master" ]; then + TAGS="$TAGS,ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:latest,ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:master" + fi - # echo ::set-output name=tags::${TAGS} - # - name: Log in to GitHub Docker Registry - # uses: docker/login-action@v1 - # with: - # registry: ghcr.io - # username: ${{ github.repository_owner }} - # password: ${{ secrets.GITHUB_TOKEN }} - # - name: Build container image - # uses: docker/build-push-action@v2 - # with: - # push: true - # tags: ${{ steps.prep.outputs.tags }} \ No newline at end of file + echo ::set-output name=tags::${TAGS} + - name: Log in to GitHub Docker Registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build container image + uses: docker/build-push-action@v2 + with: + push: true + tags: ${{ steps.prep.outputs.tags }} \ No newline at end of file diff --git a/config/worldserver.ini b/config/worldserver.ini new file mode 100644 index 0000000000..ae2b4f025c --- /dev/null +++ b/config/worldserver.ini @@ -0,0 +1,259 @@ +####################################### +# PSForever Server configuration file # +####################################### + +################################################################################################### +# EXAMPLE CONFIG +# +# Variable (type) +# Description: Brief description what the variable is doing. +# Important: Annotation for important things about this variable. +# Example: "Example, i.e. if the value is a string" +# Range: [0, 10] - (Disabled, Enabled) +# Default: 10 - (Enabled|Comment|Variable name in case of grouped config options) +# 0 - (Disabled|Comment|Variable name in case of grouped config options) +# +# Note to developers: +# - Copy this example to keep the formatting. +# - Line breaks should be at column 100. +################################################################################################### + +################################################################################################### +# DATABASE SETTINGS +################################################################################################### + +[database] + +# Hostname (string) +# Description: The hostname of the PostgreSQL server. +# Important: Make sure your database isn't accessible outside of localhost without a +# strong username and password! +# Default: "localhost" + +Hostname = "localhost" + +# Port (int) +# Description: The TCP port to connect to the database with. +# Range: [1, 65535] - (TCP port 1, TCP port 65535) +# Default: 5432 - (Connect to TCP port 5432 -- the default for PostgreSQL) + +Port = 5432 + +# SSL (enum) +# Description: The SSL configuration of the database connection. +# Values: Disable - (Do not use SSL -- not recommended for public servers) +# Prefer - (Try SSL first, but fallback to unencrypted) +# Require - (Use SSL and fail if it is not enabled or configured correctly +# Verify - (Use SSL and verify that the certificate is authentic) +# Default: Prefer + +SSL = Prefer + +# Database (string) +# Description: The database name to use on the SQL server. +# Important: Make sure your username has been GRANTed ALL PRIVILEGES to the database. +# See the setup documentation for instructions on achieving this. +# Default: "psforever" + +Database = "psforever" + +# Username (string) +# Description: The username to connect to the SQL server with. +# Default: "psforever" + +Username = "psforever" + +# Password (string) +# Description: The password to connect to the SQL server with. +# Important: CHANGE THIS PASSWORD BEFORE RUNNING A PUBLIC SERVER. +# Default: "psforever" + +Password = "psforever" + +################################################################################################### +# WORLDSERVER SETTINGS +################################################################################################### + +[worldserver] + +# ListeningPort (int) +# Description: The UDP listening port for the worldserver. +# Important: Must be different from the loginserver.ListeningPort. Ports below 1024 are +# privileged on Linux and may require root. +# Range: [1, 65535] - (UDP port 1, UDP port 65535) +# Default: 51001 - (Listen on UDP port 51001) + +ListeningPort = 51001 + +# Hostname (string) +# Description: The server's public hostname or IP address. Required when the server is +# behind a proxy or running in a container/virtual machine. +# Important: If left as the default, the hostname will be the same as the primary +# internet interface. +# Default: "" + +Hostname = "" + +# ServerName (string) +# Description: The name of the server as displayed in the server browser. +# Range: Length = [1, 31] +# Default: "PSForever" + +ServerName = "PSForever" + +# ServerType (enum) +# Description: How the server is displayed in the server browser. +# Values: Released, Beta, Development +# Default: Released + +ServerType = Released + +################################################################################################### +# LOGINSERVER SETTINGS +################################################################################################### + +[loginserver] + +# ListeningPort (int) +# Description: The UDP listening port for the loginserver. +# Important: Must be different from the worldserver.ListeningPort. Ports below 1024 are +# privileged on Linux and may require root. +# Range: [1, 65535] - (UDP port 1, UDP port 65535) +# Default: 51000 - (Listen on UDP port 51000) + +ListeningPort = 51000 + +# CreateMissingAccounts (boolean) +# Description: Account usernames that don't exist yet will be automatically created in the +# database. Useful for test servers and development testing. +# Important: Not recommended for production servers as typos are easy to make on +# first registration. Use PSFPortal (https://github.com/psforever/PSFPortal) +# instead. +# Default: yes - (Enabled) +# no - (Disabled) + +CreateMissingAccounts = yes + +################################################################################################### +# PSADMIN SETTINGS +################################################################################################### + +[psadmin] + +# ListeningPort (int) +# Description: The TCP listening port for the server admin interface. +# Important: Must be different from the worldserver and loginserver ListeningPort. +# Ports below 1024 are privileged on Linux and may require root. +# NEVER EXPOSE THIS PORT TO THE INTERNET! CHECK YOUR FIREWALL CONFIG. +# Range: [1, 65535] - (TCP port 1, TCP port 65535) +# Default: 51002 - (Listen on TCP port 51002) + +ListeningPort = 51002 + +################################################################################################### +# NETWORK SETTINGS +################################################################################################### + +[network] + +# Session.InboundGraceTime (time) +# Description: The maximum amount of time since the last inbound packet from a UDP session +# before it is dropped. +# Important: Lower values will cause legitimate clients to be dropped during loading +# screens, but higher values will make the server be more susceptible to +# denial of service attacks and running out of memory. +# Range: [10 seconds, 10 minutes] - (10 second grace, 10 minute grace) +# Default: 1 minute - (Clients sending a packet at least +# once a minute stay alive) + +Session.InboundGraceTime = 1 minute + +# Session.OutboundGraceTime (time) +# Description: The maximum amount of time since the last outbound packet for a UDP session +# before it is dropped. Can be used as a watchdog for hung server sessions. +# Important: Lower values will cause legitimate clients to be dropped during server +# lag spikes or Zone transitions. +# Range: [10 seconds, 10 minutes] - (10 second grace, 10 minute grace) +# Default: 1 minute - (Clients receiving a packet at least +# once a minute stay alive) + +Session.OutboundGraceTime = 1 minute + +################################################################################################### +# DEVELOPER SETTINGS +# - NETWORK SIMULATOR +################################################################################################### + +[developer] + +################################################################################################### +# NETWORK SIMULATOR +# +# NetSim.Active (boolean) +# Description: Enable artificial packet unreliability. Used for development testing. +# Active equally on upstream and downstream packets. +# Important: DO NOT enable on servers with a high packet rate as buffering increases +# the memory load of the server and it will (by design) affect performance. +# Default: no - (Disabled) +# yes - (Enabled) + +NetSim.Active = no + +# NetSim.Loss (float) +# Description: The percentage of outgoing and incoming packets that are dropped. +# Range: [0.0, 1.0] - (0% loss, 100% packet loss) +# Default: 0.02 - (2% packet loss) + +NetSim.Loss = 0.0 + +# NetSim.Delay (time) +# Description: The time a packet is buffered before being delivered to simulate delay. +# The artificial delay is in addition to any real network latency. +# Important: Longer delays will lead to larger packet buffering, which may cause +# out-of-memory errors depending on packet rate. +# Range: [0, 2 seconds] - (No delay, 2 seconds delay) +# Default: 150 milliseconds - (Packets lag for 150 milliseconds) + +NetSim.Delay = 150 milliseconds + +# NetSim.ReorderChance (float) +# Description: The percentage chance that a packet will be ordered randomly in the delay +# buffer. If the NetSim.Delay is too small then packets won't be reordered. +# Range: [0.0, 1.0] - (No packet reordering, reorder every packet) +# Default: 0.005 - (0.5% chance of a packet being reordered) + +NetSim.ReorderChance = 0.05 + +# NetSim.ReorderTime (time) +# Description: If a packet is reordered, the maximum time in the future or the past where +# it will randomly appear. +# Range: [0, 2 seconds] - (No packet reordering, randomly shift +/- 2 seconds) +# Default: 150 milliseconds - (+/- 150 milliseconds) + +NetSim.ReorderTime = 150 milliseconds + +# +################################################################################################### + + +[kamon] + +# Kamon +# +# Active (boolean) +# Description: Enables reporting of metrics to Kamon.io +# Important: Ensure the API key is set in application.conf in the same +# folder as PsLogin.scala +# Default: no - (Disabled) +# yes - (Enabled) + +Active = yes + +[antihack] + +# HitPositionDiscrepancyThreshold (int) +# Description: The distance (squared) threshold that triggers if the reported hit location of a shot does not match the object being hit's location on the server +# Range: [1, 1000000] +# Default: 10000 (sqrt 10000 = ~100 ingame units) + +HitPositionDiscrepancyThreshold = 10000 \ No newline at end of file diff --git a/pslogin/src/main/resources/user.conf b/pslogin/src/main/resources/user.conf new file mode 100644 index 0000000000..6b27fc428c --- /dev/null +++ b/pslogin/src/main/resources/user.conf @@ -0,0 +1,3 @@ +kamon { + apm.api-key = "3405691582g0h8776i44234htm" +} \ No newline at end of file diff --git a/server/src/test/scala/actor/objects/PainboxTest.scala b/server/src/test/scala/actor/objects/PainboxTest.scala new file mode 100644 index 0000000000..b545e35e0f --- /dev/null +++ b/server/src/test/scala/actor/objects/PainboxTest.scala @@ -0,0 +1,202 @@ +package actor.objects + +import actor.base.FreedContextActorTest +import actor.objects.PainboxControlTest.{CreatePlayer, RemovePlayer} +import akka.actor.{ActorContext, ActorSystem, Props} +import net.psforever.objects.Player.Respawn +import net.psforever.objects.avatar.Avatar +import net.psforever.objects.serverobject.doors.{Door, DoorControl} +import net.psforever.objects.serverobject.painbox._ +import net.psforever.objects.serverobject.structures.{Building, StructureType} +import net.psforever.objects.zones.{Zone, ZoneMap} +import net.psforever.objects.{GlobalDefinitions, Player} +import net.psforever.packet.game.UseItemMessage +import net.psforever.types._ +import org.scalatest.BeforeAndAfterEach +import org.specs2.mutable.Specification + +import scala.collection.concurrent.TrieMap +import scala.concurrent.duration._ + +class PainboxTest extends Specification { + "Painbox" should { + "Construct with all known painbox definitions" in { + Painbox(GlobalDefinitions.painbox) + Painbox(GlobalDefinitions.painbox_door_radius) + Painbox(GlobalDefinitions.painbox_door_radius_continuous) + Painbox(GlobalDefinitions.painbox_continuous) + Painbox(GlobalDefinitions.painbox_radius) + Painbox(GlobalDefinitions.painbox_radius_continuous) + + ok + } + + "Throw error with invalid object id" in { + val objectId = 1 + new PainboxDefinition(objectId) must throwA[IllegalArgumentException](message = s"${objectId} is not a valid painbox object id") + } + } +} + +class PainboxControlTest extends FreedContextActorTest with BeforeAndAfterEach { + val buildingMap = new TrieMap[Int, Building]() + val building = new Building("Building", building_guid = 0, map_id = 0, zone, StructureType.Building, GlobalDefinitions.amp_station) + + building.Position = Vector3(1f, 1f, 1f) + building.Faction = PlanetSideEmpire.VS + buildingMap += building.GUID.guid -> building + + // Initialize the zone so the SphereOfInfluence actor starts running + val zone = new Zone("test", new ZoneMap("map6"), 1) { + override def Buildings: Map[Int, Building] = { buildingMap.toMap } + } + zone.init(context) + + val playerVS = CreatePlayer(zone, PlanetSideEmpire.VS, avatarId = 0) + val playerTR = CreatePlayer(zone, PlanetSideEmpire.TR, avatarId = 1) + val playerNC = CreatePlayer(zone, PlanetSideEmpire.NC, avatarId = 2) + + override protected def beforeEach() : Unit = { + // Spawn players + playerVS.Spawn + playerVS.Position = Vector3(4f, 4f, 4f) + + playerTR.Spawn + playerTR.Position = Vector3(4f, 4f, 4f) + + playerNC.Spawn + playerNC.Position = Vector3(4f, 4f, 4f) + } + + override protected def afterEach() : Unit = { + // Kill players + playerVS.Die + playerTR.Die + playerNC.Die + } + + "PainboxControl" should { + "Damage hostile player if dependent door is open" in { + val door = Door(GlobalDefinitions.door) + door.Actor = system.actorOf(Props(classOf[DoorControl], door), "door") + door.Owner = building + door.Position = Vector3(3f, 3f, 3f) + building.Amenities = door + + val painbox = Painbox(GlobalDefinitions.painbox_door_radius) + painbox.Actor = system.actorOf(Props(classOf[PainboxControl], painbox), "painbox") + painbox.Owner = building + painbox.Position = Vector3(2f, 2f, 2f) + building.Amenities = painbox + + painbox.Actor ! Painbox.Start() + + + + // Ensure SOI actor has picked up spawned players + awaitAssert(() -> { + assert(building.PlayersInSOI.length == 3) + }, 6 seconds) + + assert(playerVS.Health == 100) + assert(playerTR.Health == 100) + assert(playerNC.Health == 100) + + door.Open = Some(playerVS) // Open the door + + painbox.Actor ! "startup" + expectNoMessage(500 milliseconds) + assert(playerVS.Health == 100) + assert(playerTR.Health < 100) + assert(playerNC.Health < 100) + } + + "Not damage hostile player is dependent door is closed" in { + + } + + "Not rely on nearby door state if not dependent on door (open)" in { +// val (player, painbox, door) = PainboxControlTest.SetUpAgents(context, PlanetSideEmpire.NC, GlobalDefinitions.painbox_continuous) +// +// val originalHealth = player.Health +// door.Open = Some(player) // Open the door +// +// painbox.Actor ! "startup" +// expectNoMessage(500 milliseconds) +// assert(player.Health < originalHealth) +// +// door.Open = None // Close the door +// expectNoMessage(500 milliseconds) +// assert(player.Health < originalHealth) + } + + "Not damage friendly players" in { + + } + + "Not damage player outside range" in { + + } + + "Not damage player if Owner faction is NEUTRAL" in { + + } + + "Throw error if no SOI is defined on Owner" in { + + } + + "Damage once per second at most" in { + + } + } +} + +object PainboxControlTest { + def CreatePlayer(zone: Zone, faction: PlanetSideEmpire.Value, avatarId: Int): Player = { + val player = Player(Avatar(avatarId, s"test-${faction.toString}", faction, CharacterSex.Male, 0, CharacterVoice.Mute)) + zone.Population ! Zone.Population.Join(player.avatar) + zone.Population ! Zone.Population.Spawn(player.avatar, player, null) + + player + } + + def RemovePlayer(zone: Zone, player: Player): Unit = { + zone.Population ! Zone.Population.Leave(player.avatar) + } + + def SetUpAgents(context: ActorContext, faction : PlanetSideEmpire.Value, definition : PainboxDefinition)(implicit system : ActorSystem) : (Player, Painbox, Door) = { + + // Initialize the zone so the SphereOfInfluence actor starts running + val zone = new Zone("test", new ZoneMap("map6"), 1) + zone.init(context) +// zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-zone") +// zone.Actor ! Zone.Init() + + val avatar = Avatar(0, "test", faction, CharacterSex.Male, 0, CharacterVoice.Mute) + val player = Player(avatar) + player.Spawn + player.Position = Vector3(4f, 4f, 4f) + zone.Population ! Zone.Population.Join(avatar) + + val building = new Building("Building", building_guid = 0, map_id = 0, zone, StructureType.Building, GlobalDefinitions.amp_station) + + building.Position = Vector3(1f, 1f, 1f) + building.Faction = PlanetSideEmpire.VS + + Thread.sleep(5000) // Give SOI actor time to repopulate + + val painbox = Painbox(definition) + painbox.Actor = system.actorOf(Props(classOf[PainboxControl], painbox), "painbox") + painbox.Owner = building + painbox.Position = Vector3(2f, 2f, 2f) + + val door = Door(GlobalDefinitions.door) + door.Actor = system.actorOf(Props(classOf[DoorControl], door), "door") + door.Owner = building + door.Position = Vector3(3f, 3f, 3f) + + (player, painbox, door) + + } +} \ No newline at end of file diff --git a/src/main/scala/net/psforever/types/LatticeCavernBenefits.scala b/src/main/scala/net/psforever/types/LatticeCavernBenefits.scala new file mode 100644 index 0000000000..ae44a15f6e --- /dev/null +++ b/src/main/scala/net/psforever/types/LatticeCavernBenefits.scala @@ -0,0 +1,23 @@ +package net.psforever.types + +/* + * Cavern benefits: (stackable)
+ * 000 - None
+ * 004 - Speed Module
+ * 008 - Shield Module
+ * 016 - Vehicle Module
+ * 032 - Equipment Module
+ * 064 - Health Module
+ * 128 - Pain Module
+ */ +object LatticeCavernBenefits extends Enumeration { + type Type = Int + + val None = Value(0) + val Speed = Value(4) + val Shield = Value(8) + val Vehicle = Value(16) + val Equipment = Value(32) + val Health = Value(64) + val Pain = Value(128) +} diff --git a/src/test/scala/objects/terminal/CaptureTerminalTest.scala b/src/test/scala/objects/terminal/CaptureTerminalTest.scala new file mode 100644 index 0000000000..0b2ea4cebc --- /dev/null +++ b/src/test/scala/objects/terminal/CaptureTerminalTest.scala @@ -0,0 +1,89 @@ +//package objects.terminal +// +//import akka.actor.{ActorRef, ActorSystem, Props} +//import base.ActorTest +//import net.psforever.objects.serverobject.CommonMessages +//import net.psforever.objects.serverobject.structures.{Building, StructureType} +//import net.psforever.objects.serverobject.terminals.{CaptureTerminal, CaptureTerminalControl, CaptureTerminalDefinition} +//import net.psforever.objects.zones.Zone +//import net.psforever.objects.{Avatar, GlobalDefinitions, Player} +//import net.psforever.packet.game.PlanetSideGUID +//import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire} +// +//class CaptureTerminalTest extends ActorTest { +// "CaptureTerminal" should { +// "construct" in { +// val terminal = CaptureTerminal(GlobalDefinitions.capture_terminal) +// terminal.Actor = system.actorOf(Props(classOf[CaptureTerminalControl], terminal), "capture-terminal-control") +// assert(terminal.Actor != ActorRef.noSender) +// } +// +// "fail on invalid object type" in { +// assertThrows[IllegalArgumentException] { +// CaptureTerminal(new CaptureTerminalDefinition(0)) +// } +// } +// +// "can be hacked" in { +// val (player, terminal) = CaptureTerminalTest.SetUpAgents(PlanetSideEmpire.TR, PlanetSideEmpire.VS, 1) +// assert(terminal.HackedBy.isEmpty) +// +// terminal.Actor ! CommonMessages.Hack(player) +// expectMsg(true) +// assert(terminal.HackedBy.nonEmpty) +// assert(terminal.HackedBy.get._1.Faction == PlanetSideEmpire.VS) +// } +// +// "can be resecured" in { +// val (player, player2, terminal) = CaptureTerminalTest.SetUpAgents(PlanetSideEmpire.TR, PlanetSideEmpire.VS, PlanetSideEmpire.TR, 2) +// assert(terminal.HackedBy.isEmpty) +// +// terminal.Actor ! CommonMessages.Hack(player) +// expectMsg(true) +// assert(terminal.HackedBy.nonEmpty) +// assert(terminal.HackedBy.get._1.Faction == PlanetSideEmpire.VS) +// +// terminal.Actor ! CommonMessages.ClearHack() +// Thread.sleep(500L) // blocking +// assert(terminal.HackedBy.isEmpty) +// } +// +// "can overwrite hack" in { +// val (player, player2, terminal) = CaptureTerminalTest.SetUpAgents(PlanetSideEmpire.TR, PlanetSideEmpire.VS, PlanetSideEmpire.NC, 3) +// assert(terminal.HackedBy.isEmpty) +// +// terminal.Actor ! CommonMessages.Hack(player) +// expectMsg(true) +// assert(terminal.HackedBy.nonEmpty) +// assert(terminal.HackedBy.get._1.Faction == PlanetSideEmpire.VS) +// +// terminal.Actor ! CommonMessages.Hack(player2) +// expectMsg(true) +// assert(terminal.HackedBy.nonEmpty) +// assert(terminal.HackedBy.get._1.Faction == PlanetSideEmpire.NC) +// } +// } +//} +// +//object CaptureTerminalTest { +// def SetUpAgents(ccFaction : PlanetSideEmpire.Value, playerFaction : PlanetSideEmpire.Value, player2Faction: PlanetSideEmpire.Value, actorId : Int)(implicit system : ActorSystem) : (Player, Player, CaptureTerminal) = { +// val (player, terminal) = SetUpAgents(ccFaction, playerFaction, actorId) +// +// val player2 = new Player(Avatar("test", player2Faction, CharacterGender.Male, 0, CharacterVoice.Mute)) +// player2.GUID = PlanetSideGUID(1) +// +// (player, player2, terminal) +// } +// +// def SetUpAgents(ccFaction : PlanetSideEmpire.Value, playerFaction : PlanetSideEmpire.Value, actorId: Int)(implicit system : ActorSystem) : (Player, CaptureTerminal) = { +// val terminal = CaptureTerminal(GlobalDefinitions.capture_terminal) +// terminal.Actor = system.actorOf(Props(classOf[CaptureTerminalControl], terminal), s"capture-terminal-control-${actorId}") +// terminal.Owner = new Building(guid = 0, map_id = 0, Zone.Nowhere, StructureType.Building) +// terminal.Owner.Faction = ccFaction +// +// val player = new Player(Avatar("test", playerFaction, CharacterGender.Male, 0, CharacterVoice.Mute)) +// player.GUID = PlanetSideGUID(1) +// +// (player, terminal) +// } +//} \ No newline at end of file From fc5de5f95016f5856cd70d6438d1f610eb09c3c9 Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 27 Jun 2021 15:13:54 +0100 Subject: [PATCH 12/15] WIP --- .github/workflows/test-server-command.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test-server-command.yml b/.github/workflows/test-server-command.yml index 85b0477521..81572db580 100644 --- a/.github/workflows/test-server-command.yml +++ b/.github/workflows/test-server-command.yml @@ -17,15 +17,8 @@ jobs: run: | DOCKER_IMAGE=test-server REPOSITORY="$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')" # Repository name must be lowercase in image tags - - if [ "$GITHUB_EVENT_NAME" == "issue_comment" ] && [ $(cat $GITHUB_EVENT_PATH | jq -r .payload.comment.body) == "/test-server" ]; then - GITHUB_SHA=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.head.sha) # GITHUB_SHA is the merge SHA, not the head commit SHA in a PR; replace it. - fi - + GITHUB_SHA=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.head.sha) # GITHUB_SHA is the merge SHA, not the head commit SHA in a PR; replace it. TAGS="ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:${GITHUB_SHA}" - if [ "${{ github.ref }}" = "refs/heads/master" ]; then - TAGS="$TAGS,ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:latest,ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:master" - fi echo ::set-output name=tags::${TAGS} - name: Log in to GitHub Docker Registry @@ -38,4 +31,4 @@ jobs: uses: docker/build-push-action@v2 with: push: true - tags: ${{ steps.prep.outputs.tags }} \ No newline at end of file + tags: ${{ steps.prep.outputs.tags }} # \ No newline at end of file From b1173a9ba3469ad25552f847b655ff8985d680d6 Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 27 Jun 2021 15:13:54 +0100 Subject: [PATCH 13/15] WIP --- .github/workflows/test-server-command.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test-server-command.yml b/.github/workflows/test-server-command.yml index 85b0477521..31b015bf2d 100644 --- a/.github/workflows/test-server-command.yml +++ b/.github/workflows/test-server-command.yml @@ -10,6 +10,10 @@ jobs: env: PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }} run: echo "$PAYLOAD_CONTEXT" + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ pull_request.head.sha }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Set variables @@ -17,15 +21,7 @@ jobs: run: | DOCKER_IMAGE=test-server REPOSITORY="$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')" # Repository name must be lowercase in image tags - - if [ "$GITHUB_EVENT_NAME" == "issue_comment" ] && [ $(cat $GITHUB_EVENT_PATH | jq -r .payload.comment.body) == "/test-server" ]; then - GITHUB_SHA=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.head.sha) # GITHUB_SHA is the merge SHA, not the head commit SHA in a PR; replace it. - fi - - TAGS="ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:${GITHUB_SHA}" - if [ "${{ github.ref }}" = "refs/heads/master" ]; then - TAGS="$TAGS,ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:latest,ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:master" - fi + TAGS="ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:${{ pull_request.head.sha }}" echo ::set-output name=tags::${TAGS} - name: Log in to GitHub Docker Registry @@ -37,5 +33,6 @@ jobs: - name: Build container image uses: docker/build-push-action@v2 with: + context: . push: true tags: ${{ steps.prep.outputs.tags }} \ No newline at end of file From 90792fca0b8b60bd0e6d811dc2a24d95226eb8ae Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 27 Jun 2021 15:51:17 +0100 Subject: [PATCH 14/15] WIP --- .github/workflows/test-server-command.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-server-command.yml b/.github/workflows/test-server-command.yml index b7ccaff44a..28da136364 100644 --- a/.github/workflows/test-server-command.yml +++ b/.github/workflows/test-server-command.yml @@ -13,7 +13,7 @@ jobs: - name: Checkout uses: actions/checkout@v2 with: - ref: ${{ pull_request.head.sha }} + ref: ${{ github.event.client_payload.pull_request.head.sha }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Set variables @@ -21,7 +21,7 @@ jobs: run: | DOCKER_IMAGE=test-server REPOSITORY="$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')" # Repository name must be lowercase in image tags - TAGS="ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:${{ pull_request.head.sha }}" + TAGS="ghcr.io/${REPOSITORY}/${DOCKER_IMAGE}:${{ github.event.client_payload.pull_request.head.sha }}" echo ::set-output name=tags::${TAGS} - name: Log in to GitHub Docker Registry @@ -35,4 +35,4 @@ jobs: with: context: . push: true - tags: ${{ steps.prep.outputs.tags }} # \ No newline at end of file + tags: ${{ steps.prep.outputs.tags }} \ No newline at end of file From 3bd7eb5ac505c39835c7724f2e9005b57031fcd9 Mon Sep 17 00:00:00 2001 From: Mazo Date: Sun, 27 Jun 2021 15:57:00 +0100 Subject: [PATCH 15/15] WIP --- .github/workflows/test-server-command.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-server-command.yml b/.github/workflows/test-server-command.yml index 28da136364..cbc68e62b1 100644 --- a/.github/workflows/test-server-command.yml +++ b/.github/workflows/test-server-command.yml @@ -35,4 +35,4 @@ jobs: with: context: . push: true - tags: ${{ steps.prep.outputs.tags }} \ No newline at end of file + tags: ${{ steps.prep.outputs.tags }} # \ No newline at end of file