GujiBlock

GujiBlock.java v1.3
整蛊残骸插件,/guji <x> <y> <z>(支持~),非OP靠近6格内变为下届岩&爆炸音,离开后还原,挖掉失效
作者: xddxmt

命令列表

  • guji通过/guji <x> <y> <z>(坐标支持~,如~1)在对应坐标生成整蛊用远古残骸
package com.gagplugin.guji;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.Sound;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.HashMap;
import java.util.Map;

/**
 * @pluginName GujiBlock
 * @author xddxmt
 * @version 1.3
 * @description 整蛊残骸插件,/guji <x> <y> <z>(支持~),非OP靠近6格内变为下届岩&爆炸音,离开后还原,挖掉失效
 * [command]guji|通过/guji <x> <y> <z>(坐标支持~,如~1)在对应坐标生成整蛊用远古残骸[/command]
 */

public class GujiBlock extends JavaPlugin implements Listener {
    private final List<GujiBlockPos> prankBlocks = new ArrayList<>();
    private final Map<GujiBlockPos, Boolean> triggeredBlocks = new HashMap<>();
    // 检测玩家靠近残骸的范围(现在是6格)
    private static final double DETECT_RADIUS = 6.0;

    @Override
    public void onEnable() {
        Bukkit.getPluginManager().registerEvents(this, this);
        new BukkitRunnable() {
            @Override
            public void run() {
                tickNearbyPlayers();
            }
        }.runTaskTimer(this, 10, 10);
        getLogger().info("GujiBlock 整蛊插件已启用!");
    }

    @Override
    public void onDisable() {
        prankBlocks.clear();
        triggeredBlocks.clear();
        getLogger().info("GujiBlock 整蛊插件已关闭,清除所有整蛊记录。");
    }

    // 指令处理,支持 ~ 相对坐标,也支持绝对坐标
    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        if (!"guji".equalsIgnoreCase(command.getName())) return false;
        if (!(sender instanceof Player)) {
            sender.sendMessage("该命令仅允许玩家在游戏内执行。");
            return true;
        }
        Player player = (Player)sender;
        if (!player.isOp()) {
            player.sendMessage("你没有权限使用该指令。");
            return true;
        }
        if (args.length != 3) {
            player.sendMessage("用法: /guji <x> <y> <z>   坐标支持 ~ (相对坐标),如: /guji ~ ~1 ~-3");
            return true;
        }
        try {
            Location base = player.getLocation();
            int x = parseCoord(args[0], base.getBlockX());
            int y = parseCoord(args[1], base.getBlockY());
            int z = parseCoord(args[2], base.getBlockZ());
            World world = player.getWorld();
            Location loc = new Location(world, x, y, z);

            Material target = loc.getBlock().getType();
            if (target != Material.AIR && target != Material.CAVE_AIR && target != Material.VOID_AIR && target != Material.NETHERRACK) {
                player.sendMessage("此位置无法放置整蛊残骸!(需为空气或下届岩)");
                return true;
            }
            loc.getBlock().setType(Material.ANCIENT_DEBRIS);
            GujiBlockPos gbp = new GujiBlockPos(world.getName(), x, y, z);
            if (!prankBlocks.contains(gbp)) prankBlocks.add(gbp);
            player.sendMessage("§a已在 " + x + " " + y + " " + z + " 生成整蛊用远古残骸。");
        } catch (Exception e) {
            player.sendMessage("请输入正确的坐标!支持 ~ 相对坐标,例如 /guji ~ ~-1 ~2");
        }
        return true;
    }

    // 解析坐标参数,兼容~相对坐标
    private int parseCoord(String arg, int base) throws NumberFormatException {
        arg = arg.trim();
        if (arg.startsWith("~")) {
            if (arg.length() == 1) {
                return base;
            } else {
                int offset = Integer.parseInt(arg.substring(1));
                return base + offset;
            }
        } else {
            return Integer.parseInt(arg);
        }
    }

    // 定时检测整蛊点状态,控制自动切换
    private void tickNearbyPlayers() {
        Iterator<GujiBlockPos> iterator = prankBlocks.iterator();
        while (iterator.hasNext()) {
            GujiBlockPos gb = iterator.next();
            World world = Bukkit.getWorld(gb.worldName);
            if (world == null) continue;
            Location blockLoc = new Location(world, gb.x, gb.y, gb.z);

            // 若方块已丢失,清理所有状态
            Material type = blockLoc.getBlock().getType();
            if (type != Material.ANCIENT_DEBRIS && type != Material.NETHERRACK) {
                triggeredBlocks.remove(gb);
                iterator.remove();
                continue;
            }

            boolean anyNonOpNearby = false;
            for (Player p : world.getPlayers()) {
                if (p.isOp()) continue;
                if (p.getLocation().distance(blockLoc.clone().add(0.5,0.5,0.5)) <= DETECT_RADIUS) {
                    anyNonOpNearby = true;
                    break;
                }
            }
            boolean isTriggered = triggeredBlocks.containsKey(gb);

            if (!isTriggered && type == Material.ANCIENT_DEBRIS && anyNonOpNearby) {
                // 靠近,变下界岩
                blockLoc.getBlock().setType(Material.NETHERRACK);
                world.playSound(blockLoc, Sound.ENTITY_GENERIC_EXPLODE, 0.7f, 1.4f);
                triggeredBlocks.put(gb, true);
            } else if (isTriggered && (!anyNonOpNearby)) {
                // 离开还原
                if (blockLoc.getBlock().getType() == Material.NETHERRACK) {
                    blockLoc.getBlock().setType(Material.ANCIENT_DEBRIS);
                    world.playSound(blockLoc, Sound.BLOCK_ANCIENT_DEBRIS_HIT, 0.7f, 0.9f);
                }
                triggeredBlocks.remove(gb);
            }
        }
    }

    // 方块被挖掉就立刻失效、清状态
    @EventHandler
    public void onBlockBreak(BlockBreakEvent event) {
        Location loc = event.getBlock().getLocation();
        Iterator<GujiBlockPos> iterator = prankBlocks.iterator();
        while (iterator.hasNext()) {
            GujiBlockPos gb = iterator.next();
            if (gb.match(loc)) {
                iterator.remove();
                triggeredBlocks.remove(gb);
                event.getPlayer().sendMessage("§d你破坏了一块“假的”残骸……");
                break;
            }
        }
    }

    // 坐标+世界为关键信息,实现 equals/hashCode 便于map/list管理
    private static class GujiBlockPos {
        final String worldName;
        final int x, y, z;
        GujiBlockPos(String worldName, int x, int y, int z) {
            this.worldName = worldName;
            this.x = x; this.y = y; this.z = z;
        }
        boolean match(Location loc) {
            return loc.getWorld() != null
                && loc.getWorld().getName().equals(worldName)
                && loc.getBlockX() == x
                && loc.getBlockY() == y
                && loc.getBlockZ() == z;
        }
        @Override
        public boolean equals(Object o) {
            if (!(o instanceof GujiBlockPos)) return false;
            GujiBlockPos p = (GujiBlockPos)o;
            return worldName.equals(p.worldName) && x == p.x && y == p.y && z == p.z;
        }
        @Override
        public int hashCode() {
            return worldName.hashCode() ^ x ^ (y << 8) ^ (z << 16);
        }
    }
}

上一篇: ChunkPreloader下一篇: RewardKill

举报内容

意见反馈