From ae1be5a73bee3ae92048f69a753436ef7c07167f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Sanchez?= Date: Tue, 18 Jun 2024 11:14:01 -0300 Subject: [PATCH 1/4] Delete central backend brazil workflow because it doesn't exist (#705) --- .../central-brazil-testing-deploy.yml | 75 ------------------- 1 file changed, 75 deletions(-) delete mode 100644 .github/workflows/central-brazil-testing-deploy.yml diff --git a/.github/workflows/central-brazil-testing-deploy.yml b/.github/workflows/central-brazil-testing-deploy.yml deleted file mode 100644 index 6ddfb0af0..000000000 --- a/.github/workflows/central-brazil-testing-deploy.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: Deploy to Brazil Central testing -on: - workflow_dispatch: - -jobs: - build-deploy: - name: Build and deploy to Brazil testing - runs-on: ubuntu-latest - environment: - name: testing-brazil - url: https://central-europe-testing.curseofmirra.com/ - - steps: - - uses: actions/checkout@v4 - - - name: Tailscale - uses: tailscale/github-action@v2 - with: - oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} - oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} - tags: tag:ci - - - name: Create ssh private key file from env var - env: - SSH_KEY: ${{ secrets.SSH_KEY }} - SSH_HOST: ${{ vars.TS_CENTRAL_HOST }} - run: | - set -ex - mkdir -p ~/.ssh/ - sed -E 's/(-+(BEGIN|END) OPENSSH PRIVATE KEY-+) *| +/\1\n/g' <<< "$SSH_KEY" > ~/.ssh/id_ed25519 - chmod 400 ~/.ssh/id_ed25519 - retries=5; until ssh-keyscan $SSH_HOST >> ~/.ssh/known_hosts || [ $retries -eq 0 ]; do ((retries--)); sleep 5; done - - - name: Copy deploy script - env: - SSH_USERNAME: ${{ vars.SSH_USERNAME }} - SSH_HOST: ${{ vars.TS_CENTRAL_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_CENTRAL_HOST }} - SSH_USERNAME: ${{ vars.SSH_USERNAME }} - MIX_ENV: ${{ vars.MIX_ENV }} - RELEASE: central_backend - 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 }} - JWT_PRIVATE_KEY_BASE_64: ${{ secrets.JWT_PRIVATE_KEY_BASE_64 }} - SECRET_KEY_BASE: ${{ secrets.SECRET_KEY_BASE }} - NEWRELIC_APP_NAME: ${{ vars.NEWRELIC_APP_NAME }} - NEWRELIC_KEY: ${{ secrets.NEWRELIC_KEY }} - BRANCH_NAME: ${{ github.head_ref || github.ref_name }} - run: | - set -ex - ssh ${SSH_USERNAME}@${SSH_HOST} \ - BRANCH_NAME=${BRANCH_NAME} \ - MIX_ENV=${MIX_ENV} \ - RELEASE=${RELEASE} \ - 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} \ - JWT_PRIVATE_KEY_BASE_64=${JWT_PRIVATE_KEY_BASE_64} \ - NEWRELIC_APP_NAME=${NEWRELIC_APP_NAME} \ - NEWRELIC_KEY=${NEWRELIC_KEY} \ - /home/${SSH_USERNAME}/deploy-script/deploy.sh From 275d4b75a521767719e0f8ee8b359e33d3ddee0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Sanchez?= Date: Tue, 18 Jun 2024 12:20:17 -0300 Subject: [PATCH 2/4] Gh 692 allow client to toggle bots (#693) * wip * Add new ToggleZone protobuff message * Handle new :toggle_zone message in GameSocketHandler * Refactor zone messages in game updater to perform toggle zone behavior * wip * Add new ToggleZone client and bots server messages * Add server_toggle_zone broadcast message handlers in game updater * Handle new server_toggle_bots message in bots manager to freeze bots when requested * Decode client_toggle_bots messages to trigger server_toggle_bots broadcast message * Group server and client toggle bots to single message ToggleBots * Delete messages.proto newline * Delete IO.inspect/2 call * Delete testing purposes key in game state --- apps/arena/lib/arena/game_socket_handler.ex | 7 + apps/arena/lib/arena/game_updater.ex | 17 +- .../lib/arena/serialization/messages.pb.ex | 8 + .../serialization/messages.pb.ex | 18 ++ apps/bot_manager/lib/bot_state_machine.ex | 4 + apps/bot_manager/lib/game_socket_handler.ex | 5 +- apps/bot_manager/lib/protobuf/messages.pb.ex | 8 + .../assets/js/protobuf/messages_pb.js | 237 +++++++++++++++++- .../lib/game_client/protobuf/messages.pb.ex | 8 + apps/serialization/messages.proto | 3 + 10 files changed, 308 insertions(+), 7 deletions(-) diff --git a/apps/arena/lib/arena/game_socket_handler.ex b/apps/arena/lib/arena/game_socket_handler.ex index 9d7b4b616..598fb8421 100644 --- a/apps/arena/lib/arena/game_socket_handler.ex +++ b/apps/arena/lib/arena/game_socket_handler.ex @@ -150,6 +150,10 @@ defmodule Arena.GameSocketHandler do end end + def websocket_info({:toggle_bots, message}, state) do + {:reply, {:binary, message}, state} + end + @impl true def websocket_info(message, state) do Logger.info("You should not be here: #{inspect(message)}") @@ -199,6 +203,9 @@ defmodule Arena.GameSocketHandler do defp handle_decoded_message(%{action_type: {:toggle_zone, _zone_params}}, state), do: GameUpdater.toggle_zone(state.game_pid) + defp handle_decoded_message(%{action_type: {:toggle_bots, _bots_params}}, state), + do: GameUpdater.toggle_bots(state.game_pid) + defp handle_decoded_message(_action_type, %{enable: false} = _state), do: nil defp handle_decoded_message( diff --git a/apps/arena/lib/arena/game_updater.ex b/apps/arena/lib/arena/game_updater.ex index 00a62ccde..c6a10722b 100644 --- a/apps/arena/lib/arena/game_updater.ex +++ b/apps/arena/lib/arena/game_updater.ex @@ -11,7 +11,7 @@ defmodule Arena.GameUpdater do alias Arena.Game.Effect alias Arena.{Configuration, Entities} alias Arena.Game.{Player, Skill} - alias Arena.Serialization.{GameEvent, GameState, GameFinished} + alias Arena.Serialization.{GameEvent, GameState, GameFinished, ToggleBots} alias Phoenix.PubSub alias Arena.Utils alias Arena.Game.Trap @@ -43,6 +43,10 @@ defmodule Arena.GameUpdater do GenServer.cast(game_pid, :toggle_zone) end + def toggle_bots(game_pid) do + GenServer.cast(game_pid, :toggle_bots) + end + ########################## # END API ########################## @@ -151,6 +155,17 @@ defmodule Arena.GameUpdater do {:noreply, state} end + def handle_cast(:toggle_bots, state) do + encoded_msg = + GameEvent.encode(%GameEvent{ + event: {:toggle_bots, %ToggleBots{}} + }) + + PubSub.broadcast(Arena.PubSub, state.game_state.game_id, {:toggle_bots, encoded_msg}) + + {:noreply, state} + end + ########################## # END API Callbacks ########################## diff --git a/apps/arena/lib/arena/serialization/messages.pb.ex b/apps/arena/lib/arena/serialization/messages.pb.ex index 0460d762d..120e5129b 100644 --- a/apps/arena/lib/arena/serialization/messages.pb.ex +++ b/apps/arena/lib/arena/serialization/messages.pb.ex @@ -121,6 +121,7 @@ defmodule Arena.Serialization.GameEvent do field(:update, 2, type: Arena.Serialization.GameState, oneof: 0) field(:finished, 3, type: Arena.Serialization.GameFinished, oneof: 0) field(:ping, 4, type: Arena.Serialization.PingUpdate, oneof: 0) + field(:toggle_bots, 5, type: Arena.Serialization.ToggleBots, json_name: "toggleBots", oneof: 0) end defmodule Arena.Serialization.GameFinished.PlayersEntry do @@ -634,6 +635,12 @@ defmodule Arena.Serialization.ToggleZone do use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" end +defmodule Arena.Serialization.ToggleBots do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" +end + defmodule Arena.Serialization.GameAction do @moduledoc false @@ -652,6 +659,7 @@ defmodule Arena.Serialization.GameAction do ) field(:toggle_zone, 6, type: Arena.Serialization.ToggleZone, json_name: "toggleZone", oneof: 0) + field(:toggle_bots, 7, type: Arena.Serialization.ToggleBots, json_name: "toggleBots", oneof: 0) field(:timestamp, 3, type: :int64) end diff --git a/apps/arena_load_test/lib/arena_load_test/serialization/messages.pb.ex b/apps/arena_load_test/lib/arena_load_test/serialization/messages.pb.ex index bfcf70f38..6239b497b 100644 --- a/apps/arena_load_test/lib/arena_load_test/serialization/messages.pb.ex +++ b/apps/arena_load_test/lib/arena_load_test/serialization/messages.pb.ex @@ -121,6 +121,12 @@ defmodule ArenaLoadTest.Serialization.GameEvent do field(:update, 2, type: ArenaLoadTest.Serialization.GameState, oneof: 0) field(:finished, 3, type: ArenaLoadTest.Serialization.GameFinished, oneof: 0) field(:ping, 4, type: ArenaLoadTest.Serialization.PingUpdate, oneof: 0) + + field(:toggle_bots, 5, + type: ArenaLoadTest.Serialization.ToggleBots, + json_name: "toggleBots", + oneof: 0 + ) end defmodule ArenaLoadTest.Serialization.GameFinished.PlayersEntry do @@ -676,6 +682,12 @@ defmodule ArenaLoadTest.Serialization.ToggleZone do use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" end +defmodule ArenaLoadTest.Serialization.ToggleBots do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" +end + defmodule ArenaLoadTest.Serialization.GameAction do @moduledoc false @@ -699,6 +711,12 @@ defmodule ArenaLoadTest.Serialization.GameAction do oneof: 0 ) + field(:toggle_bots, 7, + type: ArenaLoadTest.Serialization.ToggleBots, + json_name: "toggleBots", + oneof: 0 + ) + field(:timestamp, 3, type: :int64) end diff --git a/apps/bot_manager/lib/bot_state_machine.ex b/apps/bot_manager/lib/bot_state_machine.ex index 2d05864eb..cb08224f6 100644 --- a/apps/bot_manager/lib/bot_state_machine.ex +++ b/apps/bot_manager/lib/bot_state_machine.ex @@ -6,6 +6,10 @@ defmodule BotManager.BotStateMachine do alias BotManager.Utils alias BotManager.Math.Vector + def decide_action(%{bots_enabled?: false}) do + {:move, %{x: 0, y: 0}} + end + def decide_action(%{game_state: game_state, bot_player: bot_player}) do closest_player = map_directions_to_players(game_state, bot_player) diff --git a/apps/bot_manager/lib/game_socket_handler.ex b/apps/bot_manager/lib/game_socket_handler.ex index 1d98eb555..9222ecea6 100644 --- a/apps/bot_manager/lib/game_socket_handler.ex +++ b/apps/bot_manager/lib/game_socket_handler.ex @@ -28,7 +28,7 @@ defmodule BotManager.GameSocketHandler do def handle_connect(_conn, state) do send(self(), :decide_action) send(self(), :perform_action) - {:ok, state} + {:ok, Map.put(state, :bots_enabled?, true)} end def handle_frame({:binary, frame}, state) do @@ -49,6 +49,9 @@ defmodule BotManager.GameSocketHandler do %{event: {:finished, _}} -> exit(:shutdown) + %{event: {:toggle_bots, _}} -> + {:ok, Map.put(state, :bots_enabled?, not state.bots_enabled?)} + _ -> {:ok, state} end diff --git a/apps/bot_manager/lib/protobuf/messages.pb.ex b/apps/bot_manager/lib/protobuf/messages.pb.ex index 8b4658f6c..030b39c7e 100644 --- a/apps/bot_manager/lib/protobuf/messages.pb.ex +++ b/apps/bot_manager/lib/protobuf/messages.pb.ex @@ -121,6 +121,7 @@ defmodule BotManager.Protobuf.GameEvent do field(:update, 2, type: BotManager.Protobuf.GameState, oneof: 0) field(:finished, 3, type: BotManager.Protobuf.GameFinished, oneof: 0) field(:ping, 4, type: BotManager.Protobuf.PingUpdate, oneof: 0) + field(:toggle_bots, 5, type: BotManager.Protobuf.ToggleBots, json_name: "toggleBots", oneof: 0) end defmodule BotManager.Protobuf.GameFinished.PlayersEntry do @@ -634,6 +635,12 @@ defmodule BotManager.Protobuf.ToggleZone do use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" end +defmodule BotManager.Protobuf.ToggleBots do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" +end + defmodule BotManager.Protobuf.GameAction do @moduledoc false @@ -652,6 +659,7 @@ defmodule BotManager.Protobuf.GameAction do ) field(:toggle_zone, 6, type: BotManager.Protobuf.ToggleZone, json_name: "toggleZone", oneof: 0) + field(:toggle_bots, 7, type: BotManager.Protobuf.ToggleBots, json_name: "toggleBots", oneof: 0) field(:timestamp, 3, type: :int64) end diff --git a/apps/game_client/assets/js/protobuf/messages_pb.js b/apps/game_client/assets/js/protobuf/messages_pb.js index 03878623e..0200d4174 100644 --- a/apps/game_client/assets/js/protobuf/messages_pb.js +++ b/apps/game_client/assets/js/protobuf/messages_pb.js @@ -67,6 +67,7 @@ goog.exportSymbol('proto.PowerUpstatus', null, global); goog.exportSymbol('proto.Projectile', null, global); goog.exportSymbol('proto.ProjectileStatus', null, global); goog.exportSymbol('proto.SelectBounty', null, global); +goog.exportSymbol('proto.ToggleBots', null, global); goog.exportSymbol('proto.ToggleZone', null, global); goog.exportSymbol('proto.Trap', null, global); goog.exportSymbol('proto.TrapStatus', null, global); @@ -828,6 +829,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.ToggleZone.displayName = 'proto.ToggleZone'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.ToggleBots = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.ToggleBots, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.ToggleBots.displayName = 'proto.ToggleBots'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -1897,7 +1919,7 @@ proto.JoinedLobby.serializeBinaryToWriter = function(message, writer) { * @private {!Array>} * @const */ -proto.GameEvent.oneofGroups_ = [[1,2,3,4]]; +proto.GameEvent.oneofGroups_ = [[1,2,3,4,5]]; /** * @enum {number} @@ -1907,7 +1929,8 @@ proto.GameEvent.EventCase = { JOINED: 1, UPDATE: 2, FINISHED: 3, - PING: 4 + PING: 4, + TOGGLE_BOTS: 5 }; /** @@ -1951,7 +1974,8 @@ proto.GameEvent.toObject = function(includeInstance, msg) { joined: (f = msg.getJoined()) && proto.GameJoined.toObject(includeInstance, f), update: (f = msg.getUpdate()) && proto.GameState.toObject(includeInstance, f), finished: (f = msg.getFinished()) && proto.GameFinished.toObject(includeInstance, f), - ping: (f = msg.getPing()) && proto.PingUpdate.toObject(includeInstance, f) + ping: (f = msg.getPing()) && proto.PingUpdate.toObject(includeInstance, f), + toggleBots: (f = msg.getToggleBots()) && proto.ToggleBots.toObject(includeInstance, f) }; if (includeInstance) { @@ -2008,6 +2032,11 @@ proto.GameEvent.deserializeBinaryFromReader = function(msg, reader) { reader.readMessage(value,proto.PingUpdate.deserializeBinaryFromReader); msg.setPing(value); break; + case 5: + var value = new proto.ToggleBots; + reader.readMessage(value,proto.ToggleBots.deserializeBinaryFromReader); + msg.setToggleBots(value); + break; default: reader.skipField(); break; @@ -2069,6 +2098,14 @@ proto.GameEvent.serializeBinaryToWriter = function(message, writer) { proto.PingUpdate.serializeBinaryToWriter ); } + f = message.getToggleBots(); + if (f != null) { + writer.writeMessage( + 5, + f, + proto.ToggleBots.serializeBinaryToWriter + ); + } }; @@ -2220,6 +2257,43 @@ proto.GameEvent.prototype.hasPing = function() { }; +/** + * optional ToggleBots toggle_bots = 5; + * @return {?proto.ToggleBots} + */ +proto.GameEvent.prototype.getToggleBots = function() { + return /** @type{?proto.ToggleBots} */ ( + jspb.Message.getWrapperField(this, proto.ToggleBots, 5)); +}; + + +/** + * @param {?proto.ToggleBots|undefined} value + * @return {!proto.GameEvent} returns this +*/ +proto.GameEvent.prototype.setToggleBots = function(value) { + return jspb.Message.setOneofWrapperField(this, 5, proto.GameEvent.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.GameEvent} returns this + */ +proto.GameEvent.prototype.clearToggleBots = function() { + return this.setToggleBots(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.GameEvent.prototype.hasToggleBots = function() { + return jspb.Message.getField(this, 5) != null; +}; + + @@ -9295,6 +9369,107 @@ proto.ToggleZone.serializeBinaryToWriter = function(message, writer) { + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.ToggleBots.prototype.toObject = function(opt_includeInstance) { + return proto.ToggleBots.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.ToggleBots} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.ToggleBots.toObject = function(includeInstance, msg) { + var f, obj = { + + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.ToggleBots} + */ +proto.ToggleBots.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.ToggleBots; + return proto.ToggleBots.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.ToggleBots} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.ToggleBots} + */ +proto.ToggleBots.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.ToggleBots.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.ToggleBots.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.ToggleBots} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.ToggleBots.serializeBinaryToWriter = function(message, writer) { + var f = undefined; +}; + + + /** * Oneof group definitions for this message. Each group defines the field * numbers belonging to that group. When of these fields' value is set, all @@ -9303,7 +9478,7 @@ proto.ToggleZone.serializeBinaryToWriter = function(message, writer) { * @private {!Array>} * @const */ -proto.GameAction.oneofGroups_ = [[1,2,4,5,6]]; +proto.GameAction.oneofGroups_ = [[1,2,4,5,6,7]]; /** * @enum {number} @@ -9314,7 +9489,8 @@ proto.GameAction.ActionTypeCase = { ATTACK: 2, USE_ITEM: 4, SELECT_BOUNTY: 5, - TOGGLE_ZONE: 6 + TOGGLE_ZONE: 6, + TOGGLE_BOTS: 7 }; /** @@ -9360,6 +9536,7 @@ proto.GameAction.toObject = function(includeInstance, msg) { useItem: (f = msg.getUseItem()) && proto.UseItem.toObject(includeInstance, f), selectBounty: (f = msg.getSelectBounty()) && proto.SelectBounty.toObject(includeInstance, f), toggleZone: (f = msg.getToggleZone()) && proto.ToggleZone.toObject(includeInstance, f), + toggleBots: (f = msg.getToggleBots()) && proto.ToggleBots.toObject(includeInstance, f), timestamp: jspb.Message.getFieldWithDefault(msg, 3, 0) }; @@ -9422,6 +9599,11 @@ proto.GameAction.deserializeBinaryFromReader = function(msg, reader) { reader.readMessage(value,proto.ToggleZone.deserializeBinaryFromReader); msg.setToggleZone(value); break; + case 7: + var value = new proto.ToggleBots; + reader.readMessage(value,proto.ToggleBots.deserializeBinaryFromReader); + msg.setToggleBots(value); + break; case 3: var value = /** @type {number} */ (reader.readInt64()); msg.setTimestamp(value); @@ -9495,6 +9677,14 @@ proto.GameAction.serializeBinaryToWriter = function(message, writer) { proto.ToggleZone.serializeBinaryToWriter ); } + f = message.getToggleBots(); + if (f != null) { + writer.writeMessage( + 7, + f, + proto.ToggleBots.serializeBinaryToWriter + ); + } f = message.getTimestamp(); if (f !== 0) { writer.writeInt64( @@ -9690,6 +9880,43 @@ proto.GameAction.prototype.hasToggleZone = function() { }; +/** + * optional ToggleBots toggle_bots = 7; + * @return {?proto.ToggleBots} + */ +proto.GameAction.prototype.getToggleBots = function() { + return /** @type{?proto.ToggleBots} */ ( + jspb.Message.getWrapperField(this, proto.ToggleBots, 7)); +}; + + +/** + * @param {?proto.ToggleBots|undefined} value + * @return {!proto.GameAction} returns this +*/ +proto.GameAction.prototype.setToggleBots = function(value) { + return jspb.Message.setOneofWrapperField(this, 7, proto.GameAction.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.GameAction} returns this + */ +proto.GameAction.prototype.clearToggleBots = function() { + return this.setToggleBots(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.GameAction.prototype.hasToggleBots = function() { + return jspb.Message.getField(this, 7) != null; +}; + + /** * optional int64 timestamp = 3; * @return {number} diff --git a/apps/game_client/lib/game_client/protobuf/messages.pb.ex b/apps/game_client/lib/game_client/protobuf/messages.pb.ex index da0d75501..777b214b0 100644 --- a/apps/game_client/lib/game_client/protobuf/messages.pb.ex +++ b/apps/game_client/lib/game_client/protobuf/messages.pb.ex @@ -121,6 +121,7 @@ defmodule GameClient.Protobuf.GameEvent do field(:update, 2, type: GameClient.Protobuf.GameState, oneof: 0) field(:finished, 3, type: GameClient.Protobuf.GameFinished, oneof: 0) field(:ping, 4, type: GameClient.Protobuf.PingUpdate, oneof: 0) + field(:toggle_bots, 5, type: GameClient.Protobuf.ToggleBots, json_name: "toggleBots", oneof: 0) end defmodule GameClient.Protobuf.GameFinished.PlayersEntry do @@ -634,6 +635,12 @@ defmodule GameClient.Protobuf.ToggleZone do use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" end +defmodule GameClient.Protobuf.ToggleBots do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" +end + defmodule GameClient.Protobuf.GameAction do @moduledoc false @@ -652,6 +659,7 @@ defmodule GameClient.Protobuf.GameAction do ) field(:toggle_zone, 6, type: GameClient.Protobuf.ToggleZone, json_name: "toggleZone", oneof: 0) + field(:toggle_bots, 7, type: GameClient.Protobuf.ToggleBots, json_name: "toggleBots", oneof: 0) field(:timestamp, 3, type: :int64) end diff --git a/apps/serialization/messages.proto b/apps/serialization/messages.proto index 52d9286d0..e9d3084db 100644 --- a/apps/serialization/messages.proto +++ b/apps/serialization/messages.proto @@ -39,6 +39,7 @@ message GameEvent { GameState update = 2; GameFinished finished = 3; PingUpdate ping = 4; + ToggleBots toggle_bots = 5; } } @@ -301,6 +302,7 @@ message SelectBounty { } message ToggleZone { } +message ToggleBots { } message GameAction { oneof action_type { @@ -309,6 +311,7 @@ message GameAction { UseItem use_item = 4; SelectBounty select_bounty = 5; ToggleZone toggle_zone = 6; + ToggleBots toggle_bots = 7; } int64 timestamp = 3; } From ee2c62b333b04fac2b8fda4793a581476cbec92a Mon Sep 17 00:00:00 2001 From: Marco <20408709+marco-paulucci@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:08:57 +0200 Subject: [PATCH 3/4] balance (#684) * h4ck + projectiles H4ck - Made (even more) faster than the rest - Slingshot: reduced speed to adapt to new movement speeds - Denial of Service: reduced amount of time h4ck needs to stand still - Dash: increased cooldown by one second to compensate for movespeed buff Valtimer - Antimatter: reduced speed to adapt to new movement speeds * skills rebalance * powerup crates - adjusted crate size to better match sprite - removed one crate from center to nerf @Nico-Sanchez - will add more crates when we have map editor * math is hard --------- Co-authored-by: agustinesco --- apps/arena/priv/config.json | 127 +++++++----------- apps/game_backend/priv/characters_config.json | 6 +- 2 files changed, 53 insertions(+), 80 deletions(-) diff --git a/apps/arena/priv/config.json b/apps/arena/priv/config.json index c1705e0ba..b29a3f6db 100644 --- a/apps/arena/priv/config.json +++ b/apps/arena/priv/config.json @@ -862,7 +862,7 @@ "activation_delay_ms": 150, "is_passive": false, "autoaim": true, - "max_autoaim_range": 800, + "max_autoaim_range": 700, "stamina_cost": 1, "can_pick_destination": false, "block_movement": true, @@ -870,7 +870,7 @@ { "circle_hit": { "damage": 64, - "range": 380.0, + "range": 350.0, "offset": 400 } } @@ -885,7 +885,7 @@ "activation_delay_ms": 300, "is_passive": false, "autoaim": true, - "max_autoaim_range": 1500, + "max_autoaim_range": 1200, "can_pick_destination": true, "block_movement": true, "mechanics": [ @@ -893,8 +893,8 @@ "spawn_pool": { "name": "singularity", "duration_ms": 5000, - "radius": 500.0, - "range": 1500.0, + "radius": 450.0, + "range": 1200.0, "effects_to_apply": [ "singularity" ] @@ -911,19 +911,19 @@ "activation_delay_ms": 200, "is_passive": false, "autoaim": true, - "max_autoaim_range": 1500, + "max_autoaim_range": 1300, "can_pick_destination": true, "block_movement": true, "mechanics": [ { "leap": { - "range": 1500.0, + "range": 1300.0, "speed": 50.0, - "radius": 650, + "radius": 600, "on_arrival_mechanic": { "circle_hit": { "damage": 92, - "range": 650.0, + "range": 600.0, "offset": 0 } } @@ -935,11 +935,11 @@ "name": "h4ck_denial_of_service", "cooldown_mechanism": "time", "cooldown_ms": 9000, - "execution_duration_ms": 500, - "activation_delay_ms": 400, + "execution_duration_ms": 200, + "activation_delay_ms": 300, "is_passive": false, "autoaim": true, - "max_autoaim_range": 1500, + "max_autoaim_range": 1200, "can_pick_destination": true, "block_movement": true, "mechanics": [ @@ -947,8 +947,8 @@ "spawn_pool": { "name": "denial_of_service", "duration_ms": 2500, - "radius": 550.0, - "range": 1500.0, + "radius": 500.0, + "range": 1200.0, "effects_to_apply": [ "denial_of_service" ] @@ -964,7 +964,7 @@ "activation_delay_ms": 0, "is_passive": false, "autoaim": true, - "max_autoaim_range": 1600, + "max_autoaim_range": 1300, "stamina_cost": 1, "can_pick_destination": false, "block_movement": true, @@ -973,7 +973,7 @@ "multi_shoot": { "angle_between": 22.0, "amount": 3, - "speed": 65.0, + "speed": 53.0, "duration_ms": 1000, "remove_on_collision": true, "projectile_offset": 100, @@ -987,7 +987,7 @@ { "name": "h4ck_dash", "cooldown_mechanism": "time", - "cooldown_ms": 4500, + "cooldown_ms": 5500, "execution_duration_ms": 250, "activation_delay_ms": 0, "is_passive": false, @@ -998,7 +998,7 @@ "mechanics": [ { "dash": { - "speed": 120.0, + "speed": 90.0, "duration": 250 } } @@ -1018,7 +1018,7 @@ "mechanics": [ { "dash": { - "speed": 100.0, + "speed": 80.0, "duration": 330 } } @@ -1031,18 +1031,18 @@ "activation_delay_ms": 0, "is_passive": false, "autoaim": true, - "max_autoaim_range": 800, + "max_autoaim_range": 650, "stamina_cost": 1, "can_pick_destination": false, "block_movement": true, "mechanics": [ { "multi_circle_hit": { - "damage": 21, + "damage": 22, "range": 280.0, "interval_ms": 200, "amount": 3, - "move_by": 200.0, + "move_by": 100.0, "offset": 200.0 } } @@ -1053,7 +1053,7 @@ "name": "uma_veil_radiance", "cooldown_mechanism": "time", "cooldown_ms": 9000, - "execution_duration_ms": 400, + "execution_duration_ms": 300, "activation_delay_ms": 150, "is_passive": false, "autoaim": true, @@ -1063,7 +1063,7 @@ "mechanics": [ { "circle_hit": { - "damage": 68, + "damage": 80, "range": 800.0, "offset": 0 } @@ -1087,7 +1087,7 @@ "mechanics": [ { "dash": { - "speed": 120.0, + "speed": 95.0, "duration": 250 } } @@ -1110,34 +1110,13 @@ "mechanics": [ { "teleport": { - "range": 1200, + "range": 1100, "duration_ms": 150 } } ], "effects_to_apply": [] }, - { - "name": "uma_sneak", - "cooldown_mechanism": "time", - "cooldown_ms": 5000, - "execution_duration_ms": 250, - "activation_delay_ms": 0, - "is_passive": false, - "autoaim": false, - "max_autoaim_range": 0, - "can_pick_destination": false, - "block_movement": true, - "mechanics": [ - { - "dash": { - "speed": 120.0, - "duration": 250 - } - } - ], - "effects_to_apply": [] - }, { "name": "valt_antimatter", "cooldown_mechanism": "stamina", @@ -1145,14 +1124,14 @@ "activation_delay_ms": 150, "is_passive": false, "autoaim": true, - "max_autoaim_range": 1600, + "max_autoaim_range": 1300, "stamina_cost": 1, "can_pick_destination": false, "block_movement": true, "mechanics": [ { "simple_shoot": { - "speed": 55.0, + "speed": 45.0, "duration_ms": 1100, "remove_on_collision": true, "projectile_offset": 100, @@ -1221,22 +1200,27 @@ } ], "power_up": { - "distance_to_power_up": 500, - "power_up_damage_modifier": 0.10, - "power_up_health_modifier": 0.10, + "distance_to_power_up": 400, + "power_up_damage_modifier": 0.08, + "power_up_health_modifier": 0.08, "radius": 200.0 } }, "effects": [ { "name": "invisible", - "duration_ms": 3500, + "duration_ms": 4000, "remove_on_action": true, "one_time_application": false, "effect_mechanics": { "invisible": { "execute_multiple_times": true, "effect_delay_ms": 0 + }, + "speed_boost": { + "modifier": 0.25, + "effect_delay_ms": 0, + "execute_multiple_times": false } } }, @@ -1369,33 +1353,22 @@ "crates": [ { "position": { - "y": 500.0, - "x": 0.0 - }, - "shape": "circle", - "radius": 250.0, - "health": 250, - "vertices": [], - "amount_of_power_ups": 1 - }, - { - "position": { - "y": -250.0, - "x": 250.0 + "y": 230.0, + "x": 260.0 }, "shape": "circle", - "radius": 250.0, + "radius": 150.0, "health": 250, "vertices": [], "amount_of_power_ups": 1 }, { "position": { - "y": -250.0, - "x": -250.0 + "y": 230.0, + "x": -40.0 }, "shape": "circle", - "radius": 250.0, + "radius": 150.0, "health": 250, "vertices": [], "amount_of_power_ups": 1 @@ -1406,7 +1379,7 @@ "x": 2630.0 }, "shape": "circle", - "radius": 250.0, + "radius": 150.0, "health": 250, "vertices": [], "amount_of_power_ups": 1 @@ -1417,7 +1390,7 @@ "x": 4360.0 }, "shape": "circle", - "radius": 250.0, + "radius": 150.0, "health": 250, "vertices": [], "amount_of_power_ups": 1 @@ -1428,7 +1401,7 @@ "x": -4650.0 }, "shape": "circle", - "radius": 250.0, + "radius": 150.0, "health": 250, "vertices": [], "amount_of_power_ups": 1 @@ -1439,7 +1412,7 @@ "x": -3960.0 }, "shape": "circle", - "radius": 250.0, + "radius": 150.0, "health": 250, "vertices": [], "amount_of_power_ups": 1 @@ -1450,7 +1423,7 @@ "x": 290.0 }, "shape": "circle", - "radius": 250.0, + "radius": 150.0, "health": 250, "vertices": [], "amount_of_power_ups": 1 @@ -1461,7 +1434,7 @@ "x": 2400.0 }, "shape": "circle", - "radius": 250.0, + "radius": 150.0, "health": 250, "vertices": [], "amount_of_power_ups": 1 @@ -1472,7 +1445,7 @@ "x": 4950.0 }, "shape": "circle", - "radius": 250.0, + "radius": 150.0, "health": 250, "vertices": [], "amount_of_power_ups": 1 diff --git a/apps/game_backend/priv/characters_config.json b/apps/game_backend/priv/characters_config.json index 949e38682..81a23135b 100644 --- a/apps/game_backend/priv/characters_config.json +++ b/apps/game_backend/priv/characters_config.json @@ -3,7 +3,7 @@ { "name": "muflus", "active": true, - "base_speed": 19.0, + "base_speed": 17.5, "base_size": 110.0, "base_health": 440, "base_stamina": 3, @@ -20,7 +20,7 @@ { "name": "h4ck", "active": true, - "base_speed": 21.0, + "base_speed": 22.5, "base_size": 90.0, "base_health": 400, "base_stamina": 3, @@ -54,7 +54,7 @@ { "name": "valtimer", "active": false, - "base_speed": 20.5, + "base_speed": 20.0, "base_size": 100.0, "base_health": 400, "base_stamina": 3, From b7f2f514fcb6665f693a25c41b570ce5a463c6ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Sanchez?= Date: Wed, 19 Jun 2024 11:42:47 -0300 Subject: [PATCH 4/4] [GH-699] Add environment default options in quick game (#701) * Make zone and bots configurable and toggle them off in quick match * Restore shrinking initial value * Move toggle bots message from init to game start --- apps/arena/lib/arena/game_launcher.ex | 10 +++++++--- apps/arena/lib/arena/game_updater.ex | 21 ++++++++++++++------- apps/arena/priv/config.json | 4 +++- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/apps/arena/lib/arena/game_launcher.ex b/apps/arena/lib/arena/game_launcher.ex index 738c48cec..a60ee77e6 100644 --- a/apps/arena/lib/arena/game_launcher.ex +++ b/apps/arena/lib/arena/game_launcher.ex @@ -65,7 +65,10 @@ defmodule Arena.GameLauncher do @impl true def handle_call({:join_quick_game, client_id, character_name, player_name}, {from_pid, _}, state) do - create_game_for_clients([{client_id, character_name, player_name, from_pid}]) + create_game_for_clients([{client_id, character_name, player_name, from_pid}], %{ + bots_enabled: false, + zone_enabled: false + }) {:reply, :ok, state} end @@ -128,13 +131,14 @@ defmodule Arena.GameLauncher do # Receives a list of clients. # Fills the given list with bots clients, creates a game and tells every client to join that game. - defp create_game_for_clients(clients) do + defp create_game_for_clients(clients, game_params \\ %{}) do bot_clients = get_bot_clients(Application.get_env(:arena, :players_needed_in_match) - Enum.count(clients)) {:ok, game_pid} = GenServer.start(Arena.GameUpdater, %{ clients: clients, - bot_clients: bot_clients + bot_clients: bot_clients, + game_params: game_params }) game_id = game_pid |> :erlang.term_to_binary() |> Base58.encode() diff --git a/apps/arena/lib/arena/game_updater.ex b/apps/arena/lib/arena/game_updater.ex index c6a10722b..5a203e1b6 100644 --- a/apps/arena/lib/arena/game_updater.ex +++ b/apps/arena/lib/arena/game_updater.ex @@ -51,9 +51,11 @@ defmodule Arena.GameUpdater do # END API ########################## - def init(%{clients: clients, bot_clients: bot_clients}) do + def init(%{clients: clients, bot_clients: bot_clients, game_params: game_params}) do game_id = self() |> :erlang.term_to_binary() |> Base58.encode() game_config = Configuration.get_game_config() + game_config = Map.put(game_config, :game, Map.merge(game_config.game, game_params)) + game_state = new_game(game_id, clients ++ bot_clients, game_config) match_id = Ecto.UUID.generate() @@ -174,6 +176,12 @@ defmodule Arena.GameUpdater do # Game Callbacks ########################## + def handle_info(:toggle_bots, state) do + GenServer.cast(self(), :toggle_bots) + + {:noreply, state} + end + def handle_info(:update_game, %{game_state: game_state} = state) do Process.send_after(self(), :update_game, state.game_config.game.tick_rate_ms) now = DateTime.utc_now() |> DateTime.to_unix(:millisecond) @@ -234,12 +242,11 @@ defmodule Arena.GameUpdater do send(self(), :natural_healing) send(self(), {:end_game_check, Map.keys(state.game_state.players)}) - state = - state - |> put_in([:game_state, :zone, :enabled], true) - |> put_in([:game_state, :status], :RUNNING) + unless state.game_config.game.bots_enabled do + toggle_bots(self()) + end - {:noreply, state} + {:noreply, put_in(state, [:game_state, :status], :RUNNING)} end def handle_info({:end_game_check, last_players_ids}, state) do @@ -653,7 +660,7 @@ defmodule Arena.GameUpdater do |> Map.put(:external_wall, Entities.new_external_wall(0, config.map.radius)) |> Map.put(:zone, %{ radius: config.map.radius, - enabled: false, + enabled: config.game.zone_enabled, shrinking: false, next_zone_change_timestamp: initial_timestamp + config.game.zone_shrink_start_ms + config.game.start_game_time_ms diff --git a/apps/arena/priv/config.json b/apps/arena/priv/config.json index b29a3f6db..9c3f865de 100644 --- a/apps/arena/priv/config.json +++ b/apps/arena/priv/config.json @@ -852,7 +852,9 @@ "zone_start_interval_ms": 20000, "zone_damage_interval_ms": 1000, "zone_damage": 40, - "item_spawn_interval_ms": 7500 + "item_spawn_interval_ms": 7500, + "bots_enabled": true, + "zone_enabled": true }, "skills": [ {