Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into 435-rename-game_backe…
Browse files Browse the repository at this point in the history
…nd-release
  • Loading branch information
Nico-Sanchez committed Apr 8, 2024
2 parents 7cf7c80 + 0b2c244 commit fe8edd5
Show file tree
Hide file tree
Showing 32 changed files with 739 additions and 88 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/arena-brazil-testing-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,11 @@ jobs:
PHX_SERVER: ${{ vars.PHX_SERVER }}
PHX_HOST: ${{ vars.HOST }}
PORT: ${{ vars.ARENA_PORT }}
BOT_MANAGER_PORT: ${{ vars.BOT_MANAGER_PORT }}
BOT_MANAGER_HOST: ${{ vars.LOADTEST_CLIENT_HOST }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SECRET_KEY_BASE: ${{ secrets.SECRET_KEY_BASE }}
NEWRELIC_APP_NAME: ${{ vars.NEWRELIC_APP_NAME_BRAZIL }}
NEWRELIC_APP_NAME: ${{ vars.NEWRELIC_APP_NAME }}
NEWRELIC_KEY: ${{ secrets.NEWRELIC_KEY }}
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
run: |
Expand All @@ -70,7 +73,10 @@ jobs:
RELEASE=${RELEASE} \
PHX_SERVER=${PHX_SERVER} \
PHX_HOST=${PHX_HOST} \
BOT_MANAGER_HOST=${BOT_MANAGER_HOST} \
PORT=${PORT} \
BOT_MANAGER_PORT=${BOT_MANAGER_PORT} \
DATABASE_URL=${DATABASE_URL} \
SECRET_KEY_BASE=${SECRET_KEY_BASE} \
NEWRELIC_APP_NAME=${NEWRELIC_APP_NAME} \
NEWRELIC_KEY=${NEWRELIC_KEY} \
Expand Down
16 changes: 11 additions & 5 deletions .github/workflows/arena-europe-testing-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
- name: Create ssh private key file from env var
env:
SSH_KEY: ${{ secrets.SSH_KEY }}
TS_HOST: ${{ vars.TS_EUROPE_HOST }}
TS_HOST: ${{ vars.TS_HOST }}
run: |
set -ex
mkdir -p ~/.ssh/
Expand All @@ -44,22 +44,25 @@ jobs:
- name: Copy deploy script
env:
SSH_USERNAME: ${{ vars.SSH_USERNAME }}
SSH_HOST: ${{ vars.TS_EUROPE_HOST }}
SSH_HOST: ${{ vars.TS_HOST }}
run: |
set -ex
rsync -avz --mkpath devops/deploy.sh ${SSH_USERNAME}@${SSH_HOST}:/home/${SSH_USERNAME}/deploy-script/
- name: Execute deploy script
env:
SSH_HOST: ${{ vars.TS_EUROPE_HOST }}
SSH_HOST: ${{ vars.TS_HOST }}
SSH_USERNAME: ${{ vars.SSH_USERNAME }}
MIX_ENV: ${{ vars.MIX_ENV }}
RELEASE: ${{ inputs.release }}
PHX_SERVER: ${{ vars.PHX_SERVER }}
PHX_HOST: ${{ vars.EUROPE_HOST }}
PHX_HOST: ${{ vars.HOST }}
PORT: ${{ vars.ARENA_PORT }}
BOT_MANAGER_PORT: ${{ vars.BOT_MANAGER_PORT }}
BOT_MANAGER_HOST: ${{ vars.LOADTEST_CLIENT_HOST }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SECRET_KEY_BASE: ${{ secrets.SECRET_KEY_BASE }}
NEWRELIC_APP_NAME: ${{ vars.NEWRELIC_APP_NAME_EUROPE }}
NEWRELIC_APP_NAME: ${{ vars.NEWRELIC_APP_NAME }}
NEWRELIC_KEY: ${{ secrets.NEWRELIC_KEY }}
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
run: |
Expand All @@ -71,6 +74,9 @@ jobs:
PHX_SERVER=${PHX_SERVER} \
PHX_HOST=${PHX_HOST} \
PORT=${PORT} \
BOT_MANAGER_PORT=${BOT_MANAGER_PORT} \
BOT_MANAGER_HOST=${BOT_MANAGER_HOST} \
DATABASE_URL=${DATABASE_URL} \
SECRET_KEY_BASE=${SECRET_KEY_BASE} \
NEWRELIC_APP_NAME=${NEWRELIC_APP_NAME} \
NEWRELIC_KEY=${NEWRELIC_KEY} \
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/loadtest-brazil-client-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
- arena
- arena_load_test
- game_client
- bot_manager
required: true
target_server:
type: choice
Expand Down Expand Up @@ -62,11 +63,11 @@ jobs:
MIX_ENV: ${{ vars.MIX_ENV }}
RELEASE: ${{ inputs.release }}
TARGET_SERVER: ${{ inputs.target_server }}
BRAZIL_HOST: ${{ vars.brazil_host }}
EUROPE_HOST: ${{ vars.europe_host }}
PHX_SERVER: ${{ vars.PHX_SERVER }}
PHX_HOST: ${{ vars.LOADTEST_CLIENT_HOST }}
PORT: ${{ vars.ARENA_PORT }}
BOT_MANAGER_PORT: ${{ vars.BOT_MANAGER_PORT }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SECRET_KEY_BASE: ${{ secrets.SECRET_KEY_BASE }}
NEWRELIC_APP_NAME: ${{ vars.NEWRELIC_APP_NAME_LOADTEST }}
NEWRELIC_KEY: ${{ secrets.NEWRELIC_KEY }}
Expand All @@ -78,11 +79,11 @@ jobs:
MIX_ENV=${MIX_ENV} \
RELEASE=${RELEASE} \
TARGET_SERVER=${TARGET_SERVER} \
BRAZIL_HOST=${BRAZIL_HOST} \
EUROPE_HOST=${EUROPE_HOST} \
PHX_SERVER=${PHX_SERVER} \
PHX_HOST=${PHX_HOST} \
PORT=${PORT} \
BOT_MANAGER_PORT=${BOT_MANAGER_PORT} \
DATABASE_URL=${DATABASE_URL} \
SECRET_KEY_BASE=${SECRET_KEY_BASE} \
NEWRELIC_APP_NAME=${NEWRELIC_APP_NAME} \
NEWRELIC_KEY=${NEWRELIC_KEY} \
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/loadtest-brazil-server-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ jobs:
SSH_USERNAME: ${{ vars.SSH_USERNAME }}
MIX_ENV: ${{ vars.MIX_ENV }}
RELEASE: ${{ inputs.release }}
BRAZIL_HOST: ${{ vars.brazil_host }}
EUROPE_HOST: ${{ vars.europe_host }}
PHX_SERVER: ${{ vars.PHX_SERVER }}
PHX_HOST: ${{ vars.LOADTEST_SERVER_HOST }}
PORT: ${{ vars.ARENA_PORT }}
BOT_MANAGER_PORT: ${{ vars.BOT_MANAGER_PORT }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SECRET_KEY_BASE: ${{ secrets.SECRET_KEY_BASE }}
NEWRELIC_APP_NAME: ${{ vars.NEWRELIC_APP_NAME_LOADTEST }}
NEWRELIC_KEY: ${{ secrets.NEWRELIC_KEY }}
Expand All @@ -70,11 +70,11 @@ jobs:
BRANCH_NAME=${BRANCH_NAME} \
MIX_ENV=${MIX_ENV} \
RELEASE=${RELEASE} \
BRAZIL_HOST=${BRAZIL_HOST} \
EUROPE_HOST=${EUROPE_HOST} \
PHX_SERVER=${PHX_SERVER} \
PHX_HOST=${PHX_HOST} \
PORT=${PORT} \
BOT_MANAGER_PORT=${BOT_MANAGER_PORT} \
DATABASE_URL=${DATABASE_URL} \
SECRET_KEY_BASE=${SECRET_KEY_BASE} \
NEWRELIC_APP_NAME=${NEWRELIC_APP_NAME} \
NEWRELIC_KEY=${NEWRELIC_KEY} \
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/loadtest-europe-client-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
- arena
- arena_load_test
- game_client
- bot_manager
required: true
target_server:
type: choice
Expand Down Expand Up @@ -62,11 +63,11 @@ jobs:
MIX_ENV: ${{ vars.MIX_ENV }}
RELEASE: ${{ inputs.release }}
TARGET_SERVER: ${{ inputs.target_server }}
BRAZIL_HOST: ${{ vars.brazil_host }}
EUROPE_HOST: ${{ vars.europe_host }}
PHX_SERVER: ${{ vars.PHX_SERVER }}
PHX_HOST: ${{ vars.LOADTEST_CLIENT_HOST }}
PORT: ${{ vars.ARENA_PORT }}
BOT_MANAGER_PORT: ${{ vars.BOT_MANAGER_PORT }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SECRET_KEY_BASE: ${{ secrets.SECRET_KEY_BASE }}
NEWRELIC_APP_NAME: ${{ vars.NEWRELIC_APP_NAME_LOADTEST }}
NEWRELIC_KEY: ${{ secrets.NEWRELIC_KEY }}
Expand All @@ -78,11 +79,11 @@ jobs:
MIX_ENV=${MIX_ENV} \
RELEASE=${RELEASE} \
TARGET_SERVER=${TARGET_SERVER} \
BRAZIL_HOST=${BRAZIL_HOST} \
EUROPE_HOST=${EUROPE_HOST} \
PHX_SERVER=${PHX_SERVER} \
PHX_HOST=${PHX_HOST} \
PORT=${PORT} \
BOT_MANAGER_PORT=${BOT_MANAGER_PORT} \
DATABASE_URL=${DATABASE_URL} \
SECRET_KEY_BASE=${SECRET_KEY_BASE} \
NEWRELIC_APP_NAME=${NEWRELIC_APP_NAME} \
NEWRELIC_KEY=${NEWRELIC_KEY} \
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/loadtest-europe-server-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ jobs:
SSH_USERNAME: ${{ vars.SSH_USERNAME }}
MIX_ENV: ${{ vars.MIX_ENV }}
RELEASE: ${{ inputs.release }}
BRAZIL_HOST: ${{ vars.brazil_host }}
EUROPE_HOST: ${{ vars.europe_host }}
PHX_SERVER: ${{ vars.PHX_SERVER }}
PHX_HOST: ${{ vars.LOADTEST_SERVER_HOST }}
PORT: ${{ vars.ARENA_PORT }}
BOT_MANAGER_PORT: ${{ vars.BOT_MANAGER_PORT }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SECRET_KEY_BASE: ${{ secrets.SECRET_KEY_BASE }}
NEWRELIC_APP_NAME: ${{ vars.NEWRELIC_APP_NAME_LOADTEST }}
NEWRELIC_KEY: ${{ secrets.NEWRELIC_KEY }}
Expand All @@ -70,11 +70,11 @@ jobs:
BRANCH_NAME=${BRANCH_NAME} \
MIX_ENV=${MIX_ENV} \
RELEASE=${RELEASE} \
BRAZIL_HOST=${BRAZIL_HOST} \
EUROPE_HOST=${EUROPE_HOST} \
PHX_SERVER=${PHX_SERVER} \
PHX_HOST=${PHX_HOST} \
PORT=${PORT} \
BOT_MANAGER_PORT=${BOT_MANAGER_PORT} \
DATABASE_URL=${DATABASE_URL} \
SECRET_KEY_BASE=${SECRET_KEY_BASE} \
NEWRELIC_APP_NAME=${NEWRELIC_APP_NAME} \
NEWRELIC_KEY=${NEWRELIC_KEY} \
Expand Down
33 changes: 33 additions & 0 deletions apps/arena/docs/collision-detection.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Collision detection

## Jeffrey Thompson's implementation
A collision detection library implementation based on [https://www.jeffreythompson.org/collision-detection/](https://www.jeffreythompson.org/collision-detection/).

We are working with entities.
Expand Down Expand Up @@ -54,3 +55,35 @@ If you only need to detect when a circle collides with the "walls" of the polygo

It is necessary to clarify that there are other types of collisions that we do not need to implement at the moment, for example Polygon/Polygon.

## SAT (Simple Axis Theorem) implementation
A collision detection library implementation based on the [SAT theorem](https://dyn4j.org/2010/01/sat/).

We'll keep working with entities with the same shapes as the ones used by Jeffrey Thompson.

To detect a collision between two entities, we'll iterate over an axis for each pair of vertices from both entities that collided.
For circular shapes, we'll check the axis that's formed between the circle center and the closest polygon vertex, and then cast the
maximum and minimum vertex to the normal of each pair of vertices. As soon as we find an axis where the cast of the shapes are not overlapping, we can safely say that the entities are not colliding.

#### Triangle example for axis where the cast in the axis are overlapping
![Polygons axis overlapping](./images/sat-overlapping.jpg "Polygons axis overlapping")
#### Triangle example for axis where the cast in the axis are not overlapping
![Polygons axis not overlapping](./images/sat-no-overlapping.jpg "Polygons axis not overlapping")

The collisions we currently support are:

1. Circle with polygon:
![Circle/Polygon not colliding](./images/circle-polygon-not-colliding.jpg "Circle/Polygon not colliding")

![Circle/Polygon colliding](./images/circle-polygon-colliding.jpg "Circle/Polygon colliding")



## Collision resolution

The Jeffrey Thompson's implementation for collision detection is ideal since it's the cheapest way to
detect that two entities collided, but it's incomplete since we can only detect that a collision occurred
and nothing else, so we decided to take the following approach:

1. We use the Jeffrey Thompson's implementation to detect that a collision actually happened.
2. Using SAT we can get the normal that will resolve that collision and the amount of movement we should do
so the entities are no longer colliding, so when a collision occurs we will use SAT to push the entities in the direction that, with the minimum movement, will resolve that collision.
Binary file added apps/arena/docs/images/sat-no-overlapping.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/arena/docs/images/sat-overlapping.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 16 additions & 3 deletions apps/arena/lib/arena/entities.ex
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,15 @@ defmodule Arena.Entities do
}
end

def new_circular_obstacle(id, position, radius) do
def new_obstacle(id, %{position: position, radius: radius, shape: shape, vertices: vertices}) do
%{
id: id,
category: :obstacle,
shape: :circle,
shape: get_shape(shape),
name: "Obstacle" <> Integer.to_string(id),
position: position,
radius: radius,
vertices: [],
vertices: vertices,
speed: 0.0,
direction: %{
x: 0.0,
Expand Down Expand Up @@ -244,6 +244,13 @@ defmodule Arena.Entities do
}}
end

def maybe_add_custom_info(entity) when entity.category == :obstacle do
{:obstacle,
%Arena.Serialization.Obstacle{
color: "red"
}}
end

def maybe_add_custom_info(entity) when entity.category == :pool do
{:pool,
%Arena.Serialization.Pool{
Expand All @@ -261,4 +268,10 @@ defmodule Arena.Entities do
def maybe_add_custom_info(_entity) do
nil
end

defp get_shape("polygon"), do: :polygon
defp get_shape("circle"), do: :circle
defp get_shape("line"), do: :line
defp get_shape("point"), do: :point
defp get_shape(_), do: nil
end
42 changes: 37 additions & 5 deletions apps/arena/lib/arena/game/player.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ defmodule Arena.Game.Player do
alias Arena.Utils
alias Arena.Game.Skill

def add_action(player, action_name, duration_ms) do
Process.send_after(self(), {:remove_skill_action, player.id, action_name}, duration_ms)
def add_action(player, action) do
Process.send_after(self(), {:remove_skill_action, player.id, action.action}, action.duration)

update_in(player, [:aditional_info, :current_actions], fn current_actions ->
current_actions ++ [%{action: action_name, duration: duration_ms}]
current_actions ++ [action]
end)
end

Expand Down Expand Up @@ -189,19 +189,39 @@ defmodule Arena.Game.Player do
skill.activation_delay_ms
)

action_name = skill_key_execution_action(skill_key)
action =
%{
action: skill_key_execution_action(skill_key),
duration: skill.execution_duration_ms
}
|> maybe_add_destination(player, skill_direction, skill)

player =
add_action(player, action_name, skill.execution_duration_ms)
add_action(player, action)
|> apply_skill_cooldown(skill_key, skill)
|> put_in([:direction], skill_direction |> Utils.normalize())
|> put_in([:is_moving], false)
|> put_in([:aditional_info, :last_skill_triggered], System.monotonic_time(:millisecond))
|> maybe_make_invincible(skill)

put_in(game_state, [:players, player.id], player)
end
end

# This is a messy solution to get a mechanic result before actually running the mechanic since the client needed the
# position in wich the player will spawn when the skill start and not when we actually execute the teleport
# this is also optimistic since we asume the destination will be always available
defp maybe_add_destination(action, player, skill_direction, %{mechanics: [{:teleport, teleport}]}) do
target_position = %{
x: player.position.x + skill_direction.x * teleport.range,
y: player.position.y + skill_direction.y * teleport.range
}

Map.put(action, :destination, target_position)
end

defp maybe_add_destination(action, _, _, _), do: action

@doc """
Receives a player that owns the damage and the damage number
Expand Down Expand Up @@ -362,4 +382,16 @@ defmodule Arena.Game.Player do
player
end
end

defp maybe_make_invincible(
player,
%{inmune_while_executing: true, execution_duration_ms: execution_duration_ms} = _skill
) do
Process.send_after(self(), {:remove_damage_immunity, player.id}, execution_duration_ms)
put_in(player, [:aditional_info, :damage_immunity], true)
end

defp maybe_make_invincible(player, _) do
player
end
end
Loading

0 comments on commit fe8edd5

Please sign in to comment.