2026/07/08(水)ネザーゲートの利用を禁止させる

マルチサーバーでネザー解禁を後日にするためのスクリプト。
火打石と打ちがねで、ネザーゲートを開通させることはできる。
しかし、入ろうとするとプレイヤーにデバフがかかりゲートが破壊される。
// ========================================================================
// ネザーゲート禁止
// ========================================================================
let enable_nether_gate_check = true;

system.runInterval(() => {

    if (!enable_nether_gate_check) return;

    for (const player of world.getPlayers()) {
        try {
            const dim = player.dimension;
            const loc = player.location;

            // プレイヤー周囲 ±1 にポータルがあるかチェック
            let nearPortal = false;
            const searchRange = 1;

            outerLoop: for (let dx = -searchRange; dx <= searchRange; dx++) {
                for (let dy = -searchRange; dy <= searchRange; dy++) {
                    for (let dz = -searchRange; dz <= searchRange; dz++) {
                        const block = dim.getBlock({
                            x: Math.floor(loc.x) + dx,
                            y: Math.floor(loc.y) + dy,
                            z: Math.floor(loc.z) + dz
                        });

                        if (block?.typeId === "minecraft:portal") {
                            nearPortal = true;
                            break outerLoop;
                        }
                    }
                }
            }

            if (!nearPortal) continue;

            // 安全な場所を探す(強制TP用、現在未使用だがおいておく)
            const offsets = [1];
            let safeSpot = null;

            for (let attempt = 0; attempt < 10; attempt++) {
                const dx = offsets[Math.floor(Math.random() * offsets.length)] * (Math.random() < 0.5 ? -1 : 1);
                const dz = offsets[Math.floor(Math.random() * offsets.length)] * (Math.random() < 0.5 ? -1 : 1);

                const tx = Math.floor(loc.x) + dx;
                const ty = Math.floor(loc.y);
                const tz = Math.floor(loc.z) + dz;

                const foot = dim.getBlock({ x: tx, y: ty, z: tz });
                const under = dim.getBlock({ x: tx, y: ty - 1, z: tz });

                if (
                    foot?.typeId === "minecraft:air" &&
                    under && 
                    under.typeId !== "minecraft:air" &&
                    under.typeId !== "minecraft:portal"
                ) {
                    safeSpot = { x: tx + 0.5, y: ty, z: tz + 0.5 };
                    break;
                }
            }

            if (safeSpot) {
                // 効果付与
                player.addEffect("wither", 80, { amplifier: 2, showParticles: false });
                player.addEffect("darkness", 160, { amplifier: 20, showParticles: false });

                player.sendMessage("§c§lネザーゲートは解禁されていません。");

                // 周辺のネザーゲート(ポータルブロック)をair置換
                const x = Math.floor(loc.x);
                const y = Math.floor(loc.y);
                const z = Math.floor(loc.z);
                const destroyRadius = 3;

                player.runCommand(
                    `fill ${x - destroyRadius} ${y - destroyRadius} ${z - destroyRadius} ` +
                    `${x + destroyRadius} ${y + destroyRadius} ${z + destroyRadius} ` +
                    `air replace minecraft:portal`
                );

            }
        } catch (error) {
            // ランタイムエラーをキャッチ(プレイヤーが不正な状態の場合など)
            console.warn(`ネザーゲート禁止処理でエラーが発生: ${error}`);
        }
    }
}, 30);

2026/07/08(水)オーバーワールドの活動範囲を制限する

統合版はワールドーボーダーを簡単に設置できない。
そこで、代わりにあらかじめ設定したワールド範囲から外に出るとデバフを掛けるようする。
let worldArea = 2048;// ワールドの範囲(±2048)

// ========================================================================
// ワールドの範囲外に出たら警告
// ========================================================================
system.runInterval(() => {
    for (const p of world.getPlayers()) {
        const loc = p.location;
        // ワールドの範囲外か?
        if (Math.abs(loc.x) > worldArea || Math.abs(loc.z) > worldArea) {
            // title コマンドで警告表示
            p.runCommand(`title @s title "§cワールド範囲外"`);
            // めまい効果を付与
            p.addEffect("nausea", 60, { amplifier: 3, showParticles: false });
            // 速度低下効果を付与
            p.addEffect("slowness", 60, { amplifier: 5, showParticles: false });
            // ダメージを与える
            p.runCommand(`damage @s 1`);
        }
    }
}, 40);

2026/07/08(水)製図台の使用を禁止

マルチサーバーで地図埋めをされると新要素実装エリアがクソ遠くなって糞迷惑なので製図台そのものを使用禁止にするスクリプト。
プレイヤーに地図拡張させないようにするためにはこれに加えて作業台レシピも改造する必要がある。
// ========================================================================
// 製図台の使用を禁止
// ========================================================================
let enable_cartography_table_check = true;

world.beforeEvents.playerInteractWithBlock.subscribe(ev => {
    if (!enable_cartography_table_check) return;

    const block = ev.block;
    if (!block) return;

    // 製図台ならキャンセル
    if (block.typeId === "minecraft:cartography_table") {
        ev.cancel = true;
        ev.player.sendMessage("製図台の使用は解禁されていません");
    }
});

2026/07/08(水)鍛冶台に耐久値チェックの機能を追加

統合版には、装備の耐久値を調べる方法がないのでスクリプトで追加した。
鍛冶台に向かってスニークすることで耐久値一覧のフォームを表示して確認できる。
function getBlockInFront(player, maxDistance = 1) {
    const loc = player.location;
    const dir = player.getViewDirection(); // プレイヤーの視線方向ベクトル

    if(!dir) return null;

    for (let i = 1; i <= maxDistance; i++) {
        const x = loc.x + dir.x * i;
        const y = loc.y + 0.9 + dir.y * i; // 視線の高さに補正
        const z = loc.z + dir.z * i;

        const block = player.dimension.getBlock({ x, y, z });
        if (!block) continue;

        // 空気以外なら「前方のブロック」とみなす
        if (block.typeId !== "minecraft:air") {
            return block;
        }
    }

    return null;
}

// ========================================================================
// 鍛冶台の前でしゃがむと装備の耐久値一覧を表示する
// ========================================================================
system.runInterval(() => {
    for (const p of world.getPlayers()){

        // 前方ブロックを取得
        const block = getBlockInFront(p, 1);
        if (!block) continue;

        // 鍛冶台か?
        if (block.typeId !== "minecraft:smithing_table") continue;

        // しゃがんでいるか?
        if (!p.isSneaking) {
          p.removeTag("smithing_ui_open");
          continue;
        }

        // ★ Form を一度だけ出すためのタグ
        if (p.hasTag("smithing_ui_open")) continue;
        p.addTag("smithing_ui_open");

        // 装備の耐久値一覧を作る
        const eq = p.getComponent("minecraft:equippable");

        if(!eq) {
            p.sendMessage("§c装備情報を取得できませんでした。");
            continue;
        }

        const slots = [
            [EquipmentSlot.Mainhand, "ウェポン"],
            [EquipmentSlot.Offhand, "オフハンド"],
            [EquipmentSlot.Head, "ヘルメット"],
            [EquipmentSlot.Chest, "チェスト"],
            [EquipmentSlot.Legs, "レギンス"],
            [EquipmentSlot.Feet, "ブーツ"]
        ];

        let body = "";

        for (const [slot, name] of slots) {
            const item = eq.getEquipment(slot);
            if (!item) {
                body += `${name}: なし\n`;
                continue;
            }

            const dura = item.getComponent("minecraft:durability");
            if (!dura) {
                body += `${name}: 耐久なし\n`;
                continue;
            }

            const remain = dura.maxDurability - dura.damage;
            body += `${name}: ${remain} / ${dura.maxDurability}\n`;
        }        

        // Form UI を作成
        const form = new ActionFormData()
            .title("装備の耐久値一覧")
            .body(body)
            .button("閉じる");

        form.show(p).then(() => {
            // Form を閉じたらタグを消す
            p.removeTag("smithing_ui_open");
        });
    }
}, 30);