Spigot の AttributeModifier 関連を解剖する

# 初めに

:::note warn
(追記 2024/11/12)
この記事はバージョン 1.20.4 以下の環境向けに書かれています。
 1.21 辺りで AttributeModifier に多くの変更が加えられたため、この記事に記載されている手法が非推奨になっていることがあります。
:::


この記事では Minecraft の AttributeModifier 関連の要素についての解説を行い、最後に使用例のコードを示します。

Spigot の、と銘打ってはいますが paper でも動作します。ご安心を。


# AttributeModifier とは何か
AttributeModifier とは、アイテムをメインハンドやサブハンドに持つ、頭、胴などに装備したときに何かしらの追加効果を付与するものです。
- name (String型) (この AttributeModifier の識別子(?))
- UUID (この AttributeModifier の識別子(?))
- Attribute (効果の種類)
- Attribute.Operation (効果値の操作)
- EquipmentSlot (効果を発揮する部位)
- value(Double型) (効果値)

上記の要素から構成されます。

> [Spigot Class AttributeModifier](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/attribute/AttributeModifier.html)


# コンストラクタ
- AttributeModifier
  - String name
  - double amount
  - AttributeModifier.Operation operation

- AttributeModifier
  - UUID uuid
  - String name
  - double amount
  - AttributeModifier.Operation operation

- AttributeModifier
  - UUID uuid
  - String name
  - double amount
  - AttributeModifier.Operation operation
  - EquipmentSlot slot


# Attribute
Attribute は効果の種類を示します。
以下での説明は「上昇、減衰」を省略しています。

それぞれの詳しい解説は [Fandom Minecraft Wiki 属性](https://minecraft.fandom.com/ja/wiki/%E5%B1%9E%E6%80%A7) を参照してください。


### GENERIC_ARMOR
装備したときの防具値

防具値 5 増加でマーク2.5個分増えます↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403016/db4b1cc7-2d4a-d0fb-6f1b-48896ca1ff0f.png)

防具値 100 増加を指定してもマークは10個までしか表示されませんが、内部の被ダメージ計算には反映されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403016/90f5689e-e7db-2ee2-ff58-4447a526ab1b.png)

下記に記す防具値の働きから、防具値 25 以上はダメージを 100 % 吸収します。

:::note info
被ダメージについて
> _防具が受け止めることができるダメージでは、防御点1点ごとに4%のダメージを吸収し、防御点が増す毎にプレイヤーの受けるダメージは減少する。つまり、防具バーがすべて埋まれば80%のダメージを吸収することとなる。_
[Minecraft Fandom Wiki 防具](https://minecraft.fandom.com/ja/wiki/%E9%98%B2%E5%85%B7#%E9%98%B2%E5%BE%A1%E7%82%B9)
:::

### GENERIC_ARMOR_TOUGHNESS
装備したときの防具の耐久値

防具を装着しているときのみ発動する防具値操作
値の適用方法は `GENERIC_ARMOR` と同じ

例)
- `GENERIC_ARMOR_TOUGHNESS = 5` のアイテム + `防具値 3 の防具`　= 防具値 8
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403016/a9bf9287-642f-270d-373a-904b5bc2425b.png)

- `GENERIC_ARMOR_TOUGHNESS = 5` のアイテム + 装備無し = 防具値 0


### GENERIC_ATTACK_DAMAGE
攻撃力
value range: 0 ~ 2048

`GENERICK_ATTACK_DAMAGE = 5` のアイテムを用いて敵を殴るとき、その攻撃力は
`素手の攻撃力(1) + GENERIC_ATTACK_DAMAGE(5) = 6`
となります。

### GENERIC_ATTACK_KNOCKBACK
ノックバック
value range: 0 ~ 5

ノックバック攻撃を持つ敵にのみ効果が適用されるため、プレイヤーがこの属性を持つアイテムで敵を殴っても特に追加の効果は無い。

### GENERIC_ATTACK_SPEED
攻撃速度
value range: 0 ~ 1024

1秒間に値の分だけ攻撃が出来るようになる。

### GENERIC_FLYING_SPEED
飛行速度
value range: 0 ~ 1024

ミツバチとオウムのみ効果を享受することが出来る。

### GENERIC_FOLLOW_RANGE
モブからの検知範囲
value range: 0 ~ 2048

モブの索敵範囲(ブロック)

### GENERIC_KNOCKBACK_RESISTANCE
ノックバック耐性
value range: 0 ~ 1

1 でノックバックしなくなる。

### GENERIC_LUCK
幸運
value range: -1024 ~ 1024

モブからのレアドロップやダンジョンチェストの中身の希少なアイテムの出やすさに影響する。

### GENERIC_MAX_HEALTH
最大体力
value range: 0 ~ 1024

ハート0.5(HP 1)個単位で追加できる。
プラス 1 で以下の写真のようになる。↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403016/4225fbaa-cf48-44a5-50ab-24912b4c078c.png)


### GENERIC_MOVEMENT_SPEED
移動速度
value range: 0 ~ 1024

プレイヤーの場合、歩き状態で 1 秒間に `この値 * 20` ブロックだけ移動する。
ベース値は 0.1 なので、歩き状態で 2 (ブロック/秒) の移動速度である。
`+ 1` するだけで移動速度は `2 (ブロック/秒)` から 11 倍の `22 (ブロック/秒)` になる。

### HORSE_JUMP_STRENGTH
馬の跳躍力
value range: 0 ~ 2

### ZOMBIE_SPAWN_REINGORCEMENTS
ゾンビが援軍を呼ぶ確率
value range: 0 ~ 1

# AttributeModifier.Operation
ベース値(初期値または既に設定されている値)に対する値の操作

### ADD_NUMBER
ベース値に加算(もしくは減算)する

### ADD_SCALAR
不明

### MULTIPLY_SCALAR_1
ベース値に 1 を加算したのち、値を掛ける
`value = 0.5`のときに適用すると、`効果 +50 %` として扱われる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403016/b3de9340-2efc-3b7e-8811-0e4a64431488.png)

マイナス値も設定可能で、 `value = -0.5` のときに適用すると、 `効果 -50 %` として扱われる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403016/c8e8480e-20ee-d59a-ad7e-b57f4a5a68ef.png)



# EquipmentSlot
効果が波及する装備スロット。
そのスロットに装備すると効果が得られる、と考えてもよい。

- CHEST (胴)
- FEET (足)
- HAND (利き手)
- HEAD (頭)
- LEGS (脚 / レギンス)
- OFF_HAND (弓手)

__EquipmentSlotを設定しない場合、上記のどのスロットに配置しても効果が与えられる__
(`GENERIC_ATTACK_DAMAGE` の EquipmentSlot を設定しなかった例 ↓ )
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403016/659a78eb-d207-9f19-6ab3-7566ec896c58.png)


# value
double 型で指定する。
指定のない限り、値の範囲は絶対値 1.7 ^ 308 らしいです。(情報ソースによってまちまち)

# 利用例
- アイテムに攻撃力上昇と攻撃速度上昇を与える
```java
ItemStack item = new ItemStack(Material.GRASS_BLOCK);
ItemMeta meta = item.getItemMeta();

// 攻撃力上昇 (+10)
Attribute damage = Attribute.GENERIC_ATTACK_DAMAGE;
AttributeModifier damageModifier = new AttributeModifier(UUID.randomUUID(), "generic.attackDamage", 10d, AttributeModifier.Operation.ADD_NUMBER);
meta.addAttributeModifier(damage, damageModifier);

// 攻撃速度上昇 (+10)
Attribute speed = Attribute.GENERIC_ATTACK_SPEED;
AttributeModifier speedModifier = new AttributeModifier(UUID.randomUUID(), "generic.attackSpeed", 10d, AttributeModifier.Operation.ADD_NUMBER);
meta.addAttributeModifier(speed, speedModifier);

item.setItemMeta(meta);
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403016/461b6df3-9800-9cf2-f72b-421cd0358745.png)