This commit is contained in:
2025-10-25 18:27:24 +08:00
parent 57c24b1dce
commit 4d09482fb1
6 changed files with 373 additions and 128 deletions

View File

@@ -17,14 +17,10 @@ import java.util.UUID;
public class PlayerTags { public class PlayerTags {
private final Survival plugin; private final Survival plugin;
private final File tagsFile; private final File tagsFile;
// 原有:玩家-称号列表映射
private final Map<UUID, List<String>> playerTags = new HashMap<>(); private final Map<UUID, List<String>> playerTags = new HashMap<>();
// 新增:玩家-(称号-到期时间戳映射毫秒级永久用Long.MAX_VALUE
private final Map<UUID, Map<String, Long>> expireTimeMap = new HashMap<>(); private final Map<UUID, Map<String, Long>> expireTimeMap = new HashMap<>();
// 原有:玩家-选中称号索引映射
public Map<UUID, Integer> playerselectTag = new HashMap<>(); public Map<UUID, Integer> playerselectTag = new HashMap<>();
// 常量7天的毫秒数7*24*60*60*1000
private static final long SEVEN_DAYS_MS = 604800000L; private static final long SEVEN_DAYS_MS = 604800000L;
public PlayerTags(Survival plugin) { public PlayerTags(Survival plugin) {
@@ -32,36 +28,28 @@ public class PlayerTags {
this.tagsFile = new File(plugin.getDataFolder(), "playertags.data"); this.tagsFile = new File(plugin.getDataFolder(), "playertags.data");
} }
/**
* 核心辅助:清理玩家的所有过期称号(所有方法调用前先执行)
*/
public void cleanExpiredTags(Player player) { public void cleanExpiredTags(Player player) {
UUID uuid = player.getUniqueId(); UUID uuid = player.getUniqueId();
List<String> validTags = new ArrayList<>(); List<String> validTags = new ArrayList<>();
List<String> allTags = playerTags.getOrDefault(uuid, new ArrayList<>()); List<String> allTags = playerTags.getOrDefault(uuid, new ArrayList<>());
Map<String, Long> tagExpires = expireTimeMap.getOrDefault(uuid, new HashMap<>()); Map<String, Long> tagExpires = expireTimeMap.getOrDefault(uuid, new HashMap<>());
// 遍历所有称号,保留未过期的
for (String tag : allTags) { for (String tag : allTags) {
long expireTime = tagExpires.getOrDefault(tag, Long.MAX_VALUE); long expireTime = tagExpires.getOrDefault(tag, Long.MAX_VALUE);
// 未过期判断永久MAX或当前时间 < 到期时间
if (expireTime == Long.MAX_VALUE || System.currentTimeMillis() < expireTime) { if (expireTime == Long.MAX_VALUE || System.currentTimeMillis() < expireTime) {
validTags.add(tag); validTags.add(tag);
} else { } else {
// 过期:移除过期时间记录
tagExpires.remove(tag); tagExpires.remove(tag);
} }
} }
// 更新有效称号列表和过期时间映射
if (validTags.isEmpty()) { if (validTags.isEmpty()) {
playerTags.remove(uuid); playerTags.remove(uuid);
expireTimeMap.remove(uuid); expireTimeMap.remove(uuid);
playerselectTag.put(uuid, -1); // 无有效称号,重置选中索引 playerselectTag.put(uuid, -1);
} else { } else {
playerTags.put(uuid, validTags); playerTags.put(uuid, validTags);
expireTimeMap.put(uuid, tagExpires); expireTimeMap.put(uuid, tagExpires);
// 检查选中的称号是否已过期:若过期/索引无效,重置索引
int currentIndex = playerselectTag.getOrDefault(uuid, -1); int currentIndex = playerselectTag.getOrDefault(uuid, -1);
if (currentIndex == -1 || currentIndex >= validTags.size()) { if (currentIndex == -1 || currentIndex >= validTags.size()) {
playerselectTag.put(uuid, -1); playerselectTag.put(uuid, -1);
@@ -69,11 +57,8 @@ public class PlayerTags {
} }
} }
/**
* 获取当前选中的称号索引(自动过滤过期)
*/
public int getCurrentTag(Player player) { public int getCurrentTag(Player player) {
cleanExpiredTags(player); // 先清理过期 cleanExpiredTags(player);
UUID uuid = player.getUniqueId(); UUID uuid = player.getUniqueId();
Integer index = playerselectTag.get(uuid); Integer index = playerselectTag.get(uuid);
if (index == null) { if (index == null) {
@@ -82,34 +67,29 @@ public class PlayerTags {
List<String> validTags = playerTags.getOrDefault(uuid, new ArrayList<>()); List<String> validTags = playerTags.getOrDefault(uuid, new ArrayList<>());
if (validTags.isEmpty() || index < 0 || index >= validTags.size()) { if (validTags.isEmpty() || index < 0 || index >= validTags.size()) {
playerselectTag.put(uuid, -1); // 索引无效,重置 playerselectTag.put(uuid, -1);
return -1; return -1;
} }
return index; return index;
} }
/**
* 设置玩家选择的标签索引(自动过滤过期)
*/
public boolean setSelectedTag(Player player, int index) { public boolean setSelectedTag(Player player, int index) {
cleanExpiredTags(player); // 先清理过期 cleanExpiredTags(player);
UUID uuid = player.getUniqueId(); UUID uuid = player.getUniqueId();
List<String> validTags = playerTags.getOrDefault(uuid, new ArrayList<>()); List<String> validTags = playerTags.getOrDefault(uuid, new ArrayList<>());
// 无有效称号或索引无效,返回失败
if (validTags.isEmpty() || index < 0 || index >= validTags.size()) { if (validTags.isEmpty() || index < 0 || index >= validTags.size()) {
playerselectTag.put(uuid, -1); playerselectTag.put(uuid, -1);
return false; return false;
} }
// 设置选中索引,返回成功
playerselectTag.put(uuid, index); playerselectTag.put(uuid, index);
return true; return true;
} }
/** /**
* 加载称号数据核心逻辑——识别旧数据并转为7天过期 * 修复核心正确读取新版本数据中的expireTimeMap避免误判为旧数据
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void loadTags() { public void loadTags() {
@@ -118,17 +98,27 @@ public class PlayerTags {
} }
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(tagsFile))) { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(tagsFile))) {
// 读取第一个对象判断是旧版本List<String>)还是新版本(含过期时间 // 读取三个核心对象(新版本数据结构
Object firstObj = ois.readObject(); Object firstObj = ois.readObject();
Object secondObj = ois.readObject(); Object secondObj = ois.readObject();
Object thirdObj = null; // 新版本的第三个对象expireTimeMap Object thirdObj = ois.readObject(); // 关键修复:读取第三个对象expireTimeMap
// 1. 识别旧版本数据(仅2个对象playerTags + playerselectTag // 1. 优先判断新版本数据(3个对象完整
if (firstObj instanceof Map<?, ?> && secondObj instanceof Map<?, ?> && ois.available() == 0) { if (firstObj instanceof Map<?, ?> && secondObj instanceof Map<?, ?> && thirdObj instanceof Map<?, ?>) {
// 强制转换并加载数据
playerTags.putAll((Map<UUID, List<String>>) firstObj);
playerselectTag.putAll((Map<UUID, Integer>) secondObj);
expireTimeMap.putAll((Map<UUID, Map<String, Long>>) thirdObj);
plugin.getLogger().info("新版本称号数据加载完成!共加载 " + playerTags.size() + " 个玩家的称号");
return; // 加载成功直接返回,避免进入旧数据处理
}
// 2. 处理旧版本数据仅2个对象无expireTimeMap
if (firstObj instanceof Map<?, ?> && secondObj instanceof Map<?, ?>) {
Map<UUID, List<String>> oldPlayerTags = (Map<UUID, List<String>>) firstObj; Map<UUID, List<String>> oldPlayerTags = (Map<UUID, List<String>>) firstObj;
Map<UUID, Integer> oldSelectTag = (Map<UUID, Integer>) secondObj; Map<UUID, Integer> oldSelectTag = (Map<UUID, Integer>) secondObj;
// 旧数据转换:为每个称号设置“当前时间+7天”的到期时间 // 旧数据转换为7天过期
for (Map.Entry<UUID, List<String>> entry : oldPlayerTags.entrySet()) { for (Map.Entry<UUID, List<String>> entry : oldPlayerTags.entrySet()) {
UUID uuid = entry.getKey(); UUID uuid = entry.getKey();
List<String> oldTags = entry.getValue(); List<String> oldTags = entry.getValue();
@@ -136,34 +126,27 @@ public class PlayerTags {
continue; continue;
} }
// 为当前玩家创建“称号-到期时间”映射
Map<String, Long> tagExpires = new HashMap<>(); Map<String, Long> tagExpires = new HashMap<>();
long sevenDaysLater = System.currentTimeMillis() + SEVEN_DAYS_MS; // 7天后到期 long sevenDaysLater = System.currentTimeMillis() + SEVEN_DAYS_MS;
for (String tag : oldTags) { for (String tag : oldTags) {
tagExpires.put(tag, sevenDaysLater); // 每个旧称号都设为7天过期 tagExpires.put(tag, sevenDaysLater);
} }
// 存入新结构 playerTags.put(uuid, new ArrayList<>(oldTags));
playerTags.put(uuid, new ArrayList<>(oldTags)); // 复制旧称号列表 expireTimeMap.put(uuid, tagExpires);
expireTimeMap.put(uuid, tagExpires); // 存入7天过期时间
} }
// 恢复选中索引
playerselectTag.putAll(oldSelectTag); playerselectTag.putAll(oldSelectTag);
plugin.getLogger().info("旧版本称号数据加载完成已自动转为7日后到期"); plugin.getLogger().info("旧版本称号数据加载完成已自动转为7日后到期");
return;
}
} // 3. 数据格式错误
// 2. 识别新版本数据3个对象playerTags + playerselectTag + expireTimeMap plugin.getLogger().warning("称号数据格式错误,无法识别!");
else if (firstObj instanceof Map<?, ?> && secondObj instanceof Map<?, ?> && thirdObj instanceof Map<?, ?>) {
playerTags.putAll((Map<UUID, List<String>>) firstObj);
playerselectTag.putAll((Map<UUID, Integer>) secondObj);
expireTimeMap.putAll((Map<UUID, Map<String, Long>>) thirdObj);
plugin.getLogger().info("新版本称号数据加载完成!");
}
} catch (IOException | ClassNotFoundException e) { } catch (IOException | ClassNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
// 回退逻辑:仅加载称号列表,所有称号设为7天过期 // 回退逻辑仅加载称号列表设为7天过期
try (ObjectInputStream fallback = new ObjectInputStream(new FileInputStream(tagsFile))) { try (ObjectInputStream fallback = new ObjectInputStream(new FileInputStream(tagsFile))) {
Object obj = fallback.readObject(); Object obj = fallback.readObject();
if (obj instanceof Map<?, ?> oldPlayerTags) { if (obj instanceof Map<?, ?> oldPlayerTags) {
@@ -176,7 +159,7 @@ public class PlayerTags {
for (Object tagObj : (List<?>) entry.getValue()) { for (Object tagObj : (List<?>) entry.getValue()) {
if (tagObj instanceof String tag) { if (tagObj instanceof String tag) {
tags.add(tag); tags.add(tag);
tagExpires.put(tag, sevenDaysLater); // 回退时也设为7天过期 tagExpires.put(tag, sevenDaysLater);
} }
} }
@@ -193,16 +176,13 @@ public class PlayerTags {
} }
} }
/**
* 保存称号数据同步保存playerTags、playerselectTag、expireTimeMap
*/
public void saveTags() { public void saveTags() {
if (!tagsFile.getParentFile().exists()) { if (!tagsFile.getParentFile().exists()) {
tagsFile.getParentFile().mkdirs(); tagsFile.getParentFile().mkdirs();
} }
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(tagsFile))) { try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(tagsFile))) {
// 按顺序写入3个核心结构(新版本 // 按顺序写入个核心结构(与加载时对应
oos.writeObject(playerTags); oos.writeObject(playerTags);
oos.writeObject(playerselectTag); oos.writeObject(playerselectTag);
oos.writeObject(expireTimeMap); oos.writeObject(expireTimeMap);
@@ -211,71 +191,50 @@ public class PlayerTags {
} }
} }
/**
* 获取玩家的有效称号列表(自动过滤过期)
*/
public List<String> getTags(Player player) { public List<String> getTags(Player player) {
cleanExpiredTags(player); cleanExpiredTags(player);
return playerTags.getOrDefault(player.getUniqueId(), new ArrayList<>()); return playerTags.getOrDefault(player.getUniqueId(), new ArrayList<>());
} }
/**
* 新增称号:默认永久(可手动指定过期时间)
*
* @param player 目标玩家
* @param tag 称号名称
* @param isPermanent 是否永久true=永久false=7天过期
*/
public void addTag(Player player, String tag, boolean isPermanent) { public void addTag(Player player, String tag, boolean isPermanent) {
cleanExpiredTags(player); // 先清理过期 cleanExpiredTags(player);
UUID uuid = player.getUniqueId(); UUID uuid = player.getUniqueId();
List<String> tags = playerTags.computeIfAbsent(uuid, k -> new ArrayList<>()); List<String> tags = playerTags.computeIfAbsent(uuid, k -> new ArrayList<>());
Map<String, Long> tagExpires = expireTimeMap.computeIfAbsent(uuid, k -> new HashMap<>()); Map<String, Long> tagExpires = expireTimeMap.computeIfAbsent(uuid, k -> new HashMap<>());
// 避免重复添加相同称号
if (!tags.contains(tag)) { if (!tags.contains(tag)) {
tags.add(tag); tags.add(tag);
// 设置过期时间:永久=Long.MAX_VALUE临时=当前时间+7天
long expireTime = isPermanent ? Long.MAX_VALUE : System.currentTimeMillis() + SEVEN_DAYS_MS; long expireTime = isPermanent ? Long.MAX_VALUE : System.currentTimeMillis() + SEVEN_DAYS_MS;
tagExpires.put(tag, expireTime); tagExpires.put(tag, expireTime);
} }
} }
/**
* 重载原有addTag方法默认添加永久称号保持向下兼容
*/
public void addTag(Player player, String tag, int days) { public void addTag(Player player, String tag, int days) {
cleanExpiredTags(player); // 先清理过期 cleanExpiredTags(player);
UUID uuid = player.getUniqueId(); UUID uuid = player.getUniqueId();
List<String> tags = playerTags.computeIfAbsent(uuid, k -> new ArrayList<>()); List<String> tags = playerTags.computeIfAbsent(uuid, k -> new ArrayList<>());
Map<String, Long> tagExpires = expireTimeMap.computeIfAbsent(uuid, k -> new HashMap<>()); Map<String, Long> tagExpires = expireTimeMap.computeIfAbsent(uuid, k -> new HashMap<>());
// 避免重复添加相同称号
if (!tags.contains(tag)) { if (!tags.contains(tag)) {
tags.add(tag); tags.add(tag);
long expireTime; long expireTime;
if (days == 999) { if (days == 999) {
expireTime = Long.MAX_VALUE; // 999天视为永久 expireTime = Long.MAX_VALUE;
} else if (days <= 0) { } else if (days <= 0) {
expireTime = System.currentTimeMillis() - 1; // 天数≤0立即过期触发清理 expireTime = System.currentTimeMillis() - 1;
} else { } else {
// 计算有效期:当前时间 + 天数×24×60×60×1000转换为毫秒
expireTime = System.currentTimeMillis() + (long) days * 24 * 60 * 60 * 1000; expireTime = System.currentTimeMillis() + (long) days * 24 * 60 * 60 * 1000;
} }
tagExpires.put(tag, expireTime); tagExpires.put(tag, expireTime);
} }
} }
/**
* 移除称号:同时删除过期时间记录
*/
public void removeTag(Player player, String tag) { public void removeTag(Player player, String tag) {
cleanExpiredTags(player); cleanExpiredTags(player);
UUID uuid = player.getUniqueId(); UUID uuid = player.getUniqueId();
List<String> tags = playerTags.get(uuid); List<String> tags = playerTags.get(uuid);
Map<String, Long> tagExpires = expireTimeMap.get(uuid); Map<String, Long> tagExpires = expireTimeMap.get(uuid);
// 移除称号列表和过期时间映射中的对应条目
if (tags != null) { if (tags != null) {
tags.remove(tag); tags.remove(tag);
if (tags.isEmpty()) { if (tags.isEmpty()) {
@@ -293,7 +252,6 @@ public class PlayerTags {
} }
} }
// 若移除的是当前选中称号,重置索引
int currentIndex = playerselectTag.getOrDefault(uuid, -1); int currentIndex = playerselectTag.getOrDefault(uuid, -1);
List<String> validTags = playerTags.getOrDefault(uuid, new ArrayList<>()); List<String> validTags = playerTags.getOrDefault(uuid, new ArrayList<>());
if (currentIndex != -1 && (currentIndex >= validTags.size() || !validTags.contains(tag))) { if (currentIndex != -1 && (currentIndex >= validTags.size() || !validTags.contains(tag))) {
@@ -301,30 +259,20 @@ public class PlayerTags {
} }
} }
/**
* 新增:获取称号的到期时间(返回时间戳,单位毫秒)
*
* @return 永久返回-1过期/不存在返回-2有效返回到期时间戳
*/
public long getTagExpireTime(Player player, String tag) { public long getTagExpireTime(Player player, String tag) {
cleanExpiredTags(player); cleanExpiredTags(player);
UUID uuid = player.getUniqueId(); UUID uuid = player.getUniqueId();
Map<String, Long> tagExpires = expireTimeMap.getOrDefault(uuid, new HashMap<>()); Map<String, Long> tagExpires = expireTimeMap.getOrDefault(uuid, new HashMap<>());
List<String> validTags = playerTags.getOrDefault(uuid, new ArrayList<>()); List<String> validTags = playerTags.getOrDefault(uuid, new ArrayList<>());
// 称号不存在或已过期,返回-2
if (!validTags.contains(tag)) { if (!validTags.contains(tag)) {
return -2; return -2;
} }
long expireTime = tagExpires.getOrDefault(tag, Long.MAX_VALUE); long expireTime = tagExpires.getOrDefault(tag, Long.MAX_VALUE);
// 永久称号返回-1否则返回时间戳
return expireTime == Long.MAX_VALUE ? -1 : expireTime; return expireTime == Long.MAX_VALUE ? -1 : expireTime;
} }
/**
* 新增获取称号的剩余时间返回字符串如“2天3小时”
*/
public String getTagRemainingTime(Player player, String tag) { public String getTagRemainingTime(Player player, String tag) {
long expireTime = getTagExpireTime(player, tag); long expireTime = getTagExpireTime(player, tag);
if (expireTime == -1) { if (expireTime == -1) {
@@ -334,18 +282,15 @@ public class PlayerTags {
return "已过期/不存在"; return "已过期/不存在";
} }
// 计算剩余毫秒数(可能为负,需处理)
long remainingMs = expireTime - System.currentTimeMillis(); long remainingMs = expireTime - System.currentTimeMillis();
if (remainingMs <= 0) { if (remainingMs <= 0) {
return "已过期"; return "已过期";
} }
// 转换为天、时、分
long days = remainingMs / (24 * 60 * 60 * 1000); long days = remainingMs / (24 * 60 * 60 * 1000);
long hours = (remainingMs % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000); long hours = (remainingMs % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000);
long minutes = (remainingMs % (60 * 60 * 1000)) / (60 * 1000); long minutes = (remainingMs % (60 * 60 * 1000)) / (60 * 1000);
// 拼接剩余时间字符串
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (days > 0) sb.append(days).append(""); if (days > 0) sb.append(days).append("");
if (hours > 0) sb.append(hours).append("小时"); if (hours > 0) sb.append(hours).append("小时");

View File

@@ -3,15 +3,23 @@ package org.xgqy.survival;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import org.xgqy.survival.command.DqshopCommandExecutor; import org.xgqy.survival.command.DqshopCommandExecutor;
import org.xgqy.survival.command.FriendCommandExecutor;
import org.xgqy.survival.command.HandleCommandExecutor; import org.xgqy.survival.command.HandleCommandExecutor;
import org.xgqy.survival.command.HelpCommandExecutor; import org.xgqy.survival.command.HelpCommandExecutor;
import org.xgqy.survival.command.HubCommandExecutor; import org.xgqy.survival.command.HubCommandExecutor;
import org.xgqy.survival.command.InventoryCommandExecutor;
import org.xgqy.survival.command.KillCommandExecutor;
import org.xgqy.survival.command.LandCommandExecutor;
import org.xgqy.survival.command.LoginCommandExecutor; import org.xgqy.survival.command.LoginCommandExecutor;
import org.xgqy.survival.command.PartyCommandExecutor; import org.xgqy.survival.command.PartyCommandExecutor;
import org.xgqy.survival.command.PcCommandExecutor;
import org.xgqy.survival.command.PointCommandExecutor;
import org.xgqy.survival.command.PvpCommandExecutor; import org.xgqy.survival.command.PvpCommandExecutor;
import org.xgqy.survival.command.RegCommandExecutor; import org.xgqy.survival.command.RegCommandExecutor;
import org.xgqy.survival.command.ReportCommandExecutor; import org.xgqy.survival.command.ReportCommandExecutor;
@@ -20,25 +28,34 @@ import org.xgqy.survival.command.TagCommandExecutor;
import org.xgqy.survival.command.TeleportCommandExecutor; import org.xgqy.survival.command.TeleportCommandExecutor;
import org.xgqy.survival.command.TpAccCommandExecutor; import org.xgqy.survival.command.TpAccCommandExecutor;
import org.xgqy.survival.command.TpFinCommandExecutor; import org.xgqy.survival.command.TpFinCommandExecutor;
import org.xgqy.survival.command.msgCommandExecutor;
import org.xgqy.survival.event.ChatEvent; import org.xgqy.survival.event.ChatEvent;
import org.xgqy.survival.event.ChooseTagEvent; import org.xgqy.survival.event.ChooseTagEvent;
import org.xgqy.survival.event.JoinEvent; import org.xgqy.survival.event.JoinEvent;
import org.xgqy.survival.event.LandEvent;
import org.xgqy.survival.event.LoginEvent; import org.xgqy.survival.event.LoginEvent;
import org.xgqy.survival.event.QuitEvent;
import java.io.File;
import java.io.IOException;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public final class Survival extends JavaPlugin { public final class Survival extends JavaPlugin {
private PlayerTags playerTags; private PlayerTags playerTags;
private AccountManager accountManager; // 新增账号管理器 private AccountManager accountManager;
public Map<Player, Boolean> krt = new HashMap<>(); public Map<Player, Boolean> krt = new HashMap<>();
public Map<Player, Player> banlist = new HashMap<>(); public Map<Player, Player> banlist = new HashMap<>();
public Map<Player, String> banreason = new HashMap<>(); public Map<Player, String> banreason = new HashMap<>();
public Map<Player, HashSet<Player>> reportlist = new HashMap<>(); public Map<Player, HashSet<Player>> reportlist = new HashMap<>();
// Teleport
public Map<Player, Player> teleport = new HashMap<>(); public Map<Player, Player> teleport = new HashMap<>();
public Map<Player, Player> Ateleport = new HashMap<>(); public Map<Player, Player> Ateleport = new HashMap<>();
public Map<Player, Location> teleportp = new HashMap<>(); public Map<Player, Location> teleportp = new HashMap<>();
@@ -59,18 +76,88 @@ public final class Survival extends JavaPlugin {
friend friend
---------------------------------------- ----------------------------------------
*/ */
public Map<Player,List<Player>> friends = new HashMap<>(); public Map<Player, List<Player>> friends = new ConcurrentHashMap<>();
public Map<Player, List<Player>> waiting = new ConcurrentHashMap<>();
/* /*
---------------------------------------- ----------------------------------------
信用分
---------------------------------------- ----------------------------------------
*/ */
public Map<Player, Integer> ppoint = new HashMap<>();
private List<String> msg = new ArrayList<>(); private List<String> msg = new ArrayList<>();
public Map<Player, String> breason = new HashMap<>();
/*
----------------------------------------
领地
----------------------------------------
*/
public static class Land{
public Location start,end;
public List<Boolean> defaultperm;
public String owner;
public Map<String,List<Boolean>> perm;
public boolean boomb;
public Land(Location start,Location end,List<Boolean> defaultperm,String owner,Map<String,List<Boolean>> perm){
this.start=start;
this.end=end;
this.defaultperm = defaultperm;
this.owner=owner;
this.perm=perm;
}
public Boolean getBoomb(){
return boomb;
}
public void setBoomb(Boolean boomb){
this.boomb=boomb;
}
public Location getStart(){
return start;
}
public Location getEnd(){
return end;
}
public List<Boolean> getDefaultperm(){
return defaultperm;
}
public String getOwner(){
return owner;
}
public List<Boolean> getPerm(Player player){
return perm.getOrDefault(player,null);
}
public void setStart(Location start){
this.start=start;
}
public void setEnd(Location end) {
this.end = end;
}
public void setDefaultperm(List<Boolean> defaultperm){
this.defaultperm=defaultperm;
}
public void setOwner(String owner){
this.owner=owner;
}
public void setPerm(Player player,List<Boolean> perm){
this.perm.put(player.getName(),perm);
}
}
public List<Land> land =new ArrayList<>();
public Map<Player,String> inland=new HashMap<>();
// 信用分数据文件相关
private File ppointFile;
private FileConfiguration ppointConfig;
@Override @Override
public void onEnable() { public void onEnable() {
// 初始化账号管理器 // 初始化账号管理器
accountManager = new AccountManager(this); accountManager = new AccountManager(this);
// 初始化信用分数据文件
initPpointFile();
// 加载已在线玩家的信用分数据
loadPpoint();
msg.add(ChatColor.GREEN + "可以用 /help 命令来查看命令列表"); msg.add(ChatColor.GREEN + "可以用 /help 命令来查看命令列表");
msg.add(ChatColor.GREEN + "如果遇到作弊玩家可以用 /report <玩家名> <原因> 来举报!管理员会很快处理的"); msg.add(ChatColor.GREEN + "如果遇到作弊玩家可以用 /report <玩家名> <原因> 来举报!管理员会很快处理的");
msg.add(ChatColor.GREEN + "想传送到玩家怎么办? 用 /teleport <玩家名> 命令!"); msg.add(ChatColor.GREEN + "想传送到玩家怎么办? 用 /teleport <玩家名> 命令!");
@@ -81,7 +168,12 @@ public final class Survival extends JavaPlugin {
msg.add(ChatColor.GREEN + "今天签到了吗?快输入 /qd 签到吧!"); msg.add(ChatColor.GREEN + "今天签到了吗?快输入 /qd 签到吧!");
msg.add(ChatColor.GREEN + "其实可以输入 /pvp 来开启/关闭自己的pvp模式"); msg.add(ChatColor.GREEN + "其实可以输入 /pvp 来开启/关闭自己的pvp模式");
msg.add(ChatColor.RED + "你不可以把别人的家毁掉!这样你将会受到处罚"); msg.add(ChatColor.RED + "你不可以把别人的家毁掉!这样你将会受到处罚");
msg.add(ChatColor.GOLD+"能给我捐点钱吗"); msg.add(ChatColor.GREEN + "每日坚持签到可以获得信用分");
msg.add(ChatColor.GREEN + "服务器官网: https://starpavilion.xyz");
msg.add(ChatColor.GREEN + "赞助我们? https://starpavilion.xyz/sponsor.html");
msg.add(ChatColor.RED+"封禁者会在此处公示: https://starpavilion.xyz/bans.html");
msg.add(ChatColor.RED + "信用分过低将会导致你的账号受限甚至永久封禁!");
msg.add(ChatColor.GREEN + "信用分被扣除会提醒如果您的信用分被莫名扣除请及时到QQ群 717903781 申诉。");
new BukkitRunnable() { new BukkitRunnable() {
@Override @Override
@@ -95,49 +187,227 @@ public final class Survival extends JavaPlugin {
} }
}.runTaskLater(this, 20 * 60); }.runTaskLater(this, 20 * 60);
// Plugin startup logic new BukkitRunnable() {
@Override
public void run() {
for (Player plr : Bukkit.getOnlinePlayers()) {
// 检查玩家是否有违规扣分记录
if (plr.getScoreboard().getObjective("handled") != null &&
plr.getScoreboard().getObjective("handled").getScore(plr).getScore() != 0) {
ZonedDateTime beijingTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedTime = beijingTime.format(formatter);
// 确保玩家信用分已初始化
int currentPoint = ppoint.getOrDefault(plr, 100);
int deductPoint = plr.getScoreboard().getObjective("handled").getScore(plr).getScore();
int newPoint = currentPoint - deductPoint;
//ppoint.put(plr, newPoint);
// 发送扣分提示
plr.sendMessage(ChatColor.RED + "警告" + ChatColor.WHITE + " | " + ChatColor.RED + "您的账号 " + ChatColor.YELLOW + plr.getName() + ChatColor.RED + "" + ChatColor.WHITE + formattedTime + ChatColor.RED + " 有疑似违规行为,扣取信用分 " + ChatColor.YELLOW + deductPoint + ChatColor.RED + " 分。\n");
plr.sendMessage(ChatColor.RED + "-----------警告单-----------");
plr.sendMessage(ChatColor.RED + "|账号名: " + ChatColor.YELLOW + plr.getName());
plr.sendMessage(ChatColor.RED + "|违规时间: " + ChatColor.YELLOW + formattedTime);
plr.sendMessage(ChatColor.RED + "|违规行为: " + ChatColor.YELLOW + breason.getOrDefault(plr, "管理员扣分"));
plr.sendMessage(ChatColor.RED + "|违规扣分: " + ChatColor.YELLOW + deductPoint + "");
plr.sendMessage(ChatColor.RED + "|剩余信用分: " + ChatColor.YELLOW + newPoint);
// 根据剩余信用分执行处罚
if (newPoint > 80) {
plr.sendMessage(ChatColor.RED + "|采取处罚: " + ChatColor.YELLOW + "");
} else if (newPoint <= 0) {
plr.kickPlayer(ChatColor.RED + "您好! 您由于在 " + formattedTime + " 信用分小于 0 ,我们决定对你的账号 " + plr.getName() + " 采取\n" + ChatColor.RED + ChatColor.BOLD + "永久封禁\n" + ChatColor.RED + "措施如果您想解封您的账号请到QQ群 717903781 申诉\n\n" + ChatColor.RED + "如果您对本次处罚不满,请采取以下措施:\n" + ChatColor.YELLOW + "1.如果您对自己的行为" + ChatColor.BOLD + " 问心无愧 " + ChatColor.YELLOW + "请立即向QQ 2213866559 发送解封申请\n" + ChatColor.YELLOW + "2.如果您属实有违规行为,请" + ChatColor.BOLD + "手写" + ChatColor.YELLOW + "一篇 " + ChatColor.BOLD + "100字以上且AIGC合格" + ChatColor.YELLOW + " 的检讨发送到申诉QQ群态度诚恳我们将会对你进行解封");
} else if (newPoint <= 20) {
plr.sendMessage(ChatColor.RED + "|采取处罚: " + ChatColor.YELLOW + "限制行为及发言,列入监管名单,限制功能使用");
} else if (newPoint <= 50) {
plr.sendMessage(ChatColor.RED + "|采取处罚: " + ChatColor.YELLOW + "限制行为及发言,限制功能使用");
} else if (newPoint <= 80) {
plr.sendMessage(ChatColor.RED + "|采取处罚: " + ChatColor.YELLOW + "监管行为及发言,签到将奖励转换为信用分");
}
plr.sendMessage(ChatColor.RED + "|为了维护游戏环境,请不要违规!");
plr.sendMessage(ChatColor.RED + "----------------------------");
// 清理临时数据
breason.remove(plr);
plr.getScoreboard().getObjective("handled").getScore(plr).setScore(0);
// 实时保存扣分后的信用分数据
savePpoint();
}
}
}
}.runTaskTimer(this, 20 * 5, 20 * 5);
// 初始化玩家标签
playerTags = new PlayerTags(this); playerTags = new PlayerTags(this);
playerTags.loadTags(); playerTags.loadTags();
// 注册事件监听器,包括新的登录事件 // 注册事件监听器
Bukkit.getPluginManager().registerEvents(new JoinEvent(this), this); Bukkit.getPluginManager().registerEvents(new JoinEvent(this), this);
Bukkit.getPluginManager().registerEvents(new ChatEvent(this), this); Bukkit.getPluginManager().registerEvents(new ChatEvent(this), this);
Bukkit.getPluginManager().registerEvents(new ChooseTagEvent(this), this); Bukkit.getPluginManager().registerEvents(new ChooseTagEvent(this), this);
Bukkit.getPluginManager().registerEvents(new LoginEvent(this), this); // 新增登录事件监听器 Bukkit.getPluginManager().registerEvents(new LoginEvent(this), this);
Bukkit.getPluginManager().registerEvents(new QuitEvent(this),this); Bukkit.getPluginManager().registerEvents(new LandEvent(this),this);
//Bukkit.getPluginManager().registerEvents(new AntiExploit(),this);
//Bukkit.getPluginManager().registerEvents(new AntiXray(this),this);
// 注册命令执行器,包括新的注册和登录命令 // 注册命令执行器
getCommand("report").setExecutor(new ReportCommandExecutor(this)); getCommand("report").setExecutor(new ReportCommandExecutor(this));
getCommand("handle").setExecutor(new HandleCommandExecutor(this)); getCommand("handle").setExecutor(new HandleCommandExecutor(this));
getCommand("pvp").setExecutor(new PvpCommandExecutor(this)); getCommand("pvp").setExecutor(new PvpCommandExecutor(this));
getCommand("settag").setExecutor(new SetTagCommandExecutor(this)); getCommand("settag").setExecutor(new SetTagCommandExecutor(this));
getCommand("help").setExecutor(new HelpCommandExecutor(this)); getCommand("help").setExecutor(new HelpCommandExecutor(this));
//getCommand("fly").setExecutor(new FlyCommandExecutor(this));
getCommand("tag").setExecutor(new TagCommandExecutor(this)); getCommand("tag").setExecutor(new TagCommandExecutor(this));
getCommand("hub").setExecutor(new HubCommandExecutor(this)); getCommand("hub").setExecutor(new HubCommandExecutor(this));
getCommand("teleport").setExecutor(new TeleportCommandExecutor(this)); getCommand("teleport").setExecutor(new TeleportCommandExecutor(this));
getCommand("tpacc").setExecutor(new TpAccCommandExecutor(this)); getCommand("tpacc").setExecutor(new TpAccCommandExecutor(this));
getCommand("tpfin").setExecutor(new TpFinCommandExecutor(this)); getCommand("tpfin").setExecutor(new TpFinCommandExecutor(this));
getCommand("shop").setExecutor(new DqshopCommandExecutor(this)); getCommand("shop").setExecutor(new DqshopCommandExecutor(this));
getCommand("reg").setExecutor(new RegCommandExecutor(this)); // 新增注册命令 getCommand("reg").setExecutor(new RegCommandExecutor(this));
getCommand("login").setExecutor(new LoginCommandExecutor(this)); // 新增登录命令 getCommand("login").setExecutor(new LoginCommandExecutor(this));
getCommand("party").setExecutor(new PartyCommandExecutor(this)); getCommand("party").setExecutor(new PartyCommandExecutor(this));
getCommand("inventory").setExecutor(new InventoryCommandExecutor(this));
getCommand("pc").setExecutor(new PcCommandExecutor(this));
getCommand("msg").setExecutor(new msgCommandExecutor(this));
getCommand("friend").setExecutor(new FriendCommandExecutor(this));
getCommand("point").setExecutor(new PointCommandExecutor(this));
getCommand("selfkill").setExecutor(new KillCommandExecutor(this));
getCommand("land").setExecutor(new LandCommandExecutor(this));
getLogger().info("Survival插件已启用信用分持久化功能加载完成");
} }
@Override @Override
public void onDisable() { public void onDisable() {
// 保存玩家标签数据
playerTags.saveTags(); playerTags.saveTags();
accountManager.saveAccounts(); // 保存账号信息
// Plugin shutdown logic // 保存信用分数据
savePpoint();
// 保存好友数据
try {
FriendCommandExecutor executor = (FriendCommandExecutor) this.getCommand("friend").getExecutor();
if (executor != null) {
executor.saveFriendData();
getLogger().info("好友数据已保存!");
}
} catch (Exception e) {
getLogger().severe("插件卸载时保存好友数据失败:" + e.getMessage());
} }
// 保存账号信息
accountManager.saveAccounts();
getLogger().info("Survival插件已禁用所有数据已保存");
}
// 初始化信用分数据文件
private void initPpointFile() {
// 创建插件数据文件夹(若不存在)
File dataFolder = getDataFolder();
if (!dataFolder.exists()) {
if (dataFolder.mkdirs()) {
getLogger().info("插件数据文件夹创建成功!");
} else {
getLogger().severe("插件数据文件夹创建失败!");
return;
}
}
// 创建信用分文件路径plugins/Survival/ppoint.yml
ppointFile = new File(dataFolder, "ppoint.yml");
if (!ppointFile.exists()) {
try {
if (ppointFile.createNewFile()) {
getLogger().info("信用分数据文件创建成功!");
} else {
getLogger().severe("信用分数据文件创建失败!");
}
} catch (IOException e) {
getLogger().severe("创建信用分文件时发生异常:" + e.getMessage());
}
}
// 加载配置文件
ppointConfig = YamlConfiguration.loadConfiguration(ppointFile);
}
// 保存信用分数据到文件(关键修正处)
public void savePpoint() {
if (ppointConfig == null || ppointFile == null) {
getLogger().severe("信用分配置未初始化,保存失败!");
return;
}
// 修正清空原有配置的正确方式将所有键设为null或移除
for (String key : ppointConfig.getKeys(false)) {
ppointConfig.set(key, null); // 用null覆盖原有值或用 ppointConfig.remove(key) 直接移除键
}
// 将在线玩家的信用分存入配置用UUID作为键参数完整
for (Map.Entry<Player, Integer> entry : ppoint.entrySet()) {
Player player = entry.getKey();
if (player.isOnline()) {
UUID playerUuid = player.getUniqueId();
ppointConfig.set(playerUuid.toString(), entry.getValue()); // 完整参数路径UUID字符串+ 值(信用分)
}
}
// 写入文件
try {
ppointConfig.save(ppointFile);
getLogger().info("信用分数据保存成功!");
} catch (IOException e) {
getLogger().severe("保存信用分数据失败:" + e.getMessage());
}
}
// 加载信用分数据(仅加载在线玩家)
private void loadPpoint() {
if (ppointConfig == null || ppointFile == null) {
getLogger().severe("信用分配置未初始化,加载失败!");
return;
}
// 遍历配置中的所有UUID为在线玩家分配信用分
for (String uuidStr : ppointConfig.getKeys(false)) {
try {
UUID playerUuid = UUID.fromString(uuidStr);
Player player = Bukkit.getPlayer(playerUuid);
if (player != null && player.isOnline()) {
// 读取信用分默认100分
int point = ppointConfig.getInt(uuidStr, 100);
ppoint.put(player, point);
getLogger().info("加载玩家 " + player.getName() + " 的信用分:" + point);
}
} catch (IllegalArgumentException e) {
getLogger().warning("无效的UUID格式" + uuidStr + ",跳过该数据");
}
}
}
// 玩家上线时加载其信用分供JoinEvent/LoginEvent调用
public void loadPlayerPpoint(Player player) {
if (ppointConfig == null) {
getLogger().severe("信用分配置未初始化,无法加载玩家 " + player.getName() + " 的信用分!");
return;
}
UUID playerUuid = player.getUniqueId();
String uuidStr = playerUuid.toString();
// 读取已有信用分无数据则设为默认100分
int point = ppointConfig.getInt(uuidStr, 100);
ppoint.put(player, point);
getLogger().info("玩家 " + player.getName() + " 上线,加载信用分:" + point);
}
// 获取玩家标签管理器
public PlayerTags getPlayerTags() { public PlayerTags getPlayerTags() {
return playerTags; return playerTags;
} }
// 新增获取账号管理器的方法 // 获取账号管理器
public AccountManager getAccountManager() { public AccountManager getAccountManager() {
return accountManager; return accountManager;
} }

View File

@@ -28,6 +28,7 @@ public class HelpCommandExecutor implements CommandExecutor {
sender.sendMessage(ChatColor.GREEN+"/party <参数> <参数> - 队伍"); sender.sendMessage(ChatColor.GREEN+"/party <参数> <参数> - 队伍");
sender.sendMessage(ChatColor.GREEN+"/friend <参数> <参数> - 好友"); sender.sendMessage(ChatColor.GREEN+"/friend <参数> <参数> - 好友");
sender.sendMessage(ChatColor.GREEN+"/msg <内容> - 私聊"); sender.sendMessage(ChatColor.GREEN+"/msg <内容> - 私聊");
sender.sendMessage(ChatColor.GREEN+"/selfkill - 自杀");
sender.sendMessage(ChatColor.YELLOW + "-----------------------------"); sender.sendMessage(ChatColor.YELLOW + "-----------------------------");
return true; return true;
} }

View File

@@ -45,12 +45,14 @@ public class ChooseTagEvent implements Listener {
return; return;
} }
if (!event.getView().getTitle().contains("称号") && !event.getView().getTitle().contains("商城")&& !event.getView().getTitle().contains("背包")) { if (!event.getView().getTitle().contains("称号") && !event.getView().getTitle().contains("商城")&& !event.getView().getTitle().contains("背包")&& !event.getView().getTitle().contains("签到")) {
return; return;
} }
event.setCancelled(true); event.setCancelled(true);
if (event.getView().getTitle().contains("称号")) { if(event.getView().getTitle().contains("签到")){
} else if (event.getView().getTitle().contains("称号")) {
ItemStack clickedItem = event.getCurrentItem(); ItemStack clickedItem = event.getCurrentItem();
if (clickedItem == null || clickedItem.getType() != Material.NAME_TAG) { if (clickedItem == null || clickedItem.getType() != Material.NAME_TAG) {
return; return;

View File

@@ -21,6 +21,12 @@ public class JoinEvent implements Listener {
@EventHandler @EventHandler
private void join(PlayerJoinEvent e) { private void join(PlayerJoinEvent e) {
if(plugin.ppoint.getOrDefault(e.getPlayer(),100) <= 0){
e.getPlayer().kickPlayer(ChatColor.RED+"您好! 您由于 信用分小于 0 ,我们决定对你的账号 "+ e.getPlayer().getName() +" 采取\n"+ChatColor.RED+ChatColor.BOLD+"永久封禁\n"+ChatColor.RED+"措施如果您想解封您的账号请到QQ群 717903781 申诉\n\n"+ChatColor.RED+"如果您对本次处罚不满,请采取以下措施:\n"+ChatColor.YELLOW+"1.如果您对自己的行为"+ChatColor.BOLD+" 问心无愧 "+ChatColor.YELLOW+"请立即向QQ 2213866559 发送解封申请\n"+ChatColor.YELLOW+"2.如果您属实有违规行为,请"+ChatColor.BOLD+"手写"+ChatColor.YELLOW+"一篇 "+ChatColor.BOLD+"100字以上且AIGC合格"+ChatColor.YELLOW+" 的检讨发送到申诉QQ群态度诚恳我们将会对你进行解封");
}
if(plugin.ppoint.getOrDefault(e.getPlayer(),100) == 100){
plugin.ppoint.put(e.getPlayer(),100);
}
PlayerTags playertags = plugin.getPlayerTags(); PlayerTags playertags = plugin.getPlayerTags();
List<String> tags = playertags.getTags(e.getPlayer()); List<String> tags = playertags.getTags(e.getPlayer());
if (!tags.isEmpty() && playertags.getCurrentTag(e.getPlayer()) != -1) { if (!tags.isEmpty() && playertags.getCurrentTag(e.getPlayer()) != -1) {

View File

@@ -45,6 +45,9 @@ commands:
reg: reg:
description: to register an account description: to register an account
usage: /<command> <password> <password> usage: /<command> <password> <password>
pc:
description: chat in a party
usage: /<command> <message>
login: login:
description: to login description: to login
usage: /<command> <password> usage: /<command> <password>
@@ -59,9 +62,27 @@ commands:
msg: msg:
description: private chat with friend description: private chat with friend
usage: /<command> <player> <message> usage: /<command> <player> <message>
qd:
description: qian dao
usage: /<command>
friend: friend:
description: add friend description: add friend
usage: /<command> <add|allow|deny|remove> <player> usage: /<command> <add|allow|deny|remove> <player>
gift:
description: gift
usage: /<command>
aboutme:
description: about you
usage: /<command>
point:
description: change point
usage: /<command> <player> <set|add|remove> <number>
land:
description: change point
usage: /<command> <player> <set|add|remove> <number>
selfkill:
description: self kill
usage: /<command>
permissions: permissions:
permission.settag: permission.settag:
description: Allows setting player tags description: Allows setting player tags