ScriptAPIでチーム内チャットを作ってみよう

<!--
導入
チャット送信
　送信先の指定
  タグ取得
  取得したタグに対してsendmessage
  
チャット検知
　　送信内容をそのまま取得して送信
　　送信者の名前を取得する。
   なんかいい感じに表示される。
   名前の色を変更

まとめ

参考文書
  

読みづらいので検知と送信を入れ替えた。
  
-->



「マイクラ アドオン チームチャット」と検索するといくつかの配布されたアドオンが見つかります。

　それぞれに得手不得手ありますが、どうしても自分の思い通りにはどうしてもなりませんし、そもそも自分が配布マップを作るとしたら、全部自分でやりたくなりません？

  と、言うことで今回はチームごとにチャットを分ける、もといチャットの送信先を自分と同じチームのプレイヤーのみにする方法を解説していきます。
 


:::note warn

ScriptAPIやJavascript自体の使い方は説明しません、あらかじめご了承ください。

:::









# プレイヤーにメッセージを送る

``Player.sendmessage("")``を使用してメッセージを送信可能です。

チャット欄に自由にメッセージを送れます。**String型** か**Rawtext** (tellrawのやつ)でメッセージ内容を指定できます。




```diff_javascript
import { world } from '@minecraft/server';

const Players = world.getPlayers();
//プレイヤーを取得。

for(let _i=0;_i<Players.length;_i++){

Players[_i].sendMessage("テストサーバーにようこそ！！！アイテムを右クリックでメニューを開けます。")
}

```

`` world.getPlayers()``でプレイヤー全員を取得して、forを利用してプレイヤー単体を取り出しています。もちろん、``getPlayers()``に限った話でなく返ってくるのが、同じものなら取得方法がどうであれ、プレイヤーにメッセージは送れます。



# プレイヤーがチャットをしたことを検知する
worldクラスの``chatSend``で検知ができます。上記の物と組み合わせた場合は以下のようになります。
```diff_javascript
import { world } from '@minecraft/server';

world.beforeEvents.chatSend.subscribe((event) => {
    event.cancel = true;
   //本来のチャット送信を止めるかどうか

    
//ここに処理

    const Players = world.getPlayers();
    //プレイヤーを取得。
    
    for(let _i=0;_i<Players.length;_i++){
    
    Players[_i].sendMessage("テストサーバーにようこそ！！！アイテムを右クリックでメニューを開けます。")
    //元のメッセージの変わりのメッセージ
}

});

```


## beforeEventとafterEvents
これらの違いは、**読み取り専用**か**読み取りと書き込み両方可能**かという違いがあります。

こう聞くと afterEvents のほうがよく見えますが、**beforeEvent** だと``event.cancel``を使用して**元のメッセージの送信**を**キャンセル**することができるのです。時と場合に応じて使い分けてください。


 この記事では キャンセルを使うために**beforeEvent を使用**します。


先程のコードを `afterEvents`で書くと以下のようになります。
 ```diff_javascript 
world.afterEvents.chatSend.subscribe((event) => {
    //ここに処理
 
 
             event.cancel = true;
 
             //本来のチャット送信を止めるかどうか
            //afterEventsだとできない
 
 
    
            const Players = world.getPlayers();
            //プレイヤーを取得。
            
            for(let _i=0;_i<Players.length;_i++){
            
            Players[_i].sendMessage("テストサーバーにようこそ！！！アイテムを右クリックでメニューを開けます。")
    
 }});
 
```


# チャットの送信先の指定
今までコードでは**ワールド内のすべてのプレイヤー**に**伝えられてしまいます**ので**同じチームのプレイヤーのみ**に、送信するようにしてみましょう。

```diff_javascript
import { world } from '@minecraft/server';

world.beforeEvents.chatSend.subscribe((event) => {
    //ここに処理
+ if(event.sender.hasTag("RedTeam")){
+ //event.senderはチャットを送信したプレイヤー
            event.cancel = true;

            const Players = world.getPlayers(
+           {tags:["RedTeam"]});
            //タグ"RedTeam"がついた
            //プレイヤーを取得。
            
            for(let _i=0;_i<Players.length;_i++){
            
            Players[_i].sendMessage("テストサーバーにようこそ！！！アイテムを右クリックでメニューを開けます。")
             }
+           }

});
```
チームタグがついていないプレイヤーがチャットの送信ができないので、``event.sender.hasTag()``で該当するタグが付いている場合のみに処理を実行しています。

また、`` Word.getplyers();``内で[EntityQueryOptions](https://learn.microsoft.com/en-us/minecraft/creator/scriptapi/minecraft/server/entityqueryoptions?view=minecraft-bedrock-stable) を使用することで対象を絞り込んでいます。

〇〇なタグを持つプレイヤーや、〇〇な名前かどうかで絞り込めます。絞り込む条件のリストは[こちら](https://learn.microsoft.com/en-us/minecraft/creator/scriptapi/minecraft/server/entityfilter?view=minecraft-bedrock-stable)の公式ドキュメントをご確認ください。



<details><summary>条件の例</summary>

 ### `tags:`
 「/tag」 コマンドでつけられるタグがついているかどうかで絞り込みます。配列でタグを指定でき、配列内の全てのタグがついているプレイヤーのみを返します。
 
 ```diff_javascript
const Players = Word.getplyers({tags:["Red","Blue","One","two"]})
 ```

  ### `name:`
  指定した名前をもつプレイヤーを返します。カスタムコマンドで送信先を手動で指定したりできます。
```diff_javascript
const Players = world.getPlayers({name:"ここにプレイヤーの名前"})
```
 ### ``excludeNames:``
 
配列内で名前を指定し、そのプレイヤー達を除外できます。
    
```diff_javascript
const Players = world.getPlayers({excludeNames:["ここにプレイヤーの名前","Steve","Alex"]})
```


</details>



# 書いたチャット内容を送信する

何を言っても歓迎のメッセージしか送られない状態になっているので元々のチャット内容を取得して送信します。
```diff_javascript

world.beforeEvents.chatSend.subscribe((event) => {
    //ここに処理

            
    if(event.sender.hasTag("RedTeam")){
        event.cancel = true;
      
        const Players = world.getPlayers(
        {tags:["RedTeam"]});
        //タグ"RedTeam"がついた
        //プレイヤーを取得。

+       const messege = event.message;

         
   
          
            
        for(let _i=0;_i<Players.length;_i++){
        
+       Players[_i].sendMessage(`${messege}`)
       
       }
      }
     }
    );

 
```

 `event.messege` でチャット内容をそのまま取得し、それを同じチームのプレイヤーに返しています。プレイヤーが、「こんにちは」というと名前や所属チームが出て来ずに「こんにちは」だけが送信される状態です。


 




## 名前の取得
バニラのチャットのように見せるには、チャットを書いたプレイヤーの名前の取得は欠かせません。``event.sender.name``で取得可能です。

```diff_javascript
world.beforeEvents.chatSend.subscribe((event) => {
  const Players = world.getPlayers(
  {tags:["RedTeam"]}
  //フィルターを設定。
  );
  //プレイヤーを取得。
  
  if(event.sender.hasTag("RedTeam")){
          event.cancel = true;
          
          const messege = event.message;
          const Name = event.sender.name
          
          for(let _i=0;_i<Players.length;_i++){
           
           Players[_i].sendMessage(`<${Name}> ${messege}`) 
          }
  
  
      }
  });
  

```
## チームごとに文字色を変更する
今、どこのチームのプレイヤーとチャットしているかわかるように、チームによって名前が書かれる部分の文字色を変えてみましょう。


```diff_javascript
    world.beforeEvents.chatSend.subscribe((event) => {
        //ここに処理

           if(event.sender.hasTag("RedTeam")){
   
    
             event.cancel = true;

+            let color = "§r"//デフォルトの文字色
+    
+            
+            color = "§c"
+            
+            //赤チームのタグが付いているときに色を赤(コーラル)に変更
           

            const Players = world.getPlayers(
           {tags:["RedTeam"]});
            //タグ"RedTeam"がついた
            //プレイヤーを取得。
    
         
            
            for(let _i=0;_i<Players.length;_i++){
                const Name = event.sender.name
                const messege = event.message;
                
+                Players[_i].sendMessage(`<${color}${Name}§r>  ${messege}`) 
    
            }
           }
        })
    })

```


文字色の変更には、マイクラの **§文字列** を使用しています。§記号の後に英数字を付けることで文字の色が変わるあれですね。

送信したプレイヤーにタグ"Redteam"付いている場合は　名前の前に§ 記号の後に「c」をつけて文字色を**赤色**に変更しています。**名前のみを赤色にする**為、`§c`で赤色にしてから **`§r`を付けてリセット** しています。


## 複数のチームに対応する

複数のチームに対応するには、チームごとにフィルターと文字色を切り替えます。
```diff_javascript



  world.beforeEvents.chatSend.subscribe((event) => {
  //ここに処理
  event.cancel = true; 
 

  
  let color = "§r"; // デフォルトの色（リセット）

+  let filter = {};

+  // 赤チームの場合の処理
+   if (event.sender.hasTag("RedTeam")) {
+      color = "§c"; // 色を赤（コーラル）に設定
+      filter = { tags: ["RedTeam"] }; // 赤チームのタグを持つプレイヤーをフィルター
+  }

+  // 青チームの場合の処理
+  if (event.sender.hasTag("BlueTeam")) {
+      color = "§b"; // 色を青（ライトブルー）に設定
+      filter = { tags: ["BlueTeam"] }; // 青チームのタグを持つプレイヤーをフィルター
+  }
+
+  // フィルター条件に一致するプレイヤーを取得
+  
+  const Players = world.getPlayers(filter);

  // プレイヤーごとにメッセージを送信

  for (let i = 0; i < Players.length; i++) {
      const Name = event.sender.name; // メッセージ送信者の名前
      const message = event.message; // メッセージ内容
      Players[i].sendMessage(`<${color}${Name}§r>  ${message}`);
      //変わりにメッセージを送信
  }

});

```
先ほどのコードでは対応したチーム以外では直接チャットを送信していましたが、こちらではチームに入っていなくともキャンセルされて、変わりのメッセージを送信するようになっています。


# 実際に試してみる
`/tag`コマンドで"Redteam"タグを付けて試してみましょう
```
/tag @s add Redteam
```


:::note info

<<font color="Red" backgraund="black">Steve</font>> Redteamタグをつけてこのように表示されていれば完成です。

:::


# まとめ

- チャットしたことを取得するには``chatSend``を使う

- チャットにメッセージを送信するには``Sendmessge()``を使う
- ``event.messge`` で元々のチャット内容を取得

今回はScriptAPIを使用して、チームチャットを作る方法を解説しました。誰かの為になれば幸いです。

# 参考

https://ja.minecraft.wiki/w/%E8%A3%85%E9%A3%BE%E3%82%B3%E3%83%BC%E3%83%89
 

https://qiita.com/yuki2825624/items/e62ed10a71d43903bb22