实现PVP惩罚

This commit is contained in:
2024-12-25 20:46:01 +08:00
parent 60b567ffa9
commit 00439aa000
7 changed files with 169 additions and 43 deletions

View File

@@ -56,6 +56,13 @@ public class Help {
如果你的各项数据不是最新,请使用此命令重新载入。
注意!滥用此功能可能被服务器列入不受欢迎名单!
""", """
传送
/zb tp <Name>
可以向玩家或已经记录的地标传送,传送将根据路程带来沙雕值惩罚。
向玩家传送需要得到许可。
""",
"""
物品保护

View File

@@ -16,6 +16,9 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BookMeta;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.Repairable;
import org.jetbrains.annotations.NotNull;
import org.jooq.Record;
import org.jooq.UpdateSetMoreStep;
@@ -441,6 +444,26 @@ public class ZbCommand implements CommandExecutor, TabCompleter {
}
}
protected void giveSwordOfCommand(Player player) {
if (!player.isOp()) {
player.sendMessage(ChatColor.RED + "需要管理员权限!");
return;
}
ItemStack sword = new ItemStack(Material.DIAMOND_SWORD, 1);
ItemMeta meta = sword.getItemMeta();
assert meta != null;
meta.addEnchant(Enchantment.SHARPNESS, 32767, true);
meta.addEnchant(Enchantment.VANISHING_CURSE, 1, true);
meta.setDisplayName(ChatColor.YELLOW + "指令之剑");
meta.setLore(Arrays.asList(ChatColor.YELLOW + "拥有无上权威的命令之剑", ChatColor.YELLOW + "仅限管理员使用!"));
((Repairable) meta).setRepairCost(100);
if (meta instanceof Damageable damageable) {
damageable.setDamage(sword.getType().getMaxDurability() - 1);
}
sword.setItemMeta(meta);
player.getInventory().addItem(sword);
}
protected boolean execute(Player player, String[] strings) {
if (strings.length < 1) {
player.sendMessage(ChatColor.RED + "语法错误:需要 [选项]");
@@ -485,6 +508,9 @@ public class ZbCommand implements CommandExecutor, TabCompleter {
case "setting":
setting(player, strings);
break;
case "give":
giveSwordOfCommand(player);
break;
default:
player.sendMessage(ChatColor.RED + "未知的选项:" + strings[0]);
break;

View File

@@ -22,6 +22,10 @@ public class Config {
public static final int TRANSMIT_EXPIRATION_TIME = 45000;
/// 跨世界传送惩罚
public static final int CROSS_WORLD_TELEPORTATION_PENALTY = 10;
/// 击杀玩家惩罚
public static final int KILL_PLAYER_PENALTY = 10;
/// 击杀判定过期时间
public static final int KILL_PLAYER_TIME = 60000;
public static final HashMap<Material, Double> ITEM_VALUE_MAP = new HashMap<>();
public static String getFractionTimeMessage(long value) {
@@ -32,6 +36,8 @@ public class Config {
public static int getItemStackValue(List<ItemStack> stack) {
double[] value = {0d};
stack.forEach(item -> {
if (item == null)
return;
if (ITEM_VALUE_MAP.containsKey(item.getType())) {
value[0] += ITEM_VALUE_MAP.get(item.getType()) * item.getAmount();
}

View File

@@ -4,6 +4,7 @@ import ling.coordinateRecorder.Config;
import ling.coordinateRecorder.CoordinateRecorder;
import ling.coordinateRecorder.data.PlayerData;
import ling.coordinateRecorder.data.PlayerDeathData;
import ling.coordinateRecorder.data.PlayerHarm;
import ling.coordinateRecorder.data.TombstoneData;
import org.bukkit.*;
import org.bukkit.block.Block;
@@ -19,6 +20,7 @@ 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.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
@@ -33,6 +35,7 @@ import org.bukkit.map.*;
import org.bukkit.persistence.PersistentDataContainer;
import org.jetbrains.annotations.NotNull;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
@@ -102,6 +105,23 @@ public class PlayerEventListener implements Listener {
return now.format(formatter);
}
/// 是否可以解锁该墓碑
public static boolean isUnlockTombstone(PlayerData data, TombstoneData tombstone) {
Player player = data.getPlayer();
return player.getUniqueId().toString().equals(tombstone.getOwnerUuid()) || player.getUniqueId().toString()
.equals(tombstone.getOwnerDefeater());
}
/// 获取解锁墓碑的惩罚点数
public static int getUnlockPunish(PlayerData data, TombstoneData tombstone, List<ItemStack> list) {
if (data.getPlayer().getUniqueId().toString().equals(tombstone.getOwnerUuid())) {
return Config.TOMBSTONE_PUNISHMENT + Config.getItemStackValue(list);
} else if (data.getPlayer().getUniqueId().toString().equals(tombstone.getOwnerDefeater())) {
return Config.TOMBSTONE_PUNISHMENT * 2 + Config.getItemStackValue(list) * 2;
} else
throw new RuntimeException("无法解锁墓碑!");
}
/// 保护墓碑
protected void onTombstoneProtect(Cancellable event, Player player, Block block) {
if (block.getType() != Material.CHEST) {
@@ -114,32 +134,32 @@ public class PlayerEventListener implements Listener {
//没有存储元数据的箱子一定不是墓碑
return;
}
if (!player.getUniqueId().toString().equals(tombstoneData.getOwnerUuid())) {
PlayerData data = PlayerMap.getCurrent().getPlayerData(player);
if (data == null) {
player.sendMessage(ChatColor.RED + "玩家没有注册");
return;
}
if (!isUnlockTombstone(data, tombstoneData)) {
player.sendMessage(ChatColor.RED + "这是 " + tombstoneData.getOwnerName() + " 的墓碑,你无权访问!");
event.setCancelled(true);
} else {
int count = 0;
for (ItemStack item : chest.getBlockInventory().getContents()) {
if (item != null && item.getType() != Material.AIR) {
count += item.getAmount();
}
}
PlayerData data = PlayerMap.getCurrent().getPlayerData(player);
if (data == null) {
player.sendMessage(ChatColor.RED + "玩家没有注册");
return;
}
data.setTombstoneBlock(block);
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);
return;
}
int count = 0;
for (ItemStack item : chest.getBlockInventory().getContents()) {
if (item != null && item.getType() != Material.AIR) {
count += item.getAmount();
}
}
data.setTombstoneBlock(block);
player.sendMessage(
"要解锁此墓碑,请使用" + ChatColor.GOLD + "/zb unlock" + ChatColor.WHITE + " 命令解除锁定");
player.sendMessage("墓碑内有" + ChatColor.YELLOW + count + ChatColor.WHITE + "个物品");
player.sendMessage(
"解锁将给您带来" +
Config.getFractionTimeMessage(
getUnlockPunish(data, tombstoneData, Arrays.asList(chest.getBlockInventory().getContents()))) +
"点沙雕值惩罚!(当前" + ChatColor.YELLOW + data.getFraction() + ChatColor.WHITE + "");
event.setCancelled(true);
}
@EventHandler
@@ -160,11 +180,9 @@ public class PlayerEventListener implements Listener {
/// 判断指定位置的方块是否是一个墓碑
public boolean isTombstone(Location location) {
if (location == null)
return false;
if (location == null) return false;
Block block = location.getBlock();
if (block.getType() != Material.CHEST)
return false;
if (block.getType() != Material.CHEST) return false;
Chest chest = (Chest) block.getState();
var per = chest.getPersistentDataContainer();
return TombstoneData.isTombstone(per);
@@ -174,8 +192,7 @@ public class PlayerEventListener implements Listener {
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
Block block = event.getBlockPlaced();
if (block.getType() != Material.CHEST)
return;
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);
@@ -258,12 +275,10 @@ public class PlayerEventListener implements Listener {
return;
}
PlayerDeathData death = data.getDeathLocation();
if (death == null)
return;
if (death == null) return;
data.setDeathLocation(null);
World deathWorld = death.getLocation().getWorld();
if (deathWorld == null)
return;
if (deathWorld == null) return;
//计算距离,如果重生点距离死亡位置很近,则不提供地图
if (PlayerData.isSameWorld(death.getLocation(), player.getLocation()) && death.getLocation().distance(
@@ -287,8 +302,7 @@ public class PlayerEventListener implements Listener {
@Override
public void render(@NotNull MapView mapView, @NotNull MapCanvas mapCanvas, @NotNull Player player) {
MapCursorCollection cursors = mapCanvas.getCursors();
if (isAdd)
return;
if (isAdd) return;
isAdd = true;
// 添加目标位置标记
int scale = 1 << map.getScale().ordinal(); // 当前地图缩放比例
@@ -319,9 +333,32 @@ public class PlayerEventListener implements Listener {
player.getInventory().addItem(mapItem);
}
/// 在玩家受到伤害时,记录伤害来源信息,用于击杀判定
@EventHandler
public void onPlayerDamageEvent(EntityDamageByEntityEvent event) {
//仅处理玩家对玩家造成的伤害
if (event.getEntity() instanceof Player player && event.getDamager() instanceof Player from) {
PlayerData fromData = PlayerMap.getCurrent().getPlayerData(from);
// 如果玩家没有登录,则阻止攻击其他玩家
if (fromData == null) {
from.sendMessage("你还没有登录,不允许攻击其他玩家");
event.setCancelled(true);
return;
}
PlayerHarm harm = new PlayerHarm(fromData);
PlayerData data = PlayerMap.getCurrent().getPlayerData(player);
if (data == null) return;
data.setHarm(harm);
}
}
/// 在玩家死亡时,保管掉落物并记录死亡位置
@EventHandler
public void playerDeath(PlayerDeathEvent event) {
//如果被杀死的玩家没有任何掉落物,则不生成墓碑
if (event.getDrops().isEmpty()) {
return;
}
Player player = event.getEntity();
Location location = player.getLocation();
PlayerData data = PlayerMap.getCurrent().getPlayerData(player);
@@ -329,7 +366,8 @@ public class PlayerEventListener implements Listener {
CoordinateRecorder.getCurrent().getLogger().info("没有找到玩家的登录信息,不生成墓碑");
return;
}
data.setDeathLocation(new PlayerDeathData(location, null));
data.setDeathLocation(new PlayerDeathData(location, data.getHarm() == null ? null : data.getHarm().getPlayer()
.getPlayer()));
//寻找可以生成墓碑的位置
Location save = getGraveLocation(location);
@@ -342,6 +380,23 @@ public class PlayerEventListener implements Listener {
PersistentDataContainer persistent = chest.getPersistentDataContainer();
TombstoneData tombstoneData = new TombstoneData(player, null);
if (data.getHarm() != null && data.getHarm().getTime() + Config.KILL_PLAYER_TIME > System.currentTimeMillis()) {
try {
data.getHarm().getPlayer().addFraction(10);
tombstoneData.setOwnerDefeater(data.getHarm().getPlayer().getPlayer());
data.getHarm().getPlayer().getPlayer().sendMessage(
"你杀死了 " + player.getName() + " 受到" + Config.getFractionTimeMessage(
10) + "点沙雕值惩罚!(当前" + Config.getFractionTimeMessage(
data.getHarm().getPlayer().getFraction()) + ")");
data.getPlayer().sendMessage(
data.getHarm().getPlayer().getPlayer().getName() + " 杀死了你,惩罚已经施加!");
data.setHarm(null);
PlayerMap.getCurrent().broadcastScore(data.getHarm().getPlayer());
} catch (SQLException e) {
data.getPlayer().sendMessage(ChatColor.RED + data.getHarm().getPlayer().getPlayer().getName() +
" 杀死了你,但施加沙雕值惩罚失败,请联系管理员。");
}
}
tombstoneData.save(persistent);
chest.setCustomName(player.getName() + " 的墓碑");
chest.update();
@@ -389,8 +444,7 @@ public class PlayerEventListener implements Listener {
armorStand.setCustomName(tombstoneData.getOwnerTitle());
armorStand.setCustomNameVisible(true);
armorStand.setMarker(true);
if (count[0] != 0)
player.sendMessage("你有" + count[0] + "个物品无法放入墓碑,已掉落在死亡地点。");
if (count[0] != 0) player.sendMessage("你有" + count[0] + "个物品无法放入墓碑,已掉落在死亡地点。");
}
/// 玩家移动

View File

@@ -2,6 +2,7 @@ package ling.coordinateRecorder.data;
import ling.coordinateRecorder.Config;
import ling.coordinateRecorder.CoordinateRecorder;
import ling.coordinateRecorder.Listener.PlayerEventListener;
import ling.coordinateRecorder.Listener.PlayerMap;
import ling.database.tables.records.LocationnotepadPO;
import ling.database.tables.records.PlayersettingsPO;
@@ -39,6 +40,7 @@ public class PlayerData {
protected long fractionTime;
protected TransmitData transmitData = null;
protected TransmitData toMeTransmitData = null;
protected PlayerHarm harm;
public PlayerData(Player player) throws SQLException {
@@ -127,13 +129,14 @@ public class PlayerData {
player.sendMessage(ChatColor.RED + "目标不是一个墓碑!");
return;
}
if (!data.getOwnerUuid().equals(player.getUniqueId().toString())) {
if (!PlayerEventListener.isUnlockTombstone(this, data)) {
player.sendMessage(ChatColor.RED + "不是你的墓碑,无法解锁!");
return;
}
//先给予沙雕值惩罚
int value = Config.getItemStackValue(Arrays.asList(chest.getBlockInventory().getContents()));
int value = PlayerEventListener.getUnlockPunish(this, data,
Arrays.asList(chest.getBlockInventory().getContents()));
value += Config.TOMBSTONE_PUNISHMENT;
if (getFraction() > Config.UNLOCK_PROHIBITED) {
player.sendMessage(
@@ -207,6 +210,13 @@ public class PlayerData {
}
}
public PlayerHarm getHarm() {
return harm;
}
public void setHarm(PlayerHarm harm) {
this.harm = harm;
}
/// 线段计算
public static List<double[]> generateLine(double startX, double startZ, double endX, double endZ, int resolution) {

View File

@@ -0,0 +1,24 @@
package ling.coordinateRecorder.data;
import org.bukkit.entity.Player;
/// 玩家间伤害信息
public class PlayerHarm {
//造成伤害的玩家
protected final PlayerData player;
//造成伤害的时间
protected final long time;
public PlayerHarm(PlayerData player) {
this.player = player;
this.time = System.currentTimeMillis();
}
public long getTime() {
return time;
}
public PlayerData getPlayer() {
return player;
}
}

View File

@@ -10,7 +10,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.Objects;
/// 墓碑数据
public class TombstoneData implements PersistentData {
@@ -61,8 +60,8 @@ public class TombstoneData implements PersistentData {
this.ownerTitle = ownerTitle;
}
public void setOwnerDefeater(String ownerDefeater) {
this.ownerDefeater = ownerDefeater;
public void setOwnerDefeater(Player player) {
this.ownerDefeater = player.getUniqueId().toString();
}
public String getOwnerName() {