Friday, September 20, 2024 7:07:14 AM
> settings

Customize


Authenticate

> exile_territory.rb
# frozen_string_literal: true

module ESM
  class ExileTerritory < ArmaRecord
    class ArmaError < ESM::Exception::Error
    end

    FLAG_TEXTURES = %w[
      exile_assets\texture\flag\flag_mate_bis_co.paa exile_assets\texture\flag\flag_mate_vish_co.paa exile_assets\texture\flag\flag_mate_hollow_co.paa
      exile_assets\texture\flag\flag_mate_legion_ca.paa exile_assets\texture\flag\flag_mate_21dmd_co.paa exile_assets\texture\flag\flag_mate_spawny_co.paa
      exile_assets\texture\flag\flag_mate_secretone_co.paa exile_assets\texture\flag\flag_mate_stitchmoonz_co.paa
      exile_assets\texture\flag\flag_mate_commandermalc_co.paa \A3\Data_F\Flags\flag_blue_co.paa \A3\Data_F\Flags\flag_green_co.paa
      \A3\Data_F\Flags\flag_red_co.paa \A3\Data_F\Flags\flag_white_co.paa \A3\Data_F\Flags\flag_uk_co.paa exile_assets\texture\flag\flag_country_de_co.paa
      exile_assets\texture\flag\flag_country_at_co.paa exile_assets\texture\flag\flag_country_sct_co.paa exile_assets\texture\flag\flag_country_ee_co.paa
      exile_assets\texture\flag\flag_country_cz_co.paa exile_assets\texture\flag\flag_country_nl_co.paa exile_assets\texture\flag\flag_country_hr_co.paa
      exile_assets\texture\flag\flag_country_cn_co.paa exile_assets\texture\flag\flag_country_ru_co.paa exile_assets\texture\flag\flag_country_ir_co.paa
      exile_assets\texture\flag\flag_country_by_co.paa exile_assets\texture\flag\flag_country_fi_co.paa exile_assets\texture\flag\flag_country_fr_co.paa
      exile_assets\texture\flag\flag_country_au_co.paa exile_assets\texture\flag\flag_country_be_co.paa exile_assets\texture\flag\flag_country_se_co.paa
      exile_assets\texture\flag\flag_country_pl_co.paa exile_assets\texture\flag\flag_country_pl2_co.paa exile_assets\texture\flag\flag_country_pt_co.paa
      exile_assets\texture\flag\flag_mate_zanders_streched_co.paa exile_assets\texture\flag\flag_misc_brunswik_co.paa
      exile_assets\texture\flag\flag_misc_dorset_co.paa exile_assets\texture\flag\flag_misc_svarog_co.paa exile_assets\texture\flag\flag_misc_exile_co.paa
      exile_assets\texture\flag\flag_misc_utcity_co.paa exile_assets\texture\flag\flag_misc_dickbutt_co.paa exile_assets\texture\flag\flag_misc_rainbow_co.paa
      exile_assets\texture\flag\flag_misc_battleye_co.paa exile_assets\texture\flag\flag_misc_bss_co.paa exile_assets\texture\flag\flag_misc_skippy_co.paa
      exile_assets\texture\flag\flag_misc_kiwifern_co.paa exile_assets\texture\flag\flag_misc_trololol_co.paa exile_assets\texture\flag\flag_misc_dream_cat_co.paa
      exile_assets\texture\flag\flag_misc_pirate_co.paa exile_assets\texture\flag\flag_misc_pedobear_co.paa exile_assets\texture\flag\flag_misc_petoria_co.paa
      exile_assets\texture\flag\flag_misc_smashing_co.paa exile_assets\texture\flag\flag_misc_lemonparty_co.paa exile_assets\texture\flag\flag_misc_rma_co.paa
      exile_assets\texture\flag\flag_cp_co.paa exile_assets\texture\flag\flag_trouble2_co.paa exile_assets\texture\flag\flag_exile_city_co.paa
      exile_assets\texture\flag\flag_misc_eraser1_co.paa exile_assets\texture\flag\flag_misc_willbeeaten_co.paa
      exile_assets\texture\flag\flag_misc_privateproperty_co.paa exile_assets\texture\flag\flag_misc_nuclear_co.paa
      exile_assets\texture\flag\flag_misc_lazerkiwi_co.paa exile_assets\texture\flag\flag_misc_beardageddon_co.paa exile_assets\texture\flag\flag_country_dk_co.paa
      exile_assets\texture\flag\flag_country_it_co.paa exile_assets\texture\flag\flag_misc_alkohol_co.paa exile_assets\texture\flag\flag_misc_kickass_co.paa
      exile_assets\texture\flag\flag_misc_knuckles_co.paa exile_assets\texture\flag\flag_misc_snake_co.paa exile_assets\texture\flag\flag_misc_weeb_co.paa
    ].freeze

    self.table_name = "territory"

    attribute :id, :integer
    attribute :server_id, :integer # Not a database field in mysql
    attribute :esm_custom_id, :string
    attribute :owner_uid, :string
    attribute :name, :string
    attribute :position_x, :float
    attribute :position_y, :float
    attribute :position_z, :float
    attribute :radius, :float
    attribute :level, :integer
    attribute :flag_texture, :string
    attribute :flag_stolen, :boolean, default: false
    attribute :flag_stolen_by_uid, :string
    attribute :flag_stolen_at, :datetime
    attribute :created_at, :datetime, default: -> { Time.current }
    attribute :last_paid_at, :datetime, default: -> { Time.current }
    attribute :xm8_protectionmoney_notified, :boolean, default: false
    attribute :build_rights, :json
    attribute :moderators, :json
    attribute :esm_payment_counter, :integer, default: 0
    attribute :deleted_at, :datetime

    # Not database backed
    attribute :number_of_constructions, :integer, default: 0

    has_many :containers, class_name: "ESM::ExileContainer", dependent: :destroy
    has_many :constructions, class_name: "ESM::ExileConstruction", dependent: :destroy

    after_save :update_arma

    scope :active, -> { where(deleted_at: nil) }
    scope :not_stolen, -> { where(flag_stolen: false) }
    scope :owned_by, ->(user) { where(owner_uid: user.steam_uid) }
    scope :not_owned_by, ->(user) { where.not(owner_uid: user.steam_uid) }
    scope :built_by, ->(user) { where("build_rights LIKE ?", "%#{user.steam_uid}%") }
    scope :moderated_by, ->(user) { where("moderators LIKE ?", "%#{user.steam_uid}%") }
    scope :not_moderated_by, ->(user) { where.not("moderators LIKE ?", "%#{user.steam_uid}%") }

    scope :with_no_membership_for, ->(user) do
      where.not(owner_uid: user.steam_uid)
        .and(where.not("build_rights LIKE ?", "%#{user.steam_uid}%"))
        .and(where.not("moderators LIKE ?", "%#{user.steam_uid}%"))
    end

    def self.sampled_for(server)
      territory = all.sample
      territory.tap { |t| t.server_id = server.id }
    end

    def add_moderators!(*steam_uids)
      self.moderators |= steam_uids
      self.build_rights |= steam_uids

      save! if changed?
      self
    end

    alias_method :add_moderator!, :add_moderators!

    def add_builders!(*steam_uids)
      self.build_rights |= steam_uids

      save! if changed?
      self
    end

    alias_method :add_builder!, :add_builders!

    def revoke_membership(steam_uid)
      self.owner_uid = ESM::Test.steam_uid if owner_uid == steam_uid
      moderators.delete(steam_uid)
      build_rights.delete(steam_uid)
      save! if changed?
      self
    end

    def change_owner(steam_uid)
      old_owner_uid = owner_uid

      moderators.delete(old_owner_uid)
      build_rights.delete(old_owner_uid)

      self.owner_uid = steam_uid
      self.moderators |= [steam_uid]
      self.build_rights |= [steam_uid]

      save! if changed?
      self
    end

    def server
      ESM::Server.find(server_id)
    end

    def encoded_id
      @encoded_id ||= begin
        hashids = Hashids.new(server.server_key, 5, "abcdefghijklmnopqrstuvwxyz")
        hashids.encode(id)
      end
    end

    def create_flag
      sqf = <<~SQF
        private _territory = #{id} call ESMs_system_territory_get;
        if !(isNull _territory) exitWith { true };

        #{id} call ExileServer_system_territory_database_load;

        sleep 0.1;
        private _territory = #{id} call ESMs_system_territory_get;
        if (isNull _territory) exitWith { false };

        #{set_variables(MAPPING.keys)}

        !(isNull _territory)
      SQF

      success = server.execute_sqf!(sqf)
      raise ArmaError, "Failed to create flag for territory id:#{id}" unless success
    end

    def delete_flag
      # The sleep is required because Arma deletes a vehicle on the next frame
      sqf = <<~SQF
        private _territory = #{id} call ESMs_system_territory_get;
        if (isNull _territory) exitWith { true };

        deleteVehicle _territory;

        sleep 0.1;
        private _territory = #{id} call ESMs_system_territory_get;
        isNull(_territory)
      SQF

      success = server.execute_sqf!(sqf)
      raise ArmaError, "Failed to delete flag for territory id:#{id}" unless success
    end

    private

    MAPPING = {
      owner_uid: "ExileOwnerUID",
      moderators: "ExileTerritoryModerators",
      build_rights: "ExileTerritoryBuildRights",
      flag_stolen: "ExileFlagStolen",
      radius: "ExileTerritorySize",
      level: "ExileTerritoryLevel",
      number_of_constructions: "ExileTerritoryNumberOfConstructions",
      esm_payment_counter: "ESM_PaymentCounter"
    }.stringify_keys.freeze

    def set_variables(items)
      items.map_join(" ") do |attribute|
        arma_variable = MAPPING[attribute]
        if arma_variable.nil?
          warn!(
            "Territory attribute #{attribute.quoted} was updated but does not have a MAPPING entry"
          )
          next
        end

        value =
          if attribute == "flag_stolen"
            flag_stolen ? 1 : 0
          else
            public_send(attribute)
          end

        "_territory setVariable [#{arma_variable.to_json}, #{value.to_json}];"
      end
    end

    # _territory setVariable ["ExileTerritoryName", _name, true];
    # _territory setVariable ["ExileDatabaseID", _id];
    # _territory setVariable ["ExileOwnerUID", _owner, true];
    # _territory setVariable ["ExileTerritorySize", _radius, true];
    # _territory setVariable ["ExileTerritoryLevel", _level, true];
    # _territory setVariable ["ExileTerritoryLastPayed", _lastPayed];
    # _territory call ExileServer_system_territory_maintenance_recalculateDueDate;
    # _territory setVariable ["ExileTerritoryNumberOfConstructions", _data select 15, true];
    # _territory setVariable ["ExileRadiusShown", false, true];
    # _territory setVariable ["ExileFlagStolen",_flagStolen,true];
    # _territory setVariable ["ExileFlagTexture",_flagTexture];
    def update_arma
      return if previously_new_record?

      changed_items = previous_changes.slice(*MAPPING.keys)
      return if changed_items.blank?

      sqf = <<~STRING
        private _territory = #{id} call ESMs_system_territory_get;
        #{set_variables(changed_items.keys)}
      STRING

      server.execute_sqf!(sqf)
    end
  end
end
All opinions represented herein are my own
- © 2024 itsthedevman
- build 340fbb8