【中級】MoLangクエリの壁を越えろ!ビヘイビア限定クエリをリソースで使う方法

【中級】

この「中級」カテゴリの記事は、アドオン制作において一歩踏み込んだ技術を扱います。

📚 中級を見るのに適したレベルとは?

この中級技能は、触ったことがないにしても、アドオンのほぼすべての分野をざっくりと理解しており、その回で使用する分野の根本的説明がなくとも、自分で調べたりも含めて記事についてくることができるレベルを想定しています。

入門、初級で全ての説明が済んでいるわけではありませんので、書かれている内容がわからない方は、各自調べながらついてきていただけると幸いです。

今回の記事を読む上での前提技能は以下の通りです。

  • 前提技能:
    • クエリ(query)を使用し、animation_controllerclient_entity(リソースの〇〇.entity.json)、animationなどを記述できること。
    • JavaScriptを使ったScript APIの基本的な導入と動作が理解できること。

💡 本題:クエリの制約と解決策

MoLangクエリには、リソースパックでしか機能しないものや、ビヘイビアパックでしか機能しないものが存在します。

気になる方は、ドキュメントのmolang.htmlからClient (Resource Packs) onlyResourceBehavior Packsなどと検索をかけてみてください。(ただし、ドキュメントに書かれてないものでも機能しないものが多数あります。)

リソースパックでのみ機能するクエリ(例)ビヘイビアパックでのみ機能するクエリ(例)
query.distance_from_cameraquery.scoreboard
query.bone_originquery.head_y_rotation
query.is_local_playerquery.had_component_group

開発中、「ビヘイビアでしか機能しないクエリ(例: q.scoreboard)の結果に応じて、リソースの見た目を変えたい」という問題が頻発します。

この問題を解決できるのが、「ビヘイビアでしか機能しないクエリを、リソースでも扱えるデータ(property)に格納する」という方法です。

⚠️ 注意事項

「リソースでしか機能しないクエリ(例: query.bone_origin)の結果を、ビヘイビアで使う」という逆方向の処理は、現状できません(できる方法があれば、ぜひ教えてほしいぐらいです!)。

⚙️ 解決策:propertyを使用したデータ連携

エンティティに与えることのできるデータのうち、リソースパックでも扱える値はvariantskin_idなどがありますが、これらは個数が限られています。

そこで今回は、エンティティに数字やtrue/falseなどを付与できるpropertyを使用します。これらはq.property(プロパティー名)としてリソース、ビヘイビアのどちらでも利用可能です。

今回はプレイヤーのq.scoreboardの結果をリソースに渡すことを例に、実際にやっていきましょう。

今回のステップ

  1. ビヘイビアのエンティティデータにpropertyを追加し、利用可能な状態にする。
  2. Script API(JavaScript)を使用し、常にq.scoreboardと同じ値propertyを更新し続ける。
  3. リソースでq.propertyを使用し、見た目の制御に利用する。

1. ビヘイビア:プロパティの定義

まずは、プロパティを定義して、そのエンティティにプロパティがある状態にします。

ファイル: behavior_pack/entities/player.json

minecraft:entity内のdescriptionブロックに、propertiesを追加します。

JSON

{
  "format_version": "1.18.20",
  "minecraft:entity": {
    "description": {
      "identifier": "minecraft:player",
      "is_spawnable": false,
      "is_summonable": false,
      "is_experimental": false,
      "properties": {
        "property:test":{
          "client_sync":true,
          "range": [-2147483647,2147483647],
          "default":0,
          "type":"int"
        }
      }
    },
    // 以下省略
// ...
  • "property:test": プロパティの名称です。必ず:で区切ったものである必要があります。
  • "client_sync":true: リソースパック側(クライアント側)でこのプロパティを使用可能にするための必須項目です。
  • "type":"int": 今回はスコア(整数)を格納するためintを指定します。少数を含むならfloattrue/falseならboolを指定します。
  • ⚠️ 注意事項: 1種類のエンティティに追加できるプロパティーの種類は32個までです。よほどのことがなければ超えません。

2. Script API:プロパティの更新

定義したプロパティに、Script API(JavaScript)を使用して、常にプレイヤーのスコアを格納し続けます。

2-1. Scriptモジュールの有効化

まず、ビヘイビアパックのmanifest.jsonに以下のmodulesdependenciesを追加し、Script APIを有効化し、scripts/_index.jsが動作するように設定します。(UUIDとバージョンは適宜変更してください。)

JSON

// manifest.json の modules の例
    "modules": [
        {
            "type": "script",
            "language": "javascript",
            "uuid": "1a1b53fc-5653-4a75-91b7-9cdF027674ae",
            "version": [1, 0, 0],
            "entry": "scripts/_index.js" /* 起動ファイル */
        },
        // ... 他のデータモジュールなど
    ],
    "dependencies": [
        {
            "module_name": "@minecraft/server",
            "version": "1.15.0" /* 使用するAPIのバージョン */
        }
    ]

2-2. スコアの取得とプロパティへの格納

ファイル: behavior_pack/scripts/_index.js

system.runIntervalを使って毎チック全プレイヤーを確認し、player.setPropertyでスコアをproperty:testに格納します。

JavaScript

import { system, world, Entity, Player } from "@minecraft/server"

system.runInterval(async () => {
    const playerList = world.getAllPlayers()
    for (let i = 0; i < playerList.length; i++) {
        const player = playerList[i]
        // スコアを取得し、property:testを更新する
        player.setProperty("property:test", getScoreEntity(player, "test"))
    }
})

function getScoreEntity(entity, objectiveName) {
    const objective = world.scoreboard.getObjective(objectiveName);

    if (objective == undefined) {
        // スコアボードが存在しない場合は0を返す
        return 0
    }
    else if (objective.getScore(entity.scoreboardIdentity) == undefined) {
        return 0
    }
    else {
        return objective.getScore(entity.scoreboardIdentity);
    }
};

3. リソース:プロパティの使用

これで、ビヘイビアパック側でプレイヤーのスコアがリアルタイムでq.property('property:test')に格納され続ける状態になりました。

リソースパック側では、通常通りq.propertyを使用して値を参照できます。

ファイル: resource_pack/entity/player.entity.json

一例として、プレイヤーのサイズをスコアに応じて変更してみましょう。

JSON

// ...省略
      "scripts": {
        "scale": "q.property('property:test')/100", /* スコア100で1倍、200で2倍 */
        "initialize": [
// ...省略
  • "scale": "q.property('property:test')/100"
    • q.property('property:test')で取得したスコアを100で割ることで、スコアが100なら1.0倍、200なら2.0倍のサイズに変わります。

実際にマイクラで確認し、testという名前のobjectiveを作成、プレイヤーにスコアを入れると、サイズが変わるはずです。

📝 まとめ

  • ビヘイビアでしか機能しないq.scoreboardと同じ値を、propertyという共通のデータ領域を経由することで、リソースパック側で利用できるようになりました。
  • この技術は、q.scoreboardだけでなく、ビヘイビア限定の他のクエリや、Script APIで取得できるあらゆる情報(例: 時間帯、特定の座標など)をリソースに渡す際に応用できます。

今回はスコアを例にしましたが、各クエリごとに、Script APIで取得する方法が異なりますので、ぜひ試してみてください!わからないクエリやわからないことがあれば、コメントしていただければと思います。

コメント

タイトルとURLをコピーしました