攻撃した、倒した相手を検知したいよね

##### はじめに
攻撃したエンティティ、倒したエンティティを基準に関数を実行する機能についてです。バージョン1.21.3時点の情報でお話しします。

:::note warn
注意
思いつきの実装のため不完全です。
また、今回の機能でプレイヤーを対象にはできません！
:::
# 結論
前置きとか要らんからさっさと仕様を見せろ、という方のために結論からです。
解説などは後ほど。

### Advancementファイル
```ruby:攻撃した進捗
{
  "criteria": {
    "hurt": {
      "trigger": "minecraft:player_hurt_entity"
    }
  },
  "rewards": {
    "function": "攻撃の関数"
  }
}
```
```ruby:倒した進捗
{
  "criteria": {
    "kill": {
      "trigger": "minecraft:player_killed_entity",
    }
  },
  "rewards": {
    "function": "討伐の関数"
  }
}
```
まず２つのadvancementファイルを作りましょう。
### Functionファイル
```ruby:## 攻撃の関数
  # 進捗のリセット
    advancement revoke @s only 攻撃した進捗

  # on attackerでの検知
    execute as @e at @s on attacker
        as @e[distance=0,limit=1] if data entity @s {HurtTime:10s}
            run function 実行させたい関数
```
```ruby:## 討伐の関数
# 進捗のリセット
  advancement revoke @s only 倒した進捗

# 死亡中のエンティティに乗っているマーカーから確認
  execute as @e[type=marker,tag=ID] on vehicle 
      if data entity @s {Health:0f} run function 討伐の関数2
```
```ruby:## 討伐の関数2
# 乗っているマーカーを削除
  execute on passengers run kill @s

  実行したいコマンド
```
３つのfunctionファイルを作ります。@eなどはある程度エンティティを絞るタグも入れると良いかもしれませんね。
### 使い方
1.`summon`コマンドで上に「`ID`のタグ付きmarker」の乗ったエンティティを出します。
2.攻撃、討伐などします。

以上で実装は終了です。お疲れ様でした。

# 挨拶
どうもおはしあ。けいらぎっていいます。
12月3日の枠でお会いしたかもしれません。ご覧いただけましたか？
今回は攻撃した相手、倒した相手に関数を実行してもらいたいというお話です。
実は対象のエンティティを指定するのは意外と難しいんですよね。色々と手順を踏めば再現できるかもしれないとなったので、メモとして残しておきます。
え？カスタムエンチャントで良いって？それはまぁ...

## 前置き
Minecraftには、「攻撃したこと」や「討伐したこと」を検知する進捗(Advancement)があります。
ただし、それを達成したときの関数は、攻撃した人しか実行できません。
なので「倒したモブがどんなデータを持っているか」や「攻撃したモブの所にパーティクルを表示する」などは簡単にはできないのです。ちょっと前に出たカスタムエンチャントを使うと、攻撃した相手をしっかり指定できるんですけどね。
~~じゃあカスタムエンチャントでいいだろ！~~ うるさい！

# 解説 攻撃編
仕様をざっくり解説すると、
1.エンティティが、攻撃してきたプレイヤーを指定
2.その位置のモブ(自身)を再指定
3.もし攻撃されていたら実行

となっています。順を追って解説します。

## 1.エンティティが攻撃してきたプレイヤーを指定
最近追加された`execute on`というサブコマンドは、実行対象における様々な行動をしたエンティティに実行対象を移すことができます。今回は`attacker`を利用することで、自分を攻撃してきたエンティティを指定しています。そこでプレイヤーを一度指定し、それが通っていれば「攻撃をしてきたやつがいる」と判断しましょうというお話です。
### `execute on attcker`について
「攻撃してきた相手」に実行対象を移すというコマンドです。
例えば、これを村人に実行させた場合、攻撃をしてきたゾンビに実行対象を移すといった感じです。
最後に攻撃されてから5秒ほどデータを保持しています。「自身が攻撃した相手」は検知できないことに注意してください。

## 2.その位置のモブ(自身)を再指定
```ruby:# on attackerでの検知
execute as @e at @s on attacker as @e[distance=0,limit=1] ...
```
わざわざ`as @e[distance=0,limit=1]`を挟んでいる理由ですが、`on attacker`以降のコマンドは**攻撃したエンティティ**、つまりプレイヤーが実行対象となっています。それを各自攻撃されたエンティティに対象を戻すためにこんなことをやっています。
実行対象が変わっても、実行位置が変わるわけではない為、「もとの位置と同じ座標にいるエンティティ」を指定すると実質的に攻撃されたエンティティに戻るわけですね。
(正直これで本当に反例無く動作するのか怪しいです。誰か教えてください)
#### 豆知識 ～ 「@n」
@n = @e[sort=nearest,limit=1]
「一番近い一体のエンティティ」を指定します。便利ですね。
ただ、これを行うたびに全エンティティが距離を測り、近い順に並び替える処理が走るので使い所には気をつけましょう。

## 3.もし攻撃されていたら実行
```ruby:# on attackerでの検知
... if data entity @s {HurtTime:10s} run ...
```
`HurtTime`とは、モブが攻撃されたときに見た目が赤くなる状態の残り時間を表すデータです。攻撃された瞬間から10tickの間継続するため、10sを指定していれば攻撃されたと判定できますね。
これらによって実行対象が攻撃したモブに移るので、以降のコマンドや関数で実行させてください。
### 注意点
`HurtTime`管理なので、予め叩いていた炎上中のモブなどが勝手に実行されると思います。この機構は勝手に実行されても大きな影響のないコマンドに限定した方が良いかもしれません。
自分はモブのHPバーを操作する機構にだけ使っています。
##### Q. じゃあ最初から`tick.mcfunction`で見てればいいじゃん
A. うるせ〜〜～！！！！知らね〜〜〜〜！！！！

僕`tick.`にたくさんコマンド入れるの好きじゃないんですよ。重そうだし。
どのみち進捗が毎tick監視してるじゃんとかいう話は聞きません。

# 解説 討伐編
討伐ともなると、更に面倒な仕様が舞い降りてきます。
「モブが死亡し、赤くなって横に倒れている時間」は、**@eの検知に選ばれなくなります。** これのせいでモブに対して実行するのが難しくなっています。
が、海外Discordを漁っていたところ`execute on`で別のエンティティから実行すれば検知できるということがわかりました。よってあらかじめ何かエンティティを付属させておき、倒れたモブがいたなら実行という形をとることで実装しています。
なので自然スポーンしたモブとかを準備無しで検知はできません。かなしあ
```ruby:事前準備
summon zombie ~ ~ ~ {Passengers:[{id:"marker",Tags:["ID"]}]}
```   
あらかじめこんな感じのコマンドで`ID`マーカーの乗ったモブを出しておきましょう。

そして順序としてはこちらです。    
1.マーカーが、乗っているエンティティを指定
2.HPが0なら実行

## 1. マーカーが、乗っているエンティティを指定
```ruby:# 死亡中のエンティティに乗っているマーカーから確認
execute as @e[type=marker,tag=ID] on vehicle ...
```
死亡中のエンティティは対象に引っかからないということなので、マーカーを初めの実行対象とします。
`execute on vehicle`を用いると、自分が乗っているエンティティを実行対象に移します。今回のモブはマーカーが乗っているので、これ以降のコマンドはマーカーの下の子が対象となります。

## 2.HPが0なら実行
```ruby:# 死亡中のエンティティに乗っているマーカーから確認
... if data entity @s {Health:0f} run ...
```
エンティティのHPが0であるなら死亡している状態となるため、これを検知の手段としています。



### 終わり？
なんか短くない？だってメモ書きだし...
じゃあ小ネタでも書くか...
## 小ネタ `item`コマンドで直接jsonを記述
`item modify`は、データパック内のjsonファイルを用いてアイテムを編集することができるコマンドです。通常は`item_modifier`フォルダに入れたファイルを呼び出して実行する物ですが、実は無理やりコマンドの中に書き込むこともできます。
```
item modify entity @s weapon.mainhand {"function":"minecraft:set_name","entity":"this","name":{"text":"名前を変えるよ"}}
```
これの利点はここにマクロを組み込めることですね。前回おまけで紹介したアイテムチェッカーは、元来これでコンポーネントをストレージからマクロを組んで付与するような機構でした。(というかそれで知った)
よかったら試してみてください。`item_modifier`のファイルを作るほどではないなってときにも役立ちます。

## おわり
てことで今回は攻撃した対象をなんとかして指定できないかというお話でした。
質問や改善点などあればお気軽にどうぞ！できれば優しく、フランクな感じで。
初心者かつ昨日思いついた機構なので荒があるかもしれません。ぜひこれを基に改良され、システムが広まり、コマンドの世界がより良くなることを願っています。(他力本願)
公式で`execute on victim`みたいなのが実装されてくれれば全部解決するんですけどね。
それでは、ご覧いただきありがとうございました。
おつなも！