Minecraft插件CommandExecutor使用HashMap执行undo时表为空如何解决
问题根源
你现在的核心问题是bloques HashMap的作用域定义错误:
- 你把
bloques声明在了onCommand方法内部,每次服务器触发命令执行调用onCommand方法时,都会重新创建一个全新的空HashMap,方法执行结束后这个局部变量就会被回收,下一次执行undo命令时拿到的是新创建的空Map,自然读不到之前存储的数据。 - 额外你还存在语法错误:方法内部的局部变量不能加
public修饰符,而且代码里没有声明player变量就直接使用了。
修复方案
第一步:调整HashMap的作用域
将bloques从onCommand方法里移到类层级定义,这样整个类实例的生命周期内,这个Map都是复用的,不会每次调用命令就重置。如果要支持多玩家独立撤销,还可以把Map嵌套一层,键为玩家UUID,值为对应该玩家的操作记录:
// 定义在你的CommandExecutor类内部、所有方法的外面 private final Map<UUID, Map<Location, Material>> playerBlockRecords = new HashMap<>();
第二步:修改命令逻辑
适配新的存储结构,调整column和undo命令的逻辑:
public boolean onCommand(CommandSender sender, Command cmd, String s, String[] arg) { // 先判断发送者类型,强转为Player if (!(sender instanceof Player player)) { sender.sendMessage(ChatColor.RED + "该命令仅能由玩家执行。"); return true ; } UUID playerId = player.getUniqueId(); if (cmd.getName().equalsIgnoreCase("column")) { // 初始化当前玩家的本次操作记录容器 Map<Location, Material> bloques = new HashMap<>(); int x = player.getLocation().getBlockX() ; int y = player.getLocation().getBlockY() ; int z = player.getLocation().getBlockZ() ; for (int j=0 ; j<=2 ; j++) { for (int i = Integer.parseInt(arg[0]); i > 0; i--) { Block targetBlock = player.getWorld().getBlockAt(x+j-1, y + 2+ i, z); Material originalType = targetBlock.getType(); bloques.put(targetBlock.getLocation(), originalType) ; targetBlock.setType(Material.getMaterial(arg[1].toUpperCase())); } } // 把本次操作记录存到全局玩家记录里 playerBlockRecords.put(playerId, bloques); return true ; } if (cmd.getName().equalsIgnoreCase("undo")){ // 取出当前玩家最近的操作记录 Map<Location, Material> bloques = playerBlockRecords.get(playerId); if (bloques == null || bloques.isEmpty()) { player.sendMessage(ChatColor.RED + "没有可撤销的操作"); return true; } for (Map.Entry<Location, Material> entry : bloques.entrySet()) { player.getWorld().getBlockAt(entry.getKey()).setType(entry.getValue()); } // 撤销完成后清理记录,避免重复撤销 playerBlockRecords.remove(playerId); player.sendMessage(ChatColor.GREEN + "操作已撤销"); return true ; } return true; }
拓展提示
如果需要支持多步撤销,可以把玩家对应的存储结构换成栈/队列存储多次操作记录即可;如果需要跨服务器重启支持撤销,可以将记录持久化到本地文件或数据库。
内容的提问来源于stack exchange,提问作者Alex Ramos Peña
相关产品推荐
相关产品推荐

