Wednesday, July 15, 2026 2:04:08 AM
> server_initialization_v1.rb
# frozen_string_literal: true

module ESM
  module Event
    class ServerInitializationV1
      attr_reader :packet if ESM.env.test?

      def initialize(connection:, server:, parameters:)
        @connection = connection
        @server = server
        @params = parameters
        @community = @server.community
        @guild = ESM.discord_bot.server(@community.guild_id)
      end

      def run!
        # Updates the database with information from the server
        initialize_server!

        # We need to let the DLL know some stuff (namely a lot of stuff)
        build_settings_packet

        # Send packet to server
        send_response
      end

      # Called when an admin updates some settings.
      def update
        # We need to let the DLL know some stuff (namely a lot of stuff)
        build_settings_packet

        # Send packet to server
        send_response
      end

      private

      def initialize_server!
        update_server!
        update_server_settings!
        store_territory_info!
      end

      def update_server!
        @server.update!(
          server_name: @params.server_name,
          server_start_time: DateTime.parse(@params.server_start_time).utc,
          server_version: "1.0.0",
          disconnected_at: nil
        )
      end

      def update_server_settings!
        @server.server_setting.update(
          territory_price_per_object: @params.price_per_object,
          territory_lifetime: @params.territory_lifetime,
          server_restart_hour: @params.server_restart.first,
          server_restart_min: @params.server_restart.second
        )
      end

      def store_territory_info!
        @server.territories.delete_all

        # All territory info is prefixed with `territory_level_`
        territory_info = @params.to_h.select { |key, _| key.to_s.starts_with?("territory_level_") }
        territories =
          territory_info.map do |_, info|
            {
              server_id: @server.id,
              territory_level: info[:level],
              territory_purchase_price: info[:purchase_price],
              territory_radius: info[:radius],
              territory_object_count: info[:object_count]
            }
          end

        ESM::Territory.import(territories)
      end

      def build_settings_packet
        settings = @server.server_setting
        rewards = @server.server_reward

        @packet = OpenStruct.new(
          function_name: "postServerInitialization",
          server_id: @server.server_id,
          territory_admins: build_territory_admins.to_json,
          extdb_path: settings.extdb_path || "",
          gambling_modifier: settings.gambling_modifier,
          gambling_payout: settings.gambling_payout_base,
          gambling_randomizer_max: settings.gambling_payout_randomizer_max,
          gambling_randomizer_mid: settings.gambling_payout_randomizer_mid,
          gambling_randomizer_min: settings.gambling_payout_randomizer_min,
          gambling_win_chance: settings.gambling_win_percentage,
          logging_add_player_to_territory: settings.logging_add_player_to_territory,
          logging_demote_player: settings.logging_demote_player,
          logging_exec: settings.logging_exec,
          logging_gamble: settings.logging_gamble,
          logging_modify_player: settings.logging_modify_player,
          logging_pay_territory: settings.logging_pay_territory,
          logging_promote_player: settings.logging_promote_player,
          logging_remove_player_from_territory: settings.logging_remove_player_from_territory,
          logging_reward: settings.logging_reward_player,
          logging_transfer: settings.logging_transfer_poptabs,
          logging_upgrade_territory: settings.logging_upgrade_territory,
          logging_path: settings.logging_path || "",
          max_payment_count: settings.max_payment_count,
          request_thread_tick: settings.request_thread_tick,
          request_thread_type: settings.request_thread_type == "exile",
          taxes_territory_payment: settings.territory_payment_tax / 100,
          taxes_territory_upgrade: settings.territory_upgrade_tax / 100,
          reward_player_poptabs: rewards.player_poptabs,
          reward_locker_poptabs: rewards.locker_poptabs,
          reward_respect: rewards.respect,
          reward_items: rewards.reward_items.to_a.to_json,
          is_premium: true # Needed for legacy v1.0 support
        )
      end

      def build_territory_admins
        # Get all roles with administrator or that are set as territory admins
        roles = @guild.roles.select { |role| role.permissions.administrator || @community.territory_admin_ids.include?(role.id.to_s) }

        # Get all of the user's discord IDs who have these roles
        discord_ids =
          roles.map do |role|
            role.users.map { |user| user.id.to_s }
          end.flatten

        # Pluck all the steam UIDs we have, including the guild owners
        ESM::User.where(discord_id: discord_ids + [@guild.owner.id.to_s]).where.not(steam_uid: nil).pluck(:steam_uid)
      end

      def send_response
        # Build the request
        request = ESM::Websocket::Request.new(command_name: "post_initialization", parameters: @packet.to_h, remove_on_ignore: true)

        # After the server has replied to this request, notify the community and allow commands.
        request.on_reply = lambda do |connection|
          server = connection.server
          info!(server_id: server.server_id, uptime: server.uptime)

          # Trigger a connect notification
          embed = server.status_embed(:connected)
          server.community.log_event(:reconnect, embed)

          # Set the connection to be available for commands
          connection.ready = true
        end

        # Send it to the dll, don't use `Websocket#deliver` for this since it will raise on the connection not being ready.
        @connection.deliver!(request)
      end
    end
  end
end
All opinions represented herein are my own
- © 2024 - 2026 itsthedevman
- build 43aa0d7