强化墓碑保护,解锁墓碑扣除沙雕值
保护墓碑免受爆炸的破坏,阻止玩家通过漏斗、以及连接大箱子的方法盗取墓碑内的物品。 解锁墓碑将扣除沙雕值
This commit is contained in:
@@ -71,6 +71,7 @@ public class Help {
|
||||
沙雕值
|
||||
|
||||
一种具备惩罚性质的数据,沙雕值过高将获得一系列debuff。
|
||||
沙雕值每隔5分钟恢复一点。
|
||||
使用此命令检查玩家沙雕值:
|
||||
/zb sb <Name>
|
||||
""",
|
||||
|
||||
@@ -227,6 +227,8 @@ public class ZbCommand implements CommandExecutor, TabCompleter {
|
||||
return;
|
||||
}
|
||||
data.locationListUpdate();
|
||||
data.loadPlayerSettings();
|
||||
PlayerMap.getCurrent().broadcastScore(data);
|
||||
player.sendMessage("已重新载入数据");
|
||||
}
|
||||
|
||||
|
||||
82
src/main/java/ling/coordinateRecorder/Config.java
Normal file
82
src/main/java/ling/coordinateRecorder/Config.java
Normal file
@@ -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<Material, Double> ITEM_VALUE_MAP = new HashMap<>();
|
||||
|
||||
/// 计算物品堆的价值
|
||||
public static int getItemStackValue(List<ItemStack> 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);
|
||||
}
|
||||
}
|
||||
@@ -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<Entity> entities = world.getNearbyEntities(event.getLocation(), 30, 30, 30);
|
||||
entities.forEach(player -> {
|
||||
player.sendMessage("爆炸波及到墓碑,为了保护墓碑,爆炸已取消!");
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 爆炸保护
|
||||
@EventHandler
|
||||
public void onBlockExplode(BlockExplodeEvent event) {
|
||||
// 获取爆炸影响的方块
|
||||
List<Block> 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<ItemStack> items = event.getDrops();
|
||||
//有价值物品
|
||||
List<ItemStack> valuable = new ArrayList<>();
|
||||
//无价值物品
|
||||
List<ItemStack> worthless = new ArrayList<>();
|
||||
items.forEach(item -> {
|
||||
if (Config.ITEM_VALUE_MAP.containsKey(item.getType())) {
|
||||
valuable.add(item);
|
||||
} else {
|
||||
worthless.add(item);
|
||||
}
|
||||
});
|
||||
//先将有价值的物品存入箱子
|
||||
HashMap<Integer, ItemStack> 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] + "个物品无法放入墓碑,已掉落在死亡地点。");
|
||||
}
|
||||
|
||||
/// 玩家移动
|
||||
|
||||
@@ -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<UUID, PlayerData> 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<UUID, PlayerData> enter : playerList.entrySet()) {
|
||||
enter.getValue().updatePlayerFraction(data);
|
||||
}
|
||||
}
|
||||
|
||||
/// 提供玩家分数
|
||||
private void initScore(PlayerData data) {
|
||||
public void initScore(PlayerData data) {
|
||||
for (Map.Entry<UUID, PlayerData> enter : playerList.entrySet()) {
|
||||
data.updatePlayerFraction(enter.getValue());
|
||||
}
|
||||
@@ -45,7 +45,7 @@ public class PlayerMap {
|
||||
for (Map.Entry<UUID, PlayerData> 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());
|
||||
|
||||
@@ -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 + ")");
|
||||
}
|
||||
|
||||
/// 在给定位置绘制六芒星
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user