GujiBlock.java v1.3
整蛊残骸插件,/guji <x> <y> <z>(支持~),非OP靠近6格内变为下届岩&爆炸音,离开后还原,挖掉失效
命令列表
- 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);
}
}
}