diff --git a/src/main/java/ling/coordinateRecorder/Commands/Help.java b/src/main/java/ling/coordinateRecorder/Commands/Help.java index 61e293c..b056548 100644 --- a/src/main/java/ling/coordinateRecorder/Commands/Help.java +++ b/src/main/java/ling/coordinateRecorder/Commands/Help.java @@ -71,6 +71,7 @@ public class Help { 沙雕值 一种具备惩罚性质的数据,沙雕值过高将获得一系列debuff。 +沙雕值每隔5分钟恢复一点。 使用此命令检查玩家沙雕值: /zb sb """, diff --git a/src/main/java/ling/coordinateRecorder/Commands/ZbCommand.java b/src/main/java/ling/coordinateRecorder/Commands/ZbCommand.java index eeebdff..c54f879 100644 --- a/src/main/java/ling/coordinateRecorder/Commands/ZbCommand.java +++ b/src/main/java/ling/coordinateRecorder/Commands/ZbCommand.java @@ -227,6 +227,8 @@ public class ZbCommand implements CommandExecutor, TabCompleter { return; } data.locationListUpdate(); + data.loadPlayerSettings(); + PlayerMap.getCurrent().broadcastScore(data); player.sendMessage("已重新载入数据"); } diff --git a/src/main/java/ling/coordinateRecorder/Config.java b/src/main/java/ling/coordinateRecorder/Config.java new file mode 100644 index 0000000..40c7f95 --- /dev/null +++ b/src/main/java/ling/coordinateRecorder/Config.java @@ -0,0 +1,82 @@ +package ling.coordinateRecorder; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.List; + +public class Config { + /// 奖励得分间隔 + public static final int REWARD_INTERVAL = 60 * 5; + /// 生成墓碑的基准沙雕值惩罚 + public static final int TOMBSTONE_PUNISHMENT = 3; + /// 禁止解锁墓碑阈值 + public static final int UNLOCK_PROHIBITED = 24; + public static final HashMap ITEM_VALUE_MAP = new HashMap<>(); + + /// 计算物品堆的价值 + public static int getItemStackValue(List stack) { + double[] value = {0d}; + stack.forEach(item -> { + if (ITEM_VALUE_MAP.containsKey(item.getType())) { + value[0] += ITEM_VALUE_MAP.get(item.getType()) * item.getAmount(); + } + }); + if (value[0] > 30) + value[0] = 30; + return (int) value[0]; + } + + static { + // 钻石 + ITEM_VALUE_MAP.put(Material.DIAMOND, 0.2d); + ITEM_VALUE_MAP.put(Material.DIAMOND_ORE, 0.2d); + ITEM_VALUE_MAP.put(Material.DIAMOND_BLOCK, 1.8d); + // 铁 + ITEM_VALUE_MAP.put(Material.IRON_ORE, 0.01); + ITEM_VALUE_MAP.put(Material.IRON_INGOT, 0.01); + ITEM_VALUE_MAP.put(Material.IRON_BLOCK, 0.09); + // 金 + ITEM_VALUE_MAP.put(Material.GOLD_ORE, 0.02); + ITEM_VALUE_MAP.put(Material.GOLD_INGOT, 0.02); + ITEM_VALUE_MAP.put(Material.GOLD_BLOCK, 0.18); + // 绿宝石 + ITEM_VALUE_MAP.put(Material.EMERALD, 0.2d); + ITEM_VALUE_MAP.put(Material.EMERALD_BLOCK, 1.8d); + ITEM_VALUE_MAP.put(Material.EMERALD_ORE, 0.2d); + + // 末影之眼 + ITEM_VALUE_MAP.put(Material.ENDER_EYE, 0.8d); + //龙蛋 + ITEM_VALUE_MAP.put(Material.DRAGON_EGG, 10d); + //龙息 + ITEM_VALUE_MAP.put(Material.DRAGON_BREATH, 2d); + //附魔书 + ITEM_VALUE_MAP.put(Material.ENCHANTED_BOOK, 1d); + + //下界合金 + ITEM_VALUE_MAP.put(Material.NETHERITE_INGOT, 1d); + ITEM_VALUE_MAP.put(Material.NETHERITE_BLOCK, 9d); + + //钻石装备 + ITEM_VALUE_MAP.put(Material.DIAMOND_SWORD, 1d); + ITEM_VALUE_MAP.put(Material.DIAMOND_AXE, 1d); + ITEM_VALUE_MAP.put(Material.DIAMOND_SHOVEL, 1d); + ITEM_VALUE_MAP.put(Material.DIAMOND_PICKAXE, 1d); + ITEM_VALUE_MAP.put(Material.DIAMOND_BOOTS, 1d); + ITEM_VALUE_MAP.put(Material.DIAMOND_LEGGINGS, 1d); + ITEM_VALUE_MAP.put(Material.DIAMOND_CHESTPLATE, 1d); + ITEM_VALUE_MAP.put(Material.DIAMOND_HELMET, 1d); + + //下界合金装备 + ITEM_VALUE_MAP.put(Material.NETHERITE_SWORD, 1d); + ITEM_VALUE_MAP.put(Material.NETHERITE_AXE, 1d); + ITEM_VALUE_MAP.put(Material.NETHERITE_SHOVEL, 1d); + ITEM_VALUE_MAP.put(Material.NETHERITE_PICKAXE, 1d); + ITEM_VALUE_MAP.put(Material.NETHERITE_BOOTS, 1d); + ITEM_VALUE_MAP.put(Material.NETHERITE_LEGGINGS, 1d); + ITEM_VALUE_MAP.put(Material.NETHERITE_CHESTPLATE, 1d); + ITEM_VALUE_MAP.put(Material.NETHERITE_HELMET, 1d); + } +} diff --git a/src/main/java/ling/coordinateRecorder/Listener/PlayerEventListener.java b/src/main/java/ling/coordinateRecorder/Listener/PlayerEventListener.java index dd592bc..4128ab8 100644 --- a/src/main/java/ling/coordinateRecorder/Listener/PlayerEventListener.java +++ b/src/main/java/ling/coordinateRecorder/Listener/PlayerEventListener.java @@ -1,5 +1,6 @@ package ling.coordinateRecorder.Listener; +import ling.coordinateRecorder.Config; import ling.coordinateRecorder.CoordinateRecorder; import ling.coordinateRecorder.data.PlayerData; import ling.coordinateRecorder.data.PlayerDeathData; @@ -8,14 +9,19 @@ import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.Chest; import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockExplodeEvent; import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.inventory.InventoryMoveItemEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; @@ -29,7 +35,7 @@ import org.jetbrains.annotations.NotNull; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.Arrays; +import java.util.*; /// 玩家事件监听器 public class PlayerEventListener implements Listener { @@ -124,8 +130,14 @@ public class PlayerEventListener implements Listener { return; } data.setTombstoneBlock(block); - player.sendMessage("这是你的墓碑,请使用/zb unlock 命令解除锁定"); - player.sendMessage("墓碑内有" + count + "个物品"); + player.sendMessage( + "这是你的墓碑,请使用" + ChatColor.GOLD + "/zb unlock" + ChatColor.WHITE + " 命令解除锁定"); + player.sendMessage("墓碑内有" + ChatColor.YELLOW + count + ChatColor.WHITE + "个物品"); + player.sendMessage("解锁将给您带来" + ChatColor.YELLOW + (Config.TOMBSTONE_PUNISHMENT + + Config.getItemStackValue( + Arrays.asList(chest.getBlockInventory() + .getContents()))) + + ChatColor.WHITE + "点沙雕值惩罚!(当前" + ChatColor.YELLOW + data.getFraction() + ChatColor.WHITE + ")"); event.setCancelled(true); } } @@ -146,6 +158,82 @@ public class PlayerEventListener implements Listener { onTombstoneProtect(event, player, block); } + /// 判断指定位置的方块是否是一个墓碑 + public boolean isTombstone(Location location) { + if (location == null) + return false; + Block block = location.getBlock(); + if (block.getType() != Material.CHEST) + return false; + Chest chest = (Chest) block.getState(); + var per = chest.getPersistentDataContainer(); + return TombstoneData.isTombstone(per); + } + + /// 阻止玩家在墓碑附近摆放箱子,防止偷窃物品 + @EventHandler + public void onBlockPlace(BlockPlaceEvent event) { + Block block = event.getBlockPlaced(); + if (block.getType() != Material.CHEST) + return; + Location a1 = block.getLocation().clone().add(1, 0, 0); + Location a2 = block.getLocation().clone().add(-1, 0, 0); + Location a3 = block.getLocation().clone().add(0, 0, 1); + Location a4 = block.getLocation().clone().add(0, 0, -1); + + if (isTombstone(a1) || isTombstone(a2) || isTombstone(a3) || isTombstone(a4)) { + event.getPlayer().sendMessage(ChatColor.RED + "这是一个墓碑,你无法创建和它相连的大箱子!"); + event.setCancelled(true); + } + + } + + /// 爆炸保护 + @EventHandler + public void onExplosion(EntityExplodeEvent event) { + World world = event.getLocation().getWorld(); + assert world != null; + // 获取爆炸位置附近的方块 + for (Block block : event.blockList()) { + // 检查方块是否是墓碑 + if (isTombstone(block.getLocation())) { + // 阻止墓碑被摧毁 + event.setCancelled(true); + //通知附近玩家 + Collection entities = world.getNearbyEntities(event.getLocation(), 30, 30, 30); + entities.forEach(player -> { + player.sendMessage("爆炸波及到墓碑,为了保护墓碑,爆炸已取消!"); + }); + return; + } + } + } + + /// 爆炸保护 + @EventHandler + public void onBlockExplode(BlockExplodeEvent event) { + // 获取爆炸影响的方块 + List affectedBlocks = event.blockList(); + + // 遍历爆炸影响的方块 + for (Block block : affectedBlocks) { + if (isTombstone(block.getLocation())) { + // 如果爆炸影响了墓碑,取消该方块的摧毁 + event.blockList().remove(block); + } + } + } + + /// 阻止通过漏斗从墓碑中取出物品 + @EventHandler + public void onInventoryMoveItem(InventoryMoveItemEvent event) { + Inventory source = event.getSource(); + if (isTombstone(source.getLocation())) { + System.out.println("阻止漏斗"); + event.setCancelled(true); + } + } + /// 阻止墓碑被火焰点燃 @EventHandler public void onBlockIgnite(BlockIgniteEvent event) { @@ -260,10 +348,36 @@ public class PlayerEventListener implements Listener { //将玩家掉落物存入箱子 Inventory chestInventory = chest.getBlockInventory(); - for (ItemStack item : event.getDrops()) { - if (item != null) chestInventory.addItem(item); - } + List items = event.getDrops(); + //有价值物品 + List valuable = new ArrayList<>(); + //无价值物品 + List worthless = new ArrayList<>(); + items.forEach(item -> { + if (Config.ITEM_VALUE_MAP.containsKey(item.getType())) { + valuable.add(item); + } else { + worthless.add(item); + } + }); + //先将有价值的物品存入箱子 + HashMap other = chestInventory.addItem(valuable.toArray(new ItemStack[0])); + valuable.clear(); + other.forEach((k, v) -> { + valuable.add(v); + }); + //再将无价值物品存入箱子,确保优先保护有价值的物品。 + other = chestInventory.addItem(worthless.toArray(new ItemStack[0])); + other.forEach((k, v) -> { + valuable.add(v); + }); + int[] count = {0}; + valuable.forEach(v -> { + count[0] += v.getAmount(); + }); + // 将无法放入墓碑的物品丢在地上。 event.getDrops().clear(); + event.getDrops().addAll(valuable); //在墓碑上方生成悬浮文字 Location textLocation = location.clone().add(0, 1.5, 0); @@ -275,7 +389,8 @@ public class PlayerEventListener implements Listener { armorStand.setCustomName(tombstoneData.getOwnerTitle()); armorStand.setCustomNameVisible(true); armorStand.setMarker(true); - + if (count[0] != 0) + player.sendMessage("你有" + count[0] + "个物品无法放入墓碑,已掉落在死亡地点。"); } /// 玩家移动 diff --git a/src/main/java/ling/coordinateRecorder/Listener/PlayerMap.java b/src/main/java/ling/coordinateRecorder/Listener/PlayerMap.java index 7b9eba9..b04fae2 100644 --- a/src/main/java/ling/coordinateRecorder/Listener/PlayerMap.java +++ b/src/main/java/ling/coordinateRecorder/Listener/PlayerMap.java @@ -1,5 +1,6 @@ package ling.coordinateRecorder.Listener; +import ling.coordinateRecorder.Config; import ling.coordinateRecorder.CoordinateRecorder; import ling.coordinateRecorder.data.PlayerData; import org.bukkit.Bukkit; @@ -17,24 +18,23 @@ public class PlayerMap { protected HashMap playerList = new HashMap<>(); protected static final CoordinateRecorder plugin = CoordinateRecorder.getCurrent(); protected static final PlayerMap current = new PlayerMap(); - //奖励得分间隔 - protected final static int REWARD_INTERVAL = 60 * 5; + private PlayerMap() { Bukkit.getScheduler().runTaskTimer(CoordinateRecorder.getCurrent(), this::flashTime, 0L, 200L); Bukkit.getScheduler().runTaskTimer(CoordinateRecorder.getCurrent(), this::awardFraction, 0L, - 20 * REWARD_INTERVAL); + 20 * Config.REWARD_INTERVAL); } /// 广播玩家分数 - private void broadcastScore(PlayerData data) { + public void broadcastScore(PlayerData data) { for (Map.Entry enter : playerList.entrySet()) { enter.getValue().updatePlayerFraction(data); } } /// 提供玩家分数 - private void initScore(PlayerData data) { + public void initScore(PlayerData data) { for (Map.Entry enter : playerList.entrySet()) { data.updatePlayerFraction(enter.getValue()); } @@ -45,7 +45,7 @@ public class PlayerMap { for (Map.Entry enter : playerList.entrySet()) { try { // 跳过加入时间不足的玩家 - if (enter.getValue().getFractionTime() > System.currentTimeMillis() - REWARD_INTERVAL * 800) + if (enter.getValue().getFractionTime() > System.currentTimeMillis() - Config.REWARD_INTERVAL * 800) continue; if (enter.getValue().addFraction(-1)) { broadcastScore(enter.getValue()); diff --git a/src/main/java/ling/coordinateRecorder/data/PlayerData.java b/src/main/java/ling/coordinateRecorder/data/PlayerData.java index 6d0759e..ef90288 100644 --- a/src/main/java/ling/coordinateRecorder/data/PlayerData.java +++ b/src/main/java/ling/coordinateRecorder/data/PlayerData.java @@ -1,6 +1,8 @@ package ling.coordinateRecorder.data; +import ling.coordinateRecorder.Config; import ling.coordinateRecorder.CoordinateRecorder; +import ling.coordinateRecorder.Listener.PlayerMap; import ling.database.tables.records.LocationnotepadPO; import ling.database.tables.records.PlayersettingsPO; import org.bukkit.*; @@ -16,10 +18,7 @@ import org.jooq.impl.DSL; import java.math.BigDecimal; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; +import java.util.*; import static ling.database.Tables.PLAYERSETTINGS; import static ling.database.tables.LocationnotepadTB.LOCATIONNOTEPAD; @@ -101,6 +100,23 @@ public class PlayerData { return; } + //先给予沙雕值惩罚 + int value = Config.getItemStackValue(Arrays.asList(chest.getBlockInventory().getContents())); + value += Config.TOMBSTONE_PUNISHMENT; + if (getFraction() > Config.UNLOCK_PROHIBITED) { + player.sendMessage( + "您的沙雕值过高,禁止解锁墓碑!( >" + ChatColor.RED + Config.UNLOCK_PROHIBITED + ChatColor.WHITE + " )"); + return; + } + try { + addFraction(value); + PlayerMap.getCurrent().broadcastScore(this); + } catch (SQLException e) { + player.sendMessage(ChatColor.RED + "解锁墓碑失败:服务器内部错误"); + CoordinateRecorder.getCurrent().getLogger().severe("添加沙雕值出错:" + e.getMessage()); + return; + } + Location location = tombstoneBlock.getLocation(); World world = location.getWorld(); assert world != null; @@ -118,7 +134,8 @@ public class PlayerData { //播放雷击特效 world.strikeLightningEffect(location); //world.playSound(location, Sound.ENTITY_LIGHTNING_BOLT_THUNDER, 1.0f, 1.0f); - player.sendMessage("墓碑已解锁!"); + player.sendMessage( + "墓碑已解锁!您受到了" + ChatColor.YELLOW + value + ChatColor.WHITE + "点沙雕值惩罚!(当前" + ChatColor.RED + getFraction() + ChatColor.WHITE + ")"); } /// 在给定位置绘制六芒星 diff --git a/src/main/java/ling/coordinateRecorder/data/TombstoneData.java b/src/main/java/ling/coordinateRecorder/data/TombstoneData.java index edffb75..71a50bc 100644 --- a/src/main/java/ling/coordinateRecorder/data/TombstoneData.java +++ b/src/main/java/ling/coordinateRecorder/data/TombstoneData.java @@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; +import java.util.Objects; /// 墓碑数据 public class TombstoneData implements PersistentData { @@ -81,7 +82,8 @@ public class TombstoneData implements PersistentData { } public static boolean isTombstone(PersistentDataContainer data) { - return data.has(OWNER_NAME) && data.has(OWNER_UUID) && data.has(OWNER_TITLE) && data.has(OWNER_DEFEATER); + return data.has(OWNER_NAME) && data.has(OWNER_UUID) && data.has(OWNER_TITLE) && data.has( + OWNER_DEFEATER); } @Override